PageRenderTime 27ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/add-ons/pjmt/Photoshop_IRB.php

https://github.com/jcplat/console-seolan
PHP | 1514 lines | 924 code | 214 blank | 376 comment | 88 complexity | e58043abc2d91c4d79fa8f5f487ca4ef MD5 | raw file
Possible License(s): LGPL-2.0, LGPL-2.1, GPL-3.0, Apache-2.0, BSD-3-Clause

Large files files are truncated, but you can click here to view the full file

  1. <?
  2. /******************************************************************************
  3. *
  4. * Filename: Photoshop_IRB.php
  5. *
  6. * Description: Provides functions for reading and writing information to/from
  7. * the 'App 13' Photoshop Information Resource Block segment of
  8. * JPEG format files
  9. *
  10. * Author: Evan Hunter
  11. *
  12. * Date: 23/7/2004
  13. *
  14. * Project: PHP JPEG Metadata Toolkit
  15. *
  16. * Revision: 1.11
  17. *
  18. * Changes: 1.00 -> 1.02 : changed get_Photoshop_IRB to work with corrupted
  19. * resource names which Photoshop can still read
  20. * 1.02 -> 1.03 : Fixed put_Photoshop_IRB to output "Photoshop 3.0\x00"
  21. * string with every APP13 segment, not just the first one
  22. * 1.03 -> 1.10 : changed get_Photoshop_IRB to fix processing of embedded resource names,
  23. * after discovering that Photoshop does not process
  24. * resource names according to the standard :
  25. * "Adobe Photoshop 6.0 File Formats Specification, Version 6.0, Release 2, November 2000"
  26. * This is an update to the change 1.00 -> 1.02, which was not fully correct
  27. * changed put_Photoshop_IRB to fix the writing of embedded resource name,
  28. * to avoid creating blank resources, and to fix a problem
  29. * causing the IRB block to be incorrectly positioned if no APP segments existed.
  30. * changed get_Photoshop_IPTC to initialise the output array correctly.
  31. * 1.10 -> 1.11 : Moved code out of get_Photoshop_IRB into new function unpack_Photoshop_IRB_Data
  32. * to allow reading of IRB blocks embedded within EXIF (for TIFF Files)
  33. * Moved code out of put_Photoshop_IRB into new function pack_Photoshop_IRB_Data
  34. * to allow writing of IRB blocks embedded within EXIF (for TIFF Files)
  35. * Enabled the usage of $GLOBALS['HIDE_UNKNOWN_TAGS'] to hide unknown resources
  36. * changed Interpret_IRB_to_HTML to allow thumbnail links to work when
  37. * toolkit is portable across directories
  38. *
  39. *
  40. * URL: http://electronics.ozhiker.com
  41. *
  42. * Copyright: Copyright Evan Hunter 2004
  43. *
  44. * License: This file is part of the PHP JPEG Metadata Toolkit.
  45. *
  46. * The PHP JPEG Metadata Toolkit is free software; you can
  47. * redistribute it and/or modify it under the terms of the
  48. * GNU General Public License as published by the Free Software
  49. * Foundation; either version 2 of the License, or (at your
  50. * option) any later version.
  51. *
  52. * The PHP JPEG Metadata Toolkit is distributed in the hope
  53. * that it will be useful, but WITHOUT ANY WARRANTY; without
  54. * even the implied warranty of MERCHANTABILITY or FITNESS
  55. * FOR A PARTICULAR PURPOSE. See the GNU General Public License
  56. * for more details.
  57. *
  58. * You should have received a copy of the GNU General Public
  59. * License along with the PHP JPEG Metadata Toolkit; if not,
  60. * write to the Free Software Foundation, Inc., 59 Temple
  61. * Place, Suite 330, Boston, MA 02111-1307 USA
  62. *
  63. * If you require a different license for commercial or other
  64. * purposes, please contact the author: evan@ozhiker.com
  65. *
  66. ******************************************************************************/
  67. // Change: as of version 1.11 - added to ensure the HIDE_UNKNOWN_TAGS variable is set even if EXIF.php is not included
  68. if ( !isset( $GLOBALS['HIDE_UNKNOWN_TAGS'] ) ) $GLOBALS['HIDE_UNKNOWN_TAGS']= FALSE;
  69. include_once 'IPTC.php';
  70. include_once 'Unicode.php';
  71. // TODO: Many Photoshop IRB resources not interpeted
  72. // TODO: Obtain a copy of the Photoshop CS File Format Specification
  73. // TODO: Find out what Photoshop IRB resources 1061, 1062 & 1064 are
  74. // TODO: Test get_Photoshop_IRB and put_Photoshop_IRB with multiple APP13 segments
  75. /******************************************************************************
  76. *
  77. * Function: get_Photoshop_IRB
  78. *
  79. * Description: Retrieves the Photoshop Information Resource Block (IRB) information
  80. * from an App13 JPEG segment and returns it as an array. This may
  81. * include IPTC-NAA IIM Information. Uses information
  82. * supplied by the get_jpeg_header_data function
  83. *
  84. * Parameters: jpeg_header_data - a JPEG header data array in the same format
  85. * as from get_jpeg_header_data
  86. *
  87. * Returns: IRBdata - The array of Photoshop IRB records
  88. * FALSE - if an APP 13 Photoshop IRB segment could not be found,
  89. * or if an error occured
  90. *
  91. ******************************************************************************/
  92. function get_Photoshop_IRB( $jpeg_header_data )
  93. {
  94. // Photoshop Image Resource blocks can span several JPEG APP13 segments, so we need to join them up if there are more than one
  95. $joined_IRB = "";
  96. //Cycle through the header segments
  97. for( $i = 0; $i < count( $jpeg_header_data ); $i++ )
  98. {
  99. // If we find an APP13 header,
  100. if ( strcmp ( $jpeg_header_data[$i]['SegName'], "APP13" ) == 0 )
  101. {
  102. // And if it has the photoshop label,
  103. if( strncmp ( $jpeg_header_data[$i]['SegData'], "Photoshop 3.0\x00", 14) == 0 )
  104. {
  105. // join it to the other previous IRB data
  106. $joined_IRB .= substr ( $jpeg_header_data[$i]['SegData'], 14 );
  107. }
  108. }
  109. }
  110. // If there was some Photoshop IRB information found,
  111. if ( $joined_IRB != "" )
  112. {
  113. // Found a Photoshop Image Resource Block - extract it.
  114. // Change: Moved code into unpack_Photoshop_IRB_Data to allow TIFF reading as of 1.11
  115. return unpack_Photoshop_IRB_Data( $joined_IRB );
  116. }
  117. else
  118. {
  119. // No Photoshop IRB found
  120. return FALSE;
  121. }
  122. }
  123. /******************************************************************************
  124. * End of Function: get_Photoshop_IRB
  125. ******************************************************************************/
  126. /******************************************************************************
  127. *
  128. * Function: put_Photoshop_IRB
  129. *
  130. * Description: Adds or modifies the Photoshop Information Resource Block (IRB)
  131. * information from an App13 JPEG segment. If a Photoshop IRB already
  132. * exists, it is replaced, otherwise a new one is inserted, using the
  133. * supplied data. Uses information supplied by the get_jpeg_header_data
  134. * function
  135. *
  136. * Parameters: jpeg_header_data - a JPEG header data array in the same format
  137. * as from get_jpeg_header_data
  138. * new_IRB_data - an array of the data to be stored in the Photoshop
  139. * IRB segment. Should be in the same format as received
  140. * from get_Photoshop_IRB
  141. *
  142. * Returns: jpeg_header_data - the JPEG header data array with the
  143. * Photoshop IRB added.
  144. * FALSE - if an error occured
  145. *
  146. ******************************************************************************/
  147. function put_Photoshop_IRB( $jpeg_header_data, $new_IRB_data )
  148. {
  149. // Delete all existing Photoshop IRB blocks - the new one will replace them
  150. //Cycle through the header segments
  151. for( $i = 0; $i < count( $jpeg_header_data ) ; $i++ )
  152. {
  153. // If we find an APP13 header,
  154. if ( strcmp ( $jpeg_header_data[$i]['SegName'], "APP13" ) == 0 )
  155. {
  156. // And if it has the photoshop label,
  157. if( strncmp ( $jpeg_header_data[$i]['SegData'], "Photoshop 3.0\x00", 14) == 0 )
  158. {
  159. // Delete the block information - it needs to be rebuilt
  160. array_splice( $jpeg_header_data, $i, 1 );
  161. }
  162. }
  163. }
  164. // Now we have deleted the pre-existing blocks
  165. // Retrieve the Packed Photoshop IRB Data
  166. // Change: Moved code into pack_Photoshop_IRB_Data to allow TIFF writing as of 1.11
  167. $packed_IRB_data = pack_Photoshop_IRB_Data( $new_IRB_data );
  168. // Change : This section changed to fix incorrect positioning of IRB segment, as of revision 1.10
  169. // when there are no APP segments present
  170. //Cycle through the header segments in reverse order (to find where to put the APP13 block - after any APP0 to APP12 blocks)
  171. $i = count( $jpeg_header_data ) - 1;
  172. while (( $i >= 0 ) && ( ( $jpeg_header_data[$i]['SegType'] > 0xED ) || ( $jpeg_header_data[$i]['SegType'] < 0xE0 ) ) )
  173. {
  174. $i--;
  175. }
  176. // Cycle through the packed output data until it's size is less than 32000 bytes, outputting each 32000 byte block to an APP13 segment
  177. while ( strlen( $packed_IRB_data ) > 32000 )
  178. {
  179. // 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
  180. // Write a 32000 byte APP13 segment
  181. array_splice($jpeg_header_data, $i +1 , 0, array( "SegType" => 0xED,
  182. "SegName" => "APP13",
  183. "SegDesc" => $GLOBALS[ "JPEG_Segment_Descriptions" ][ 0xED ],
  184. "SegData" => "Photoshop 3.0\x00" . substr( $packed_IRB_data,0,32000) ) );
  185. // Delete the 32000 bytes from the packed output data, that were just output
  186. $packed_IRB_data = substr_replace($packed_IRB_data, '', 0, 32000);
  187. $i++;
  188. }
  189. // 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
  190. array_splice($jpeg_header_data, $i + 1 , 0, "" );
  191. $jpeg_header_data[$i + 1] = array( "SegType" => 0xED,
  192. "SegName" => "APP13",
  193. "SegDesc" => $GLOBALS[ "JPEG_Segment_Descriptions" ][ 0xED ],
  194. "SegData" => "Photoshop 3.0\x00" . $packed_IRB_data );
  195. return $jpeg_header_data;
  196. }
  197. /******************************************************************************
  198. * End of Function: put_Photoshop_IRB
  199. ******************************************************************************/
  200. /******************************************************************************
  201. *
  202. * Function: get_Photoshop_IPTC
  203. *
  204. * Description: Retrieves IPTC-NAA IIM information from within a Photoshop
  205. * IRB (if it is present) and returns it in an array. Uses
  206. * information supplied by the get_jpeg_header_data function
  207. *
  208. * Parameters: Photoshop_IRB_data - an array of Photoshop IRB records, as
  209. * returned from get_Photoshop_IRB
  210. *
  211. * Returns: IPTC_Data_Out - The array of IPTC-NAA IIM records
  212. * FALSE - if an IPTC-NAA IIM record could not be found, or if
  213. * an error occured
  214. *
  215. ******************************************************************************/
  216. function get_Photoshop_IPTC( $Photoshop_IRB_data )
  217. {
  218. // Change: Initialise array correctly, as of revision 1.10
  219. $IPTC_Data_Out = array();
  220. //Cycle through the Photoshop 8BIM records looking for the IPTC-NAA record
  221. for( $i = 0; $i < count( $Photoshop_IRB_data ); $i++ )
  222. {
  223. // Check if each record is a IPTC record (which has id 0x0404)
  224. if ( $Photoshop_IRB_data[$i]['ResID'] == 0x0404 )
  225. {
  226. // We've found an IPTC block - Decode it
  227. $IPTC_Data_Out = get_IPTC( $Photoshop_IRB_data[$i]['ResData'] );
  228. }
  229. }
  230. // If there was no records put into the output array,
  231. if ( count( $IPTC_Data_Out ) == 0 )
  232. {
  233. // Then return false
  234. return FALSE;
  235. }
  236. else
  237. {
  238. // Otherwise return the array
  239. return $IPTC_Data_Out;
  240. }
  241. }
  242. /******************************************************************************
  243. * End of Function: get_Photoshop_IPTC
  244. ******************************************************************************/
  245. /******************************************************************************
  246. *
  247. * Function: put_Photoshop_IPTC
  248. *
  249. * Description: Inserts a new IPTC-NAA IIM resource into a Photoshop
  250. * IRB, or replaces an the existing resource if one is present.
  251. * Uses information supplied by the get_Photoshop_IRB function
  252. *
  253. * Parameters: Photoshop_IRB_data - an array of Photoshop IRB records, as
  254. * returned from get_Photoshop_IRB, into
  255. * which the IPTC-NAA IIM record will be inserted
  256. * new_IPTC_block - an array of IPTC-NAA records in the same format
  257. * as those returned by get_Photoshop_IPTC
  258. *
  259. * Returns: Photoshop_IRB_data - The Photoshop IRB array with the
  260. * IPTC-NAA IIM resource inserted
  261. *
  262. ******************************************************************************/
  263. function put_Photoshop_IPTC( $Photoshop_IRB_data, $new_IPTC_block )
  264. {
  265. $iptc_block_pos = -1;
  266. //Cycle through the 8BIM records looking for the IPTC-NAA record
  267. for( $i = 0; $i < count( $Photoshop_IRB_data ); $i++ )
  268. {
  269. // Check if each record is a IPTC record (which has id 0x0404)
  270. if ( $Photoshop_IRB_data[$i]['ResID'] == 0x0404 )
  271. {
  272. // We've found an IPTC block - save the position
  273. $iptc_block_pos = $i;
  274. }
  275. }
  276. // If no IPTC block was found, create a new one
  277. if ( $iptc_block_pos == -1 )
  278. {
  279. // New block position will be at the end of the array
  280. $iptc_block_pos = count( $Photoshop_IRB_data );
  281. }
  282. // Write the new IRB resource to the Photoshop IRB array with no data
  283. $Photoshop_IRB_data[$iptc_block_pos] = array( "ResID" => 0x0404,
  284. "ResName" => $GLOBALS['Photoshop_ID_Names'][ 0x0404 ],
  285. "ResDesc" => $GLOBALS[ "Photoshop_ID_Descriptions" ][ 0x0404 ],
  286. "ResEmbeddedName" => "\x00\x00",
  287. "ResData" => put_IPTC( $new_IPTC_block ) );
  288. // Return the modified IRB
  289. return $Photoshop_IRB_data;
  290. }
  291. /******************************************************************************
  292. * End of Function: put_Photoshop_IPTC
  293. ******************************************************************************/
  294. /******************************************************************************
  295. *
  296. * Function: Interpret_IRB_to_HTML
  297. *
  298. * Description: Generates html showing the information contained in a Photoshop
  299. * IRB data array, as retrieved with get_Photoshop_IRB, including
  300. * any IPTC-NAA IIM records found.
  301. *
  302. * Please note that the following resource numbers are not currently
  303. * decoded: ( Many of these do not apply to JPEG images)
  304. * 0x03E9, 0x03EE, 0x03EF, 0x03F0, 0x03F1, 0x03F2, 0x03F6, 0x03F9,
  305. * 0x03FA, 0x03FB, 0x03FD, 0x03FE, 0x0400, 0x0401, 0x0402, 0x0405,
  306. * 0x040E, 0x040F, 0x0410, 0x0412, 0x0413, 0x0415, 0x0416, 0x0417,
  307. * 0x041B, 0x041C, 0x041D, 0x0BB7
  308. *
  309. * ( Also these Obsolete resource numbers)
  310. * 0x03E8, 0x03EB, 0x03FC, 0x03FF, 0x0403
  311. *
  312. *
  313. * Parameters: IRB_array - a Photoshop IRB data array as from get_Photoshop_IRB
  314. * filename - the name of the JPEG file being processed ( used
  315. * by the script which displays the Photoshop thumbnail)
  316. *
  317. *
  318. * Returns: output_str - the HTML string
  319. *
  320. ******************************************************************************/
  321. function Interpret_IRB_to_HTML( $IRB_array, $filename )
  322. {
  323. // Create a string to receive the HTML
  324. $output_str = "";
  325. // Check if the Photoshop IRB array is valid
  326. if ( $IRB_array !== FALSE )
  327. {
  328. // Create another string to receive secondary HTML to be appended at the end
  329. $secondary_output_str = "";
  330. // Add the Heading to the HTML
  331. $output_str .= "<h2 class=\"Photoshop_Main_Heading\">Contains Photoshop Information Resource Block (IRB)</h2>";
  332. // Add Table to the HTML
  333. $output_str .= "<table class=\"Photoshop_Table\" border=1>\n";
  334. // Cycle through each of the Photoshop IRB records, creating HTML for each
  335. foreach( $IRB_array as $IRB_Resource )
  336. {
  337. // Check if the entry is a known Photoshop IRB resource
  338. // Get the Name of the Resource
  339. if ( array_key_exists( $IRB_Resource['ResID'], $GLOBALS[ "Photoshop_ID_Names" ] ) )
  340. {
  341. $Resource_Name = $GLOBALS['Photoshop_ID_Names'][ $IRB_Resource['ResID'] ];
  342. }
  343. else
  344. {
  345. // Change: Added check for $GLOBALS['HIDE_UNKNOWN_TAGS'] to allow hiding of unknown resources as of 1.11
  346. if ( $GLOBALS['HIDE_UNKNOWN_TAGS'] == TRUE )
  347. {
  348. continue;
  349. }
  350. else
  351. {
  352. // Unknown Resource - Make appropriate name
  353. $Resource_Name = "Unknown Resource (". $IRB_Resource['ResID'] .")";
  354. }
  355. }
  356. // Add HTML for the resource as appropriate
  357. switch ( $IRB_Resource['ResID'] )
  358. {
  359. case 0x0404 : // IPTC-NAA IIM Record
  360. $secondary_output_str .= Interpret_IPTC_to_HTML( get_IPTC( $IRB_Resource['ResData'] ) );
  361. break;
  362. case 0x040B : // URL
  363. $output_str .= "<tr class=\"Photoshop_Table_Row\"><td class=\"Photoshop_Caption_Cell\">$Resource_Name</td><td class=\"Photoshop_Value_Cell\"><a href=\"" . $IRB_Resource['ResData'] . "\">" . htmlentities( $IRB_Resource['ResData'] ) ."</a></td></tr>\n";
  364. break;
  365. case 0x040A : // Copyright Marked
  366. if ( hexdec( bin2hex( $IRB_Resource['ResData'] ) ) == 1 )
  367. {
  368. $output_str .= "<tr class=\"Photoshop_Table_Row\"><td class=\"Photoshop_Caption_Cell\">$Resource_Name</td><td class=\"Photoshop_Value_Cell\"><pre>Image is Copyrighted Material</pre></td></tr>\n";
  369. }
  370. else
  371. {
  372. $output_str .= "<tr class=\"Photoshop_Table_Row\"><td class=\"Photoshop_Caption_Cell\">$Resource_Name</td><td class=\"Photoshop_Value_Cell\"><pre>Image is Not Copyrighted Material</pre></td></tr>\n";
  373. }
  374. break;
  375. case 0x040D : // Global Lighting Angle
  376. $output_str .= "<tr class=\"Photoshop_Table_Row\"><td class=\"Photoshop_Caption_Cell\">$Resource_Name</td><td class=\"Photoshop_Value_Cell\"><pre>Global lighting angle for effects layer = " . hexdec( bin2hex( $IRB_Resource['ResData'] ) ) . " degrees</pre></td></tr>\n";
  377. break;
  378. case 0x0419 : // Global Altitude
  379. $output_str .= "<tr class=\"Photoshop_Table_Row\"><td class=\"Photoshop_Caption_Cell\">$Resource_Name</td><td class=\"Photoshop_Value_Cell\"><pre>Global Altitude = " . hexdec( bin2hex( $IRB_Resource['ResData'] ) ) . "</pre></td></tr>\n";
  380. break;
  381. case 0x0421 : // Version Info
  382. $output_str .= "<tr class=\"Photoshop_Table_Row\"><td class=\"Photoshop_Caption_Cell\">$Resource_Name</td><td class=\"Photoshop_Value_Cell\"><pre>\n";
  383. $output_str .= "Version = " . hexdec( bin2hex( substr( $IRB_Resource['ResData'], 0, 4 ) ) ) . "\n";
  384. $output_str .= "Has Real Merged Data = " . ord( $IRB_Resource['ResData']{4} ) . "\n";
  385. $writer_size = hexdec( bin2hex( substr( $IRB_Resource['ResData'], 5, 4 ) ) ) * 2;
  386. $output_str .= "Writer Name = " . HTML_UTF16_Escape( substr( $IRB_Resource['ResData'], 9, $writer_size ), TRUE ) . "\n";
  387. $reader_size = hexdec( bin2hex( substr( $IRB_Resource['ResData'], 9 + $writer_size , 4 ) ) ) * 2;
  388. $output_str .= "Reader Name = " . HTML_UTF16_Escape( substr( $IRB_Resource['ResData'], 13 + $writer_size, $reader_size ), TRUE ) . "\n";
  389. $output_str .= "File Version = " . hexdec( bin2hex( substr( $IRB_Resource['ResData'], 13 + $writer_size + $reader_size, 4 ) ) ) . "\n";
  390. $output_str .= "</pre></td></tr>\n";
  391. break;
  392. case 0x0411 : // ICC Untagged
  393. if ( $IRB_Resource['ResData'] == "\x01" )
  394. {
  395. $output_str .= "<tr class=\"Photoshop_Table_Row\"><td class=\"Photoshop_Caption_Cell\">$Resource_Name</td><td class=\"Photoshop_Value_Cell\"><pre>Intentionally untagged - any assumed ICC profile handling disabled</pre></td></tr>\n";
  396. }
  397. else
  398. {
  399. $output_str .= "<tr class=\"Photoshop_Table_Row\"><td class=\"Photoshop_Caption_Cell\">$Resource_Name</td><td class=\"Photoshop_Value_Cell\"><pre>Unknown value (0x" .bin2hex( $IRB_Resource['ResData'] ). ")</pre></td></tr>\n";
  400. }
  401. break;
  402. case 0x041A : // Slices
  403. $output_str .= "<tr class=\"Photoshop_Table_Row\"><td class=\"Photoshop_Caption_Cell\">$Resource_Name</td><td class=\"Photoshop_Value_Cell\">";
  404. // Unpack the first 24 bytes
  405. $Slices_Info = unpack("NVersion/NBound_top/NBound_left/NBound_bottom/NBound_right/NStringlen", $IRB_Resource['ResData'] );
  406. $output_str .= "Version = " . $Slices_Info['Version'] . "<br>\n";
  407. $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)<br>\n";
  408. $Slicepos = 24;
  409. // Extract a Unicode String
  410. $output_str .= "Text = '" . HTML_UTF16_Escape( substr( $IRB_Resource['ResData'], 24, $Slices_Info['Stringlen']*2), TRUE ) . "'<br>\n";
  411. $Slicepos += $Slices_Info['Stringlen'] * 2;
  412. // Unpack the number of Slices
  413. $Num_Slices = hexdec( bin2hex( substr( $IRB_Resource['ResData'], $Slicepos, 4 ) ) );
  414. $output_str .= "Number of Slices = " . $Num_Slices . "\n";
  415. $Slicepos += 4;
  416. // Cycle through the slices
  417. for( $i = 1; $i <= $Num_Slices; $i++ )
  418. {
  419. $output_str .= "<br><br>Slice $i:<br>\n";
  420. // Unpack the first 16 bytes of the slice
  421. $SliceA = unpack("NID/NGroupID/NOrigin/NStringlen", substr($IRB_Resource['ResData'], $Slicepos ) );
  422. $Slicepos += 16;
  423. $output_str .= "ID = " . $SliceA['ID'] . "<br>\n";
  424. $output_str .= "Group ID = " . $SliceA['GroupID'] . "<br>\n";
  425. $output_str .= "Origin = " . $SliceA['Origin'] . "<br>\n";
  426. // Extract a Unicode String
  427. $output_str .= "Text = '" . HTML_UTF16_Escape( substr( $IRB_Resource['ResData'], $Slicepos, $SliceA['Stringlen']*2), TRUE ) . "'<br>\n";
  428. $Slicepos += $SliceA['Stringlen'] * 2;
  429. // Unpack the next 24 bytes of the slice
  430. $SliceB = unpack("NType/NLeftPos/NTopPos/NRightPos/NBottomPos/NURLlen", substr($IRB_Resource['ResData'], $Slicepos ) );
  431. $Slicepos += 24;
  432. $output_str .= "Type = " . $SliceB['Type'] . "<br>\n";
  433. $output_str .= "Position = Top:" . $SliceB['TopPos'] . ", Left:" . $SliceB['LeftPos'] . ", Bottom:" . $SliceB['BottomPos'] . ", Right:" . $SliceB['RightPos'] . " (Pixels)<br>\n";
  434. // Extract a Unicode String
  435. $output_str .= "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";
  436. $Slicepos += $SliceB['URLlen'] * 2;
  437. // Unpack the length of a Unicode String
  438. $Targetlen = hexdec( bin2hex( substr( $IRB_Resource['ResData'], $Slicepos, 4 ) ) );
  439. $Slicepos += 4;
  440. // Extract a Unicode String
  441. $output_str .= "Target = '" . HTML_UTF16_Escape( substr( $IRB_Resource['ResData'], $Slicepos, $Targetlen*2), TRUE ) . "'<br>\n";
  442. $Slicepos += $Targetlen * 2;
  443. // Unpack the length of a Unicode String
  444. $Messagelen = hexdec( bin2hex( substr( $IRB_Resource['ResData'], $Slicepos, 4 ) ) );
  445. $Slicepos += 4;
  446. // Extract a Unicode String
  447. $output_str .= "Message = '" . HTML_UTF16_Escape( substr( $IRB_Resource['ResData'], $Slicepos, $Messagelen*2), TRUE ) . "'<br>\n";
  448. $Slicepos += $Messagelen * 2;
  449. // Unpack the length of a Unicode String
  450. $AltTaglen = hexdec( bin2hex( substr( $IRB_Resource['ResData'], $Slicepos, 4 ) ) );
  451. $Slicepos += 4;
  452. // Extract a Unicode String
  453. $output_str .= "Alt Tag = '" . HTML_UTF16_Escape( substr( $IRB_Resource['ResData'], $Slicepos, $AltTaglen*2), TRUE ) . "'<br>\n";
  454. $Slicepos += $AltTaglen * 2;
  455. // Unpack the HTML flag
  456. if ( ord( $IRB_Resource['ResData']{ $Slicepos } ) === 0x01 )
  457. {
  458. $output_str .= "Cell Text is HTML<br>\n";
  459. }
  460. else
  461. {
  462. $output_str .= "Cell Text is NOT HTML<br>\n";
  463. }
  464. $Slicepos++;
  465. // Unpack the length of a Unicode String
  466. $CellTextlen = hexdec( bin2hex( substr( $IRB_Resource['ResData'], $Slicepos, 4 ) ) );
  467. $Slicepos += 4;
  468. // Extract a Unicode String
  469. $output_str .= "Cell Text = '" . HTML_UTF16_Escape( substr( $IRB_Resource['ResData'], $Slicepos, $CellTextlen*2), TRUE ) . "'<br>\n";
  470. $Slicepos += $CellTextlen * 2;
  471. // Unpack the last 12 bytes of the slice
  472. $SliceC = unpack("NAlignH/NAlignV/CAlpha/CRed/CGreen/CBlue", substr($IRB_Resource['ResData'], $Slicepos ) );
  473. $Slicepos += 12;
  474. $output_str .= "Alignment = Horizontal:" . $SliceC['AlignH'] . ", Vertical:" . $SliceC['AlignV'] . "<br>\n";
  475. $output_str .= "Alpha Colour = " . $SliceC['Alpha'] . "<br>\n";
  476. $output_str .= "Red = " . $SliceC['Red'] . "<br>\n";
  477. $output_str .= "Green = " . $SliceC['Green'] . "<br>\n";
  478. $output_str .= "Blue = " . $SliceC['Blue'] . "\n";
  479. }
  480. $output_str .= "</td></tr>\n";
  481. break;
  482. case 0x0408 : // Grid and Guides information
  483. $output_str .= "<tr class=\"Photoshop_Table_Row\"><td class=\"Photoshop_Caption_Cell\">$Resource_Name</td><td class=\"Photoshop_Value_Cell\">";
  484. // Unpack the Grids info
  485. $Grid_Info = unpack("NVersion/NGridCycleH/NGridCycleV/NGuideCount", $IRB_Resource['ResData'] );
  486. $output_str .= "Version = " . $Grid_Info['Version'] . "<br>\n";
  487. $output_str .= "Grid Cycle = " . $Grid_Info['GridCycleH']/32 . " Pixel(s) x " . $Grid_Info['GridCycleV']/32 . " Pixel(s)<br>\n";
  488. $output_str .= "Number of Guides = " . $Grid_Info['GuideCount'] . "\n";
  489. // Cycle through the Guides
  490. for( $i = 0; $i < $Grid_Info['GuideCount']; $i++ )
  491. {
  492. // Unpack the info for this guide
  493. $Guide_Info = unpack("NLocation/CDirection", substr($IRB_Resource['ResData'],16+$i*5,5) );
  494. $output_str .= "<br>Guide $i : Location = " . $Guide_Info['Location']/32 . " Pixel(s) from edge";
  495. if ( $Guide_Info['Direction'] === 0 )
  496. {
  497. $output_str .= ", Vertical\n";
  498. }
  499. else
  500. {
  501. $output_str .= ", Horizontal\n";
  502. }
  503. }
  504. break;
  505. $output_str .= "</td></tr>\n";
  506. case 0x0406 : // JPEG Quality
  507. $Qual_Info = unpack("nQuality/nFormat/nScans/Cconst", $IRB_Resource['ResData'] );
  508. $output_str .= "<tr class=\"Photoshop_Table_Row\"><td class=\"Photoshop_Caption_Cell\">$Resource_Name</td><td class=\"Photoshop_Value_Cell\">";
  509. switch ( $Qual_Info['Quality'] )
  510. {
  511. case 0xFFFD:
  512. $output_str .= "Quality 1 (Low)<br>\n";
  513. break;
  514. case 0xFFFE:
  515. $output_str .= "Quality 2 (Low)<br>\n";
  516. break;
  517. case 0xFFFF:
  518. $output_str .= "Quality 3 (Low)<br>\n";
  519. break;
  520. case 0x0000:
  521. $output_str .= "Quality 4 (Low)<br>\n";
  522. break;
  523. case 0x0001:
  524. $output_str .= "Quality 5 (Medium)<br>\n";
  525. break;
  526. case 0x0002:
  527. $output_str .= "Quality 6 (Medium)<br>\n";
  528. break;
  529. case 0x0003:
  530. $output_str .= "Quality 7 (Medium)<br>\n";
  531. break;
  532. case 0x0004:
  533. $output_str .= "Quality 8 (High)<br>\n";
  534. break;
  535. case 0x0005:
  536. $output_str .= "Quality 9 (High)<br>\n";
  537. break;
  538. case 0x0006:
  539. $output_str .= "Quality 10 (Maximum)<br>\n";
  540. break;
  541. case 0x0007:
  542. $output_str .= "Quality 11 (Maximum)<br>\n";
  543. break;
  544. case 0x0008:
  545. $output_str .= "Quality 12 (Maximum)<br>\n";
  546. break;
  547. default:
  548. $output_str .= "Unknown Quality (" . $Qual_Info['Quality'] . ")<br>\n";
  549. break;
  550. }
  551. switch ( $Qual_Info['Format'] )
  552. {
  553. case 0x0000:
  554. $output_str .= "Standard Format\n";
  555. break;
  556. case 0x0001:
  557. $output_str .= "Optimised Format\n";
  558. break;
  559. case 0x0101:
  560. $output_str .= "Progressive Format<br>\n";
  561. break;
  562. default:
  563. $output_str .= "Unknown Format (" . $Qual_Info['Format'] .")\n";
  564. break;
  565. }
  566. if ( $Qual_Info['Format'] == 0x0101 )
  567. {
  568. switch ( $Qual_Info['Scans'] )
  569. {
  570. case 0x0001:
  571. $output_str .= "3 Scans\n";
  572. break;
  573. case 0x0002:
  574. $output_str .= "4 Scans\n";
  575. break;
  576. case 0x0003:
  577. $output_str .= "5 Scans\n";
  578. break;
  579. default:
  580. $output_str .= "Unknown number of scans (" . $Qual_Info['Scans'] .")\n";
  581. break;
  582. }
  583. }
  584. $output_str .= "</td></tr>\n";
  585. break;
  586. case 0x0409 : // Thumbnail Resource
  587. case 0x040C : // Thumbnail Resource
  588. $thumb_data = unpack("NFormat/NWidth/NHeight/NWidthBytes/NSize/NCompressedSize/nBitsPixel/nPlanes", $IRB_Resource['ResData'] );
  589. $output_str .= "<tr class=\"Photoshop_Table_Row\"><td class=\"Photoshop_Caption_Cell\">$Resource_Name</td><td class=\"Photoshop_Value_Cell\"><pre>\n";
  590. $output_str .= "Format = " . (( $thumb_data['Format'] == 1 ) ? "JPEG RGB\n" : "Raw RGB\n");
  591. $output_str .= "Width = " . $thumb_data['Width'] . "\n";
  592. $output_str .= "Height = " . $thumb_data['Height'] . "\n";
  593. $output_str .= "Padded Row Bytes = " . $thumb_data['WidthBytes'] . " bytes\n";
  594. $output_str .= "Total Size = " . $thumb_data['Size'] . " bytes\n";
  595. $output_str .= "Compressed Size = " . $thumb_data['CompressedSize'] . " bytes\n";
  596. $output_str .= "Bits per Pixel = " . $thumb_data['BitsPixel'] . " bits\n";
  597. $output_str .= "Number of planes = " . $thumb_data['Planes'] . " bytes\n";
  598. // Change: as of version 1.11 - Changed to make thumbnail link portable across directories
  599. // Build the path of the thumbnail script and its filename parameter to put in a url
  600. $link_str = get_relative_path( dirname(__FILE__) . "/get_ps_thumb.php" , getcwd ( ) );
  601. $link_str .= "?filename=";
  602. $link_str .= get_relative_path( $filename, dirname(__FILE__) );
  603. // Add thumbnail link to html
  604. $output_str .= "Thumbnail Data:</pre><a class=\"Photoshop_Thumbnail_Link\" href=\"$link_str\"><img class=\"Photoshop_Thumbnail_Link\" src=\"$link_str\"></a>\n";
  605. $output_str .= "</td></tr>\n";
  606. break;
  607. case 0x0414 : // Document Specific ID's
  608. $output_str .= "<tr class=\"Photoshop_Table_Row\"><td class=\"Photoshop_Caption_Cell\">$Resource_Name</td><td class=\"Photoshop_Value_Cell\"><pre>" . hexdec( bin2hex( $IRB_Resource['ResData'] ) ) . "</pre></td></tr>\n";
  609. break;
  610. case 0x041E : // URL List
  611. $URL_count = hexdec( bin2hex( substr( $IRB_Resource['ResData'], 0, 4 ) ) );
  612. $output_str .= "<tr class=\"Photoshop_Table_Row\"><td class=\"Photoshop_Caption_Cell\">$Resource_Name</td><td class=\"Photoshop_Value_Cell\">\n";
  613. $output_str .= "$URL_count URL's in list<br>\n";
  614. $urlstr = substr( $IRB_Resource['ResData'], 4 );
  615. // TODO: Check if URL List in Photoshop IRB works
  616. for( $i = 0; $i < $URL_count; $i++ )
  617. {
  618. $url_data = unpack( "NLong/NID/NURLSize", $urlstr );
  619. $output_str .= "URL $i info: long = " . $url_data['Long'] .", ";
  620. $output_str .= "ID = " . $url_data['ID'] . ", ";
  621. $urlstr = substr( $urlstr, 12 );
  622. $url = substr( $urlstr, 0, $url_data['URLSize'] );
  623. $output_str .= "URL = <a href=\"" . xml_UTF16_clean( $url, TRUE ) . "\">" . HTML_UTF16_Escape( $url, TRUE ) . "</a><br>\n";
  624. }
  625. $output_str .= "</td></tr>\n";
  626. break;
  627. case 0x03F4 : // Grayscale and multichannel halftoning information.
  628. $output_str .= "<tr class=\"Photoshop_Table_Row\"><td class=\"Photoshop_Caption_Cell\">$Resource_Name</td><td class=\"Photoshop_Value_Cell\"><pre>\n";
  629. $output_str .= Interpret_Halftone( $IRB_Resource['ResData'] );
  630. $output_str .= "</pre></td></tr>\n";
  631. break;
  632. case 0x03F5 : // Color halftoning information
  633. $output_str .= "<tr class=\"Photoshop_Table_Row\"><td class=\"Photoshop_Caption_Cell\">$Resource_Name</td><td class=\"Photoshop_Value_Cell\"><pre>\n";
  634. $output_str .= "Cyan Halftoning Info:\n" . Interpret_Halftone( substr( $IRB_Resource['ResData'], 0, 18 ) ) . "\n\n";
  635. $output_str .= "Magenta Halftoning Info:\n" . Interpret_Halftone( substr( $IRB_Resource['ResData'], 18, 18 ) ) . "\n\n";
  636. $output_str .= "Yellow Halftoning Info:\n" . Interpret_Halftone( substr( $IRB_Resource['ResData'], 36, 18 ) ) . "\n";
  637. $output_str .= "Black Halftoning Info:\n" . Interpret_Halftone( substr( $IRB_Resource['ResData'], 54, 18 ) ) . "\n";
  638. $output_str .= "</pre></td></tr>\n";
  639. break;
  640. case 0x03F7 : // Grayscale and multichannel transfer function.
  641. $output_str .= "<tr class=\"Photoshop_Table_Row\"><td class=\"Photoshop_Caption_Cell\">$Resource_Name</td><td class=\"Photoshop_Value_Cell\"><pre>\n";
  642. $output_str .= Interpret_Transfer_Function( substr( $IRB_Resource['ResData'], 0, 28 ) ) ;
  643. $output_str .= "</pre></td></tr>\n";
  644. break;
  645. case 0x03F8 : // Color transfer functions
  646. $output_str .= "<tr class=\"Photoshop_Table_Row\"><td class=\"Photoshop_Caption_Cell\">$Resource_Name</td><td class=\"Photoshop_Value_Cell\"><pre>\n";
  647. $output_str .= "Red Transfer Function: \n" . Interpret_Transfer_Function( substr( $IRB_Resource['ResData'], 0, 28 ) ) . "\n\n";
  648. $output_str .= "Green Transfer Function: \n" . Interpret_Transfer_Function( substr( $IRB_Resource['ResData'], 28, 28 ) ) . "\n\n";
  649. $output_str .= "Blue Transfer Function: \n" . Interpret_Transfer_Function( substr( $IRB_Resource['ResData'], 56, 28 ) ) . "\n";
  650. $output_str .= "</pre></td></tr>\n";
  651. break;
  652. case 0x03F3 : // Print Flags
  653. $output_str .= "<tr class=\"Photoshop_Table_Row\"><td class=\"Photoshop_Caption_Cell\">$Resource_Name</td><td class=\"Photoshop_Value_Cell\"><pre>\n";
  654. if ( $IRB_Resource['ResData']{0} == "\x01" )
  655. {
  656. $output_str .= "Labels Selected\n";
  657. }
  658. else
  659. {
  660. $output_str .= "Labels Not Selected\n";
  661. }
  662. if ( $IRB_Resource['ResData']{1} == "\x01" )
  663. {
  664. $output_str .= "Crop Marks Selected\n";
  665. }
  666. else
  667. {
  668. $output_str .= "Crop Marks Not Selected\n";
  669. }
  670. if ( $IRB_Resource['ResData']{2} == "\x01" )
  671. {
  672. $output_str .= "Color Bars Selected\n";
  673. }
  674. else
  675. {
  676. $output_str .= "Color Bars Not Selected\n";
  677. }
  678. if ( $IRB_Resource['ResData']{3} == "\x01" )
  679. {
  680. $output_str .= "Registration Marks Selected\n";

Large files files are truncated, but you can click here to view the full file