source: extensions/edit_gmaps/admin/include/Photoshop_IRB.php @ 10060

Last change on this file since 10060 was 9412, checked in by cljosse, 13 years ago
File size: 78.2 KB
Line 
1<?php
2
3/******************************************************************************
4*
5* Filename:     Photoshop_IRB.php
6*
7* Description:  Provides functions for reading and writing information to/from
8*               the 'App 13' Photoshop Information Resource Block segment of
9*               JPEG format files
10*
11* Author:      Evan Hunter
12*
13* Date:         23/7/2004
14*
15* Project:      PHP JPEG Metadata Toolkit
16*
17* Revision:     1.11
18*
19* Changes:      1.00 -> 1.02 : changed get_Photoshop_IRB to work with corrupted
20*                              resource names which Photoshop can still read
21*               1.02 -> 1.03 : Fixed put_Photoshop_IRB to output "Photoshop 3.0\x00"
22*                              string with every APP13 segment, not just the first one
23*               1.03 -> 1.10 : changed get_Photoshop_IRB to fix processing of embedded resource names,
24*                              after discovering that Photoshop does not process
25*                              resource names according to the standard :
26*                              "Adobe Photoshop 6.0 File Formats Specification, Version 6.0, Release 2, November 2000"
27*                              This is an update to the change 1.00 -> 1.02, which was not fully correct
28*                              changed put_Photoshop_IRB to fix the writing of embedded resource name,
29*                              to avoid creating blank resources, and to fix a problem
30*                              causing the IRB block to be incorrectly positioned if no APP segments existed.
31*                              changed get_Photoshop_IPTC to initialise the output array correctly.
32*               1.10 -> 1.11 : Moved code out of get_Photoshop_IRB into new function unpack_Photoshop_IRB_Data
33*                              to allow reading of IRB blocks embedded within EXIF (for TIFF Files)
34*                              Moved code out of put_Photoshop_IRB into new function pack_Photoshop_IRB_Data
35*                              to allow writing of IRB blocks embedded within EXIF (for TIFF Files)
36*                              Enabled the usage of $GLOBALS['HIDE_UNKNOWN_TAGS'] to hide unknown resources
37*                              changed Interpret_IRB_to_HTML to allow thumbnail links to work when
38*                              toolkit is portable across directories
39*
40*
41* URL:          http://electronics.ozhiker.com
42*
43* Copyright:    Copyright " . $auteur . " 2004
44*
45* License:      This file is part of the PHP JPEG Metadata Toolkit.
46*
47*               The PHP JPEG Metadata Toolkit is free software; you can
48*               redistribute it and/or modify it under the terms of the
49*               GNU General Public License as published by the Free Software
50*               Foundation; either version 2 of the License, or (at your
51*               option) any later version.
52*
53*               The PHP JPEG Metadata Toolkit is distributed in the hope
54*               that it will be useful, but WITHOUT ANY WARRANTY; without
55*               even the implied warranty of MERCHANTABILITY or FITNESS
56*               FOR A PARTICULAR PURPOSE.  See the GNU General Public License
57*               for more details.
58*
59*               You should have received a copy of the GNU General Public
60*               License along with the PHP JPEG Metadata Toolkit; if not,
61*               write to the Free Software Foundation, Inc., 59 Temple
62*               Place, Suite 330, Boston, MA  02111-1307  USA
63*
64*               If you require a different license for commercial or other
65*               purposes, please contact the author: evan@ozhiker.com
66*
67******************************************************************************/
68
69// Change: as of version 1.11 - added to ensure the HIDE_UNKNOWN_TAGS variable is set even if EXIF.php is not included
70if ( !isset( $GLOBALS['HIDE_UNKNOWN_TAGS'] ) )     $GLOBALS['HIDE_UNKNOWN_TAGS']= FALSE;
71
72include_once INCLUDE_PATH.'IPTC.php';
73include_once INCLUDE_PATH.'Unicode.php';
74
75
76
77// TODO: Many Photoshop IRB resources not interpeted
78// TODO: Obtain a copy of the Photoshop CS File Format Specification
79// TODO: Find out what Photoshop IRB resources 1061, 1062 & 1064 are
80// TODO: Test get_Photoshop_IRB and put_Photoshop_IRB with multiple APP13 segments
81
82/******************************************************************************
83*
84* Function:     get_Photoshop_IRB
85*
86* Description:  Retrieves the Photoshop Information Resource Block (IRB) information
87*               from an App13 JPEG segment and returns it as an array. This may
88*               include IPTC-NAA IIM Information. Uses information
89*               supplied by the get_jpeg_header_data function
90*
91* Parameters:   jpeg_header_data - a JPEG header data array in the same format
92*                                  as from get_jpeg_header_data
93*
94* Returns:      IRBdata - The array of Photoshop IRB records
95*               FALSE - if an APP 13 Photoshop IRB segment could not be found,
96*                       or if an error occured
97*
98******************************************************************************/
99
100function get_Photoshop_IRB( $jpeg_header_data )
101{
102        // Photoshop Image Resource blocks can span several JPEG APP13 segments, so we need to join them up if there are more than one
103        $joined_IRB = "";
104
105
106        //Cycle through the header segments
107        for( $i = 0; $i < count( $jpeg_header_data ); $i++ )
108        {
109                // If we find an APP13 header,
110                if ( strcmp ( $jpeg_header_data[$i]['SegName'], "APP13" ) == 0 )
111                {
112                        // And if it has the photoshop label,
113                        if( strncmp ( $jpeg_header_data[$i]['SegData'], "Photoshop 3.0\x00", 14) == 0 )
114                        {
115                                // join it to the other previous IRB data
116                                $joined_IRB .= substr ( $jpeg_header_data[$i]['SegData'], 14 );
117                        }
118                }
119        }
120
121        // If there was some Photoshop IRB information found,
122        if ( $joined_IRB != "" )
123        {
124                // Found a Photoshop Image Resource Block - extract it.
125                // Change: Moved code into unpack_Photoshop_IRB_Data to allow TIFF reading as of 1.11
126                return unpack_Photoshop_IRB_Data( $joined_IRB );
127
128        }
129        else
130        {
131                // No Photoshop IRB found
132                return FALSE;
133        }
134
135}
136
137/******************************************************************************
138* End of Function:     get_Photoshop_IRB
139******************************************************************************/
140
141
142
143
144
145
146
147
148
149
150/******************************************************************************
151*
152* Function:     put_Photoshop_IRB
153*
154* Description:  Adds or modifies the Photoshop Information Resource Block (IRB)
155*               information from an App13 JPEG segment. If a Photoshop IRB already
156*               exists, it is replaced, otherwise a new one is inserted, using the
157*               supplied data. Uses information supplied by the get_jpeg_header_data
158*               function
159*
160* Parameters:   jpeg_header_data - a JPEG header data array in the same format
161*                                  as from get_jpeg_header_data
162*               new_IRB_data - an array of the data to be stored in the Photoshop
163*                              IRB segment. Should be in the same format as received
164*                              from get_Photoshop_IRB
165*
166* Returns:      jpeg_header_data - the JPEG header data array with the
167*                                  Photoshop IRB added.
168*               FALSE - if an error occured
169*
170******************************************************************************/
171
172function put_Photoshop_IRB( $jpeg_header_data, $new_IRB_data )
173{
174        // Delete all existing Photoshop IRB blocks - the new one will replace them
175
176        //Cycle through the header segments
177        for( $i = 0; $i < count( $jpeg_header_data ) ; $i++ )
178        {
179                // If we find an APP13 header,
180                if ( strcmp ( $jpeg_header_data[$i]['SegName'], "APP13" ) == 0 )
181                {
182                        // And if it has the photoshop label,
183                        if( strncmp ( $jpeg_header_data[$i]['SegData'], "Photoshop 3.0\x00", 14) == 0 )
184                        {
185                                // Delete the block information - it needs to be rebuilt
186                                array_splice( $jpeg_header_data, $i, 1 );
187                        }
188                }
189        }
190
191
192        // Now we have deleted the pre-existing blocks
193
194
195        // Retrieve the Packed Photoshop IRB Data
196        // Change: Moved code into pack_Photoshop_IRB_Data to allow TIFF writing as of 1.11
197        $packed_IRB_data = pack_Photoshop_IRB_Data( $new_IRB_data );
198
199        // Change : This section changed to fix incorrect positioning of IRB segment, as of revision 1.10
200        //          when there are no APP segments present
201
202        //Cycle through the header segments in reverse order (to find where to put the APP13 block - after any APP0 to APP12 blocks)
203        $i = count( $jpeg_header_data ) - 1;
204        while (( $i >= 0 ) && ( ( $jpeg_header_data[$i]['SegType'] > 0xED ) || ( $jpeg_header_data[$i]['SegType'] < 0xE0 ) ) )
205        {
206                $i--;
207        }
208
209
210
211        // Cycle through the packed output data until it's size is less than 32000 bytes, outputting each 32000 byte block to an APP13 segment
212        while ( strlen( $packed_IRB_data ) > 32000 )
213        {
214                // Change: Fixed put_Photoshop_IRB to output "Photoshop 3.0\x00" string with every APP13 segment, not just the first one, as of 1.03
215
216                // Write a 32000 byte APP13 segment
217                array_splice($jpeg_header_data, $i +1  , 0, array(  "SegType" => 0xED,
218                                                                "SegName" => "APP13",
219                                                                "SegDesc" => $GLOBALS[ "JPEG_Segment_Descriptions" ][ 0xED ],
220                                                                "SegData" => "Photoshop 3.0\x00" . substr( $packed_IRB_data,0,32000) ) );
221
222                // Delete the 32000 bytes from the packed output data, that were just output
223                $packed_IRB_data = substr_replace($packed_IRB_data, '', 0, 32000);
224                $i++;
225        }
226
227        // Write the last block of packed output data to an APP13 segment - Note array_splice doesn't work with multidimensional arrays, hence inserting a blank string
228        array_splice($jpeg_header_data, $i + 1 , 0, "" );
229        $jpeg_header_data[$i + 1] =  array( "SegType" => 0xED,
230                                        "SegName" => "APP13",
231                                        "SegDesc" => $GLOBALS[ "JPEG_Segment_Descriptions" ][ 0xED ],
232                                        "SegData" => "Photoshop 3.0\x00" . $packed_IRB_data );
233
234        return $jpeg_header_data;
235}
236
237/******************************************************************************
238* End of Function:     put_Photoshop_IRB
239******************************************************************************/
240
241
242
243
244
245
246
247
248/******************************************************************************
249*
250* Function:     get_Photoshop_IPTC
251*
252* Description:  Retrieves IPTC-NAA IIM information from within a Photoshop
253*               IRB (if it is present) and returns it in an array. Uses
254*               information supplied by the get_jpeg_header_data function
255*
256* Parameters:   Photoshop_IRB_data - an array of Photoshop IRB records, as
257*                                    returned from get_Photoshop_IRB
258*
259* Returns:      IPTC_Data_Out - The array of IPTC-NAA IIM records
260*               FALSE - if an IPTC-NAA IIM record could not be found, or if
261*                       an error occured
262*
263******************************************************************************/
264
265function get_Photoshop_IPTC( $Photoshop_IRB_data )
266{
267
268        // Change: Initialise array correctly, as of revision 1.10
269        $IPTC_Data_Out = array();
270
271        //Cycle through the Photoshop 8BIM records looking for the IPTC-NAA record
272        for( $i = 0; $i < count( $Photoshop_IRB_data ); $i++ )
273        {
274                // Check if each record is a IPTC record (which has id 0x0404)
275                if ( $Photoshop_IRB_data[$i]['ResID']  == 0x0404 )
276                {
277                        // We've found an IPTC block - Decode it
278                        $IPTC_Data_Out = get_IPTC( $Photoshop_IRB_data[$i]['ResData'] );
279                }
280        }
281
282        // If there was no records put into the output array,
283        if ( count( $IPTC_Data_Out ) == 0 )
284        {
285                // Then return false
286                return FALSE;
287        }
288        else
289        {
290                // Otherwise return the array
291                return $IPTC_Data_Out;
292        }
293
294}
295/******************************************************************************
296* End of Function:     get_Photoshop_IPTC
297******************************************************************************/
298
299
300
301
302
303
304/******************************************************************************
305*
306* Function:     put_Photoshop_IPTC
307*
308* Description:  Inserts a new IPTC-NAA IIM resource into a Photoshop
309*               IRB, or replaces an the existing resource if one is present.
310*               Uses information supplied by the get_Photoshop_IRB function
311*
312* Parameters:   Photoshop_IRB_data - an array of Photoshop IRB records, as
313*                                    returned from get_Photoshop_IRB, into
314*                                    which the IPTC-NAA IIM record will be inserted
315*               new_IPTC_block - an array of IPTC-NAA records in the same format
316*                                as those returned by get_Photoshop_IPTC
317*
318* Returns:      Photoshop_IRB_data - The Photoshop IRB array with the
319*                                     IPTC-NAA IIM resource inserted
320*
321******************************************************************************/
322
323function put_Photoshop_IPTC( $Photoshop_IRB_data, $new_IPTC_block )
324{
325        $iptc_block_pos = -1;
326
327        //Cycle through the 8BIM records looking for the IPTC-NAA record
328        for( $i = 0; $i < count( $Photoshop_IRB_data ); $i++ )
329        {
330                // Check if each record is a IPTC record (which has id 0x0404)
331                if ( $Photoshop_IRB_data[$i]['ResID']  == 0x0404 )
332                {
333                        // We've found an IPTC block - save the position
334                        $iptc_block_pos = $i;
335                }
336        }
337
338        // If no IPTC block was found, create a new one
339        if ( $iptc_block_pos == -1 )
340        {
341                // New block position will be at the end of the array
342                $iptc_block_pos = count( $Photoshop_IRB_data );
343        }
344
345
346        // Write the new IRB resource to the Photoshop IRB array with no data
347        $Photoshop_IRB_data[$iptc_block_pos] = array(   "ResID" =>   0x0404,
348                                                        "ResName" => $GLOBALS['Photoshop_ID_Names'][ 0x0404 ],
349                                                        "ResDesc" => $GLOBALS[ "Photoshop_ID_Descriptions" ][ 0x0404 ],
350                                                        "ResEmbeddedName" => "\x00\x00",
351                                                        "ResData" => put_IPTC( $new_IPTC_block ) );
352
353
354        // Return the modified IRB
355        return $Photoshop_IRB_data;
356}
357
358/******************************************************************************
359* End of Function:     put_Photoshop_IPTC
360******************************************************************************/
361
362
363
364
365
366
367
368
369/******************************************************************************
370*
371* Function:     Interpret_IRB_to_HTML
372*
373* Description:  Generates html showing the information contained in a Photoshop
374*               IRB data array, as retrieved with get_Photoshop_IRB, including
375*               any IPTC-NAA IIM records found.
376*
377*               Please note that the following resource numbers are not currently
378*               decoded: ( Many of these do not apply to JPEG images)
379*               0x03E9, 0x03EE, 0x03EF, 0x03F0, 0x03F1, 0x03F2, 0x03F6, 0x03F9,
380*               0x03FA, 0x03FB, 0x03FD, 0x03FE, 0x0400, 0x0401, 0x0402, 0x0405,
381*               0x040E, 0x040F, 0x0410, 0x0412, 0x0413, 0x0415, 0x0416, 0x0417,
382*               0x041B, 0x041C, 0x041D, 0x0BB7
383*
384*               ( Also these Obsolete resource numbers)
385*               0x03E8, 0x03EB, 0x03FC, 0x03FF, 0x0403
386*
387*
388* Parameters:   IRB_array - a Photoshop IRB data array as from get_Photoshop_IRB
389*               filename - the name of the JPEG file being processed ( used
390*                          by the script which displays the Photoshop thumbnail)
391*
392*
393* Returns:      output_str - the HTML string
394*
395******************************************************************************/
396
397function Interpret_IRB_to_HTML( $IRB_array, $filename )
398{
399        // Create a string to receive the HTML
400        $output_str = "";
401
402        // Check if the Photoshop IRB array is valid
403        if ( $IRB_array !== FALSE )
404        {
405
406                // Create another string to receive secondary HTML to be appended at the end
407                $secondary_output_str = "";
408
409                // Add the Heading to the HTML
410                $output_str .= "<fieldset class='fieldset' ><legend>Contains Photoshop Information Resource Block (IRB)</legend>";
411               
412                // Add Table to the HTML
413                $output_str .= "<table class=\"Photoshop_Table\" border=1>";
414               
415                // Cycle through each of the Photoshop IRB records, creating HTML for each
416                foreach( $IRB_array as $IRB_Resource )
417                {
418                        // Check if the entry is a known Photoshop IRB resource
419
420                        // Get the Name of the Resource
421                        if ( array_key_exists( $IRB_Resource['ResID'], $GLOBALS[ "Photoshop_ID_Names" ] ) )
422                        {
423                                $Resource_Name = $GLOBALS['Photoshop_ID_Names'][ $IRB_Resource['ResID'] ];
424                        }
425                        else
426                        {
427                                // Change: Added check for $GLOBALS['HIDE_UNKNOWN_TAGS'] to allow hiding of unknown resources as of 1.11
428                                if ( $GLOBALS['HIDE_UNKNOWN_TAGS'] == TRUE )
429                                {
430                                        continue;
431                                }
432                                else
433                                {
434                                        // Unknown Resource - Make appropriate name
435                                        $Resource_Name = "Unknown Resource (". $IRB_Resource['ResID'] .")";
436                                }
437                        }
438                $tabval=$IRB_Resource;
439                $tabval['Type_src']="IRB";
440                $tabval['Tag Name']=$Resource_Name;
441                $tabval['Text Value']= "N.C";
442           
443                        // Add HTML for the resource as appropriate
444                        switch ( $IRB_Resource['ResID'] )
445                        {
446
447                                case 0x0404 : // IPTC-NAA IIM Record
448                                        $secondary_output_str .= Interpret_IPTC_to_HTML( get_IPTC( $IRB_Resource['ResData'] ) );
449                                        break;
450
451                                case 0x040B : // URL
452                                         $tabval['Text Value']= "<a href=\"" . $IRB_Resource['ResData'] . "\">" . htmlentities( $IRB_Resource['ResData'] ) ."</a>";
453                                        break;
454
455                                case 0x040A : // Copyright Marked
456                                        if ( hexdec( bin2hex( $IRB_Resource['ResData'] ) ) == 1 )
457                                        {
458                                                 $tabval['Text Value']= "Image is Copyrighted Material";
459                                        }
460                                        else
461                                        {
462                                                 $tabval['Text Value']= "Image is Not Copyrighted Material";
463                                        }
464                                        break;
465
466                                case 0x040D : // Global Lighting Angle
467                                         $tabval['Text Value']= "Global lighting angle for effects layer = " . hexdec( bin2hex( $IRB_Resource['ResData'] ) ) . " degrees";
468                                        break;
469
470                                case 0x0419 : // Global Altitude
471                                         $tabval['Text Value']= "Global Altitude = " . hexdec( bin2hex( $IRB_Resource['ResData'] ) );
472                                        break;
473
474                                case 0x0421 : // Version Info
475                                   
476                                         $tabval['Text Value'] = "Version = " . hexdec( bin2hex( substr( $IRB_Resource['ResData'], 0, 4 ) ) ) . "\n";
477                                         $tabval['Text Value'] .= "Has Real Merged Data = " . ord( $IRB_Resource['ResData']{4} ) . "\n";
478                                        $writer_size = hexdec( bin2hex( substr( $IRB_Resource['ResData'], 5, 4 ) ) ) * 2;
479
480                                         $tabval['Text Value'] .= "Writer Name = " . HTML_UTF16_Escape( substr( $IRB_Resource['ResData'], 9, $writer_size ), TRUE ) . "\n";
481                                        $reader_size = hexdec( bin2hex( substr( $IRB_Resource['ResData'], 9 + $writer_size , 4 ) ) ) * 2;
482                                         $tabval['Text Value'] .= "Reader Name = " . HTML_UTF16_Escape( substr( $IRB_Resource['ResData'], 13 + $writer_size, $reader_size ), TRUE ) . "\n";
483                                         $tabval['Text Value'] .= "File Version = " . hexdec( bin2hex( substr( $IRB_Resource['ResData'], 13 + $writer_size + $reader_size, 4 ) ) ) . "\n";
484                                       
485                                        break;
486
487                                case 0x0411 : // ICC Untagged
488                                        if ( $IRB_Resource['ResData'] == "\x01" )
489                                        {
490                                                 $tabval['Text Value']= "Intentionally untagged - any assumed ICC profile handling disabled";
491                                        }
492                                        else
493                                        {
494                                                 $tabval['Text Value']= "Unknown value (0x" .bin2hex( $IRB_Resource['ResData'] ). ")";
495                                        }
496                                        break;
497
498                                case 0x041A : // Slices
499                                         $tabval['Text Value']= "";
500
501                                        // Unpack the first 24 bytes
502                                        $Slices_Info = unpack("NVersion/NBound_top/NBound_left/NBound_bottom/NBound_right/NStringlen", $IRB_Resource['ResData'] );
503                                        $tabval['Text Value'] .= "Version = " . $Slices_Info['Version'] . "<br>\n";
504                                        $tabval['Text Value'] .= "Bounding Rectangle =  Top:" . $Slices_Info['Bound_top'] . ", Left:" . $Slices_Info['Bound_left'] . ", Bottom:" . $Slices_Info['Bound_bottom'] . ", Right:" . $Slices_Info['Bound_right'] . " (Pixels)<br>\n";
505                                        $Slicepos = 24;
506
507                                        // Extract a Unicode String
508                                       $tabval['Text Value'] .= "Text = '" . HTML_UTF16_Escape( substr( $IRB_Resource['ResData'], 24, $Slices_Info['Stringlen']*2), TRUE ) . "'<br>\n";
509                                        $Slicepos += $Slices_Info['Stringlen'] * 2;
510
511                                        // Unpack the number of Slices
512                                        $Num_Slices = hexdec( bin2hex( substr( $IRB_Resource['ResData'], $Slicepos, 4 ) ) );
513                                        $tabval['Text Value'] .= "Number of Slices = " . $Num_Slices . "\n";
514                                        $Slicepos += 4;
515
516                                        // Cycle through the slices
517                                        for( $i = 1; $i <= $Num_Slices; $i++ )
518                                        {
519                                                 $tabval['Text Value'] .= "<br><br>Slice $i:<br>\n";
520
521                                                // Unpack the first 16 bytes of the slice
522                                                $SliceA = unpack("NID/NGroupID/NOrigin/NStringlen", substr($IRB_Resource['ResData'], $Slicepos ) );
523                                                $Slicepos += 16;
524                                                 $tabval['Text Value'] .= "ID = " . $SliceA['ID'] . "<br>\n";
525                                                 $tabval['Text Value'] .= "Group ID = " . $SliceA['GroupID'] . "<br>\n";
526                                                 $tabval['Text Value'] .= "Origin = " . $SliceA['Origin'] . "<br>\n";
527
528                                                // Extract a Unicode String
529                                                 $tabval['Text Value'] .= "Text = '" . HTML_UTF16_Escape( substr( $IRB_Resource['ResData'], $Slicepos, $SliceA['Stringlen']*2), TRUE ) . "'<br>\n";
530                                                $Slicepos += $SliceA['Stringlen'] * 2;
531
532                                                // Unpack the next 24 bytes of the slice
533                                                $SliceB = unpack("NType/NLeftPos/NTopPos/NRightPos/NBottomPos/NURLlen", substr($IRB_Resource['ResData'], $Slicepos )  );
534                                                $Slicepos += 24;
535                                                 $tabval['Text Value'] .= "Type = " . $SliceB['Type'] . "<br>\n";
536                                                 $tabval['Text Value'] .= "Position =  Top:" . $SliceB['TopPos'] . ", Left:" . $SliceB['LeftPos'] . ", Bottom:" . $SliceB['BottomPos'] . ", Right:" . $SliceB['RightPos'] . " (Pixels)<br>\n";
537
538                                                // Extract a Unicode String
539                                                 $tabval['Text Value'] .= "URL = <a href='" . substr( $IRB_Resource['ResData'], $Slicepos, $SliceB['URLlen']*2) . "'>" . HTML_UTF16_Escape( substr( $IRB_Resource['ResData'], $Slicepos, $SliceB['URLlen']*2), TRUE ) . "</a><br>\n";
540                                                $Slicepos += $SliceB['URLlen'] * 2;
541
542                                                // Unpack the length of a Unicode String
543                                                $Targetlen = hexdec( bin2hex( substr( $IRB_Resource['ResData'], $Slicepos, 4 ) ) );
544                                                $Slicepos += 4;
545                                                // Extract a Unicode String
546                                                 $tabval['Text Value'] .= "Target = '" . HTML_UTF16_Escape( substr( $IRB_Resource['ResData'], $Slicepos, $Targetlen*2), TRUE ) . "'<br>\n";
547                                                $Slicepos += $Targetlen * 2;
548
549                                                // Unpack the length of a Unicode String
550                                                $Messagelen = hexdec( bin2hex( substr( $IRB_Resource['ResData'], $Slicepos, 4 ) ) );
551                                                $Slicepos += 4;
552                                                // Extract a Unicode String
553                                                 $tabval['Text Value'] .= "Message = '" . HTML_UTF16_Escape( substr( $IRB_Resource['ResData'], $Slicepos, $Messagelen*2), TRUE ) . "'<br>\n";
554                                                $Slicepos += $Messagelen * 2;
555
556                                                // Unpack the length of a Unicode String
557                                                $AltTaglen = hexdec( bin2hex( substr( $IRB_Resource['ResData'], $Slicepos, 4 ) ) );
558                                                $Slicepos += 4;
559                                                // Extract a Unicode String
560                                                 $tabval['Text Value'] .= "Alt Tag = '" . HTML_UTF16_Escape( substr( $IRB_Resource['ResData'], $Slicepos, $AltTaglen*2), TRUE ) . "'<br>\n";
561                                                $Slicepos += $AltTaglen * 2;
562
563                                                // Unpack the HTML flag
564                                                if ( ord( $IRB_Resource['ResData']{ $Slicepos } ) === 0x01 )
565                                                {
566                                                         $tabval['Text Value'] .= "Cell Text is HTML<br>\n";
567                                                }
568                                                else
569                                                {
570                                                         $tabval['Text Value'] .= "Cell Text is NOT HTML<br>\n";
571                                                }
572                                                $Slicepos++;
573
574                                                // Unpack the length of a Unicode String
575                                                $CellTextlen = hexdec( bin2hex( substr( $IRB_Resource['ResData'], $Slicepos, 4 ) ) );
576                                                $Slicepos += 4;
577                                                // Extract a Unicode String
578                                                 $tabval['Text Value'] .= "Cell Text = '" . HTML_UTF16_Escape( substr( $IRB_Resource['ResData'], $Slicepos, $CellTextlen*2), TRUE ) . "'<br>\n";
579                                                $Slicepos += $CellTextlen * 2;
580
581
582                                                // Unpack the last 12 bytes of the slice
583                                                $SliceC = unpack("NAlignH/NAlignV/CAlpha/CRed/CGreen/CBlue", substr($IRB_Resource['ResData'], $Slicepos )  );
584                                                $Slicepos += 12;
585                                                 $tabval['Text Value'] .= "Alignment =  Horizontal:" . $SliceC['AlignH'] . ", Vertical:" . $SliceC['AlignV'] . "<br>\n";
586                                                 $tabval['Text Value'] .= "Alpha Colour = " . $SliceC['Alpha'] . "<br>\n";
587                                                 $tabval['Text Value'] .= "Red = " . $SliceC['Red'] . "<br>\n";
588                                                 $tabval['Text Value'] .= "Green = " . $SliceC['Green'] . "<br>\n";
589                                                 $tabval['Text Value'] .= "Blue = " . $SliceC['Blue'] . "\n";
590                                        }
591
592                                       
593
594                                        break;
595
596
597                                case 0x0408 : // Grid and Guides information
598                                         $tabval['Text Value']= "";
599
600                                        // Unpack the Grids info
601                                        $Grid_Info = unpack("NVersion/NGridCycleH/NGridCycleV/NGuideCount", $IRB_Resource['ResData'] );
602                                         $tabval['Text Value'] .= "Version = " . $Grid_Info['Version'] . "<br>\n";
603                                         $tabval['Text Value'] .= "Grid Cycle = " . $Grid_Info['GridCycleH']/32 . " Pixel(s)  x  " . $Grid_Info['GridCycleV']/32 . " Pixel(s)<br>\n";
604                                         $tabval['Text Value'] .= "Number of Guides = " . $Grid_Info['GuideCount'] . "\n";
605
606                                        // Cycle through the Guides
607                                        for( $i = 0; $i < $Grid_Info['GuideCount']; $i++ )
608                                        {
609                                                // Unpack the info for this guide
610                                                $Guide_Info = unpack("NLocation/CDirection", substr($IRB_Resource['ResData'],16+$i*5,5) );
611                                                 $tabval['Text Value'] .= "<br>Guide $i : Location = " . $Guide_Info['Location']/32 . " Pixel(s) from edge";
612                                                if ( $Guide_Info['Direction'] === 0 )
613                                                {
614                                                         $tabval['Text Value'] .= ", Vertical\n";
615                                                }
616                                                else
617                                                {
618                                                         $tabval['Text Value'] .= ", Horizontal\n";
619                                                }
620                                        }
621                                        break;
622                                     
623
624                                case 0x0406 : // JPEG Quality
625                                        $Qual_Info = unpack("nQuality/nFormat/nScans/Cconst", $IRB_Resource['ResData'] );
626                                         $tabval['Text Value']= "";
627                                        switch ( $Qual_Info['Quality'] )
628                                        {
629                                                case 0xFFFD:
630                                                         $tabval['Text Value'] .= "Quality 1 (Low)<br>\n";
631                                                        break;
632                                                case 0xFFFE:
633                                                         $tabval['Text Value'] .= "Quality 2 (Low)<br>\n";
634                                                        break;
635                                                case 0xFFFF:
636                                                         $tabval['Text Value'] .= "Quality 3 (Low)<br>\n";
637                                                        break;
638                                                case 0x0000:
639                                                         $tabval['Text Value'] .= "Quality 4 (Low)<br>\n";
640                                                        break;
641                                                case 0x0001:
642                                                         $tabval['Text Value'] .= "Quality 5 (Medium)<br>\n";
643                                                        break;
644                                                case 0x0002:
645                                                         $tabval['Text Value'] .= "Quality 6 (Medium)<br>\n";
646                                                        break;
647                                                case 0x0003:
648                                                         $tabval['Text Value'] .= "Quality 7 (Medium)<br>\n";
649                                                        break;
650                                                case 0x0004:
651                                                         $tabval['Text Value'] .= "Quality 8 (High)<br>\n";
652                                                        break;
653                                                case 0x0005:
654                                                         $tabval['Text Value'] .= "Quality 9 (High)<br>\n";
655                                                        break;
656                                                case 0x0006:
657                                                         $tabval['Text Value'] .= "Quality 10 (Maximum)<br>\n";
658                                                        break;
659                                                case 0x0007:
660                                                         $tabval['Text Value'] .= "Quality 11 (Maximum)<br>\n";
661                                                        break;
662                                                case 0x0008:
663                                                         $tabval['Text Value'] .= "Quality 12 (Maximum)<br>\n";
664                                                        break;
665                                                default:
666                                                         $tabval['Text Value'] .= "Unknown Quality (" . $Qual_Info['Quality'] . ")<br>\n";
667                                                        break;
668                                        }
669
670                                        switch ( $Qual_Info['Format'] )
671                                        {
672                                                case 0x0000:
673                                                         $tabval['Text Value'] .= "Standard Format\n";
674                                                        break;
675                                                case 0x0001:
676                                                         $tabval['Text Value'] .= "Optimised Format\n";
677                                                        break;
678                                                case 0x0101:
679                                                         $tabval['Text Value'] .= "Progressive Format<br>\n";
680                                                        break;
681                                                default:
682                                                         $tabval['Text Value'] .= "Unknown Format (" . $Qual_Info['Format'] .")\n";
683                                                        break;
684                                        }
685                                        if ( $Qual_Info['Format'] == 0x0101 )
686                                        {
687                                                switch ( $Qual_Info['Scans'] )
688                                                {
689                                                        case 0x0001:
690                                                                 $tabval['Text Value'] .= "3 Scans\n";
691                                                                break;
692                                                        case 0x0002:
693                                                                 $tabval['Text Value'] .= "4 Scans\n";
694                                                                break;
695                                                        case 0x0003:
696                                                                 $tabval['Text Value'] .= "5 Scans\n";
697                                                                break;
698                                                        default:
699                                                                 $tabval['Text Value'] .= "Unknown number of scans (" . $Qual_Info['Scans'] .")\n";
700                                                                break;
701                                                }
702                                        }
703                                         
704                                        break;
705
706                                case 0x0409 : // Thumbnail Resource
707                                case 0x040C : // Thumbnail Resource
708                                        $thumb_data = unpack("NFormat/NWidth/NHeight/NWidthBytes/NSize/NCompressedSize/nBitsPixel/nPlanes", $IRB_Resource['ResData'] );
709                                         $tabval['Text Value']= "";
710                                         $tabval['Text Value'] .= "Format = " . (( $thumb_data['Format'] == 1 ) ? "JPEG RGB\n" :  "Raw RGB\n");
711                                         $tabval['Text Value'] .= "Width = " . $thumb_data['Width'] . "\n";
712                                         $tabval['Text Value'] .= "Height = " . $thumb_data['Height'] . "\n";
713                                         $tabval['Text Value'] .= "Padded Row Bytes = " . $thumb_data['WidthBytes'] . " bytes\n";
714                                         $tabval['Text Value'] .= "Total Size = " . $thumb_data['Size'] . " bytes\n";
715                                         $tabval['Text Value'] .= "Compressed Size = " . $thumb_data['CompressedSize'] . " bytes\n";
716                                         $tabval['Text Value'] .= "Bits per Pixel = " . $thumb_data['BitsPixel'] . " bits\n";
717                                         $tabval['Text Value'] .= "Number of planes = " . $thumb_data['Planes'] . " bytes\n";
718
719                                        // Change: as of version 1.11 - Changed to make thumbnail link portable across directories
720                                        // Build the path of the thumbnail script and its filename parameter to put in a url
721                                        $link_str = get_relative_path( dirname(__FILE__) . "/get_ps_thumb.php" , getcwd ( ) );
722                                        $link_str .= "?filename=";
723                                        $link_str .= get_relative_path( $filename, dirname(__FILE__) );
724
725                                        // Add thumbnail link to html
726                                         $tabval['Text Value'] .= "Thumbnail Data:</pre><a class=\"Photoshop_Thumbnail_Link\" href=\"$link_str\"><img class=\"Photoshop_Thumbnail_Link\" src=\"$link_str\"></a>\n";
727
728                                         $tabval['Text Value'] .=  "</td></tr>\n";
729                                        break;
730
731                                case 0x0414 : // Document Specific ID's
732                                         $tabval['Text Value']=  hexdec( bin2hex( $IRB_Resource['ResData'] ) ) ;
733                                        break;
734
735                                case 0x041E : // URL List
736                                        $URL_count = hexdec( bin2hex( substr( $IRB_Resource['ResData'], 0, 4 ) ) );
737                                         $tabval['Text Value']= "\n";
738                                         $tabval['Text Value'] .= "$URL_count URL's in list<br>\n";
739                                        $urlstr = substr( $IRB_Resource['ResData'], 4 );
740                                        // TODO: Check if URL List in Photoshop IRB works
741                                        for( $i = 0; $i < $URL_count; $i++ )
742                                        {
743                                                $url_data = unpack( "NLong/NID/NURLSize", $urlstr );
744                                                 $tabval['Text Value'] .= "URL $i info: long = " . $url_data['Long'] .", ";
745                                                 $tabval['Text Value'] .= "ID = " . $url_data['ID'] . ", ";
746                                                $urlstr = substr( $urlstr, 12 );
747                                                $url = substr( $urlstr, 0, $url_data['URLSize'] );
748                                                 $tabval['Text Value'] .= "URL = <a href=\"" . xml_UTF16_clean( $url, TRUE ) . "\">" . HTML_UTF16_Escape( $url, TRUE ) . "</a><br>\n";
749                                        }
750                                         $tabval['Text Value'] .= "";
751                                        break;
752                                case 0x03F4 : // Grayscale and multichannel halftoning information.
753                                       
754                                        $tabval['Text Value'] .= Interpret_Halftone( $IRB_Resource['ResData'] );
755                                         
756                                        break;
757                                case 0x03F5 : // Color halftoning information
758                                 
759                                         $tabval['Text Value'] = "Cyan Halftoning Info:\n" . Interpret_Halftone( substr( $IRB_Resource['ResData'], 0, 18 ) ) . "\n\n";
760                                         $tabval['Text Value'] .= "Magenta Halftoning Info:\n" . Interpret_Halftone( substr( $IRB_Resource['ResData'], 18, 18 ) ) . "\n\n";
761                                         $tabval['Text Value'] .= "Yellow Halftoning Info:\n" . Interpret_Halftone( substr( $IRB_Resource['ResData'], 36, 18 ) ) . "\n";
762                                         $tabval['Text Value'] .= "Black Halftoning Info:\n" . Interpret_Halftone( substr( $IRB_Resource['ResData'], 54, 18 ) ) . "\n";
763                                         
764                                        break;
765
766                                case 0x03F7 : // Grayscale and multichannel transfer function.
767 
768                                         $tabval['Text Value'] = Interpret_Transfer_Function( substr( $IRB_Resource['ResData'], 0, 28 ) ) ;
769                                     
770                                        break;
771
772                                case 0x03F8 : // Color transfer functions
773 
774                                        $tabval['Text Value'] = "Red Transfer Function:   \n" . Interpret_Transfer_Function( substr( $IRB_Resource['ResData'], 0, 28 ) ) . "\n";
775                                        $tabval['Text Value'] .= "Green Transfer Function: \n" . Interpret_Transfer_Function( substr( $IRB_Resource['ResData'], 28, 28 ) ) . "\n";
776                                        $tabval['Text Value'] .= "Blue Transfer Function:  \n" . Interpret_Transfer_Function( substr( $IRB_Resource['ResData'], 56, 28 ) ) . "\n";
777                                   
778                                        break;
779
780                                case 0x03F3 : // Print Flags
781                                         $tabval['Text Value']= "";
782                                        if ( $IRB_Resource['ResData']{0} == "\x01" )
783                                        {
784                                                 $tabval['Text Value'] .= "Labels Selected\n";
785                                        }
786                                        else
787                                        {
788                                                 $tabval['Text Value'] .= "Labels Not Selected\n";
789                                        }
790                                        if ( $IRB_Resource['ResData']{1} == "\x01" )
791                                        {
792                                                 $tabval['Text Value'] .= "Crop Marks Selected\n";
793                                        }
794                                        else
795                                        {
796                                                 $tabval['Text Value'] .= "Crop Marks Not Selected\n";
797                                        }
798                                        if ( $IRB_Resource['ResData']{2} == "\x01" )
799                                        {
800                                                 $tabval['Text Value'] .= "Color Bars Selected\n";
801                                        }
802                                        else
803                                        {
804                                                 $tabval['Text Value'] .= "Color Bars Not Selected\n";
805                                        }
806                                        if ( $IRB_Resource['ResData']{3} == "\x01" )
807                                        {
808                                                 $tabval['Text Value'] .= "Registration Marks Selected\n";
809                                        }
810                                        else
811                                        {
812                                                 $tabval['Text Value'] .= "Registration Marks Not Selected\n";
813                                        }
814                                        if ( $IRB_Resource['ResData']{4} == "\x01" )
815                                        {
816                                                 $tabval['Text Value'] .= "Negative Selected\n";
817                                        }
818                                        else
819                                        {
820                                                 $tabval['Text Value'] .= "Negative Not Selected\n";
821                                        }
822                                        if ( $IRB_Resource['ResData']{5} == "\x01" )
823                                        {
824                                                 $tabval['Text Value'] .= "Flip Selected\n";
825                                        }
826                                        else
827                                        {
828                                                 $tabval['Text Value'] .= "Flip Not Selected\n";
829                                        }
830                                        if ( $IRB_Resource['ResData']{6} == "\x01" )
831                                        {
832                                                 $tabval['Text Value'] .= "Interpolate Selected\n";
833                                        }
834                                        else
835                                        {
836                                                 $tabval['Text Value'] .= "Interpolate Not Selected\n";
837                                        }
838                                        if ( $IRB_Resource['ResData']{7} == "\x01" )
839                                        {
840                                                 $tabval['Text Value'] .= "Caption Selected";
841                                        }
842                                        else
843                                        {
844                                                 $tabval['Text Value'] .= "Caption Not Selected";
845                                        }
846                                         
847                                        break;
848
849                                case 0x2710 : // Print Flags Information
850                                        $PrintFlags = unpack( "nVersion/CCentCrop/Cjunk/NBleedWidth/nBleedWidthScale", $IRB_Resource['ResData'] );
851                                         $tabval['Text Value']= "";
852                                         $tabval['Text Value'] .= "Version = " . $PrintFlags['Version'] . "\n";
853                                         $tabval['Text Value'] .= "Centre Crop Marks = " . $PrintFlags['CentCrop'] . "\n";
854                                         $tabval['Text Value'] .= "Bleed Width = " . $PrintFlags['BleedWidth'] . "\n";
855                                         $tabval['Text Value'] .= "Bleed Width Scale = " . $PrintFlags['BleedWidthScale'];
856                                         $tabval['Text Value'] .= "";
857                                        break;
858
859                                case 0x03ED : // Resolution Info
860                                        $ResInfo = unpack( "nhRes_int/nhResdec/nhResUnit/nwidthUnit/nvRes_int/nvResdec/nvResUnit/nheightUnit", $IRB_Resource['ResData'] );
861                                         $tabval['Text Value']= "";
862                                        $tabval['Text Value'] .= "Horizontal Resolution = " . ($ResInfo['hRes_int'] + $ResInfo['hResdec']/65536) . " pixels per Inch";
863                                        $tabval['Text Value'] .= "Vertical Resolution = " . ($ResInfo['vRes_int'] + $ResInfo['vResdec']/65536) . " pixels per Inch";
864                                        if ( $ResInfo['hResUnit'] == 1 )
865                                        {
866                                                $tabval['Text Value'] .= "Display units for Horizontal Resolution = Pixels per Inch\n";
867                                        }
868                                        elseif ( $ResInfo['hResUnit'] == 2 )
869                                        {
870                                                $tabval['Text Value'] .= "Display units for Horizontal Resolution = Pixels per Centimetre\n";
871                                        }
872                                        else
873                                        {
874                                                $tabval['Text Value'] .= "Display units for Horizontal Resolution = Unknown Value (". $ResInfo['hResUnit'] .")\n";
875                                        }
876
877                                        if ( $ResInfo['vResUnit'] == 1 )
878                                        {
879                                                $tabval['Text Value'] .= "Display units for Vertical Resolution = Pixels per Inch\n";
880                                        }
881                                        elseif ( $ResInfo['vResUnit'] == 2 )
882                                        {
883                                                $tabval['Text Value'] .= "Display units for Vertical Resolution = Pixels per Centimetre\n";
884                                        }
885                                        else
886                                        {
887                                               $tabval['Text Value'] .= "Display units for Vertical Resolution = Unknown Value (". $ResInfo['vResUnit'] .")\n";
888                                        }
889
890                                        if ( $ResInfo['widthUnit'] == 1 )
891                                        {
892                                                $tabval['Text Value'] .= "Display units for Image Width = Inches\n";
893                                        }
894                                        elseif ( $ResInfo['widthUnit'] == 2 )
895                                        {
896                                                $tabval['Text Value'] .= "Display units for Image Width = Centimetres\n";
897                                        }
898                                        elseif ( $ResInfo['widthUnit'] == 3 )
899                                        {
900                                               $tabval['Text Value'] .= "Display units for Image Width = Points\n";
901                                        }
902                                        elseif ( $ResInfo['widthUnit'] == 4 )
903                                        {
904                                                $tabval['Text Value'] .= "Display units for Image Width = Picas\n";
905                                        }
906                                        elseif ( $ResInfo['widthUnit'] == 5 )
907                                        {
908                                                $tabval['Text Value'] .= "Display units for Image Width = Columns\n";
909                                        }
910                                        else
911                                        {
912                                                $tabval['Text Value'] .= "Display units for Image Width = Unknown Value (". $ResInfo['widthUnit'] .")\n";
913                                        }
914
915                                        if ( $ResInfo['heightUnit'] == 1 )
916                                        {
917                                                $tabval['Text Value'] .= "Display units for Image Height = Inches";
918                                        }
919                                        elseif ( $ResInfo['heightUnit'] == 2 )
920                                        {
921                                                $tabval['Text Value'] .= "Display units for Image Height = Centimetres";
922                                        }
923                                        elseif ( $ResInfo['heightUnit'] == 3 )
924                                        {
925                                                $tabval['Text Value'] .= "Display units for Image Height = Points";
926                                        }
927                                        elseif ( $ResInfo['heightUnit'] == 4 )
928                                        {
929                                                $tabval['Text Value'] .= "Display units for Image Height = Picas";
930                                        }
931                                        elseif ( $ResInfo['heightUnit'] == 5 )
932                                        {
933                                                $tabval['Text Value'] .= "Display units for Image Height = Columns";
934                                        }
935                                        else
936                                        {
937                                                $tabval['Text Value'] .= "Display units for Image Height = Unknown Value (". $ResInfo['heightUnit'] .")";
938                                        }
939                                        $tabval['Text Value'] .= "";
940                                        break;
941
942                                default : // All other records
943                                         $tabval['Text Value'] = "RESOURCE DECODING NOT IMPLEMENTED YET<BR>" . strlen( $IRB_Resource['ResData'] ) . " bytes";
944
945                        }
946
947$output_str .=OutPut_exif($tabval);
948
949                }
950
951                // Add the table end to the HTML
952                $output_str .= "</table></fieldset>";
953
954                // Add any secondary output to the HTML
955                $output_str .= $secondary_output_str;
956
957        }
958
959        // Return the HTML
960        return $output_str;
961}
962
963/******************************************************************************
964* End of Function:     Interpret_IRB_to_HTML
965******************************************************************************/
966
967
968
969
970
971
972/******************************************************************************
973*
974*         INTERNAL FUNCTIONS
975*
976******************************************************************************/
977
978
979
980
981
982
983
984/******************************************************************************
985*
986* Function:     unpack_Photoshop_IRB_Data
987*
988* Description:  Extracts Photoshop Information Resource Block (IRB) information
989*               from a binary string containing the IRB, as read from a file
990*
991* Parameters:   IRB_Data - The binary string containing the IRB
992*
993* Returns:      IRBdata - The array of Photoshop IRB records
994*
995******************************************************************************/
996
997function unpack_Photoshop_IRB_Data( $IRB_Data )
998{
999        $pos = 0;
1000
1001        // Cycle through the IRB and extract its records - Records are started with 8BIM, so cycle until no more instances of 8BIM can be found
1002        while ( ( $pos < strlen( $IRB_Data ) ) && ( ($pos = strpos( $IRB_Data, "8BIM", $pos) ) !== FALSE ) )
1003        {
1004                // Skip the position over the 8BIM characters
1005                $pos += 4;
1006
1007                // Next two characters are the record ID - denoting what type of record it is.
1008                $ID = ord( $IRB_Data{ $pos } ) * 256 + ord( $IRB_Data{ $pos +1 } );
1009
1010                // Skip the positionover the two record ID characters
1011                $pos += 2;
1012
1013                // Next comes a Record Name - usually not used, but it should be a null terminated string, padded with 0x00 to be an even length
1014                $namestartpos = $pos;
1015
1016                // Change: Fixed processing of embedded resource names, as of revision 1.10
1017
1018                // NOTE: Photoshop does not process resource names according to the standard :
1019                // "Adobe Photoshop 6.0 File Formats Specification, Version 6.0, Release 2, November 2000"
1020                //
1021                // The resource name is actually formatted as follows:
1022                // One byte name length, followed by the null terminated ascii name string.
1023                // The field is then padded with a Null character if required, to ensure that the
1024                // total length of the name length and name is even.
1025
1026                // Name - process it
1027                // Get the length
1028                $namelen = ord ( $IRB_Data{ $namestartpos } );
1029
1030                // Total length of name and length info must be even, hence name length must be odd
1031                // Check if the name length is even,
1032                if ( $namelen % 2 == 0 )
1033                {
1034                        // add one to length to make it odd
1035                        $namelen ++;
1036                }
1037                // Extract the name
1038                $resembeddedname = trim( substr ( $IRB_Data, $namestartpos+1,  $namelen) );
1039                $pos += $namelen + 1;
1040
1041
1042                // Next is a four byte size field indicating the size in bytes of the record's data  - MSB first
1043                $datasize =     ord( $IRB_Data{ $pos } ) * 16777216 + ord( $IRB_Data{ $pos + 1 } ) * 65536 +
1044                                ord( $IRB_Data{ $pos + 2 } ) * 256 + ord( $IRB_Data{ $pos + 3 } );
1045                $pos += 4;
1046
1047                // The record is stored padded with 0x00 characters to make the size even, so we need to calculate the stored size
1048                $storedsize =  $datasize + ($datasize % 2);
1049
1050                $resdata = substr ( $IRB_Data, $pos, $datasize );
1051
1052                // Get the description for this resource
1053                // Check if this is a Path information Resource, since they have a range of ID's
1054                if ( ( $ID >= 0x07D0 ) && ( $ID <= 0x0BB6 ) )
1055                {
1056                        $ResDesc = "ID Info : Path Information (saved paths).";
1057                }
1058                else
1059                {
1060                        if ( array_key_exists( $ID, $GLOBALS[ "Photoshop_ID_Descriptions" ] ) )
1061                        {
1062                                $ResDesc = $GLOBALS[ "Photoshop_ID_Descriptions" ][ $ID ];
1063                        }
1064                        else
1065                        {
1066                                $ResDesc = "";
1067                        }
1068                }
1069
1070                // Get the Name of the Resource
1071                if ( array_key_exists( $ID, $GLOBALS[ "Photoshop_ID_Names" ] ) )
1072                {
1073                        $ResName = $GLOBALS['Photoshop_ID_Names'][ $ID ];
1074                }
1075                else
1076                {
1077                        $ResName = "";
1078                }
1079
1080
1081                // Store the Resource in the array to be returned
1082
1083                $IRB_Array[] = array(     "ResID" => $ID,
1084                                        "ResName" => $ResName,
1085                                        "ResDesc" => $ResDesc,
1086                                        "ResEmbeddedName" => $resembeddedname,
1087                                        "ResData" => $resdata );
1088
1089                // Jump over the data to the next record
1090                $pos += $storedsize;
1091        }
1092
1093        // Return the array created
1094        return $IRB_Array;
1095}
1096
1097/******************************************************************************
1098* End of Function:     unpack_Photoshop_IRB_Data
1099******************************************************************************/
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111/******************************************************************************
1112*
1113* Function:     pack_Photoshop_IRB_Data
1114*
1115* Description:  Packs a Photoshop Information Resource Block (IRB) array into it's
1116*               binary form, which can be written to a file
1117*
1118* Parameters:   IRB_data - an Photoshop IRB array to be converted. Should be in
1119*                          the same format as received from get_Photoshop_IRB
1120*
1121* Returns:      packed_IRB_data - the binary string of packed IRB data
1122*
1123******************************************************************************/
1124
1125function pack_Photoshop_IRB_Data( $IRB_data )
1126{
1127        $packed_IRB_data = "";
1128
1129        // Cycle through each resource in the IRB,
1130        foreach ($IRB_data as $resource)
1131        {
1132
1133                // Change: Fix to avoid creating blank resources, as of revision 1.10
1134
1135                // Check if there is actually any data for this resource
1136                if( strlen( $resource['ResData'] ) == 0 )
1137                {
1138                        // No data for resource - skip it
1139                        continue;
1140                }
1141
1142                // Append the 8BIM tag, and resource ID to the packed output data
1143                $packed_IRB_data .= pack("a4n", "8BIM", $resource['ResID'] );
1144
1145
1146                // Change: Fixed processing of embedded resource names, as of revision 1.10
1147
1148                // NOTE: Photoshop does not process resource names according to the standard :
1149                // "Adobe Photoshop 6.0 File Formats Specification, Version 6.0, Release 2, November 2000"
1150                //
1151                // The resource name is actually formatted as follows:
1152                // One byte name length, followed by the null terminated ascii name string.
1153                // The field is then padded with a Null character if required, to ensure that the
1154                // total length of the name length and name is even.
1155
1156                // Append Name Size
1157                $packed_IRB_data .= pack( "c", strlen(trim($resource['ResEmbeddedName'])));
1158
1159                // Append the Resource Name to the packed output data
1160                $packed_IRB_data .= trim($resource['ResEmbeddedName']);
1161
1162                // If the resource name is even length, then with the addition of
1163                // the size it becomes odd and needs to be padded to an even number
1164                if ( strlen( trim($resource['ResEmbeddedName']) ) % 2 == 0 )
1165                {
1166                        // then it needs to be evened up by appending another null
1167                        $packed_IRB_data .= "\x00";
1168                }
1169
1170                // Append the resource data size to the packed output data
1171                $packed_IRB_data .= pack("N", strlen( $resource['ResData'] ) );
1172
1173                // Append the resource data to the packed output data
1174                $packed_IRB_data .= $resource['ResData'];
1175
1176                // If the resource data is odd length,
1177                if ( strlen( $resource['ResData'] ) % 2 == 1 )
1178                {
1179                        // then it needs to be evened up by appending another null
1180                        $packed_IRB_data .= "\x00";
1181                }
1182        }
1183
1184        // Return the packed data string
1185        return $packed_IRB_data;
1186}
1187
1188/******************************************************************************
1189* End of Function:     pack_Photoshop_IRB_Data
1190******************************************************************************/
1191
1192
1193
1194
1195
1196
1197
1198
1199/******************************************************************************
1200*
1201* Internal Function:     Interpret_Transfer_Function
1202*
1203* Description:  Used by Interpret_IRB_to_HTML to interpret Color transfer functions
1204*               for Photoshop IRB resource 0x03F8. Converts the transfer function
1205*               information to a human readable version.
1206*
1207* Parameters:   Transfer_Function_Binary - a 28 byte Ink curves structure string
1208*
1209* Returns:      output_str - the text string containing the transfer function
1210*                            information
1211*
1212******************************************************************************/
1213
1214function Interpret_Transfer_Function( $Transfer_Function_Binary )
1215{
1216        // Unpack the Transfer function information
1217        $Trans_vals = unpack ( "n13Curve/nOverride",  $Transfer_Function_Binary );
1218
1219        $output_str = "Transfer Function Points: ";
1220
1221        // Cycle through each of the Transfer function array values
1222        foreach ( $Trans_vals as $Key => $val )
1223        {
1224                // Check if the value should be negative
1225                if ($val > 32768 )
1226                {
1227                        // Value should be negative - make it so
1228                        $val = $val - 65536;
1229                }
1230                // Check that the Override item is not getting in this list, and
1231                // that the value is not -1, which means ignored
1232                if ( ( $Key != "Override" ) && ( $val != -1 ) )
1233                {
1234                        // This is a valid transfer function point, output it
1235                        $output_str .= $val/10 . "%, ";
1236                }
1237        }
1238
1239        // Output the override info
1240        if ( $Trans_vals['Override'] == 0 )
1241        {
1242                $output_str .= "\nOverride: Let printer supply curve";
1243        }
1244        else
1245        {
1246                $output_str .= "\nOverride: Override printer’s default transfer curve";
1247        }
1248
1249        // Return the result
1250        return $output_str;
1251}
1252
1253/******************************************************************************
1254* End of Function:     Interpret_Transfer_Function
1255******************************************************************************/
1256
1257
1258
1259
1260
1261/******************************************************************************
1262*
1263* Internal Function:     Interpret_Halftone
1264*
1265* Description:  Used by Interpret_IRB_to_HTML to interpret Color halftoning information
1266*               for Photoshop IRB resource 0x03F5. Converts the halftoning info
1267*               to a human readable version.
1268*
1269* Parameters:   Transfer_Function_Binary - a 18 byte Halftone screen parameter
1270&                                          structure string
1271*
1272* Returns:      output_str - the text string containing the transfer function
1273*                            information
1274*
1275******************************************************************************/
1276
1277function Interpret_Halftone( $Halftone_Binary )
1278{
1279        // Create a string to receive the output
1280        $output_str = "";
1281
1282        // Unpack the binary data into an array
1283        $HalftoneInfo = unpack( "nFreqVal_int/nFreqVal_dec/nFreqScale/nAngle_int/nAngle_dec/nShapeCode/NMisc/CAccurate/CDefault", $Halftone_Binary );
1284
1285        // Interpret Ink Screen Frequency
1286        $output_str .= "Ink Screen Frequency = " . ($HalftoneInfo['FreqVal_int'] + $HalftoneInfo['FreqVal_dec']/65536) . " lines per Inch\n";
1287        if ( $HalftoneInfo['FreqScale'] == 1 )
1288        {
1289                $output_str .= "Display units for Ink Screen Frequency = Inches\n";
1290        }
1291        else
1292        {
1293                $output_str .= "Display units for Ink Screen Frequency = Centimetres\n";
1294        }
1295
1296        // Interpret Angle for screen
1297        $output_str .= "Angle for screen = " . ($HalftoneInfo['Angle_int'] + $HalftoneInfo['Angle_dec']/65536) . " degrees\n";
1298
1299        // Interpret Shape of Halftone Dots
1300        if ($HalftoneInfo['ShapeCode'] > 32768 )
1301        {
1302                $HalftoneInfo['ShapeCode'] = $HalftoneInfo['ShapeCode'] - 65536;
1303        }
1304        if ( $HalftoneInfo['ShapeCode'] == 0 )
1305        {
1306                $output_str .= "Shape of Halftone Dots = Round\n";
1307        }
1308        elseif ( $HalftoneInfo['ShapeCode'] == 1 )
1309        {
1310                $output_str .= "Shape of Halftone Dots = Ellipse\n";
1311        }
1312        elseif ( $HalftoneInfo['ShapeCode'] == 2 )
1313        {
1314                $output_str .= "Shape of Halftone Dots = Line\n";
1315        }
1316        elseif ( $HalftoneInfo['ShapeCode'] == 3 )
1317        {
1318                $output_str .= "Shape of Halftone Dots = Square\n";
1319        }
1320        elseif ( $HalftoneInfo['ShapeCode'] == 4 )
1321        {
1322                $output_str .= "Shape of Halftone Dots = Cross\n";
1323        }
1324        elseif ( $HalftoneInfo['ShapeCode'] == 6 )
1325        {
1326                $output_str .= "Shape of Halftone Dots = Diamond\n";
1327        }
1328        else
1329        {
1330                $output_str .= "Shape of Halftone Dots = Unknown shape (" . $HalftoneInfo['ShapeCode'] . ")\n";
1331        }
1332
1333        // Interpret Accurate Screens
1334        if ( $HalftoneInfo['Accurate'] == 1 )
1335        {
1336                $output_str .= "Use Accurate Screens Selected\n";
1337        }
1338        else
1339        {
1340                $output_str .= "Use Other (not Accurate) Screens Selected\n";
1341        }
1342
1343        // Interpret Printer Default Screens
1344        if ( $HalftoneInfo['Default'] == 1 )
1345        {
1346                $output_str .= "Use printer’s default screens\n";
1347        }
1348        else
1349        {
1350                $output_str .= "Use Other (not Printer Default) Screens Selected\n";
1351        }
1352
1353        // Return Text
1354        return $output_str;
1355
1356}
1357
1358/******************************************************************************
1359* End of Global Variable:     Interpret_Halftone
1360******************************************************************************/
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373/******************************************************************************
1374* Global Variable:      Photoshop_ID_Names
1375*
1376* Contents:     The Names of the Photoshop IRB resources, indexed by their
1377*               resource number
1378*
1379******************************************************************************/
1380
1381$GLOBALS[ "Photoshop_ID_Names" ] = array(
13820x03E8 => "Number of channels, rows, columns, depth, and mode. (Obsolete)",
13830x03E9 => "Macintosh print manager info ",
13840x03EB => "Indexed color table (Obsolete)",
13850x03ED => "Resolution Info",
13860x03EE => "Alpha Channel Names",
13870x03EF => "Display Info",
13880x03F0 => "Caption String",
13890x03F1 => "Border information",
13900x03F2 => "Background color",
13910x03F3 => "Print flags",
13920x03F4 => "Grayscale and multichannel halftoning information",
13930x03F5 => "Color halftoning information",
13940x03F6 => "Duotone halftoning information",
13950x03F7 => "Grayscale and multichannel transfer function",
13960x03F8 => "Color transfer functions",
13970x03F9 => "Duotone transfer functions",
13980x03FA => "Duotone image information",
13990x03FB => "Black and white values",
14000x03FC => "Obsolete Resource.",
14010x03FD => "EPS options",
14020x03FE => "Quick Mask information",
14030x03FF => "Obsolete Resource",
14040x0400 => "Layer state information",
14050x0401 => "Working path (not saved)",
14060x0402 => "Layers group information",
14070x0403 => "Obsolete Resource",
14080x0404 => "IPTC-NAA record",
14090x0405 => "Raw Format Image mode",
14100x0406 => "JPEG quality",
14110x0408 => "Grid and guides information",
14120x0409 => "Thumbnail resource",
14130x040A => "Copyright flag",
14140x040B => "URL",
14150x040C => "Thumbnail resource",
14160x040D => "Global Angle",
14170x040E => "Color samplers resource",
14180x040F => "ICC Profile",
14190x0410 => "Watermark",
14200x0411 => "ICC Untagged",
14210x0412 => "Effects visible",
14220x0413 => "Spot Halftone",
14230x0414 => "Document Specific IDs",
14240x0415 => "Unicode Alpha Names",
14250x0416 => "Indexed Color Table Count",
14260x0417 => "Tansparent Index. Index of transparent color, if any.",
14270x0419 => "Global Altitude",
14280x041A => "Slices",
14290x041B => "Workflow URL",
14300x041C => "Jump To XPEP",
14310x041D => "Alpha Identifiers",
14320x041E => "URL List",
14330x0421 => "Version Info",
14340x0BB7 => "Name of clipping path.",
14350x2710 => "Print flags information"
1436);
1437
1438/******************************************************************************
1439* End of Global Variable:     Photoshop_ID_Names
1440******************************************************************************/
1441
1442
1443
1444
1445
1446/******************************************************************************
1447* Global Variable:      Photoshop_ID_Descriptions
1448*
1449* Contents:     The Descriptions of the Photoshop IRB resources, indexed by their
1450*               resource number
1451*
1452******************************************************************************/
1453
1454$GLOBALS[ "Photoshop_ID_Descriptions" ] = array(
14550x03E8 => "Obsolete—Photoshop 2.0 only. number of channels, rows, columns, depth, and mode.",
14560x03E9 => "Optional. Macintosh print manager print info record.",
14570x03EB => "Obsolete—Photoshop 2.0 only. Contains the indexed color table.",
14580x03ED => "ResolutionInfo structure. See Appendix A in Photoshop SDK Guide.pdf",
14590x03EE => "Names of the alpha channels as a series of Pascal strings.",
14600x03EF => "DisplayInfo structure. See Appendix A in Photoshop SDK Guide.pdf",
14610x03F0 => "Optional. The caption as a Pascal string.",
14620x03F1 => "Border information. border width, border units",
14630x03F2 => "Background color.",
14640x03F3 => "Print flags. labels, crop marks, color bars, registration marks, negative, flip, interpolate, caption.",
14650x03F4 => "Grayscale and multichannel halftoning information.",
14660x03F5 => "Color halftoning information.",
14670x03F6 => "Duotone halftoning information.",
14680x03F7 => "Grayscale and multichannel transfer function.",
14690x03F8 => "Color transfer functions.",
14700x03F9 => "Duotone transfer functions.",
14710x03FA => "Duotone image information.",
14720x03FB => "Effective black and white values for the dot range.",
14730x03FC => "Obsolete Resource.",
14740x03FD => "EPS options.",
14750x03FE => "Quick Mask information. Quick Mask channel ID, Mask initially empty.",
14760x03FF => "Obsolete Resource.",
14770x0400 => "Layer state information. Index of target layer.",
14780x0401 => "Working path (not saved).",
14790x0402 => "Layers group information. Group ID for the dragging groups. Layers in a group have the same group ID.",
14800x0403 => "Obsolete Resource.",
14810x0404 => "IPTC-NAA record. This contains the File Info... information. See the IIMV4.pdf document.",
14820x0405 => "Image mode for raw format files.",
14830x0406 => "JPEG quality. Private.",
14840x0408 => "Grid and guides information.",
14850x0409 => "Thumbnail resource.",
14860x040A => "Copyright flag. Boolean indicating whether image is copyrighted. Can be set via Property suite or by user in File Info...",
14870x040B => "URL. Handle of a text string with uniform resource locator. Can be set via Property suite or by user in File Info...",
14880x040C => "Thumbnail resource.",
14890x040D => "Global Angle. Global lighting angle for effects layer.",
14900x040E => "Color samplers resource.",
14910x040F => "ICC Profile. The raw bytes of an ICC format profile, see the ICC34.pdf and ICC34.h files from the Internation Color Consortium.",
14920x0410 => "Watermark.",
14930x0411 => "ICC Untagged. Disables any assumed profile handling when opening the file. 1 = intentionally untagged.",
14940x0412 => "Effects visible. Show/hide all the effects layer.",
14950x0413 => "Spot Halftone. Version, length, variable length data.",
14960x0414 => "Document specific IDs for layer identification",
14970x0415 => "Unicode Alpha Names. Length and the string",
14980x0416 => "Indexed Color Table Count. Number of colors in table that are actually defined",
14990x0417 => "Transparent Index. Index of transparent color, if any.",
15000x0419 => "Global Altitude.",
15010x041A => "Slices.",
15020x041B => "Workflow URL. Length, string.",
15030x041C => "Jump To XPEP. Major version, Minor version, Count. Table which can include: Dirty flag, Mod date.",
15040x041D => "Alpha Identifiers.",
15050x041E => "URL List. Count of URLs, IDs, and strings",
15060x0421 => "Version Info. Version, HasRealMergedData, string of writer name, string of reader name, file version.",
15070x0BB7 => "Name of clipping path.",
15080x2710 => "Print flags information. Version, Center crop marks, Bleed width value, Bleed width scale."
1509);
1510
1511/******************************************************************************
1512* End of Global Variable:     Photoshop_ID_Descriptions
1513******************************************************************************/
1514
1515
1516
1517
1518
1519
1520?>
Note: See TracBrowser for help on using the repository browser.