Make WordPress Core

Ticket #16434: ico2_3.2.php

File ico2_3.2.php, 29.8 KB (added by Otto42, 13 years ago)

Re-formatted version of the ico library which isn't so painful to read.

Line 
1<?php
2/**
3 * @package com.jpexs.image.ico
4 *
5 * JPEXS ICO Image functions
6 * @version 2.3
7 * @author JPEXS
8 * @copyright (c) JPEXS 2004-2012
9 *
10 * Webpage: http://www.jpexs.com
11 * Email: jpexs@jpexs.com
12 *
13 * If you like my script, you can donate... visit my webpages or email me for more info.
14 *
15 *        Version changes:
16 *          2012-02-25 v2.3 - License changed to GNU/GPL v2 or v3
17 *          2012-02-18 v2.2 - License changed to GNU/GPL v3
18 *          2009-02-23 v2.1 - redesigned sourcecode, phpdoc included, all internal functions and global variables have prefix "jpexs_"
19 *                     v2.0 - For icons with Alpha channel now you can set background color
20 *                          - ImageCreateFromExeIco added
21 *                          - Fixed ICO_MAX_SIZE and ICO_MAX_COLOR values
22 *
23 * TODO list:
24 *      - better error handling
25 *      - better internal function handling
26 *      - class encapsulation
27 *
28 * License:
29 *  This program is free software: you can redistribute it and/or modify
30 *  it under the terms of the GNU General Public License as published by
31 *  the Free Software Foundation, either version 2 or version 3 of the License, or
32 *  (at your option) any later version.
33 *
34 *  This program is distributed in the hope that it will be useful,
35 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
36 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
37 *  GNU General Public License for more details.
38 *
39 *  You should have received a copy of the GNU General Public License
40 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
41 */
42
43/** TrueColor images constant  */
44define( "ICO_TRUE_COLOR", 0x1000000 );
45/** XPColor images constant (Alpha channel) */
46define( "ICO_XP_COLOR", 4294967296 );
47/** Image with maximum colors */
48define( "ICO_MAX_COLOR", -2 );
49/** Image with maximal size */
50define( "ICO_MAX_SIZE", -2 );
51
52
53/** TrueColor images constant
54 * @deprecated Deprecated since version 2.1, please use ICO_ constants
55 */
56define( "TRUE_COLOR", 0x1000000 );
57/** XPColor images constant (Alpha channel)
58 * @deprecated Deprecated since version 2.1, please use ICO_ constants
59 */
60define( "XP_COLOR", 4294967296 );
61/** Image with maximum colors
62 * @deprecated Deprecated since version 2.1, please use ICO_ constants
63 */
64define( "MAX_COLOR", -2 );
65/** Image with maximal size
66 * @deprecated Deprecated since version 2.1, please use ICO_ constants
67 */
68define( "MAX_SIZE", -2 );
69
70
71/**
72 * Reads image from a ICO file
73 *
74 * @param string $filename Target ico file to load
75 * @param int $icoColorCount Icon color count (For multiple icons ico file) - 2,16,256, ICO_TRUE_COLOR, ICO_XP_COLOR or ICO_MAX_COLOR
76 * @param int $icoSize Icon width (For multiple icons ico file) or ICO_MAX_SIZE
77 * @param int $alphaBgR Background color R value for alpha-channel images (Default is White)
78 * @param int $alphaBgG Background color G value for alpha-channel images (Default is White)
79 * @param int $alphaBgB Background color B value for alpha-channel images (Default is White)
80 * @return resource Image resource
81 */
82function imageCreateFromIco( $filename, $icoColorCount = 16, $icoSize = 16, $alphaBgR = 255, $alphaBgG = 255, $alphaBgB = 255 ) {
83        $Ikona = jpexs_GetIconsInfo( $filename );
84       
85        $IconID = -1;
86       
87        $ColMax = -1;
88        $SizeMax = -1;
89       
90        for ( $p = 0; $p < count( $Ikona ); $p++ ) {
91                $Ikona[ $p ][ "NumberOfColors" ] = pow( 2, $Ikona[ $p ][ "Info" ][ "BitsPerPixel" ] );
92        }
93       
94       
95        for ( $p = 0; $p < count( $Ikona ); $p++ ) {
96                if ( ( $ColMax == -1 ) or ( $Ikona[ $p ][ "NumberOfColors" ] >= $Ikona[ $ColMax ][ "NumberOfColors" ] ) )
97                        if ( ( $icoSize == $Ikona[ $p ][ "Width" ] ) or ( $icoSize == ICO_MAX_SIZE ) ) {
98                                $ColMax = $p;
99                        }
100               
101                if ( ( $SizeMax == -1 ) or ( $Ikona[ $p ][ "Width" ] >= $Ikona[ $SizeMax ][ "Width" ] ) )
102                        if ( ( $icoColorCount == $Ikona[ $p ][ "NumberOfColors" ] ) or ( $icoColorCount == ICO_MAX_COLOR ) ) {
103                                $SizeMax = $p;
104                        }
105               
106               
107                if ( $Ikona[ $p ][ "NumberOfColors" ] == $icoColorCount )
108                        if ( $Ikona[ $p ][ "Width" ] == $icoSize ) {
109                                $IconID = $p;
110                        }
111        }
112       
113        if ( $icoColorCount == ICO_MAX_COLOR )
114                $IconID = $ColMax;
115        if ( $icoSize == ICO_MAX_SIZE )
116                $IconID = $SizeMax;
117       
118        $ColName = $icoColorCount;
119       
120        if ( $icoSize == ICO_MAX_SIZE )
121                $icoSize = "Max";
122        if ( $ColName == ICO_TRUE_COLOR )
123                $ColName = "True";
124        if ( $ColName == ICO_XP_COLOR )
125                $ColName = "XP";
126        if ( $ColName == ICO_MAX_COLOR )
127                $ColName = "Max";
128        if ( $IconID == -1 )
129                die( "Icon with $ColName colors and $icoSize x $icoSize size doesn't exist in this file!" );
130       
131       
132        jpexs_readIcon( $filename, $IconID, $Ikona );
133       
134        $biBitCount = $Ikona[ $IconID ][ "Info" ][ "BitsPerPixel" ];
135       
136       
137        if ( $Ikona[ $IconID ][ "Info" ][ "BitsPerPixel" ] == 0 ) {
138                $Ikona[ $IconID ][ "Info" ][ "BitsPerPixel" ] = 24;
139        }
140       
141        $biBitCount = $Ikona[ $IconID ][ "Info" ][ "BitsPerPixel" ];
142        if ( $biBitCount == 0 )
143                $biBitCount = 1;
144       
145       
146        $Ikona[ $IconID ][ "BitCount" ] = $Ikona[ $IconID ][ "Info" ][ "BitsPerPixel" ];
147       
148       
149       
150        if ( $Ikona[ $IconID ][ "BitCount" ] >= 24 ) {
151                $img = imagecreatetruecolor( $Ikona[ $IconID ][ "Width" ], $Ikona[ $IconID ][ "Height" ] );
152                if ( $Ikona[ $IconID ][ "BitCount" ] == 32 ):
153                        $backcolor = imagecolorallocate( $img, $alphaBgR, $alphaBgG, $alphaBgB );
154                        imagefilledrectangle( $img, 0, 0, $Ikona[ $IconID ][ "Width" ] - 1, $Ikona[ $IconID ][ "Height" ] - 1, $backcolor );
155                endif;
156                for ( $y = 0; $y < $Ikona[ $IconID ][ "Height" ]; $y++ )
157                        for ( $x = 0; $x < $Ikona[ $IconID ][ "Width" ]; $x++ ) {
158                                $R = $Ikona[ $IconID ][ "Data" ][ $x ][ $y ][ "r" ];
159                                $G = $Ikona[ $IconID ][ "Data" ][ $x ][ $y ][ "g" ];
160                                $B = $Ikona[ $IconID ][ "Data" ][ $x ][ $y ][ "b" ];
161                                if ( $Ikona[ $IconID ][ "BitCount" ] == 32 ) {
162                                        $Alpha = 127 - round( $Ikona[ $IconID ][ "Data" ][ $x ][ $y ][ "alpha" ] * 127 / 255 );
163                                        if ( $Ikona[ $IconID ][ "Maska" ][ $x ][ $y ] == 1 )
164                                                $Alpha = 127;
165                                        $color = imagecolorexactalpha( $img, $R, $G, $B, $Alpha );
166                                        if ( $color == -1 )
167                                                $color = imagecolorallocatealpha( $img, $R, $G, $B, $Alpha );
168                                } else {
169                                        $color = imagecolorexact( $img, $R, $G, $B );
170                                        if ( $color == -1 )
171                                                $color = imagecolorallocate( $img, $R, $G, $B );
172                                }
173                               
174                                imagesetpixel( $img, $x, $y, $color );
175                               
176                        }
177               
178        } else {
179                $img = imagecreate( $Ikona[ $IconID ][ "Width" ], $Ikona[ $IconID ][ "Height" ] );
180                for ( $p = 0; $p < count( $Ikona[ $IconID ][ "Paleta" ] ); $p++ )
181                        $Paleta[ $p ] = imagecolorallocate( $img, $Ikona[ $IconID ][ "Paleta" ][ $p ][ "r" ], $Ikona[ $IconID ][ "Paleta" ][ $p ][ "g" ], $Ikona[ $IconID ][ "Paleta" ][ $p ][ "b" ] );
182               
183                for ( $y = 0; $y < $Ikona[ $IconID ][ "Height" ]; $y++ )
184                        for ( $x = 0; $x < $Ikona[ $IconID ][ "Width" ]; $x++ ) {
185                                imagesetpixel( $img, $x, $y, $Paleta[ $Ikona[ $IconID ][ "Data" ][ $x ][ $y ] ] );
186                        }
187        }
188        $IsTransparent = false;
189        for ( $y = 0; $y < $Ikona[ $IconID ][ "Height" ]; $y++ )
190                for ( $x = 0; $x < $Ikona[ $IconID ][ "Width" ]; $x++ )
191                        if ( $Ikona[ $IconID ][ "Maska" ][ $x ][ $y ] == 1 ) {
192                                $IsTransparent = true;
193                                break;
194                        }
195        if ( $Ikona[ $IconID ][ "BitCount" ] == 32 ) {
196                imagealphablending( $img, false );
197                if ( function_exists( "imagesavealpha" ) )
198                        imagesavealpha( $img, true );
199        }
200       
201        if ( $IsTransparent ) {
202                if ( ( $Ikona[ $IconID ][ "BitCount" ] >= 24 ) or ( imagecolorstotal( $img ) >= 256 ) ) {
203                        $img2 = imagecreatetruecolor( imagesx( $img ), imagesy( $img ) );
204                        imagecopy( $img2, $img, 0, 0, 0, 0, imagesx( $img ), imagesy( $img ) );
205                        imagedestroy( $img );
206                        $img = $img2;
207                        imagetruecolortopalette( $img, true, 255 );
208                       
209                }
210                $Pruhledna = imagecolorallocate( $img, 0, 0, 0 );
211                for ( $y = 0; $y < $Ikona[ $IconID ][ "Height" ]; $y++ )
212                        for ( $x = 0; $x < $Ikona[ $IconID ][ "Width" ]; $x++ )
213                                if ( $Ikona[ $IconID ][ "Maska" ][ $x ][ $y ] == 1 ) {
214                                        imagesetpixel( $img, $x, $y, $Pruhledna );
215                                }
216                imagecolortransparent( $img, $Pruhledna );
217        }
218       
219        return $img;
220       
221       
222}
223
224
225
226
227function jpexs_readIcon( $filename, $id, &$Ikona ) {
228        global $jpexs_currentBit;
229       
230        $f = fopen( $filename, "rb" );
231       
232        fseek( $f, 6 + $id * 16 );
233        $Width = jpexs_freadbyte( $f );
234        $Height = jpexs_freadbyte( $f );
235        fseek( $f, 6 + $id * 16 + 12 );
236        $OffSet = jpexs_freaddword( $f );
237        fseek( $f, $OffSet );
238       
239        $p = $id;
240       
241        $Ikona[ $p ][ "Info" ][ "HeaderSize" ] = jpexs_freadlngint( $f );
242        $Ikona[ $p ][ "Info" ][ "ImageWidth" ] = jpexs_freadlngint( $f );
243        $Ikona[ $p ][ "Info" ][ "ImageHeight" ] = jpexs_freadlngint( $f );
244        $Ikona[ $p ][ "Info" ][ "NumberOfImagePlanes" ] = jpexs_freadword( $f );
245        $Ikona[ $p ][ "Info" ][ "BitsPerPixel" ] = jpexs_freadword( $f );
246        $Ikona[ $p ][ "Info" ][ "CompressionMethod" ] = jpexs_freadlngint( $f );
247        $Ikona[ $p ][ "Info" ][ "SizeOfBitmap" ] = jpexs_freadlngint( $f );
248        $Ikona[ $p ][ "Info" ][ "HorzResolution" ] = jpexs_freadlngint( $f );
249        $Ikona[ $p ][ "Info" ][ "VertResolution" ] = jpexs_freadlngint( $f );
250        $Ikona[ $p ][ "Info" ][ "NumColorUsed" ] = jpexs_freadlngint( $f );
251        $Ikona[ $p ][ "Info" ][ "NumSignificantColors" ] = jpexs_freadlngint( $f );
252       
253       
254        $biBitCount = $Ikona[ $p ][ "Info" ][ "BitsPerPixel" ];
255       
256        if ( $Ikona[ $p ][ "Info" ][ "BitsPerPixel" ] <= 8 ) {
257                $barev = pow( 2, $biBitCount );
258               
259                for ( $b = 0; $b < $barev; $b++ ) {
260                        $Ikona[ $p ][ "Paleta" ][ $b ][ "b" ] = jpexs_freadbyte( $f );
261                        $Ikona[ $p ][ "Paleta" ][ $b ][ "g" ] = jpexs_freadbyte( $f );
262                        $Ikona[ $p ][ "Paleta" ][ $b ][ "r" ] = jpexs_freadbyte( $f );
263                        jpexs_freadbyte( $f );
264                }
265               
266                $Zbytek = ( 4 - ceil( ( $Width / ( 8 / $biBitCount ) ) ) % 4 ) % 4;
267               
268               
269                for ( $y = $Height - 1; $y >= 0; $y-- ) {
270                        $jpexs_currentBit = 0;
271                        for ( $x = 0; $x < $Width; $x++ ) {
272                                $C = jpexs_freadbits( $f, $biBitCount );
273                                $Ikona[ $p ][ "Data" ][ $x ][ $y ] = $C;
274                        }
275                       
276                        if ( $jpexs_currentBit != 0 ) {
277                                jpexs_freadbyte( $f );
278                        }
279                        for ( $g = 0; $g < $Zbytek; $g++ )
280                                jpexs_freadbyte( $f );
281                }
282               
283        } elseif ( $biBitCount == 24 ) {
284                $Zbytek = $Width % 4;
285               
286                for ( $y = $Height - 1; $y >= 0; $y-- ) {
287                        for ( $x = 0; $x < $Width; $x++ ) {
288                                $B = jpexs_freadbyte( $f );
289                                $G = jpexs_freadbyte( $f );
290                                $R = jpexs_freadbyte( $f );
291                                $Ikona[ $p ][ "Data" ][ $x ][ $y ][ "r" ] = $R;
292                                $Ikona[ $p ][ "Data" ][ $x ][ $y ][ "g" ] = $G;
293                                $Ikona[ $p ][ "Data" ][ $x ][ $y ][ "b" ] = $B;
294                        }
295                        for ( $z = 0; $z < $Zbytek; $z++ )
296                                jpexs_freadbyte( $f );
297                }
298        } elseif ( $biBitCount == 32 ) {
299                $Zbytek = $Width % 4;
300               
301                for ( $y = $Height - 1; $y >= 0; $y-- ) {
302                        for ( $x = 0; $x < $Width; $x++ ) {
303                                $B = jpexs_freadbyte( $f );
304                                $G = jpexs_freadbyte( $f );
305                                $R = jpexs_freadbyte( $f );
306                                $Alpha = jpexs_freadbyte( $f );
307                                $Ikona[ $p ][ "Data" ][ $x ][ $y ][ "r" ] = $R;
308                                $Ikona[ $p ][ "Data" ][ $x ][ $y ][ "g" ] = $G;
309                                $Ikona[ $p ][ "Data" ][ $x ][ $y ][ "b" ] = $B;
310                                $Ikona[ $p ][ "Data" ][ $x ][ $y ][ "alpha" ] = $Alpha;
311                        }
312                        for ( $z = 0; $z < $Zbytek; $z++ )
313                                jpexs_freadbyte( $f );
314                }
315        }
316       
317       
318        //Maska
319        $Zbytek = ( 4 - ceil( ( $Width / ( 8 ) ) ) % 4 ) % 4;
320        for ( $y = $Height - 1; $y >= 0; $y-- ) {
321                $jpexs_currentBit = 0;
322                for ( $x = 0; $x < $Width; $x++ ) {
323                        $C = jpexs_freadbits( $f, 1 );
324                        $Ikona[ $p ][ "Maska" ][ $x ][ $y ] = $C;
325                }
326                if ( $jpexs_currentBit != 0 ) {
327                        jpexs_freadbyte( $f );
328                }
329                for ( $g = 0; $g < $Zbytek; $g++ )
330                        jpexs_freadbyte( $f );
331        }
332        //--------------
333       
334        fclose( $f );
335       
336}
337
338function jpexs_GetIconsInfo( $filename ) {
339        global $jpexs_currentBit;
340       
341        $f = fopen( $filename, "rb" );
342       
343        $Reserved = jpexs_freadword( $f );
344        $Type = jpexs_freadword( $f );
345        $Count = jpexs_freadword( $f );
346        for ( $p = 0; $p < $Count; $p++ ) {
347                $Ikona[ $p ][ "Width" ] = jpexs_freadbyte( $f );
348                $Ikona[ $p ][ "Height" ] = jpexs_freadbyte( $f );
349                $Ikona[ $p ][ "ColorCount" ] = jpexs_freadword( $f );
350                if ( $Ikona[ $p ][ "ColorCount" ] == 0 )
351                        $Ikona[ $p ][ "ColorCount" ] = 256;
352                $Ikona[ $p ][ "Planes" ] = jpexs_freadword( $f );
353                $Ikona[ $p ][ "BitCount" ] = jpexs_freadword( $f );
354                $Ikona[ $p ][ "BytesInRes" ] = jpexs_freaddword( $f );
355                $Ikona[ $p ][ "ImageOffset" ] = jpexs_freaddword( $f );
356        }
357       
358        if ( !feof( $f ) ):
359                for ( $p = 0; $p < $Count; $p++ ) {
360                        fseek( $f, $Ikona[ $p ][ "ImageOffset" ] + 14 );
361                        $Ikona[ $p ][ "Info" ][ "BitsPerPixel" ] = jpexs_freadword( $f );
362                }
363        endif;
364        fclose( $f );
365        return $Ikona;
366}
367
368
369
370
371/**
372 * Reads image from a icon in exe file
373 * @param string $filename Target exefile
374 * @param int $icoIndex Index of the icon in exefile
375 * @param int $icoColorCount Icon color count (For multiple icons ico file) - 2,16,256, ICO_TRUE_COLOR, ICO_XP_COLOR or ICO_MAX_COLOR
376 * @param int $icoSize Icon width (For multiple icons ico file) or ICO_MAX_SIZE
377 * @param int $alphaBgR Background color R value for alpha-channel images (Default is White)
378 * @param int $alphaBgG Background color G value for alpha-channel images (Default is White)
379 * @param int $alphaBgB Background color B value for alpha-channel images (Default is White)
380 * @return resource Image resource or false on error
381 */
382function imageCreateFromExeIco( $filename, $icoIndex, $icoColorCount = 16, $icoSize = 16, $alphaBgR = 255, $alphaBgG = 255, $alphaBgB = 255 ) {
383        $ok = saveExeIcon( $filename, "icotemp.dat", $icoIndex );
384        if ( !$ok ):
385                $im = false;
386        else:
387                $im = imageCreateFromIco( "icotemp.dat", $icoColorCount, $icoSize, $alphaBgR, $alphaBgG, $alphaBgB );
388                unlink( "icotemp.dat" );
389        endif;
390        return $im;
391}
392
393
394/**
395 * Saves icon(s) from the exe file
396 * @global int $jpexs_StartOfRsrc Internal reserved variable
397 * @global int $jpexs_ImageBase Internal reserved variable
398 * @global int $jpexs_ResVirtualAddress Internal reserved variable
399 * @param string $filename Target exefile
400 * @param string $icoFileNameOrPath Filename to save ico or path (Default "") Path if you want more than 1 icon. If "", the filename is "$icoIndex.ico"
401 * @param int|array $iconIndex Index(es) of the icon in exefile  (Default -1) If -1, all icons are saved, Can be an array of indexes.
402 * @return boolean True on successful save
403 */
404function saveExeIcon( $filename, $icoFileNameOrPath = "", $iconIndex = -1 ) /*-1 for all,or can be array*/ {
405        global $jpexs_f, $jpexs_StartOfRsrc, $jpexs_ImageBase, $jpexs_ResVirtualAddress;
406        $jpexs_f = fopen( $filename, "r" );
407        $MZ = fread( $jpexs_f, 2 );
408        if ( $MZ != "MZ" )
409                NotValidExe();
410        fseek( $jpexs_f, 60 );
411        $OffsetToNewHeader = jpexs_freaddword( $jpexs_f );
412        fseek( $jpexs_f, $OffsetToNewHeader );
413        $PE = fread( $jpexs_f, 2 );
414        if ( $PE != "PE" )
415                NotValidExe();
416        fread( $jpexs_f, 4 );
417        $NumberOfSections = jpexs_freadword( $jpexs_f );
418        fseek( $jpexs_f, ftell( $jpexs_f ) + 12 );
419        $SizeOfOptionalHeader = jpexs_freadword( $jpexs_f );
420        $PosMagic = ftell( $jpexs_f ) + 2;
421        fseek( $jpexs_f, $PosMagic + $SizeOfOptionalHeader );
422       
423        for ( $p = 0; $p < $NumberOfSections; $p++ ):
424                $SectionName[ $p ] = trim( fread( $jpexs_f, 8 ) );
425                $VirtualSize[ $p ] = jpexs_freaddword( $jpexs_f );
426                $VirtualAddress[ $p ] = jpexs_freaddword( $jpexs_f );
427                $PhysicalSize[ $p ] = jpexs_freaddword( $jpexs_f );
428                $PhysicalOffset[ $p ] = jpexs_freaddword( $jpexs_f );
429                fread( $jpexs_f, 16 );
430                if ( $SectionName[ $p ] == ".rsrc" ):
431                        $jpexs_ResVirtualAddress = $VirtualAddress[ $p ];
432                        fseek( $jpexs_f, $PhysicalOffset[ $p ] );
433                        $jpexs_StartOfRsrc = $PhysicalOffset[ $p ];
434                        jpexs_readResDirectoryEntry( $R, $PhysicalOffset[ $p ] );
435                        $IconCount = null;
436                        $Ikona = null;
437                        while ( list( $key, $val ) = each( $R[ "Subdir" ] ) ):
438                                if ( $key == 14 ):
439                                        $r = 0;
440                                        while ( list( $key2, $val2 ) = each( $R[ "Subdir" ][ $key ][ "Subdir" ] ) ):
441                                                while ( list( $key3, $val3 ) = each( $R[ "Subdir" ][ $key ][ "Subdir" ][ $key2 ][ "Subdir" ] ) ):
442                                                        fseek( $jpexs_f, $val3[ "DataOffset" ] );
443                                                        $Reserved = jpexs_freadword( $jpexs_f );
444                                                        $Type = jpexs_freadword( $jpexs_f );
445                                                        $ic = jpexs_freadword( $jpexs_f );
446                                                        $IconCount[] = $ic;
447                                                        for ( $s = 0; $s < $ic; $s++ ) {
448                                                                $Ikona[ $r ][ $s ][ "Width" ] = jpexs_freadbyte( $jpexs_f );
449                                                                $Ikona[ $r ][ $s ][ "Height" ] = jpexs_freadbyte( $jpexs_f );
450                                                                $Ikona[ $r ][ $s ][ "ColorCount" ] = jpexs_freadword( $jpexs_f );
451                                                                $Ikona[ $r ][ $s ][ "Planes" ] = jpexs_freadword( $jpexs_f );
452                                                                $Ikona[ $r ][ $s ][ "BitCount" ] = jpexs_freadword( $jpexs_f );
453                                                                $Ikona[ $r ][ $s ][ "BytesInRes" ] = jpexs_freaddword( $jpexs_f );
454                                                                $Ikona[ $r ][ $s ][ "IconId" ] = jpexs_freadword( $jpexs_f );
455                                                        }
456                                                        fseek( $jpexs_f, $val3[ "DataOffset" ] );
457                                                        $r++;
458                                                endwhile;
459                                        endwhile;
460                                endif;
461                        endwhile;
462                       
463                        reset( $R[ "Subdir" ] );
464                       
465                        while ( list( $key, $val ) = each( $R[ "Subdir" ] ) ):
466                                if ( $key == 3 ):
467                                        while ( list( $key2, $val2 ) = each( $R[ "Subdir" ][ $key ][ "Subdir" ] ) ):
468                                                for ( $r = 0; $r < count( $Ikona ); $r++ ):
469                                                        for ( $s = 0; $s < count( $Ikona[ $r ] ); $s++ ):
470                                                                while ( list( $key3, $val3 ) = each( $R[ "Subdir" ][ $key ][ "Subdir" ][ $Ikona[ $r ][ $s ][ "IconId" ] ][ "Subdir" ] ) ):
471                                                                        if ( ( $iconIndex == $r ) or ( $iconIndex == -1 ) or ( ( is_array( $iconIndex ) ) and ( in_array( $r, $iconIndex ) ) ) ):
472                                                                                fseek( $jpexs_f, $val3[ "DataOffset" ] );
473                                                                                $Ikona[ $r ][ $s ][ "Data" ] = fread( $jpexs_f, $val3[ "DataSize" ] );
474                                                                                $Ikona[ $r ][ $s ][ "DataSize" ] = $val3[ "DataSize" ];
475                                                                        endif;
476                                                                endwhile;
477                                                        endfor;
478                                                endfor;
479                                        endwhile;
480                                endif;
481                        endwhile;
482                        $ok = false;
483                        for ( $r = 0; $r < count( $Ikona ); $r++ ):
484                                if ( ( $iconIndex == $r ) or ( $iconIndex == -1 ) or ( ( is_array( $iconIndex ) ) and ( in_array( $r, $iconIndex ) ) ) ):
485                                        $savefile = $icoFileNameOrPath;
486                                        if ( $icoFileNameOrPath == "" ) {
487                                                $savefile = "$r.ico";
488                                        } else {
489                                                if ( ( $iconIndex == -1 ) or ( is_array( $iconIndex ) ) )
490                                                        $savefile = $icoFileNameOrPath . "$r.ico";
491                                        }
492                                        $f2 = fopen( $savefile, "w" );
493                                        fwrite( $f2, jpexs_inttoword( 0 ) );
494                                        fwrite( $f2, jpexs_inttoword( 1 ) );
495                                        fwrite( $f2, jpexs_inttoword( count( $Ikona[ $r ] ) ) );
496                                        $Offset = 6 + 16 * count( $Ikona[ $r ] );
497                                        for ( $s = 0; $s < count( $Ikona[ $r ] ); $s++ ):
498                                                fwrite( $f2, jpexs_inttobyte( $Ikona[ $r ][ $s ][ "Width" ] ) );
499                                                fwrite( $f2, jpexs_inttobyte( $Ikona[ $r ][ $s ][ "Height" ] ) );
500                                                fwrite( $f2, jpexs_inttoword( $Ikona[ $r ][ $s ][ "ColorCount" ] ) );
501                                                fwrite( $f2, jpexs_inttoword( $Ikona[ $r ][ $s ][ "Planes" ] ) );
502                                                fwrite( $f2, jpexs_inttoword( $Ikona[ $r ][ $s ][ "BitCount" ] ) );
503                                                fwrite( $f2, jpexs_inttodword( $Ikona[ $r ][ $s ][ "BytesInRes" ] ) );
504                                                fwrite( $f2, jpexs_inttodword( $Offset ) );
505                                                $Offset += $Ikona[ $r ][ $s ][ "DataSize" ];
506                                        endfor;
507                                        for ( $s = 0; $s < count( $Ikona[ $r ] ); $s++ ):
508                                                fwrite( $f2, $Ikona[ $r ][ $s ][ "Data" ] );
509                                        endfor;
510                                        fclose( $f2 );
511                                        $ok = true;
512                                endif;
513                        endfor;
514                        return $ok;
515                endif;
516        endfor;
517       
518        fclose( $jpexs_f );
519}
520
521/**
522 * Internal function for reading exe icons
523 */
524function jpexs_readResDirectoryEntry( &$parentRes, $offset ) {
525        global $jpexs_f, $jpexs_StartOfRsrc, $jpexs_ImageBase, $jpexs_ResVirtualAddress;
526        $lastPos = ftell( $jpexs_f );
527        $Res = null;
528        fseek( $jpexs_f, $offset );
529        //IMAGE_RESOURCE_DIRECTORY
530        $Characteristics = jpexs_freaddword( $jpexs_f );
531        $TimeDateStamp = jpexs_freaddword( $jpexs_f );
532        $MajorVersion = jpexs_freadword( $jpexs_f );
533        $MinorVersion = jpexs_freadword( $jpexs_f );
534        $NumberOfNamedEntries = jpexs_freadword( $jpexs_f );
535        $NumberOfIdEntries = jpexs_freadword( $jpexs_f );
536        for ( $q = 0; $q < $NumberOfNamedEntries + $NumberOfIdEntries; $q++ ):
537        //IMAGE_RESOURCE_DIRECTORY_ENTRY
538                $ResName = jpexs_freaddword( $jpexs_f );
539                $lastPos2 = ftell( $jpexs_f );
540                if ( $ResName >= 0x80000000 ):
541                //String Name
542                        $ResNameOffset = $ResName - 0x80000000;
543                        fseek( $jpexs_f, $jpexs_StartOfRsrc + $ResNameOffset );
544                        $StringLength = jpexs_freadword( $jpexs_f );
545                        $Identificator = ( fread( $jpexs_f, $StringLength * 2 ) );
546                        fseek( $jpexs_f, $lastPos2 );
547                else:
548                //Integer Id
549                        $Identificator = $ResName;
550                endif;
551               
552                $ResOffsetToData = jpexs_freaddword( $jpexs_f );
553                if ( $ResOffsetToData >= 0x80000000 ):
554                        $SubResOffset = $ResOffsetToData - 0x80000000;
555                        jpexs_readResDirectoryEntry( $Res[ "$Identificator" ], $jpexs_StartOfRsrc + $SubResOffset );
556                else:
557                        $RawDataOffset = $ResOffsetToData;
558                        $lastPos2 = ftell( $jpexs_f );
559                        fseek( $jpexs_f, $jpexs_StartOfRsrc + $RawDataOffset );
560                        //IMAGE_RESOURCE_DATA_ENTRY
561                        $OffsetToData = jpexs_freaddword( $jpexs_f );
562                        $Res[ "$Identificator" ][ "DataOffset" ] = $jpexs_StartOfRsrc - $jpexs_ResVirtualAddress + $OffsetToData;
563                        $Res[ "$Identificator" ][ "DataSize" ] = jpexs_freaddword( $jpexs_f );
564                        $CodePage = jpexs_freaddword( $jpexs_f );
565                        $Reserved = jpexs_freaddword( $jpexs_f );
566                        fseek( $jpexs_f, $lastPos2 );
567                endif;
568        endfor;
569        fseek( $jpexs_f, $lastPos );
570        $parentRes[ "Subdir" ] = $Res;
571}
572
573/**
574 * Creates ico file from image resource(s)
575 * @param resource|array $images Target Image resource (Can be array of image resources)
576 * @param string $filename Target ico file to save icon to, If ommited or "", image is written to snadard output - use header("Content-type: image/x-icon"); */
577function imageIco( $images, $filename = "" ) {
578        if ( is_array( $images ) ) {
579                $ImageCount = count( $images );
580                $Image = $images;
581        } else {
582                $Image[ 0 ] = $images;
583                $ImageCount = 1;
584        }
585       
586       
587        $WriteToFile = false;
588       
589        if ( $filename != "" ) {
590                $WriteToFile = true;
591        }
592       
593       
594        $ret = "";
595       
596        $ret .= jpexs_inttoword( 0 ); //PASSWORD
597        $ret .= jpexs_inttoword( 1 ); //SOURCE
598        $ret .= jpexs_inttoword( $ImageCount ); //ICONCOUNT
599       
600       
601        for ( $q = 0; $q < $ImageCount; $q++ ) {
602                $img = $Image[ $q ];
603               
604                $Width = imagesx( $img );
605                $Height = imagesy( $img );
606               
607                $ColorCount = imagecolorstotal( $img );
608               
609                $Transparent = imagecolortransparent( $img );
610                $IsTransparent = $Transparent != -1;
611               
612               
613                if ( $IsTransparent )
614                        $ColorCount--;
615               
616                if ( $ColorCount == 0 ) {
617                        $ColorCount = 0;
618                        $BitCount = 24;
619                }
620                if ( ( $ColorCount > 0 ) and ( $ColorCount <= 2 ) ) {
621                        $ColorCount = 2;
622                        $BitCount = 1;
623                }
624                if ( ( $ColorCount > 2 ) and ( $ColorCount <= 16 ) ) {
625                        $ColorCount = 16;
626                        $BitCount = 4;
627                }
628                if ( ( $ColorCount > 16 ) and ( $ColorCount <= 256 ) ) {
629                        $ColorCount = 0;
630                        $BitCount = 8;
631                }
632               
633               
634               
635               
636               
637                //ICONINFO:
638                $ret .= jpexs_inttobyte( $Width ); //
639                $ret .= jpexs_inttobyte( $Height ); //
640                $ret .= jpexs_inttobyte( $ColorCount ); //
641                $ret .= jpexs_inttobyte( 0 ); //RESERVED
642               
643                $Planes = 0;
644                if ( $BitCount >= 8 )
645                        $Planes = 1;
646               
647                $ret .= jpexs_inttoword( $f, $Planes ); //PLANES
648                if ( $BitCount >= 8 )
649                        $WBitCount = $BitCount;
650                if ( $BitCount == 4 )
651                        $WBitCount = 0;
652                if ( $BitCount == 1 )
653                        $WBitCount = 0;
654                $ret .= jpexs_inttoword( $WBitCount ); //BITS
655               
656                $Zbytek = ( 4 - ( $Width / ( 8 / $BitCount ) ) % 4 ) % 4;
657                $ZbytekMask = ( 4 - ( $Width / 8 ) % 4 ) % 4;
658               
659                $PalSize = 0;
660               
661                $Size = 40 + ( $Width / ( 8 / $BitCount ) + $Zbytek ) * $Height + ( ( $Width / 8 + $ZbytekMask ) * $Height );
662                if ( $BitCount < 24 )
663                        $Size += pow( 2, $BitCount ) * 4;
664                $IconId = 1;
665                $ret .= jpexs_inttodword( $Size ); //SIZE
666                $OffSet = 6 + 16 * $ImageCount + $FullSize;
667                $ret .= jpexs_inttodword( 6 + 16 * $ImageCount + $FullSize ); //OFFSET
668                $FullSize += $Size;
669                //-------------
670               
671        }
672       
673       
674        for ( $q = 0; $q < $ImageCount; $q++ ) {
675                $img = $Image[ $q ];
676                $Width = imagesx( $img );
677                $Height = imagesy( $img );
678                $ColorCount = imagecolorstotal( $img );
679               
680                $Transparent = imagecolortransparent( $img );
681                $IsTransparent = $Transparent != -1;
682               
683                if ( $IsTransparent )
684                        $ColorCount--;
685                if ( $ColorCount == 0 ) {
686                        $ColorCount = 0;
687                        $BitCount = 24;
688                }
689                if ( ( $ColorCount > 0 ) and ( $ColorCount <= 2 ) ) {
690                        $ColorCount = 2;
691                        $BitCount = 1;
692                }
693                if ( ( $ColorCount > 2 ) and ( $ColorCount <= 16 ) ) {
694                        $ColorCount = 16;
695                        $BitCount = 4;
696                }
697                if ( ( $ColorCount > 16 ) and ( $ColorCount <= 256 ) ) {
698                        $ColorCount = 0;
699                        $BitCount = 8;
700                }
701               
702               
703               
704                //ICONS
705                $ret .= jpexs_inttodword( 40 ); //HEADSIZE
706                $ret .= jpexs_inttodword( $Width ); //
707                $ret .= jpexs_inttodword( 2 * $Height ); //
708                $ret .= jpexs_inttoword( 1 ); //PLANES
709                $ret .= jpexs_inttoword( $BitCount ); //
710                $ret .= jpexs_inttodword( 0 ); //Compress method
711               
712               
713                $ZbytekMask = ( $Width / 8 ) % 4;
714               
715                $Zbytek = ( $Width / ( 8 / $BitCount ) ) % 4;
716                $Size = ( $Width / ( 8 / $BitCount ) + $Zbytek ) * $Height + ( ( $Width / 8 + $ZbytekMask ) * $Height );
717               
718                $ret .= jpexs_inttodword( $Size ); //SIZE
719               
720                $ret .= jpexs_inttodword( 0 ); //HPIXEL_M
721                $ret .= jpexs_inttodword( 0 ); //V_PIXEL_M
722                $ret .= jpexs_inttodword( $ColorCount ); //UCOLORS
723                $ret .= jpexs_inttodword( 0 ); //DCOLORS
724                //---------------
725               
726               
727                $CC = $ColorCount;
728                if ( $CC == 0 )
729                        $CC = 256;
730               
731                if ( $BitCount < 24 ) {
732                        $ColorTotal = imagecolorstotal( $img );
733                        if ( $IsTransparent )
734                                $ColorTotal--;
735                       
736                        for ( $p = 0; $p < $ColorTotal; $p++ ) {
737                                $color = imagecolorsforindex( $img, $p );
738                                $ret .= jpexs_inttobyte( $color[ "blue" ] );
739                                $ret .= jpexs_inttobyte( $color[ "green" ] );
740                                $ret .= jpexs_inttobyte( $color[ "red" ] );
741                                $ret .= jpexs_inttobyte( 0 ); //RESERVED
742                        }
743                       
744                        $CT = $ColorTotal;
745                        for ( $p = $ColorTotal; $p < $CC; $p++ ) {
746                                $ret .= jpexs_inttobyte( 0 );
747                                $ret .= jpexs_inttobyte( 0 );
748                                $ret .= jpexs_inttobyte( 0 );
749                                $ret .= jpexs_inttobyte( 0 ); //RESERVED
750                        }
751                }
752               
753               
754               
755               
756               
757               
758                if ( $BitCount <= 8 ) {
759                        for ( $y = $Height - 1; $y >= 0; $y-- ) {
760                                $bWrite = "";
761                                for ( $x = 0; $x < $Width; $x++ ) {
762                                        $color = imagecolorat( $img, $x, $y );
763                                        if ( $color == $Transparent )
764                                                $color = imagecolorexact( $img, 0, 0, 0 );
765                                        if ( $color == -1 )
766                                                $color = 0;
767                                        if ( $color > pow( 2, $BitCount ) - 1 )
768                                                $color = 0;
769                                       
770                                        $bWrite .= jpexs_decbinx( $color, $BitCount );
771                                        if ( strlen( $bWrite ) == 8 ) {
772                                                $ret .= jpexs_inttobyte( bindec( $bWrite ) );
773                                                $bWrite = "";
774                                        }
775                                }
776                               
777                                if ( ( strlen( $bWrite ) < 8 ) and ( strlen( $bWrite ) != 0 ) ) {
778                                        $sl = strlen( $bWrite );
779                                        for ( $t = 0; $t < 8 - $sl; $t++ )
780                                                $sl .= "0";
781                                        $ret .= jpexs_inttobyte( bindec( $bWrite ) );
782                                }
783                                for ( $z = 0; $z < $Zbytek; $z++ )
784                                        $ret .= jpexs_inttobyte( 0 );
785                        }
786                }
787               
788               
789               
790                if ( $BitCount >= 24 ) {
791                        for ( $y = $Height - 1; $y >= 0; $y-- ) {
792                                for ( $x = 0; $x < $Width; $x++ ) {
793                                        $color = imagecolorsforindex( $img, imagecolorat( $img, $x, $y ) );
794                                        $ret .= jpexs_inttobyte( $color[ "blue" ] );
795                                        $ret .= jpexs_inttobyte( $color[ "green" ] );
796                                        $ret .= jpexs_inttobyte( $color[ "red" ] );
797                                        if ( $BitCount == 32 )
798                                                $ret .= jpexs_inttobyte( 0 ); //Alpha for ICO_XP_COLORS
799                                }
800                                for ( $z = 0; $z < $Zbytek; $z++ )
801                                        $ret .= jpexs_inttobyte( 0 );
802                        }
803                }
804               
805               
806                //MASK
807               
808                for ( $y = $Height - 1; $y >= 0; $y-- ) {
809                        $byteCount = 0;
810                        $bOut = "";
811                        for ( $x = 0; $x < $Width; $x++ ) {
812                                if ( ( $Transparent != -1 ) and ( imagecolorat( $img, $x, $y ) == $Transparent ) ) {
813                                        $bOut .= "1";
814                                } else {
815                                        $bOut .= "0";
816                                }
817                        }
818                        for ( $p = 0; $p < strlen( $bOut ); $p += 8 ) {
819                                $byte = bindec( substr( $bOut, $p, 8 ) );
820                                $byteCount++;
821                                $ret .= jpexs_inttobyte( $byte );
822                        }
823                        $Zbytek = $byteCount % 4;
824                        for ( $z = 0; $z < $Zbytek; $z++ ) {
825                                $ret .= jpexs_inttobyte( 0xff );
826                        }
827                }
828               
829                //------------------
830               
831        } //q
832       
833       
834       
835       
836       
837        if ( $WriteToFile ) {
838                $f = fopen( $filename, "w" );
839                fwrite( $f, $ret );
840                fclose( $f );
841        } else {
842                echo $ret;
843        }
844       
845}
846
847
848
849
850/*
851 * Internal functions:
852 *-------------------------
853 * jpexs_inttobyte($n) - returns chr(n)
854 * jpexs_inttodword($n) - returns dword (n)
855 * jpexs_inttoword($n) - returns word(n)
856 * jpexs_freadbyte($file) - reads 1 byte from $file
857 * jpexs_freadword($file) - reads 2 bytes (1 word) from $file
858 * jpexs_freaddword($file) - reads 4 bytes (1 dword) from $file
859 * jpexs_freadlngint($file) - same as freaddword($file)
860 * jpexs_decbin8($d) - returns binary string of d zero filled to 8
861 * jpexs_RetBits($byte,$start,$len) - returns bits $start->$start+$len from $byte
862 * jpexs_freadbits($file,$count) - reads next $count bits from $file
863 */
864
865
866function jpexs_decbin8( $d ) {
867        return jpexs_decbinx( $d, 8 );
868}
869
870function jpexs_decbinx( $d, $n ) {
871        $bin = decbin( $d );
872        $sbin = strlen( $bin );
873        for ( $j = 0; $j < $n - $sbin; $j++ )
874                $bin = "0$bin";
875        return $bin;
876}
877
878function jpexs_retBits( $byte, $start, $len ) {
879        $bin = jpexs_decbin8( $byte );
880        $r = bindec( substr( $bin, $start, $len ) );
881        return $r;
882       
883}
884
885
886
887$jpexs_currentBit = 0;
888function jpexs_freadbits( $f, $count ) {
889        global $jpexs_currentBit, $jpexs_SMode;
890        $Byte = jpexs_freadbyte( $f );
891        $LastCBit = $jpexs_currentBit;
892        $jpexs_currentBit += $count;
893        if ( $jpexs_currentBit == 8 ) {
894                $jpexs_currentBit = 0;
895        } else {
896                fseek( $f, ftell( $f ) - 1 );
897        }
898        return jpexs_retBits( $Byte, $LastCBit, $count );
899}
900
901
902function jpexs_freadbyte( $f ) {
903        return ord( fread( $f, 1 ) );
904}
905
906function jpexs_freadword( $f ) {
907        $b1 = jpexs_freadbyte( $f );
908        $b2 = jpexs_freadbyte( $f );
909        return $b2 * 256 + $b1;
910}
911
912
913function jpexs_freadlngint( $f ) {
914        return jpexs_freaddword( $f );
915}
916
917function jpexs_freaddword( $f ) {
918        $b1 = jpexs_freadword( $f );
919        $b2 = jpexs_freadword( $f );
920        return $b2 * 65536 + $b1;
921}
922
923function jpexs_inttobyte( $n ) {
924        return chr( $n );
925}
926
927function jpexs_inttodword( $n ) {
928        return chr( $n & 255 ) . chr( ( $n >> 8 ) & 255 ) . chr( ( $n >> 16 ) & 255 ) . chr( ( $n >> 24 ) & 255 );
929}
930
931function jpexs_inttoword( $n ) {
932        return chr( $n & 255 ) . chr( ( $n >> 8 ) & 255 );
933}
934
935?>