module.tag.xmp.php 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768
  1. <?php
  2. /////////////////////////////////////////////////////////////////
  3. /// getID3() by James Heinrich <info@getid3.org> //
  4. // available at http://getid3.sourceforge.net //
  5. // or http://www.getid3.org //
  6. // also https://github.com/JamesHeinrich/getID3 //
  7. /////////////////////////////////////////////////////////////////
  8. // See readme.txt for more details //
  9. /////////////////////////////////////////////////////////////////
  10. // //
  11. // module.tag.xmp.php //
  12. // module for analyzing XMP metadata (e.g. in JPEG files) //
  13. // dependencies: NONE //
  14. // //
  15. /////////////////////////////////////////////////////////////////
  16. // //
  17. // Module originally written [2009-Mar-26] by //
  18. // Nigel Barnes <ngbarnesØhotmail*com> //
  19. // Bundled into getID3 with permission //
  20. // called by getID3 in module.graphic.jpg.php //
  21. // ///
  22. /////////////////////////////////////////////////////////////////
  23. /**************************************************************************************************
  24. * SWISScenter Source Nigel Barnes
  25. *
  26. * Provides functions for reading information from the 'APP1' Extensible Metadata
  27. * Platform (XMP) segment of JPEG format files.
  28. * This XMP segment is XML based and contains the Resource Description Framework (RDF)
  29. * data, which itself can contain the Dublin Core Metadata Initiative (DCMI) information.
  30. *
  31. * This code uses segments from the JPEG Metadata Toolkit project by Evan Hunter.
  32. *************************************************************************************************/
  33. class Image_XMP
  34. {
  35. /**
  36. * @var string
  37. * The name of the image file that contains the XMP fields to extract and modify.
  38. * @see Image_XMP()
  39. */
  40. public $_sFilename = null;
  41. /**
  42. * @var array
  43. * The XMP fields that were extracted from the image or updated by this class.
  44. * @see getAllTags()
  45. */
  46. public $_aXMP = array();
  47. /**
  48. * @var boolean
  49. * True if an APP1 segment was found to contain XMP metadata.
  50. * @see isValid()
  51. */
  52. public $_bXMPParse = false;
  53. /**
  54. * Returns the status of XMP parsing during instantiation
  55. *
  56. * You'll normally want to call this method before trying to get XMP fields.
  57. *
  58. * @return boolean
  59. * Returns true if an APP1 segment was found to contain XMP metadata.
  60. */
  61. public function isValid()
  62. {
  63. return $this->_bXMPParse;
  64. }
  65. /**
  66. * Get a copy of all XMP tags extracted from the image
  67. *
  68. * @return array - An array of XMP fields as it extracted by the XMPparse() function
  69. */
  70. public function getAllTags()
  71. {
  72. return $this->_aXMP;
  73. }
  74. /**
  75. * Reads all the JPEG header segments from an JPEG image file into an array
  76. *
  77. * @param string $filename - the filename of the JPEG file to read
  78. * @return array $headerdata - Array of JPEG header segments
  79. * @return boolean FALSE - if headers could not be read
  80. */
  81. public function _get_jpeg_header_data($filename)
  82. {
  83. // prevent refresh from aborting file operations and hosing file
  84. ignore_user_abort(true);
  85. // Attempt to open the jpeg file - the at symbol supresses the error message about
  86. // not being able to open files. The file_exists would have been used, but it
  87. // does not work with files fetched over http or ftp.
  88. if (is_readable($filename) && is_file($filename) && ($filehnd = fopen($filename, 'rb'))) {
  89. // great
  90. } else {
  91. return false;
  92. }
  93. // Read the first two characters
  94. $data = fread($filehnd, 2);
  95. // Check that the first two characters are 0xFF 0xD8 (SOI - Start of image)
  96. if ($data != "\xFF\xD8")
  97. {
  98. // No SOI (FF D8) at start of file - This probably isn't a JPEG file - close file and return;
  99. echo '<p>This probably is not a JPEG file</p>'."\n";
  100. fclose($filehnd);
  101. return false;
  102. }
  103. // Read the third character
  104. $data = fread($filehnd, 2);
  105. // Check that the third character is 0xFF (Start of first segment header)
  106. if ($data{0} != "\xFF")
  107. {
  108. // NO FF found - close file and return - JPEG is probably corrupted
  109. fclose($filehnd);
  110. return false;
  111. }
  112. // Flag that we havent yet hit the compressed image data
  113. $hit_compressed_image_data = false;
  114. // Cycle through the file until, one of: 1) an EOI (End of image) marker is hit,
  115. // 2) we have hit the compressed image data (no more headers are allowed after data)
  116. // 3) or end of file is hit
  117. while (($data{1} != "\xD9") && (!$hit_compressed_image_data) && (!feof($filehnd)))
  118. {
  119. // Found a segment to look at.
  120. // Check that the segment marker is not a Restart marker - restart markers don't have size or data after them
  121. if ((ord($data{1}) < 0xD0) || (ord($data{1}) > 0xD7))
  122. {
  123. // Segment isn't a Restart marker
  124. // Read the next two bytes (size)
  125. $sizestr = fread($filehnd, 2);
  126. // convert the size bytes to an integer
  127. $decodedsize = unpack('nsize', $sizestr);
  128. // Save the start position of the data
  129. $segdatastart = ftell($filehnd);
  130. // Read the segment data with length indicated by the previously read size
  131. $segdata = fread($filehnd, $decodedsize['size'] - 2);
  132. // Store the segment information in the output array
  133. $headerdata[] = array(
  134. 'SegType' => ord($data{1}),
  135. 'SegName' => $GLOBALS['JPEG_Segment_Names'][ord($data{1})],
  136. 'SegDataStart' => $segdatastart,
  137. 'SegData' => $segdata,
  138. );
  139. }
  140. // If this is a SOS (Start Of Scan) segment, then there is no more header data - the compressed image data follows
  141. if ($data{1} == "\xDA")
  142. {
  143. // Flag that we have hit the compressed image data - exit loop as no more headers available.
  144. $hit_compressed_image_data = true;
  145. }
  146. else
  147. {
  148. // Not an SOS - Read the next two bytes - should be the segment marker for the next segment
  149. $data = fread($filehnd, 2);
  150. // Check that the first byte of the two is 0xFF as it should be for a marker
  151. if ($data{0} != "\xFF")
  152. {
  153. // NO FF found - close file and return - JPEG is probably corrupted
  154. fclose($filehnd);
  155. return false;
  156. }
  157. }
  158. }
  159. // Close File
  160. fclose($filehnd);
  161. // Alow the user to abort from now on
  162. ignore_user_abort(false);
  163. // Return the header data retrieved
  164. return $headerdata;
  165. }
  166. /**
  167. * Retrieves XMP information from an APP1 JPEG segment and returns the raw XML text as a string.
  168. *
  169. * @param string $filename - the filename of the JPEG file to read
  170. * @return string $xmp_data - the string of raw XML text
  171. * @return boolean FALSE - if an APP 1 XMP segment could not be found, or if an error occured
  172. */
  173. public function _get_XMP_text($filename)
  174. {
  175. //Get JPEG header data
  176. $jpeg_header_data = $this->_get_jpeg_header_data($filename);
  177. //Cycle through the header segments
  178. for ($i = 0; $i < count($jpeg_header_data); $i++)
  179. {
  180. // If we find an APP1 header,
  181. if (strcmp($jpeg_header_data[$i]['SegName'], 'APP1') == 0)
  182. {
  183. // And if it has the Adobe XMP/RDF label (http://ns.adobe.com/xap/1.0/\x00) ,
  184. if (strncmp($jpeg_header_data[$i]['SegData'], 'http://ns.adobe.com/xap/1.0/'."\x00", 29) == 0)
  185. {
  186. // Found a XMP/RDF block
  187. // Return the XMP text
  188. $xmp_data = substr($jpeg_header_data[$i]['SegData'], 29);
  189. return trim($xmp_data); // trim() should not be neccesary, but some files found in the wild with null-terminated block (known samples from Apple Aperture) causes problems elsewhere (see http://www.getid3.org/phpBB3/viewtopic.php?f=4&t=1153)
  190. }
  191. }
  192. }
  193. return false;
  194. }
  195. /**
  196. * Parses a string containing XMP data (XML), and returns an array
  197. * which contains all the XMP (XML) information.
  198. *
  199. * @param string $xml_text - a string containing the XMP data (XML) to be parsed
  200. * @return array $xmp_array - an array containing all xmp details retrieved.
  201. * @return boolean FALSE - couldn't parse the XMP data
  202. */
  203. public function read_XMP_array_from_text($xmltext)
  204. {
  205. // Check if there actually is any text to parse
  206. if (trim($xmltext) == '')
  207. {
  208. return false;
  209. }
  210. // Create an instance of a xml parser to parse the XML text
  211. $xml_parser = xml_parser_create('UTF-8');
  212. // Change: Fixed problem that caused the whitespace (especially newlines) to be destroyed when converting xml text to an xml array, as of revision 1.10
  213. // We would like to remove unneccessary white space, but this will also
  214. // remove things like newlines (&#xA;) in the XML values, so white space
  215. // will have to be removed later
  216. if (xml_parser_set_option($xml_parser, XML_OPTION_SKIP_WHITE, 0) == false)
  217. {
  218. // Error setting case folding - destroy the parser and return
  219. xml_parser_free($xml_parser);
  220. return false;
  221. }
  222. // to use XML code correctly we have to turn case folding
  223. // (uppercasing) off. XML is case sensitive and upper
  224. // casing is in reality XML standards violation
  225. if (xml_parser_set_option($xml_parser, XML_OPTION_CASE_FOLDING, 0) == false)
  226. {
  227. // Error setting case folding - destroy the parser and return
  228. xml_parser_free($xml_parser);
  229. return false;
  230. }
  231. // Parse the XML text into a array structure
  232. if (xml_parse_into_struct($xml_parser, $xmltext, $values, $tags) == 0)
  233. {
  234. // Error Parsing XML - destroy the parser and return
  235. xml_parser_free($xml_parser);
  236. return false;
  237. }
  238. // Destroy the xml parser
  239. xml_parser_free($xml_parser);
  240. // Clear the output array
  241. $xmp_array = array();
  242. // The XMP data has now been parsed into an array ...
  243. // Cycle through each of the array elements
  244. $current_property = ''; // current property being processed
  245. $container_index = -1; // -1 = no container open, otherwise index of container content
  246. foreach ($values as $xml_elem)
  247. {
  248. // Syntax and Class names
  249. switch ($xml_elem['tag'])
  250. {
  251. case 'x:xmpmeta':
  252. // only defined attribute is x:xmptk written by Adobe XMP Toolkit; value is the version of the toolkit
  253. break;
  254. case 'rdf:RDF':
  255. // required element immediately within x:xmpmeta; no data here
  256. break;
  257. case 'rdf:Description':
  258. switch ($xml_elem['type'])
  259. {
  260. case 'open':
  261. case 'complete':
  262. if (array_key_exists('attributes', $xml_elem))
  263. {
  264. // rdf:Description may contain wanted attributes
  265. foreach (array_keys($xml_elem['attributes']) as $key)
  266. {
  267. // Check whether we want this details from this attribute
  268. // if (in_array($key, $GLOBALS['XMP_tag_captions']))
  269. if (true)
  270. {
  271. // Attribute wanted
  272. $xmp_array[$key] = $xml_elem['attributes'][$key];
  273. }
  274. }
  275. }
  276. case 'cdata':
  277. case 'close':
  278. break;
  279. }
  280. case 'rdf:ID':
  281. case 'rdf:nodeID':
  282. // Attributes are ignored
  283. break;
  284. case 'rdf:li':
  285. // Property member
  286. if ($xml_elem['type'] == 'complete')
  287. {
  288. if (array_key_exists('attributes', $xml_elem))
  289. {
  290. // If Lang Alt (language alternatives) then ensure we take the default language
  291. if (isset($xml_elem['attributes']['xml:lang']) && ($xml_elem['attributes']['xml:lang'] != 'x-default'))
  292. {
  293. break;
  294. }
  295. }
  296. if ($current_property != '')
  297. {
  298. $xmp_array[$current_property][$container_index] = (isset($xml_elem['value']) ? $xml_elem['value'] : '');
  299. $container_index += 1;
  300. }
  301. //else unidentified attribute!!
  302. }
  303. break;
  304. case 'rdf:Seq':
  305. case 'rdf:Bag':
  306. case 'rdf:Alt':
  307. // Container found
  308. switch ($xml_elem['type'])
  309. {
  310. case 'open':
  311. $container_index = 0;
  312. break;
  313. case 'close':
  314. $container_index = -1;
  315. break;
  316. case 'cdata':
  317. break;
  318. }
  319. break;
  320. default:
  321. // Check whether we want the details from this attribute
  322. // if (in_array($xml_elem['tag'], $GLOBALS['XMP_tag_captions']))
  323. if (true)
  324. {
  325. switch ($xml_elem['type'])
  326. {
  327. case 'open':
  328. // open current element
  329. $current_property = $xml_elem['tag'];
  330. break;
  331. case 'close':
  332. // close current element
  333. $current_property = '';
  334. break;
  335. case 'complete':
  336. // store attribute value
  337. $xmp_array[$xml_elem['tag']] = (isset($xml_elem['attributes']) ? $xml_elem['attributes'] : (isset($xml_elem['value']) ? $xml_elem['value'] : ''));
  338. break;
  339. case 'cdata':
  340. // ignore
  341. break;
  342. }
  343. }
  344. break;
  345. }
  346. }
  347. return $xmp_array;
  348. }
  349. /**
  350. * Constructor
  351. *
  352. * @param string - Name of the image file to access and extract XMP information from.
  353. */
  354. public function __construct($sFilename)
  355. {
  356. $this->_sFilename = $sFilename;
  357. if (is_file($this->_sFilename))
  358. {
  359. // Get XMP data
  360. $xmp_data = $this->_get_XMP_text($sFilename);
  361. if ($xmp_data)
  362. {
  363. $this->_aXMP = $this->read_XMP_array_from_text($xmp_data);
  364. $this->_bXMPParse = true;
  365. }
  366. }
  367. }
  368. }
  369. /**
  370. * Global Variable: XMP_tag_captions
  371. *
  372. * The Property names of all known XMP fields.
  373. * Note: this is a full list with unrequired properties commented out.
  374. */
  375. /*
  376. $GLOBALS['XMP_tag_captions'] = array(
  377. // IPTC Core
  378. 'Iptc4xmpCore:CiAdrCity',
  379. 'Iptc4xmpCore:CiAdrCtry',
  380. 'Iptc4xmpCore:CiAdrExtadr',
  381. 'Iptc4xmpCore:CiAdrPcode',
  382. 'Iptc4xmpCore:CiAdrRegion',
  383. 'Iptc4xmpCore:CiEmailWork',
  384. 'Iptc4xmpCore:CiTelWork',
  385. 'Iptc4xmpCore:CiUrlWork',
  386. 'Iptc4xmpCore:CountryCode',
  387. 'Iptc4xmpCore:CreatorContactInfo',
  388. 'Iptc4xmpCore:IntellectualGenre',
  389. 'Iptc4xmpCore:Location',
  390. 'Iptc4xmpCore:Scene',
  391. 'Iptc4xmpCore:SubjectCode',
  392. // Dublin Core Schema
  393. 'dc:contributor',
  394. 'dc:coverage',
  395. 'dc:creator',
  396. 'dc:date',
  397. 'dc:description',
  398. 'dc:format',
  399. 'dc:identifier',
  400. 'dc:language',
  401. 'dc:publisher',
  402. 'dc:relation',
  403. 'dc:rights',
  404. 'dc:source',
  405. 'dc:subject',
  406. 'dc:title',
  407. 'dc:type',
  408. // XMP Basic Schema
  409. 'xmp:Advisory',
  410. 'xmp:BaseURL',
  411. 'xmp:CreateDate',
  412. 'xmp:CreatorTool',
  413. 'xmp:Identifier',
  414. 'xmp:Label',
  415. 'xmp:MetadataDate',
  416. 'xmp:ModifyDate',
  417. 'xmp:Nickname',
  418. 'xmp:Rating',
  419. 'xmp:Thumbnails',
  420. 'xmpidq:Scheme',
  421. // XMP Rights Management Schema
  422. 'xmpRights:Certificate',
  423. 'xmpRights:Marked',
  424. 'xmpRights:Owner',
  425. 'xmpRights:UsageTerms',
  426. 'xmpRights:WebStatement',
  427. // These are not in spec but Photoshop CS seems to use them
  428. 'xap:Advisory',
  429. 'xap:BaseURL',
  430. 'xap:CreateDate',
  431. 'xap:CreatorTool',
  432. 'xap:Identifier',
  433. 'xap:MetadataDate',
  434. 'xap:ModifyDate',
  435. 'xap:Nickname',
  436. 'xap:Rating',
  437. 'xap:Thumbnails',
  438. 'xapidq:Scheme',
  439. 'xapRights:Certificate',
  440. 'xapRights:Copyright',
  441. 'xapRights:Marked',
  442. 'xapRights:Owner',
  443. 'xapRights:UsageTerms',
  444. 'xapRights:WebStatement',
  445. // XMP Media Management Schema
  446. 'xapMM:DerivedFrom',
  447. 'xapMM:DocumentID',
  448. 'xapMM:History',
  449. 'xapMM:InstanceID',
  450. 'xapMM:ManagedFrom',
  451. 'xapMM:Manager',
  452. 'xapMM:ManageTo',
  453. 'xapMM:ManageUI',
  454. 'xapMM:ManagerVariant',
  455. 'xapMM:RenditionClass',
  456. 'xapMM:RenditionParams',
  457. 'xapMM:VersionID',
  458. 'xapMM:Versions',
  459. 'xapMM:LastURL',
  460. 'xapMM:RenditionOf',
  461. 'xapMM:SaveID',
  462. // XMP Basic Job Ticket Schema
  463. 'xapBJ:JobRef',
  464. // XMP Paged-Text Schema
  465. 'xmpTPg:MaxPageSize',
  466. 'xmpTPg:NPages',
  467. 'xmpTPg:Fonts',
  468. 'xmpTPg:Colorants',
  469. 'xmpTPg:PlateNames',
  470. // Adobe PDF Schema
  471. 'pdf:Keywords',
  472. 'pdf:PDFVersion',
  473. 'pdf:Producer',
  474. // Photoshop Schema
  475. 'photoshop:AuthorsPosition',
  476. 'photoshop:CaptionWriter',
  477. 'photoshop:Category',
  478. 'photoshop:City',
  479. 'photoshop:Country',
  480. 'photoshop:Credit',
  481. 'photoshop:DateCreated',
  482. 'photoshop:Headline',
  483. 'photoshop:History',
  484. // Not in XMP spec
  485. 'photoshop:Instructions',
  486. 'photoshop:Source',
  487. 'photoshop:State',
  488. 'photoshop:SupplementalCategories',
  489. 'photoshop:TransmissionReference',
  490. 'photoshop:Urgency',
  491. // EXIF Schemas
  492. 'tiff:ImageWidth',
  493. 'tiff:ImageLength',
  494. 'tiff:BitsPerSample',
  495. 'tiff:Compression',
  496. 'tiff:PhotometricInterpretation',
  497. 'tiff:Orientation',
  498. 'tiff:SamplesPerPixel',
  499. 'tiff:PlanarConfiguration',
  500. 'tiff:YCbCrSubSampling',
  501. 'tiff:YCbCrPositioning',
  502. 'tiff:XResolution',
  503. 'tiff:YResolution',
  504. 'tiff:ResolutionUnit',
  505. 'tiff:TransferFunction',
  506. 'tiff:WhitePoint',
  507. 'tiff:PrimaryChromaticities',
  508. 'tiff:YCbCrCoefficients',
  509. 'tiff:ReferenceBlackWhite',
  510. 'tiff:DateTime',
  511. 'tiff:ImageDescription',
  512. 'tiff:Make',
  513. 'tiff:Model',
  514. 'tiff:Software',
  515. 'tiff:Artist',
  516. 'tiff:Copyright',
  517. 'exif:ExifVersion',
  518. 'exif:FlashpixVersion',
  519. 'exif:ColorSpace',
  520. 'exif:ComponentsConfiguration',
  521. 'exif:CompressedBitsPerPixel',
  522. 'exif:PixelXDimension',
  523. 'exif:PixelYDimension',
  524. 'exif:MakerNote',
  525. 'exif:UserComment',
  526. 'exif:RelatedSoundFile',
  527. 'exif:DateTimeOriginal',
  528. 'exif:DateTimeDigitized',
  529. 'exif:ExposureTime',
  530. 'exif:FNumber',
  531. 'exif:ExposureProgram',
  532. 'exif:SpectralSensitivity',
  533. 'exif:ISOSpeedRatings',
  534. 'exif:OECF',
  535. 'exif:ShutterSpeedValue',
  536. 'exif:ApertureValue',
  537. 'exif:BrightnessValue',
  538. 'exif:ExposureBiasValue',
  539. 'exif:MaxApertureValue',
  540. 'exif:SubjectDistance',
  541. 'exif:MeteringMode',
  542. 'exif:LightSource',
  543. 'exif:Flash',
  544. 'exif:FocalLength',
  545. 'exif:SubjectArea',
  546. 'exif:FlashEnergy',
  547. 'exif:SpatialFrequencyResponse',
  548. 'exif:FocalPlaneXResolution',
  549. 'exif:FocalPlaneYResolution',
  550. 'exif:FocalPlaneResolutionUnit',
  551. 'exif:SubjectLocation',
  552. 'exif:SensingMethod',
  553. 'exif:FileSource',
  554. 'exif:SceneType',
  555. 'exif:CFAPattern',
  556. 'exif:CustomRendered',
  557. 'exif:ExposureMode',
  558. 'exif:WhiteBalance',
  559. 'exif:DigitalZoomRatio',
  560. 'exif:FocalLengthIn35mmFilm',
  561. 'exif:SceneCaptureType',
  562. 'exif:GainControl',
  563. 'exif:Contrast',
  564. 'exif:Saturation',
  565. 'exif:Sharpness',
  566. 'exif:DeviceSettingDescription',
  567. 'exif:SubjectDistanceRange',
  568. 'exif:ImageUniqueID',
  569. 'exif:GPSVersionID',
  570. 'exif:GPSLatitude',
  571. 'exif:GPSLongitude',
  572. 'exif:GPSAltitudeRef',
  573. 'exif:GPSAltitude',
  574. 'exif:GPSTimeStamp',
  575. 'exif:GPSSatellites',
  576. 'exif:GPSStatus',
  577. 'exif:GPSMeasureMode',
  578. 'exif:GPSDOP',
  579. 'exif:GPSSpeedRef',
  580. 'exif:GPSSpeed',
  581. 'exif:GPSTrackRef',
  582. 'exif:GPSTrack',
  583. 'exif:GPSImgDirectionRef',
  584. 'exif:GPSImgDirection',
  585. 'exif:GPSMapDatum',
  586. 'exif:GPSDestLatitude',
  587. 'exif:GPSDestLongitude',
  588. 'exif:GPSDestBearingRef',
  589. 'exif:GPSDestBearing',
  590. 'exif:GPSDestDistanceRef',
  591. 'exif:GPSDestDistance',
  592. 'exif:GPSProcessingMethod',
  593. 'exif:GPSAreaInformation',
  594. 'exif:GPSDifferential',
  595. 'stDim:w',
  596. 'stDim:h',
  597. 'stDim:unit',
  598. 'xapGImg:height',
  599. 'xapGImg:width',
  600. 'xapGImg:format',
  601. 'xapGImg:image',
  602. 'stEvt:action',
  603. 'stEvt:instanceID',
  604. 'stEvt:parameters',
  605. 'stEvt:softwareAgent',
  606. 'stEvt:when',
  607. 'stRef:instanceID',
  608. 'stRef:documentID',
  609. 'stRef:versionID',
  610. 'stRef:renditionClass',
  611. 'stRef:renditionParams',
  612. 'stRef:manager',
  613. 'stRef:managerVariant',
  614. 'stRef:manageTo',
  615. 'stRef:manageUI',
  616. 'stVer:comments',
  617. 'stVer:event',
  618. 'stVer:modifyDate',
  619. 'stVer:modifier',
  620. 'stVer:version',
  621. 'stJob:name',
  622. 'stJob:id',
  623. 'stJob:url',
  624. // Exif Flash
  625. 'exif:Fired',
  626. 'exif:Return',
  627. 'exif:Mode',
  628. 'exif:Function',
  629. 'exif:RedEyeMode',
  630. // Exif OECF/SFR
  631. 'exif:Columns',
  632. 'exif:Rows',
  633. 'exif:Names',
  634. 'exif:Values',
  635. // Exif CFAPattern
  636. 'exif:Columns',
  637. 'exif:Rows',
  638. 'exif:Values',
  639. // Exif DeviceSettings
  640. 'exif:Columns',
  641. 'exif:Rows',
  642. 'exif:Settings',
  643. );
  644. */
  645. /**
  646. * Global Variable: JPEG_Segment_Names
  647. *
  648. * The names of the JPEG segment markers, indexed by their marker number
  649. */
  650. $GLOBALS['JPEG_Segment_Names'] = array(
  651. 0x01 => 'TEM',
  652. 0x02 => 'RES',
  653. 0xC0 => 'SOF0',
  654. 0xC1 => 'SOF1',
  655. 0xC2 => 'SOF2',
  656. 0xC3 => 'SOF4',
  657. 0xC4 => 'DHT',
  658. 0xC5 => 'SOF5',
  659. 0xC6 => 'SOF6',
  660. 0xC7 => 'SOF7',
  661. 0xC8 => 'JPG',
  662. 0xC9 => 'SOF9',
  663. 0xCA => 'SOF10',
  664. 0xCB => 'SOF11',
  665. 0xCC => 'DAC',
  666. 0xCD => 'SOF13',
  667. 0xCE => 'SOF14',
  668. 0xCF => 'SOF15',
  669. 0xD0 => 'RST0',
  670. 0xD1 => 'RST1',
  671. 0xD2 => 'RST2',
  672. 0xD3 => 'RST3',
  673. 0xD4 => 'RST4',
  674. 0xD5 => 'RST5',
  675. 0xD6 => 'RST6',
  676. 0xD7 => 'RST7',
  677. 0xD8 => 'SOI',
  678. 0xD9 => 'EOI',
  679. 0xDA => 'SOS',
  680. 0xDB => 'DQT',
  681. 0xDC => 'DNL',
  682. 0xDD => 'DRI',
  683. 0xDE => 'DHP',
  684. 0xDF => 'EXP',
  685. 0xE0 => 'APP0',
  686. 0xE1 => 'APP1',
  687. 0xE2 => 'APP2',
  688. 0xE3 => 'APP3',
  689. 0xE4 => 'APP4',
  690. 0xE5 => 'APP5',
  691. 0xE6 => 'APP6',
  692. 0xE7 => 'APP7',
  693. 0xE8 => 'APP8',
  694. 0xE9 => 'APP9',
  695. 0xEA => 'APP10',
  696. 0xEB => 'APP11',
  697. 0xEC => 'APP12',
  698. 0xED => 'APP13',
  699. 0xEE => 'APP14',
  700. 0xEF => 'APP15',
  701. 0xF0 => 'JPG0',
  702. 0xF1 => 'JPG1',
  703. 0xF2 => 'JPG2',
  704. 0xF3 => 'JPG3',
  705. 0xF4 => 'JPG4',
  706. 0xF5 => 'JPG5',
  707. 0xF6 => 'JPG6',
  708. 0xF7 => 'JPG7',
  709. 0xF8 => 'JPG8',
  710. 0xF9 => 'JPG9',
  711. 0xFA => 'JPG10',
  712. 0xFB => 'JPG11',
  713. 0xFC => 'JPG12',
  714. 0xFD => 'JPG13',
  715. 0xFE => 'COM',
  716. );