/****************************************************************************** * * Filename: Photoshop_IRB.php * * Description: Provides functions for reading and writing information to/from * the 'App 13' Photoshop Information Resource Block segment of * JPEG format files * * Author: Evan Hunter * * Date: 23/7/2004 * * Project: PHP JPEG Metadata Toolkit * * Revision: 1.00 * * URL: http://electronics.ozhiker.com * * Copyright: Copyright Evan Hunter 2004 * * License: This file is part of the PHP JPEG Metadata Toolkit. * * The PHP JPEG Metadata Toolkit is free software; you can * redistribute it and/or modify it under the terms of the * GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your * option) any later version. * * The PHP JPEG Metadata Toolkit is distributed in the hope * that it will be useful, but WITHOUT ANY WARRANTY; without * even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public * License along with the PHP JPEG Metadata Toolkit; if not, * write to the Free Software Foundation, Inc., 59 Temple * Place, Suite 330, Boston, MA 02111-1307 USA * * If you require a different license for commercial or other * purposes, please contact the author: evan@ozhiker.com * ******************************************************************************/ include_once 'IPTC.php'; include_once 'Unicode.php'; // TODO: Many Photoshop IRB resources not interpeted // TODO: Obtain a copy of the Photoshop CS File Format Specification // TODO: Find out what Photoshop IRB resources 1061, 1062 & 1064 are /****************************************************************************** * * Function: get_Photoshop_IRB * * Description: Retrieves the Photoshop Information Resource Block (IRB) information * from an App13 JPEG segment and returns it as an array. This may * include IPTC-NAA IIM Information. Uses information * supplied by the get_jpeg_header_data function * * Parameters: jpeg_header_data - a JPEG header data array in the same format * as from get_jpeg_header_data * * Returns: IRBdata - The array of Photoshop IRB records * FALSE - if an APP 13 Photoshop IRB segment could not be found, * or if an error occured * ******************************************************************************/ function get_Photoshop_IRB( $jpeg_header_data ) { // Photoshop Image Resource blocks can span several JPEG APP13 segments, so we need to join them up if there are more than one $joined_IRB = ""; //Cycle through the header segments for( $i = 0; $i < count( $jpeg_header_data ); $i++ ) { // If we find an APP13 header, if ( strcmp ( $jpeg_header_data[$i]['SegName'], "APP13" ) == 0 ) { // And if it has the photoshop label, if( strncmp ( $jpeg_header_data[$i]['SegData'], "Photoshop 3.0\x00", 14) == 0 ) { // join it to the other previous IRB data $joined_IRB .= substr ( $jpeg_header_data[$i]['SegData'], 14 ); } } } // If there was some Photoshop IRB information found, if ( $joined_IRB != "" ) { // Found a Photoshop Image Resource Block $pos = 0; // Cycle through the IRB and extract its records - Records are started with 8BIM, so cycle until no more instances of 8BIM can be found while ( ( $pos < strlen( $joined_IRB) ) && ( ($pos = strpos( $joined_IRB, "8BIM", $pos) ) !== FALSE ) ) { // Skip the position over the 8BIM characters $pos += 4; // Next two characters are the record ID - denoting what type of record it is. $ID = ord( $joined_IRB{ $pos } ) * 256 + ord( $joined_IRB{ $pos +1 } ); // Skip the positionover the two record ID characters $pos += 2; // Next comes a Record Name - usually not used, but it is a null terminated string, padded with 0x00 to be an even length $namestartpos = $pos; // cycle through in steps of two characters until one of them is a 0x00 do { $pos +=2; } while( ( $joined_IRB{ $pos -2 } != "\x00" ) && ( $joined_IRB{ $pos -1 } != "\x00" ) ); // Extract the record Name $resembeddedname = trim( substr ( $joined_IRB, $namestartpos, $pos - $namestartpos ) ); // Next is a four byte size field indicating the size in bytes of the record's data - MSB first $datasize = ord( $joined_IRB{ $pos } ) * 16777216 + ord( $joined_IRB{ $pos + 1 } ) * 65536 + ord( $joined_IRB{ $pos + 2 } ) * 256 + ord( $joined_IRB{ $pos + 3 } ); $pos += 4; // The record is stored padded with 0x00 characters to make the size even, so we need to calculate the stored size $storedsize = $datasize + ($datasize % 2); $resdata = substr ( $joined_IRB, $pos, $datasize ); // Get the description for this resource // Check if this is a Path information Resource, since they have a range of ID's if ( ( $ID >= 0x07D0 ) && ( $ID <= 0x0BB6 ) ) { $ResDesc = "ID Info : Path Information (saved paths)."; } else { if ( array_key_exists( $ID, $GLOBALS[ "Photoshop_ID_Descriptions" ] ) ) { $ResDesc = $GLOBALS[ "Photoshop_ID_Descriptions" ][ $ID ]; } else { $ResDesc = ""; } } // Get the Name of the Resource if ( array_key_exists( $ID, $GLOBALS[ "Photoshop_ID_Names" ] ) ) { $ResName = $GLOBALS['Photoshop_ID_Names'][ $ID ]; } else { $ResName = ""; } // Store the Resource in the array to be returned $IRBdata[] = array( "ResID" => $ID, "ResName" => $ResName, "ResDesc" => $ResDesc, "ResEmbeddedName" => $resembeddedname, "ResData" => $resdata ); // Jump over the data to the next record $pos += $storedsize; } return $IRBdata; } else { // No Photoshop IRB found return FALSE; } } /****************************************************************************** * End of Function: get_Photoshop_IRB ******************************************************************************/ /****************************************************************************** * * Function: put_Photoshop_IRB * * Description: Adds or modifies the Photoshop Information Resource Block (IRB) * information from an App13 JPEG segment. If a Photoshop IRB already * exists, it is replaced, otherwise a new one is inserted, using the * supplied data. Uses information supplied by the get_jpeg_header_data * function * * Parameters: jpeg_header_data - a JPEG header data array in the same format * as from get_jpeg_header_data * new_IRB_data - an array of the data to be stored in the Photoshop * IRB segment. Should be in the same format as received * from get_Photoshop_IRB * * Returns: jpeg_header_data - the JPEG header data array with the * Photoshop IRB added. * FALSE - if an error occured * ******************************************************************************/ function put_Photoshop_IRB( $jpeg_header_data, $new_IRB_data ) { // Photoshop Image Resource blocks can span several JPEG APP13 segments, so we need to join them up if there are more than one $joined_IRB = ""; // Delete all existing Photoshop IRB blocks - the new one will replace them //Cycle through the header segments for( $i = 0; $i < count( $jpeg_header_data ) ; $i++ ) { // If we find an APP13 header, if ( strcmp ( $jpeg_header_data[$i]['SegName'], "APP13" ) == 0 ) { // And if it has the photoshop label, if( strncmp ( $jpeg_header_data[$i]['SegData'], "Photoshop 3.0\x00", 14) == 0 ) { // Delete the block information - it needs to be rebuilt array_splice( $jpeg_header_data, $i, 1 ); } } } // Now we have deleted the pre-existing blocks $packed_IRB_data = "Photoshop 3.0\x00"; // Cycle through each resource in the new IRB, foreach ($new_IRB_data as $resource) { // Append the 8BIM tag, and resource ID to the packed output data $packed_IRB_data .= pack("a4n", "8BIM", $resource['ResID'] ); // Append the Resource Name to the packed output data $packed_IRB_data .= trim($resource['ResEmbeddedName']) . "\x00"; // If the resource name is odd length, if ( strlen( trim($resource['ResEmbeddedName']) . "\x00" ) % 2 == 1 ) { // then it needs to be evened up by appending another null $packed_IRB_data .= "\x00"; } // Append the resource data size to the packed output data $packed_IRB_data .= pack("N", strlen( $resource['ResData'] ) ); // Append the resource data to the packed output data $packed_IRB_data .= $resource['ResData']; // If the resource data is odd length, if ( strlen( $resource['ResData'] ) % 2 == 1 ) { // then it needs to be evened up by appending another null $packed_IRB_data .= "\x00"; } } //Cycle through the header segments in reverse order (to find where to put the APP13 block - after any APP0 to APP12 blocks) $i = count( $jpeg_header_data ) - 1; while (( $i >= 0 ) && ( ( $jpeg_header_data[$i]['SegType'] > 0xED ) || ( $jpeg_header_data[$i]['SegType'] <= 0xE0 ) ) ) { $i--; } // Cycle through the packed output data until it's size is less than 32000 bytes, outputting each 32000 byte block to an APP13 segment while ( strlen( $packed_IRB_data ) > 32000 ) { // Write a 32000 byte APP13 segment array_splice($jpeg_header_data, $i , 0, array( "SegType" => 0xED, "SegName" => "APP13", "SegDesc" => $GLOBALS[ "JPEG_Segment_Descriptions" ][ 0xED ], "SegData" => substr( $packed_IRB_data,0,32000) ) ); // Delete the 32000 bytes from the packed output data, that were just output $packed_IRB_data = substr_replace($packed_IRB_data, '', 0, 32000); $i++; } // 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 array_splice($jpeg_header_data, $i , 0, "" ); $jpeg_header_data[$i] = array( "SegType" => 0xED, "SegName" => "APP13", "SegDesc" => $GLOBALS[ "JPEG_Segment_Descriptions" ][ 0xED ], "SegData" => $packed_IRB_data ); return $jpeg_header_data; } /****************************************************************************** * End of Function: put_Photoshop_IRB ******************************************************************************/ /****************************************************************************** * * Function: get_Photoshop_IPTC * * Description: Retrieves IPTC-NAA IIM information from within a Photoshop * IRB (if it is present) and returns it in an array. Uses * information supplied by the get_jpeg_header_data function * * Parameters: Photoshop_IRB_data - an array of Photoshop IRB records, as * returned from get_Photoshop_IRB * * Returns: IPTC_Data_Out - The array of IPTC-NAA IIM records * FALSE - if an IPTC-NAA IIM record could not be found, or if * an error occured * ******************************************************************************/ function get_Photoshop_IPTC( $Photoshop_IRB_data ) { //Cycle through the Photoshop 8BIM records looking for the IPTC-NAA record for( $i = 0; $i < count( $Photoshop_IRB_data ); $i++ ) { // Check if each record is a IPTC record (which has id 0x0404) if ( $Photoshop_IRB_data[$i]['ResID'] == 0x0404 ) { // We've found an IPTC block - Decode it $IPTC_Data_Out = get_IPTC( $Photoshop_IRB_data[$i]['ResData'] ); } } // If there was no records put into the output array, if ( count( $IPTC_Data_Out ) == 0 ) { // Then return false return FALSE; } else { // Otherwise return the array return $IPTC_Data_Out; } } /****************************************************************************** * End of Function: get_Photoshop_IPTC ******************************************************************************/ /****************************************************************************** * * Function: put_Photoshop_IPTC * * Description: Inserts a new IPTC-NAA IIM resource into a Photoshop * IRB, or replaces an the existing resource if one is present. * Uses information supplied by the get_Photoshop_IRB function * * Parameters: Photoshop_IRB_data - an array of Photoshop IRB records, as * returned from get_Photoshop_IRB, into * which the IPTC-NAA IIM record will be inserted * new_IPTC_block - an array of IPTC-NAA records in the same format * as those returned by get_Photoshop_IPTC * * Returns: Photoshop_IRB_data - The Photoshop IRB array with the * IPTC-NAA IIM resource inserted * ******************************************************************************/ function put_Photoshop_IPTC( $Photoshop_IRB_data, $new_IPTC_block ) { $iptc_block_pos = -1; //Cycle through the 8BIM records looking for the IPTC-NAA record for( $i = 0; $i < count( $Photoshop_IRB_data ); $i++ ) { // Check if each record is a IPTC record (which has id 0x0404) if ( $Photoshop_IRB_data[$i]['ResID'] == 0x0404 ) { // We've found an IPTC block - save the position $iptc_block_pos = $i; } } // If no IPTC block was found, create a new one if ( $iptc_block_pos == -1 ) { // New block position will be at the end of the array $iptc_block_pos = count( $Photoshop_IRB_data ); } // Write the new IRB resource to the Photoshop IRB array with no data $Photoshop_IRB_data[$iptc_block_pos] = array( "ResID" => 0x0404, "ResName" => $GLOBALS['Photoshop_ID_Names'][ 0x0404 ], "ResDesc" => $GLOBALS[ "Photoshop_ID_Descriptions" ][ 0x0404 ], "ResEmbeddedName" => "\x00\x00", "ResData" => put_IPTC( $new_IPTC_block ) ); // Return the modified IRB return $Photoshop_IRB_data; } /****************************************************************************** * End of Function: put_Photoshop_IPTC ******************************************************************************/ /****************************************************************************** * * Function: Interpret_IRB_to_HTML * * Description: Generates html showing the information contained in a Photoshop * IRB data array, as retrieved with get_Photoshop_IRB, including * any IPTC-NAA IIM records found. * * Please note that the following resource numbers are not currently * decoded: ( Many of these do not apply to JPEG images) * 0x03E9, 0x03EE, 0x03EF, 0x03F0, 0x03F1, 0x03F2, 0x03F6, 0x03F9, * 0x03FA, 0x03FB, 0x03FD, 0x03FE, 0x0400, 0x0401, 0x0402, 0x0405, * 0x040E, 0x040F, 0x0410, 0x0412, 0x0413, 0x0415, 0x0416, 0x0417, * 0x041B, 0x041C, 0x041D, 0x0BB7 * * ( Also these Obsolete resource numbers) * 0x03E8, 0x03EB, 0x03FC, 0x03FF, 0x0403 * * * Parameters: IRB_array - a Photoshop IRB data array as from get_Photoshop_IRB * filename - the name of the JPEG file being processed ( used * by the script which displays the Photoshop thumbnail) * * * Returns: output_str - the HTML string * ******************************************************************************/ function Interpret_IRB_to_HTML( $IRB_array, $filename ) { // Create a string to receive the HTML $output_str = ""; // Check if the Photoshop IRB array is valid if ( $IRB_array !== FALSE ) { // Create another string to receive secondary HTML to be appended at the end $secondary_output_str = ""; // Add the Heading to the HTML $output_str .= "
$Resource_Name | " . htmlentities( $IRB_Resource['ResData'] ) ." |
$Resource_Name | Image is Copyrighted Material |
$Resource_Name | Image is Not Copyrighted Material |
$Resource_Name | Global lighting angle for effects layer = " . hexdec( bin2hex( $IRB_Resource['ResData'] ) ) . " degrees |
$Resource_Name | Global Altitude = " . hexdec( bin2hex( $IRB_Resource['ResData'] ) ) . " |
$Resource_Name | \n"; $output_str .= "Version = " . hexdec( bin2hex( substr( $IRB_Resource['ResData'], 0, 4 ) ) ) . "\n"; $output_str .= "Has Real Merged Data = " . ord( $IRB_Resource['ResData']{4} ) . "\n"; $writer_size = hexdec( bin2hex( substr( $IRB_Resource['ResData'], 5, 4 ) ) ) * 2; $output_str .= "Writer Name = " . HTML_UTF16_Escape( substr( $IRB_Resource['ResData'], 9, $writer_size ), TRUE ) . "\n"; $reader_size = hexdec( bin2hex( substr( $IRB_Resource['ResData'], 9 + $writer_size , 4 ) ) ) * 2; $output_str .= "Reader Name = " . HTML_UTF16_Escape( substr( $IRB_Resource['ResData'], 13 + $writer_size, $reader_size ), TRUE ) . "\n"; $output_str .= "File Version = " . hexdec( bin2hex( substr( $IRB_Resource['ResData'], 13 + $writer_size + $reader_size, 4 ) ) ) . "\n"; $output_str .= " |
$Resource_Name | Intentionally untagged - any assumed ICC profile handling disabled |
$Resource_Name | Unknown value (0x" .bin2hex( $IRB_Resource['ResData'] ). ") |
$Resource_Name | ";
// Unpack the first 24 bytes
$Slices_Info = unpack("NVersion/NBound_top/NBound_left/NBound_bottom/NBound_right/NStringlen", $IRB_Resource['ResData'] );
$output_str .= "Version = " . $Slices_Info['Version'] . " \n"; $output_str .= "Bounding Rectangle = Top:" . $Slices_Info['Bound_top'] . ", Left:" . $Slices_Info['Bound_left'] . ", Bottom:" . $Slices_Info['Bound_bottom'] . ", Right:" . $Slices_Info['Bound_right'] . " (Pixels) \n"; $Slicepos = 24; // Extract a Unicode String $output_str .= "Text = '" . HTML_UTF16_Escape( substr( $IRB_Resource['ResData'], 24, $Slices_Info['Stringlen']*2), TRUE ) . "' \n"; $Slicepos += $Slices_Info['Stringlen'] * 2; // Unpack the number of Slices $Num_Slices = hexdec( bin2hex( substr( $IRB_Resource['ResData'], $Slicepos, 4 ) ) ); $output_str .= "Number of Slices = " . $Num_Slices . "\n"; $Slicepos += 4; // Cycle through the slices for( $i = 1; $i <= $Num_Slices; $i++ ) { $output_str .= " Slice $i: \n"; // Unpack the first 16 bytes of the slice $SliceA = unpack("NID/NGroupID/NOrigin/NStringlen", substr($IRB_Resource['ResData'], $Slicepos ) ); $Slicepos += 16; $output_str .= "ID = " . $SliceA['ID'] . " \n"; $output_str .= "Group ID = " . $SliceA['GroupID'] . " \n"; $output_str .= "Origin = " . $SliceA['Origin'] . " \n"; // Extract a Unicode String $output_str .= "Text = '" . HTML_UTF16_Escape( substr( $IRB_Resource['ResData'], $Slicepos, $SliceA['Stringlen']*2), TRUE ) . "' \n"; $Slicepos += $SliceA['Stringlen'] * 2; // Unpack the next 24 bytes of the slice $SliceB = unpack("NType/NLeftPos/NTopPos/NRightPos/NBottomPos/NURLlen", substr($IRB_Resource['ResData'], $Slicepos ) ); $Slicepos += 24; $output_str .= "Type = " . $SliceB['Type'] . " \n"; $output_str .= "Position = Top:" . $SliceB['TopPos'] . ", Left:" . $SliceB['LeftPos'] . ", Bottom:" . $SliceB['BottomPos'] . ", Right:" . $SliceB['RightPos'] . " (Pixels) \n"; // Extract a Unicode String $output_str .= "URL = " . HTML_UTF16_Escape( substr( $IRB_Resource['ResData'], $Slicepos, $SliceB['URLlen']*2), TRUE ) . " \n"; $Slicepos += $SliceB['URLlen'] * 2; // Unpack the length of a Unicode String $Targetlen = hexdec( bin2hex( substr( $IRB_Resource['ResData'], $Slicepos, 4 ) ) ); $Slicepos += 4; // Extract a Unicode String $output_str .= "Target = '" . HTML_UTF16_Escape( substr( $IRB_Resource['ResData'], $Slicepos, $Targetlen*2), TRUE ) . "' \n"; $Slicepos += $Targetlen * 2; // Unpack the length of a Unicode String $Messagelen = hexdec( bin2hex( substr( $IRB_Resource['ResData'], $Slicepos, 4 ) ) ); $Slicepos += 4; // Extract a Unicode String $output_str .= "Message = '" . HTML_UTF16_Escape( substr( $IRB_Resource['ResData'], $Slicepos, $Messagelen*2), TRUE ) . "' \n"; $Slicepos += $Messagelen * 2; // Unpack the length of a Unicode String $AltTaglen = hexdec( bin2hex( substr( $IRB_Resource['ResData'], $Slicepos, 4 ) ) ); $Slicepos += 4; // Extract a Unicode String $output_str .= "Alt Tag = '" . HTML_UTF16_Escape( substr( $IRB_Resource['ResData'], $Slicepos, $AltTaglen*2), TRUE ) . "' \n"; $Slicepos += $AltTaglen * 2; // Unpack the HTML flag if ( ord( $IRB_Resource['ResData']{ $Slicepos } ) === 0x01 ) { $output_str .= "Cell Text is HTML \n"; } else { $output_str .= "Cell Text is NOT HTML \n"; } $Slicepos++; // Unpack the length of a Unicode String $CellTextlen = hexdec( bin2hex( substr( $IRB_Resource['ResData'], $Slicepos, 4 ) ) ); $Slicepos += 4; // Extract a Unicode String $output_str .= "Cell Text = '" . HTML_UTF16_Escape( substr( $IRB_Resource['ResData'], $Slicepos, $CellTextlen*2), TRUE ) . "' \n"; $Slicepos += $CellTextlen * 2; // Unpack the last 12 bytes of the slice $SliceC = unpack("NAlignH/NAlignV/CAlpha/CRed/CGreen/CBlue", substr($IRB_Resource['ResData'], $Slicepos ) ); $Slicepos += 12; $output_str .= "Alignment = Horizontal:" . $SliceC['AlignH'] . ", Vertical:" . $SliceC['AlignV'] . " \n"; $output_str .= "Alpha Colour = " . $SliceC['Alpha'] . " \n"; $output_str .= "Red = " . $SliceC['Red'] . " \n"; $output_str .= "Green = " . $SliceC['Green'] . " \n"; $output_str .= "Blue = " . $SliceC['Blue'] . "\n"; } $output_str .= " |
$Resource_Name | ";
// Unpack the Grids info
$Grid_Info = unpack("NVersion/NGridCycleH/NGridCycleV/NGuideCount", $IRB_Resource['ResData'] );
$output_str .= "Version = " . $Grid_Info['Version'] . " \n"; $output_str .= "Grid Cycle = " . $Grid_Info['GridCycleH']/32 . " Pixel(s) x " . $Grid_Info['GridCycleV']/32 . " Pixel(s) \n"; $output_str .= "Number of Guides = " . $Grid_Info['GuideCount'] . "\n"; // Cycle through the Guides for( $i = 0; $i < $Grid_Info['GuideCount']; $i++ ) { // Unpack the info for this guide $Guide_Info = unpack("NLocation/CDirection", substr($IRB_Resource['ResData'],16+$i*5,5) ); $output_str .= " Guide $i : Location = " . $Guide_Info['Location']/32 . " Pixel(s) from edge"; if ( $Guide_Info['Direction'] === 0 ) { $output_str .= ", Vertical\n"; } else { $output_str .= ", Horizontal\n"; } } break; $output_str .= " |
$Resource_Name | ";
switch ( $Qual_Info['Quality'] )
{
case 0xFFFD:
$output_str .= "Quality 1 (Low) \n"; break; case 0xFFFE: $output_str .= "Quality 2 (Low) \n"; break; case 0xFFFF: $output_str .= "Quality 3 (Low) \n"; break; case 0x0000: $output_str .= "Quality 4 (Low) \n"; break; case 0x0001: $output_str .= "Quality 5 (Medium) \n"; break; case 0x0002: $output_str .= "Quality 6 (Medium) \n"; break; case 0x0003: $output_str .= "Quality 7 (Medium) \n"; break; case 0x0004: $output_str .= "Quality 8 (High) \n"; break; case 0x0005: $output_str .= "Quality 9 (High) \n"; break; case 0x0006: $output_str .= "Quality 10 (Maximum) \n"; break; case 0x0007: $output_str .= "Quality 11 (Maximum) \n"; break; case 0x0008: $output_str .= "Quality 12 (Maximum) \n"; break; default: $output_str .= "Unknown Quality (" . $Qual_Info['Quality'] . ") \n"; break; } switch ( $Qual_Info['Format'] ) { case 0x0000: $output_str .= "Standard Format\n"; break; case 0x0001: $output_str .= "Optimised Format\n"; break; case 0x0101: $output_str .= "Progressive Format \n"; break; default: $output_str .= "Unknown Format (" . $Qual_Info['Format'] .")\n"; break; } if ( $Qual_Info['Format'] == 0x0101 ) { switch ( $Qual_Info['Scans'] ) { case 0x0001: $output_str .= "3 Scans\n"; break; case 0x0002: $output_str .= "4 Scans\n"; break; case 0x0003: $output_str .= "5 Scans\n"; break; default: $output_str .= "Unknown number of scans (" . $Qual_Info['Scans'] .")\n"; break; } } $output_str .= " |
$Resource_Name | \n"; $output_str .= "Format = " . (( $thumb_data['Format'] == 1 ) ? "JPEG RGB\n" : "Raw RGB\n"); $output_str .= "Width = " . $thumb_data['Width'] . "\n"; $output_str .= "Height = " . $thumb_data['Height'] . "\n"; $output_str .= "Padded Row Bytes = " . $thumb_data['WidthBytes'] . " bytes\n"; $output_str .= "Total Size = " . $thumb_data['Size'] . " bytes\n"; $output_str .= "Compressed Size = " . $thumb_data['CompressedSize'] . " bytes\n"; $output_str .= "Bits per Pixel = " . $thumb_data['BitsPixel'] . " bits\n"; $output_str .= "Number of planes = " . $thumb_data['Planes'] . " bytes\n"; $output_str .= "Thumbnail Data:\n"; $output_str .= " |
$Resource_Name | " . hexdec( bin2hex( $IRB_Resource['ResData'] ) ) . " |
$Resource_Name | \n";
$output_str .= "$URL_count URL's in list \n"; $urlstr = substr( $IRB_Resource['ResData'], 4 ); // TODO: Check if URL List in Photoshop IRB works for( $i = 0; $i < $URL_count; $i++ ) { $url_data = unpack( "NLong/NID/NURLSize", $urlstr ); $output_str .= "URL $i info: long = " . $url_data['Long'] .", "; $output_str .= "ID = " . $url_data['ID'] . ", "; $urlstr = substr( $urlstr, 12 ); $url = substr( $urlstr, 0, $url_data['URLSize'] ); $output_str .= "URL = " . HTML_UTF16_Escape( $url, TRUE ) . " \n"; } $output_str .= " |
$Resource_Name | \n"; $output_str .= Interpret_Halftone( $IRB_Resource['ResData'] ); $output_str .= " |
$Resource_Name | \n"; $output_str .= "Cyan Halftoning Info:\n" . Interpret_Halftone( substr( $IRB_Resource['ResData'], 0, 18 ) ) . "\n\n"; $output_str .= "Magenta Halftoning Info:\n" . Interpret_Halftone( substr( $IRB_Resource['ResData'], 18, 18 ) ) . "\n\n"; $output_str .= "Yellow Halftoning Info:\n" . Interpret_Halftone( substr( $IRB_Resource['ResData'], 36, 18 ) ) . "\n"; $output_str .= "Black Halftoning Info:\n" . Interpret_Halftone( substr( $IRB_Resource['ResData'], 54, 18 ) ) . "\n"; $output_str .= " |
$Resource_Name | \n"; $output_str .= Interpret_Transfer_Function( substr( $IRB_Resource['ResData'], 0, 28 ) ) ; $output_str .= " |
$Resource_Name | \n"; $output_str .= "Red Transfer Function: \n" . Interpret_Transfer_Function( substr( $IRB_Resource['ResData'], 0, 28 ) ) . "\n\n"; $output_str .= "Green Transfer Function: \n" . Interpret_Transfer_Function( substr( $IRB_Resource['ResData'], 28, 28 ) ) . "\n\n"; $output_str .= "Blue Transfer Function: \n" . Interpret_Transfer_Function( substr( $IRB_Resource['ResData'], 56, 28 ) ) . "\n"; $output_str .= " |
$Resource_Name | \n"; if ( $IRB_Resource['ResData']{0} == "\x01" ) { $output_str .= "Labels Selected\n"; } else { $output_str .= "Labels Not Selected\n"; } if ( $IRB_Resource['ResData']{1} == "\x01" ) { $output_str .= "Crop Marks Selected\n"; } else { $output_str .= "Crop Marks Not Selected\n"; } if ( $IRB_Resource['ResData']{2} == "\x01" ) { $output_str .= "Color Bars Selected\n"; } else { $output_str .= "Color Bars Not Selected\n"; } if ( $IRB_Resource['ResData']{3} == "\x01" ) { $output_str .= "Registration Marks Selected\n"; } else { $output_str .= "Registration Marks Not Selected\n"; } if ( $IRB_Resource['ResData']{4} == "\x01" ) { $output_str .= "Negative Selected\n"; } else { $output_str .= "Negative Not Selected\n"; } if ( $IRB_Resource['ResData']{5} == "\x01" ) { $output_str .= "Flip Selected\n"; } else { $output_str .= "Flip Not Selected\n"; } if ( $IRB_Resource['ResData']{6} == "\x01" ) { $output_str .= "Interpolate Selected\n"; } else { $output_str .= "Interpolate Not Selected\n"; } if ( $IRB_Resource['ResData']{7} == "\x01" ) { $output_str .= "Caption Selected"; } else { $output_str .= "Caption Not Selected"; } $output_str .= " |
$Resource_Name | \n"; $output_str .= "Version = " . $PrintFlags['Version'] . "\n"; $output_str .= "Centre Crop Marks = " . $PrintFlags['CentCrop'] . "\n"; $output_str .= "Bleed Width = " . $PrintFlags['BleedWidth'] . "\n"; $output_str .= "Bleed Width Scale = " . $PrintFlags['BleedWidthScale']; $output_str .= " |
$Resource_Name | \n"; $output_str .= "Horizontal Resolution = " . ($ResInfo['hRes_int'] + $ResInfo['hResdec']/65536) . " pixels per Inch\n"; $output_str .= "Vertical Resolution = " . ($ResInfo['vRes_int'] + $ResInfo['vResdec']/65536) . " pixels per Inch\n"; if ( $ResInfo['hResUnit'] == 1 ) { $output_str .= "Display units for Horizontal Resolution = Pixels per Inch\n"; } elseif ( $ResInfo['hResUnit'] == 2 ) { $output_str .= "Display units for Horizontal Resolution = Pixels per Centimetre\n"; } else { $output_str .= "Display units for Horizontal Resolution = Unknown Value (". $ResInfo['hResUnit'] .")\n"; } if ( $ResInfo['vResUnit'] == 1 ) { $output_str .= "Display units for Vertical Resolution = Pixels per Inch\n"; } elseif ( $ResInfo['vResUnit'] == 2 ) { $output_str .= "Display units for Vertical Resolution = Pixels per Centimetre\n"; } else { $output_str .= "Display units for Vertical Resolution = Unknown Value (". $ResInfo['vResUnit'] .")\n"; } if ( $ResInfo['widthUnit'] == 1 ) { $output_str .= "Display units for Image Width = Inches\n"; } elseif ( $ResInfo['widthUnit'] == 2 ) { $output_str .= "Display units for Image Width = Centimetres\n"; } elseif ( $ResInfo['widthUnit'] == 3 ) { $output_str .= "Display units for Image Width = Points\n"; } elseif ( $ResInfo['widthUnit'] == 4 ) { $output_str .= "Display units for Image Width = Picas\n"; } elseif ( $ResInfo['widthUnit'] == 5 ) { $output_str .= "Display units for Image Width = Columns\n"; } else { $output_str .= "Display units for Image Width = Unknown Value (". $ResInfo['widthUnit'] .")\n"; } if ( $ResInfo['heightUnit'] == 1 ) { $output_str .= "Display units for Image Height = Inches"; } elseif ( $ResInfo['heightUnit'] == 2 ) { $output_str .= "Display units for Image Height = Centimetres"; } elseif ( $ResInfo['heightUnit'] == 3 ) { $output_str .= "Display units for Image Height = Points"; } elseif ( $ResInfo['heightUnit'] == 4 ) { $output_str .= "Display units for Image Height = Picas"; } elseif ( $ResInfo['heightUnit'] == 5 ) { $output_str .= "Display units for Image Height = Columns"; } else { $output_str .= "Display units for Image Height = Unknown Value (". $ResInfo['heightUnit'] .")"; } $output_str .= " |
$Resource_Name | RESOURCE DECODING NOT IMPLEMENTED YET " . strlen( $IRB_Resource['ResData'] ) . " bytes |