PHP Classes

File: class.ico.php

Recommend this page to a friend!
  Classes of Diogo Resende   Ico   class.ico.php   Download  
File: class.ico.php
Role: Class source
Content type: text/plain
Description: Main class
Class: Ico
Extract graphics from .ico files into PNG images
Author: By
Last change: Once again, thanks to Bob Brown, fixed a bug on palete color order. No need to login to get this update.
Date: 19 years ago
Size: 18,785 bytes
 

Contents

Class file image Download
<?php /** * class.ico.php * * @(#) $Header: /home/jeph/repository/classes/ico/class.ico.php,v 0.1 2005/06/08 15:12:24 jeph Exp $ **/ /** * Class Ico * Open ICO files and extract any size/depth to PNG format * * @author Diogo Resende <me@diogoresende.net> * @version 0.1 * * @method public Ico($path = '') * @method public LoadFile($path) * @method private LoadData($data) * @method public TotalIcons() * @method public GetIconInfo($index) * @method public GetIcon($index) * @method private AllocateColor(&$im, $red, $green, $blue, $alpha = 0) **/ class Ico { /** * Ico::bgcolor * Background color on icon extraction * * @type array(R, G, B) = array(255, 255, 255) * @var public **/ var $bgcolor = array(255, 255, 255); /** * Ico::bgcolor_transparent * Is background color transparent? * * @type boolean = false * @var public **/ var $bgcolor_transparent = false; /** * Ico::Ico() * Class constructor * * @param optional string $path Path to ICO file * @return void **/ function Ico($path = '') { if (strlen($path) > 0) { $this->LoadFile($path); } } /** * Ico::LoadFile() * Load an ICO file (don't need to call this is if fill the * parameter in the class constructor) * * @param string $path Path to ICO file * @return boolean Success **/ function LoadFile($path) { $this->_filename = $path; if (($fp = @fopen($path, 'rb')) !== false) { $data = ''; while (!feof($fp)) { $data .= fread($fp, 4096); } fclose($fp); return $this->LoadData($data); } return false; } /** * Ico::LoadData() * Load an ICO data. If you prefer to open the file * and return the binary data you can use this function * directly. Otherwise use LoadFile() instead. * * @param string $data Binary data of ICO file * @return boolean Success **/ function LoadData($data) { $this->formats = array(); /** * ICO header **/ $icodata = unpack("SReserved/SType/SCount", $data); $this->ico = $icodata; $data = substr($data, 6); /** * Extract each icon header **/ for ($i = 0; $i < $this->ico['Count']; $i ++) { $icodata = unpack("CWidth/CHeight/CColorCount/CReserved/SPlanes/SBitCount/LSizeInBytes/LFileOffset", $data); $icodata['FileOffset'] -= ($this->ico['Count'] * 16) + 6; if ($icodata['ColorCount'] == 0) $icodata['ColorCount'] = 256; $this->formats[] = $icodata; $data = substr($data, 16); } /** * Extract aditional headers for each extracted icon header **/ for ($i = 0; $i < count($this->formats); $i++) { $icodata = unpack("LSize/LWidth/LHeight/SPlanes/SBitCount/LCompression/LImageSize/LXpixelsPerM/LYpixelsPerM/LColorsUsed/LColorsImportant", substr($data, $this->formats[$i]['FileOffset'])); $this->formats[$i]['header'] = $icodata; $this->formats[$i]['colors'] = array(); $this->formats[$i]['BitCount'] = $this->formats[$i]['header']['BitCount']; switch ($this->formats[$i]['BitCount']) { case 32: case 24: $length = $this->formats[$i]['header']['Width'] * $this->formats[$i]['header']['Height'] * ($this->formats[$i]['BitCount'] / 8); $this->formats[$i]['data'] = substr($data, $this->formats[$i]['FileOffset'] + $this->formats[$i]['header']['Size'], $length); break; case 8: case 4: $icodata = substr($data, $this->formats[$i]['FileOffset'] + $icodata['Size'], $this->formats[$i]['ColorCount'] * 4); $offset = 0; for ($j = 0; $j < $this->formats[$i]['ColorCount']; $j++) { $this->formats[$i]['colors'][] = array( 'red' => ord($icodata[$offset]), 'green' => ord($icodata[$offset + 1]), 'blue' => ord($icodata[$offset + 2]), 'reserved' => ord($icodata[$offset + 3]) ); $offset += 4; } $length = $this->formats[$i]['header']['Width'] * $this->formats[$i]['header']['Height'] * (1 + $this->formats[$i]['BitCount']) / $this->formats[$i]['BitCount']; $this->formats[$i]['data'] = substr($data, $this->formats[$i]['FileOffset'] + ($this->formats[$i]['ColorCount'] * 4) + $this->formats[$i]['header']['Size'], $length); break; case 1: $icodata = substr($data, $this->formats[$i]['FileOffset'] + $icodata['Size'], $this->formats[$i]['ColorCount'] * 4); $this->formats[$i]['colors'][] = array( 'blue' => ord($icodata[0]), 'green' => ord($icodata[1]), 'red' => ord($icodata[2]), 'reserved' => ord($icodata[3]) ); $this->formats[$i]['colors'][] = array( 'blue' => ord($icodata[4]), 'green' => ord($icodata[5]), 'red' => ord($icodata[6]), 'reserved' => ord($icodata[7]) ); $length = $this->formats[$i]['header']['Width'] * $this->formats[$i]['header']['Height'] / 8; $this->formats[$i]['data'] = substr($data, $this->formats[$i]['FileOffset'] + $this->formats[$i]['header']['Size'] + 8, $length); break; } $this->formats[$i]['data_length'] = strlen($this->formats[$i]['data']); } return true; } /** * Ico::TotalIcons() * Return the total icons extracted at the moment * * @return integer Total icons **/ function TotalIcons() { return count($this->formats); } /** * Ico::GetIconInfo() * Return the icon header corresponding to that index * * @param integer $index Icon index * @return resource Icon header **/ function GetIconInfo($index) { if (isset($this->formats[$index])) { return $this->formats[$index]; } return false; } /** * Ico::SetBackground() * Changes background color of extraction. You can set * the 3 color components or set $red = '#xxxxxx' (HTML format) * and leave all other blanks. * * @param optional integer $red Red component * @param optional integer $green Green component * @param optional integer $blue Blue component * @return void **/ function SetBackground($red = 255, $green = 255, $blue = 255) { if (is_string($red) && preg_match('/^\#[0-9a-f]{6}$/', $red)) { $green = hexdec($red[3] . $red[4]); $blue = hexdec($red[5] . $red[6]); $red = hexdec($red[1] . $red[2]); } $this->bgcolor = array($red, $green, $blue); } /** * Ico::SetBackgroundTransparent() * Set background color to be saved as transparent * * @param optional boolean $is_transparent Is Transparent or not * @return boolean Is Transparent or not **/ function SetBackgroundTransparent($is_transparent = true) { return ($this->bgcolor_transparent = $is_transparent); } /** * Ico::GetImage() * Return an image resource with the icon stored * on the $index position of the ICO file * * @param integer $index Position of the icon inside ICO * @return resource Image resource **/ function &GetIcon($index) { if (!isset($this->formats[$index])) { return false; } /** * create image **/ $im = imagecreatetruecolor($this->formats[$index]['Width'], $this->formats[$index]['Height']); /** * paint background **/ $bgcolor = $this->AllocateColor($im, $this->bgcolor[0], $this->bgcolor[1], $this->bgcolor[2]); imagefilledrectangle($im, 0 , 0, $this->formats[$index]['Width'], $this->formats[$index]['Height'], $bgcolor); /** * set background color transparent **/ if ($this->bgcolor_transparent) { imagecolortransparent($im, $bgcolor); } /** * allocate pallete and get XOR image **/ if (in_array($this->formats[$index]['BitCount'], array(1, 4, 8, 24))) { if ($this->formats[$index]['BitCount'] != 24) { /** * color pallete **/ $c = array(); for ($i = 0; $i < $this->formats[$index]['ColorCount']; $i++) { $c[$i] = $this->AllocateColor($im, $this->formats[$index]['colors'][$i]['red'], $this->formats[$index]['colors'][$i]['green'], $this->formats[$index]['colors'][$i]['blue'], round($this->formats[$index]['colors'][$i]['reserved'] / 255 * 127)); } } /** * XOR image **/ $width = $this->formats[$index]['Width']; if (($width % 32) > 0) { $width += (32 - ($this->formats[$index]['Width'] % 32)); } $offset = $this->formats[$index]['Width'] * $this->formats[$index]['Height'] * $this->formats[$index]['BitCount'] / 8; $total_bytes = ($width * $this->formats[$index]['Height']) / 8; $bits = ''; $bytes = 0; $bytes_per_line = ($this->formats[$index]['Width'] / 8); $bytes_to_remove = (($width - $this->formats[$index]['Width']) / 8); for ($i = 0; $i < $total_bytes; $i++) { $bits .= str_pad(decbin(ord($this->formats[$index]['data'][$offset + $i])), 8, '0', STR_PAD_LEFT); $bytes++; if ($bytes == $bytes_per_line) { $i += $bytes_to_remove; $bytes = 0; } } } /** * paint each pixel depending on bit count **/ switch ($this->formats[$index]['BitCount']) { case 32: /** * 32 bits: 4 bytes per pixel [ B | G | R | ALPHA ] **/ $offset = 0; for ($i = $this->formats[$index]['Height'] - 1; $i >= 0; $i--) { for ($j = 0; $j < $this->formats[$index]['Width']; $j++) { $color = substr($this->formats[$index]['data'], $offset, 4); if (ord($color[3]) > 0) { $c = $this->AllocateColor($im, ord($color[2]), ord($color[1]), ord($color[0]), 127 - round(ord($color[3]) / 255 * 127)); imagesetpixel($im, $j, $i, $c); } $offset += 4; } } break; case 24: /** * 24 bits: 3 bytes per pixel [ B | G | R ] **/ $offset = 0; $bitoffset = 0; for ($i = $this->formats[$index]['Height'] - 1; $i >= 0; $i--) { for ($j = 0; $j < $this->formats[$index]['Width']; $j++) { if ($bits[$bitoffset] == 0) { $color = substr($this->formats[$index]['data'], $offset, 3); $c = $this->AllocateColor($im, ord($color[2]), ord($color[1]), ord($color[0])); imagesetpixel($im, $j, $i, $c); } $offset += 3; $bitoffset++; } } break; case 8: /** * 8 bits: 1 byte per pixel [ COLOR INDEX ] **/ $offset = 0; for ($i = $this->formats[$index]['Height'] - 1; $i >= 0; $i--) { for ($j = 0; $j < $this->formats[$index]['Width']; $j++) { if ($bits[$offset] == 0) { $color = ord(substr($this->formats[$index]['data'], $offset, 1)); imagesetpixel($im, $j, $i, $c[$color]); } $offset++; } } break; case 4: /** * 4 bits: half byte/nibble per pixel [ COLOR INDEX ] **/ $offset = 0; $maskoffset = 0; $leftbits = true; for ($i = $this->formats[$index]['Height'] - 1; $i >= 0; $i--) { for ($j = 0; $j < $this->formats[$index]['Width']; $j++) { if ($leftbits) { $color = substr($this->formats[$index]['data'], $offset, 1); $color = array( 'High' => bindec(substr(decbin(ord($color)), 0, 4)), 'Low' => bindec(substr(decbin(ord($color)), 4)) ); if ($bits[$maskoffset++] == 0) { imagesetpixel($im, $j, $i, $c[$color['High']]); } $leftbits = false; } else { if ($bits[$maskoffset++] == 0) { imagesetpixel($im, $j, $i, $c[$color['Low']]); } $offset++; $leftbits = true; } } } break; case 1: /** * 1 bit: 1 bit per pixel (2 colors, usually black&white) [ COLOR INDEX ] **/ $colorbits = ''; $total = strlen($this->formats[$index]['data']); for ($i = 0; $i < $total; $i++) { $colorbits .= str_pad(decbin(ord($this->formats[$index]['data'][$i])), 8, '0', STR_PAD_LEFT); } $total = strlen($colorbits); $offset = 0; for ($i = $this->formats[$index]['Height'] - 1; $i >= 0; $i--) { for ($j = 0; $j < $this->formats[$index]['Width']; $j++) { if ($bits[$offset] == 0) { imagesetpixel($im, $j, $i, $c[$colorbits[$offset]]); } $offset++; } } break; } return $im; } /** * Ico::AllocateColor() * Allocate a color on $im resource. This function prevents * from allocating same colors on the same pallete. Instead * if it finds that the color is already allocated, it only * returns the index to that color. * It supports alpha channel. * * @param resource $im Image resource * @param integer $red Red component * @param integer $green Green component * @param integer $blue Blue component * @param optional integer $alphpa Alpha channel * @return integer Color index **/ function AllocateColor(&$im, $red, $green, $blue, $alpha = 0) { $c = imagecolorexactalpha($im, $red, $green, $blue, $alpha); if ($c >= 0) { return $c; } return imagecolorallocatealpha($im, $red, $green, $blue, $alpha); } } ?>