From d1307573d3d75a7a8078c8e2942c44ba6aa63036 Mon Sep 17 00:00:00 2001 From: Jan Tojnar Date: Wed, 10 May 2017 03:16:54 +0200 Subject: [PATCH] Use IcoFileLoader instead of floIcon --- README.md | 2 +- composer.json | 2 +- composer.lock | 53 ++- gruntfile.js | 2 +- helpers/Image.php | 31 +- libs/floIcon.php | 843 ---------------------------------------------- 6 files changed, 78 insertions(+), 855 deletions(-) delete mode 100644 libs/floIcon.php diff --git a/README.md b/README.md index 1e289bcda9..ffacb4c1ca 100644 --- a/README.md +++ b/README.md @@ -88,7 +88,7 @@ Special thanks to the great programmers of this libraries which will be used in * htmLawed: http://www.bioinformatics.org/phplabware/internal_utilities/htmLawed/ * PHP Universal Feed Generator: https://github.com/ajaxray/FeedWriter * twitteroauth: https://github.com/abraham/twitteroauth -* floIcon: https://www.phpclasses.org/package/3906-PHP-Read-and-write-images-from-ICO-files.html +* Elphin IcoFileLoader: https://github.com/lordelph/icofileloader * jQuery hotkeys: https://github.com/tzuryby/jquery.hotkeys * jsmin: https://github.com/rgrove/jsmin-php * cssmin: https://code.google.com/archive/p/cssmin diff --git a/composer.json b/composer.json index 801fa2042a..b72779b7e8 100644 --- a/composer.json +++ b/composer.json @@ -10,6 +10,7 @@ "htmlawed/htmlawed": "^1.1", "j0k3r/graby": "^1.6", "linkorb/jsmin-php": "^1.0", + "lordelph/icofileloader": "^1.0", "mibe/feedwriter": "^1.0", "monolog/monolog": "^1.0", "natxet/CssMin": "^3.0", @@ -30,7 +31,6 @@ "controllers/", "daos/", "helpers/", - "libs/", "spouts/" ] }, diff --git a/composer.lock b/composer.lock index 23086cfe18..346de484c1 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "content-hash": "1ea86fe032fd37e5d2eaa7de2879b9a9", + "content-hash": "ac4ed0da52d7e0760ae190f54a523e7b", "packages": [ { "name": "bcosca/fatfree-core", @@ -624,6 +624,57 @@ ], "time": "2013-03-15T13:16:35+00:00" }, + { + "name": "lordelph/icofileloader", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/lordelph/icofileloader.git", + "reference": "c5994a348068be137cf127d1345b8781dffac0fe" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/lordelph/icofileloader/zipball/c5994a348068be137cf127d1345b8781dffac0fe", + "reference": "c5994a348068be137cf127d1345b8781dffac0fe", + "shasum": "" + }, + "require": { + "ext-gd": "*", + "php": ">=5.4.0" + }, + "require-dev": { + "jakub-onderka/php-parallel-lint": "dev-master", + "phpunit/phpunit": "~5 || ~4", + "squizlabs/php_codesniffer": "^2.3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Elphin\\IcoFileLoader\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Paul Dixon", + "email": "paul@elphin.com" + } + ], + "description": "High quality PHP package for reading and converting any .ico icon file, particularly website favicons", + "homepage": "http://icofileloader.dixo.net/", + "keywords": [ + "convert", + "extract", + "favicon", + "ico", + "icon", + "load" + ], + "time": "2017-05-14T20:00:45+00:00" + }, { "name": "mibe/feedwriter", "version": "v1.1.1", diff --git a/gruntfile.js b/gruntfile.js index 3cc602d461..7d6a9c5496 100644 --- a/gruntfile.js +++ b/gruntfile.js @@ -5,6 +5,7 @@ function isNotUnimportant(dest) { const filenameDisallowed = [ /^changelog/i, + /^contributing/i, /^copying/i, /^readme/i, /^licen[cs]e/i, @@ -85,7 +86,6 @@ module.exports = function(grunt) { { expand: true, cwd: 'controllers/', src: ['**'], dest: '/controllers'}, { expand: true, cwd: 'daos/', src: ['**'], dest: '/daos'}, { expand: true, cwd: 'helpers/', src: ['**'], dest: '/helpers'}, - { expand: true, cwd: 'libs/', src: ['**'], dest: '/libs'}, { expand: true, cwd: 'vendor/', src: ['**'], dest: '/vendor', filter: isNotUnimportant}, // public = don't zip all.js and all.css diff --git a/helpers/Image.php b/helpers/Image.php index 8001993806..8f9f35a774 100644 --- a/helpers/Image.php +++ b/helpers/Image.php @@ -2,6 +2,7 @@ namespace helpers; +use Elphin\IcoFileLoader\IcoFileService; use WideImage\WideImage; /** @@ -116,28 +117,42 @@ public function loadImage($url, $extension = 'png', $width = false, $height = fa } elseif (strtolower($imgInfo['mime']) == 'image/x-ms-bmp') { $type = 'bmp'; } else { - @unlink($tmp); - return false; } // convert ico to png if ($type == 'ico') { - $ico = new \floIcon(); - @$ico->readICO($tmp); - if (count($ico->images) == 0) { - @unlink($tmp); + $loader = new IcoFileService(); + try { + $icon = $loader->fromString($data); + } catch (\InvalidArgumentException $e) { + \F3::get('logger')->error("Icon “{$url}” is not valid", ['exception' => $e]); + + return false; + } + + $image = null; + if ($width !== false && $height !== false) { + $image = $icon->findBestForSize($width, $height); + } + + if ($image === null) { + $image = $icon->findBest(); + } + if ($image === null) { return false; } + + $data = $loader->renderImage($image); + ob_start(); - @imagepng($ico->images[count($ico->images) - 1]->getImageResource()); + imagepng($data); $data = ob_get_contents(); ob_end_clean(); } // parse image for saving it later - @unlink($tmp); try { $wideImage = WideImage::load($data); } catch (\Exception $e) { diff --git a/libs/floIcon.php b/libs/floIcon.php deleted file mode 100644 index 19b73216b1..0000000000 --- a/libs/floIcon.php +++ /dev/null @@ -1,843 +0,0 @@ -images array by order of size, smallest to largest. - This is the optimal sorting for icon files. - - countImages() - Returns a count of how many images are present in the current floIcon - object. - -floIcon public variables: - $images - Contains a numerically indexed array of floIconImage objects. - $updated - True if an image has been added since load or last formatICO, otherwise - false. - -floIconImage public functions: - getHeader() - Returns an associative array containing the information from the ICO - image header. - - getEntry() - Returns an associative array containing the information from the ICO - entry header. - - NOTE: If this icon image was created by php image resource, this may not - have accurate information until saving from floIcon with the formatICO() - function. Specifically, offset information will be inaccurate. - - getImageResource() - Returns a php image resource. Same as floIcon's getImage() function. - - setImageResource($imageResource, $desiredBitCount = 1, $pngIfWidthExceeds = 48) - Changes this icon image based on the passed image resource - ($imageResource). It will automatically determine the bit count, but can - be persuaded to increase that to $desiredBitCount if that value is - greater than the determined bit count. - - NOTE: The image resource is saved by REFERRENCE. So, if you edit it - then call getImageResource, the resource returned will be the same, - editions and all. Destruction of the resource will cause a new resource - to be created in getImageResource(). - - dealocateResource() - This destroys the image resource variable, freeing up memory. The image - will automatically be recreated when getImageResource is executed. -*/ -class floIcon { - /* - * $images is an associative array of offset integer => floIconImage object - */ - var $images; // Array of floIconImage objects. - var $updated = false; - function __construct() { - $this->images = array(); - } - function countImages() { - return count($this->images); - } - function getBestImage($height = 32, $width = 32) { - $best = false; - $bestEntry = array(); - $secondBest = false; - $secondBestEntry = array(); - foreach ($this->images as $key => $image) { - $entry = $image->getEntry(); - $header = $image->getHeader(); - if (!@$entry["BitCount"]) { - $entry["BitCount"] = $header["BitCount"]; - } - if ($entry["Height"] == $height && $entry["Width"] == $width && $entry["BitCount"] == 32) { - return $image->getImageResource(); - } elseif ($entry["Height"] == $height && $entry["Width"] == $width && $entry["BitCount"] > min(4, @$bestEntry["BitCount"])) { - $best = $image; - $bestEntry = $entry; - } elseif ( - !$secondBest or - $entry["Height"] >= $secondBestEntry["Height"] && - $entry["Width"] >= $secondBestEntry["Width"] && - $secondBestEntry["BitCount"] >= $secondBestEntry["BitCount"] and - ( - $entry["Height"] <= 64 && $entry["Height"] > $secondBestEntry["Height"] and - $entry["Height"] > 64 && $entry["Height"] < $secondBestEntry["Height"] - ) || - ( - $entry["Width"] <= 64 && $entry["Width"] > $secondBestEntry["Width"] and - $entry["Width"] > 64 && $entry["Width"] < $secondBestEntry["Width"] - ) || - $secondBestEntry["BitCount"] > $secondBestEntry["BitCount"] - ) { - $secondBest = $image; - $secondBestEntry = $entry; - } - } - if ($best) { - return $best->getImageResource(); - } elseif ($secondBest) { - if ($secondBestEntry["Width"] != $width || $secondBestEntry["Height"] != $height) { - $imageResource = $secondBest->getImageResource(); - $newImageResource = imagecreatetruecolor($width, $height); - imagesavealpha($newImageResource, true); - imagealphablending($newImageResource, false); - imagecopyresampled($newImageResource, $imageResource, 0, 0, 0, 0, $width, $height, $secondBestEntry["Width"], $secondBestEntry["Height"]); - $this->addImage($newImageResource, 32); - return $newImageResource; - } else { - return $secondBest->getImageResource(); - } - } - } - /* - * readICO merges the icon images from the file to the current list - */ - function readICO($file, $offset = 0) { - if (file_exists($file) && filesize($file) > 0 && $filePointer = fopen($file, "r")) { - fseek($filePointer, $offset); - $header = unpack("vReserved/vType/vCount", fread($filePointer, 6)); - for ($t = 0; $t < $header["Count"]; $t++) { - $newImage = new floIconImage(); - $newImage->readImageFromICO($filePointer, 6 + ($t * 16)); - $this->images[] = $newImage; - } - fclose($filePointer); - } - } - function sortImagesBySize() { - usort($this->images, array("floIcon", "_cmpObj")); - } - function formatICO($offset = 0) { - $this->updated = false; - $output = ""; - $output .= pack("SSS", 0, 1, count($this->images)); - $output_images = ""; - foreach ($this->images as $image) { - $newImageOffset = $offset + // Whatever offset we've been given. - 6 // Header. - + (count($this->images) * 16) // Entries. - + strlen($output_images); - if ($newImageOffset > pow(256, 4) /* 4 bytes available for position */ ) { - return false; - } - $output .= $image->formatEntryForIco($newImageOffset); // The images already in there. - $output_images .= $image->formatImageForIco(); - } - return $output.$output_images; - } - function _cmpObj($a, $b) { - $aSize = $a->getSize(); - $bSize = $b->getSize(); - if ($aSize == $bSize) { - return 0; - } - return ($aSize > $bSize)?1:-1; - } - - function addImage($imageResource, $desiredBitCount = 1, $pngIfWidthExceeds = 48) { - $this->updated = true; - $newImage = new floIconImage(); - $newImage->setImageResource($imageResource, $desiredBitCount, $pngIfWidthExceeds); - $this->images[] = $newImage; - } - function getImage($offset) { - if (isset($this->images[$offset])) { - return $this->images[$offset]->getImageResource(); - } else { - return false; - } - } - /* - * getSize computes the - */ - function getSize() { - // Compute headers. - $computedSize = 6; // Always 6 bytes. - // Add image entry headers - $computedSize += count($this->images) * 16; // Entry headers are always 16 bytes. - foreach ($this->images as $image) { - $computedSize += $image->getSize() + $image->getHeaderSize(); // getSize does not include the header. - } - } -} -class floIconImage { - var $_imageResource = null; - var $_entry = ""; - var $_entryIconFormat = ""; - var $_header = ""; - var $_headerIconFormat = ""; - var $_imageIconFormat = ""; // Includes palette and mask. - function formatEntryForIco($offset) { - // Format the entry, this has to be done here because we need the offset to get the full information. - $this->_entry["FileOffset"] = $offset; - $this->_entryIconFormat = pack("CCCCSSLL", - $this->_entry["Width"]>=256?0:$this->_entry["Width"], - $this->_entry["Height"]>=256?0:$this->_entry["Height"], - $this->_entry["ColorCount"], - $this->_entry["Reserved"], - $this->_entry["Planes"], - $this->_entry["BitCount"], - $this->_entry["SizeInBytes"], - $this->_entry["FileOffset"] - ); - return $this->_entryIconFormat; - } - function formatImageForIco() { - // Format the entry, this has to be done here because we need the offset to get the full information. - return ($this->_headerIconFormat.$this->_imageIconFormat); - } - - // Will move $bitCount UP to $desiredBitCount if $bitCount is found to be less than it. - function setImageResource($imageResource, $desiredBitCount = 1, $pngIfWidthExceeds = 48) { - imagesavealpha($imageResource, true); - imagealphablending($imageResource, false); - $height = imagesy($imageResource); - $width = imagesx($imageResource); - - // Parse resource to determine header and icon format - - // Find Palette information - $is_32bit = false; // Start with an assumption and get proven wrong. - $hasTransparency = 0; - $blackColor = false; - $bitCount = 0; - $realPalette = array(); - $realIndexPalette = array(); - for ($x = 0; $x < $width && !$is_32bit; $x++) { - for ($y = 0; $y < $height && !$is_32bit; $y++) { - $colorIndex = imagecolorat($imageResource, $x, $y); - $color = imagecolorsforindex($imageResource, $colorIndex); - if ($color["alpha"] == 0) { - // No point continuing if there's more than 256 colors or it's 32bit. - if (count($realPalette) < 257 && !$is_32bit) { - $inRealPalette = false; - foreach($realPalette as $realPaletteKey => $realPaletteColor) { - if ( - $color["red"] == $realPaletteColor["red"] and - $color["green"] == $realPaletteColor["green"] and - $color["blue"] == $realPaletteColor["blue"] - ) { - $inRealPalette = $realPaletteKey; - break; - } - } - if ($inRealPalette === false) { - $realIndexPalette[$colorIndex] = count($realPalette); - if ( - $blackColor === false and - $color["red"] == 0 and - $color["green"] == 0 and - $color["blue"] == 0 - ) { - $blackColor = count($realPalette); - } - $realPalette[] = $color; - } else { - $realIndexPalette[$colorIndex] = $inRealPalette; - } - } - } else { - $hasTransparency = 1; - } - if ($color["alpha"] != 0 && $color["alpha"] != 127) { - $is_32bit = true; - } - } - } - if ($is_32bit) { - $colorCount = 0; - $bitCount = 32; - } else { - if ($hasTransparency && $blackColor === false) { - // We need a black color to facilitate transparency. Unfortunately, this can - // increase the palette size by 1 if there's no other black color. - $blackColor = count($realPalette); - $color = array( - "red" => 0, - "blue" => 0, - "green" => 0, - "alpha" => 0 - ); - $realPalette[] = $color; - } - $colorCount = count($realPalette); - if ($colorCount > 256 || $colorCount == 0) { - $bitCount = 24; - } elseif ($colorCount > 16) { - $bitCount = 8; - // 8 bit - } elseif ($colorCount > 2) { - $bitCount = 4; - // 4 bit - } else { - $bitCount = 1; - // 1 bit - } - if ($desiredBitCount > $bitCount) { - $bitCount = $desiredBitCount; - } - switch ($bitCount) { - case 24: - $colorCount = 0; - break; - case 8: - $colorCount = 256; - break; - case 4: - $colorCount = 16; - break; - case 1: - $colorCount = 2; - break; - } - } - // Create $this->_imageIconFormat... - $this->_imageIconFormat = ""; - if ($bitCount < 24) { - $iconPalette = array(); - // Save Palette - foreach ($realIndexPalette as $colorIndex => $paletteIndex) { - $color = $realPalette[$paletteIndex]; - $this->_imageIconFormat .= pack("CCCC", $color["blue"], $color["green"], $color["red"], 0); - } - while (strlen($this->_imageIconFormat) < $colorCount * 4) { - $this->_imageIconFormat .= pack("CCCC", 0, 0, 0, 0); - } - // Save Each Pixel as Palette Entry - $byte = 0; // For $bitCount < 8 math - $bitPosition = 0; // For $bitCount < 8 math - for ($y = 0; $y < $height; $y++) { - for ($x = 0; $x < $width; $x++) { - $color = imagecolorat($imageResource, $x, $height-$y-1); - if (isset($realIndexPalette[$color])) { - $color = $realIndexPalette[$color]; - } else { - $color = $blackColor; - } - - if ($bitCount < 8) { - $bitPosition += $bitCount; - $colorAdjusted = $color * pow(2, 8 - $bitPosition); - $byte += $colorAdjusted; - if ($bitPosition == 8) { - $this->_imageIconFormat .= chr($byte); - $bitPosition = 0; - $byte = 0; - } - } else { - $this->_imageIconFormat .= chr($color); - } - } - // Each row ends with dumping the remaining bits and filling up to the 32bit line with 0's. - if ($bitPosition) { - $this->_imageIconFormat .= chr($byte); - $bitPosition = 0; - $byte = 0; - } - if (strlen($this->_imageIconFormat)%4) $this->_imageIconFormat .= str_repeat(chr(0), 4-(strlen($this->_imageIconFormat)%4)); - } - } else { - // Save each pixel. - for ($y = 0; $y < $height; $y++) { - for ($x = 0; $x < $width; $x++) { - $color = imagecolorat($imageResource, $x, $height-$y-1); - $color = imagecolorsforindex($imageResource, $color); - if ($bitCount == 24) { - if ($color["alpha"]) { - $this->_imageIconFormat .= pack("CCC", 0, 0, 0); - } else { - $this->_imageIconFormat .= pack("CCC", $color["blue"], $color["green"], $color["red"]); - } - } else { - $color["alpha"] = round((127-$color["alpha"]) / 127 * 255); - $this->_imageIconFormat .= pack("CCCC", $color["blue"], $color["green"], $color["red"], $color["alpha"]); - } - } - if (strlen($this->_imageIconFormat)%4) $this->_imageIconFormat .= str_repeat(chr(0), 4-(strlen($this->_imageIconFormat)%4)); - } - } - // save AND map (transparency) - $byte = 0; // For $bitCount < 8 math - $bitPosition = 0; // For $bitCount < 8 math - for ($y = 0; $y < $height; $y++) { - for ($x = 0; $x < $width; $x++) { - if ($bitCount < 32) { - $color = imagecolorat($imageResource, $x, $height-$y-1); - $color = imagecolorsforindex($imageResource, $color); - $color = $color["alpha"] == 127?1:0; - } else { - $color = 0; - } - - $bitPosition += 1; - $colorAdjusted = $color * pow(2, 8 - $bitPosition); - $byte += $colorAdjusted; - if ($bitPosition == 8) { - $this->_imageIconFormat .= chr($byte); - $bitPosition = 0; - $byte = 0; - } - } - // Each row ends with dumping the remaining bits and filling up to the 32bit line with 0's. - if ($bitPosition) { - $this->_imageIconFormat .= chr($byte); - $bitPosition = 0; // For $bitCount < 8 math - $byte = 0; - } - while (strlen($this->_imageIconFormat)%4) { - $this->_imageIconFormat .= chr(0); - } - } - if ($colorCount >= 256) { - $colorCount = 0; - } - // Create header information... - $this->_header = array( - "Size" => 40, - "Width" => $width, - "Height" => $height*2, - "Planes" => 1, - "BitCount" => $bitCount, - "Compression" => 0, - "ImageSize" => strlen($this->_imageIconFormat), - "XpixelsPerM" => 0, - "YpixelsPerM" => 0, - "ColorsUsed" => $colorCount, - "ColorsImportant" => 0, - ); - $this->_headerIconFormat = pack("LLLSSLLLLLL", - $this->_header["Size"], - $this->_header["Width"], - $this->_header["Height"], - - $this->_header["Planes"], - $this->_header["BitCount"], - - $this->_header["Compression"], - $this->_header["ImageSize"], - $this->_header["XpixelsPerM"], - $this->_header["YpixelsPerM"], - $this->_header["ColorsUsed"], - $this->_header["ColorsImportant"] - ); - $this->_entry = array( - "Width" => $width, - "Height" => $height, - "ColorCount" => $colorCount, - "Reserved" => 0, - "Planes" => 1, - "BitCount" => $bitCount, - "SizeInBytes" => $this->_header["Size"] + $this->_header["ImageSize"], - "FileOffset" => -1, - ); - $this->_entryIconFormat = ""; // This won't get set until it's needed with the offset. - $this->_imageResource = $imageResource; - - // Make png if width exceeds limit for old ico style - if ($width > $pngIfWidthExceeds) { - // I wish there were a better way to get the info than this. If anyone needs a version that doesn't use OB, I can have one that creates a TMP file. - ob_start(); - imagepng($imageResource); - $imageAsPng = ob_get_contents(); - ob_end_clean(); - $this->_headerIconFormat = ""; - $this->_imageIconFormat = $imageAsPng; - } - - - } - function _createImageResource() { - if ($newImage = @imagecreatefromstring($this->_headerIconFormat.$this->_imageIconFormat)) { - // Vista supports PNG. - $this->_headerIconFormat = ""; - $this->_imageIconFormat = $this->_headerIconFormat.$this->_imageIconFormat; - imagesavealpha($newImage, true); - imagealphablending($newImage, false); - $this->_imageResource = $newImage; - } elseif ($this->_entry["Height"] <= 1024 && $this->_entry["Width"] <= 1024) { - $newImage = imagecreatetruecolor($this->_entry["Width"], $this->_entry["Height"]); - imagesavealpha($newImage, true); - imagealphablending($newImage, false); - $readPosition = 0; - $palette = array(); - if ($this->_header["BitCount"] < 24) { - // Read Palette for low bitcounts - $colorsInPalette = $this->_header["ColorsUsed"]?$this->_header["ColorsUsed"]:$this->_entry["ColorCount"]; - for ($t = 0; $t < pow(2, $this->_header["BitCount"]); $t++) { - $blue = ord($this->_imageIconFormat[$readPosition++]); - $green = ord($this->_imageIconFormat[$readPosition++]); - $red = ord($this->_imageIconFormat[$readPosition++]); - $readPosition++; // Unused "Reserved" value. - $existingPaletteEntry = imagecolorexactalpha($newImage, $red, $green, $blue, 0); - if ($existingPaletteEntry >= 0) { - $palette[] = $existingPaletteEntry; - } else { - $palette[] = imagecolorallocatealpha($newImage, $red, $green, $blue, 0); - } - } - // XOR - for ($y = 0; $y < $this->_entry["Height"]; $y++) { - $colors = array(); - for ($x = 0; $x < $this->_entry["Width"]; $x++) { - if ($this->_header["BitCount"] < 8) { - $color = array_shift($colors); - if (is_null($color)) { - $byte = ord($this->_imageIconFormat[$readPosition++]); - $tmp_color = 0; - for ($t = 7; $t >= 0; $t--) { - $bit_value = pow(2, $t); - $bit = floor($byte / $bit_value); - $byte = $byte - ($bit * $bit_value); - $tmp_color += $bit * pow(2, $t%$this->_header["BitCount"]); - if ($t%$this->_header["BitCount"] == 0) { - array_push($colors, $tmp_color); - $tmp_color = 0; - } - } - $color = array_shift($colors); - } - } else { - $color = ord($this->_imageIconFormat[$readPosition++]); - } - imagesetpixel($newImage, $x, $this->_entry["Height"]-$y-1, $palette[$color]) or die("can't set pixel"); - } - // All rows end on the 32 bit - if ($readPosition%4) $readPosition += 4-($readPosition%4); - } - } else { - // BitCount >= 24, No Palette. - // marking position because some icons mark all pixels transparent when using an AND map. - $markPosition = $readPosition; - $retry = true; - $ignoreAlpha = false; - while ($retry) { - $alphas = array(); - $retry = false; - for ($y = 0; $y < $this->_entry["Height"] and !$retry; $y++) { - for ($x = 0; $x < $this->_entry["Width"] and !$retry; $x++) { - $blue = ord($this->_imageIconFormat[$readPosition++]); - $green = ord($this->_imageIconFormat[$readPosition++]); - $red = ord($this->_imageIconFormat[$readPosition++]); - if ($this->_header["BitCount"] < 32) { - $alpha = 0; - } elseif($ignoreAlpha) { - $alpha = 0; - $readPosition++; - } else { - $alpha = ord($this->_imageIconFormat[$readPosition++]); - $alphas[$alpha] = $alpha; - $alpha = 127-round($alpha/255*127); - } - $paletteEntry = imagecolorexactalpha($newImage, $red, $green, $blue, $alpha); - if ($paletteEntry < 0) { - $paletteEntry = imagecolorallocatealpha($newImage, $red, $green, $blue, $alpha); - } - imagesetpixel($newImage, $x, $this->_entry["Height"]-$y-1, $paletteEntry) or die("can't set pixel"); - } - if ($readPosition%4) $readPosition += 4-($readPosition%4); - } - if ($this->_header["BitCount"] == 32 && isset($alphas[0]) && count($alphas) == 1) { - $retry = true; - $readPosition = $markPosition; - $ignoreAlpha = true; - } - } - - } - // AND map - if ($this->_header["BitCount"] < 32 || $ignoreAlpha) { - // Bitcount == 32, No AND (if using alpha). - $palette[-1] = imagecolorallocatealpha($newImage, 0, 0, 0, 127); - imagecolortransparent($newImage, $palette[-1]); - for ($y = 0; $y < $this->_entry["Height"]; $y++) { - $colors = array(); - for ($x = 0; $x < $this->_entry["Width"]; $x++) { - $color = array_shift($colors); - if (is_null($color)) { - $byte = ord($this->_imageIconFormat[$readPosition++]); - $tmp_color = 0; - for ($t = 7; $t >= 0; $t--) { - $bit_value = pow(2, $t); - $bit = floor($byte / $bit_value); - $byte = $byte - ($bit * $bit_value); - array_push($colors, $bit); - } - $color = array_shift($colors); - } - if ($color) { - imagesetpixel($newImage, $x, $this->_entry["Height"]-$y-1, $palette[-1]) or die("can't set pixel"); - } - } - // All rows end on the 32 bit. - if ($readPosition%4) $readPosition += 4-($readPosition%4); - } - } - if ($this->_header["BitCount"] < 24) { - imagetruecolortopalette($newImage, true, pow(2, $this->_header["BitCount"])); - } - } - $this->_imageResource = $newImage; - } - // this function expects that $_entry, $_header and $_imageIconFormat have already been read, specifically from readImageFromICO. - // Don't call this function except from there. - function readImageFromICO($filePointer, $entryOffset) { - $tmpPosition = ftell($filePointer); // So any other applications won't loose their position. - // Get the entry. - fseek($filePointer, $entryOffset); - $this->_entryIconFormat = fread($filePointer, 16); - $this->_entry = unpack("CWidth/CHeight/CColorCount/CReserved/vPlanes/vBitCount/VSizeInBytes/VFileOffset", $this->_entryIconFormat); - - // Position the file pointer. - fseek($filePointer, $this->_entry["FileOffset"]); - - // Get the header. - $this->_headerIconFormat = fread($filePointer, 40); - $this->_header = unpack("VSize/VWidth/VHeight/vPlanes/vBitCount/VCompression/VImageSize/VXpixelsPerM/VYpixelsPerM/VColorsUsed/VColorsImportant", $this->_headerIconFormat); - - // Get the image. - $this->_imageIconFormat = @fread($filePointer, $this->_entry["SizeInBytes"] - strlen($this->_headerIconFormat)); - fseek($filePointer, $tmpPosition); // So any other applications won't loose their position. - - if ($newImage = @imagecreatefromstring($this->_headerIconFormat.$this->_imageIconFormat)) { - // This is a PNG, the supposed header information is useless. - $this->_header = array ( - "Size" => 0, - "Width" => imagesx($newImage), - "Height" => imagesy($newImage) * 2, - "Planes" => 0, - "BitCount" => 32, - "Compression" => 0, - "ImageSize" => strlen($this->_imageIconFormat), - "XpixelsPerM" => 0, - "YpixelsPerM" => 0, - "ColorsUsed" => 0, - "ColorsImportant" => 0, - ); - imagedestroy($newImage); - } - - // Support for larger images requires entry marked as 0. - if ($this->_entry["Width"] == 0) { - $this->_entry["Width"] = $this->_header["Width"]; - } - if ($this->_entry["Height"] == 0) { - $this->_entry["Height"] = $this->_header["Height"]/2; - } - } - function getHeader() { - return $this->_header; - } - function getEntry() { - return $this->_entry; - } - function __construct() { - } - function getHeaderSize() { - return strlen($this->_headerIconFormat); - } - function getSize() { - return strlen($this->_imageIconFormat); - } - function getImageResource() { - if (!$this->_imageResource) $this->_createImageResource(); - return $this->_imageResource; - } - function dealocateResource() { - @imagedestroy($this->_imageResource); - $this->_imageResource = null; - } -} -?> \ No newline at end of file