module.tag.xmp.php 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774
  1. <?php
  2. /////////////////////////////////////////////////////////////////
  3. /// getID3() by James Heinrich <info@getid3.org> //
  4. // available at https://github.com/JamesHeinrich/getID3 //
  5. // or https://www.getid3.org //
  6. // or http://getid3.sourceforge.net //
  7. // see readme.txt for more details //
  8. /////////////////////////////////////////////////////////////////
  9. // //
  10. // module.tag.xmp.php //
  11. // module for analyzing XMP metadata (e.g. in JPEG files) //
  12. // dependencies: NONE //
  13. // //
  14. /////////////////////////////////////////////////////////////////
  15. // //
  16. // Module originally written [2009-Mar-26] by //
  17. // Nigel Barnes <ngbarnesØhotmail*com> //
  18. // Bundled into getID3 with permission //
  19. // called by getID3 in module.graphic.jpg.php //
  20. // ///
  21. /////////////////////////////////////////////////////////////////
  22. /**************************************************************************************************
  23. * SWISScenter Source Nigel Barnes
  24. *
  25. * Provides functions for reading information from the 'APP1' Extensible Metadata
  26. * Platform (XMP) segment of JPEG format files.
  27. * This XMP segment is XML based and contains the Resource Description Framework (RDF)
  28. * data, which itself can contain the Dublin Core Metadata Initiative (DCMI) information.
  29. *
  30. * This code uses segments from the JPEG Metadata Toolkit project by Evan Hunter.
  31. *************************************************************************************************/
  32. class Image_XMP
  33. {
  34. /**
  35. * @var string
  36. * The name of the image file that contains the XMP fields to extract and modify.
  37. * @see Image_XMP()
  38. */
  39. public $_sFilename = null;
  40. /**
  41. * @var array
  42. * The XMP fields that were extracted from the image or updated by this class.
  43. * @see getAllTags()
  44. */
  45. public $_aXMP = array();
  46. /**
  47. * @var boolean
  48. * True if an APP1 segment was found to contain XMP metadata.
  49. * @see isValid()
  50. */
  51. public $_bXMPParse = false;
  52. /**
  53. * Returns the status of XMP parsing during instantiation
  54. *
  55. * You'll normally want to call this method before trying to get XMP fields.
  56. *
  57. * @return boolean
  58. * Returns true if an APP1 segment was found to contain XMP metadata.
  59. */
  60. public function isValid()
  61. {
  62. return $this->_bXMPParse;
  63. }
  64. /**
  65. * Get a copy of all XMP tags extracted from the image
  66. *
  67. * @return array - An array of XMP fields as it extracted by the XMPparse() function
  68. */
  69. public function getAllTags()
  70. {
  71. return $this->_aXMP;
  72. }
  73. /**
  74. * Reads all the JPEG header segments from an JPEG image file into an array
  75. *
  76. * @param string $filename - the filename of the JPEG file to read
  77. * @return array|boolean $headerdata - Array of JPEG header segments,
  78. * FALSE - if headers could not be read
  79. */
  80. public function _get_jpeg_header_data($filename)
  81. {
  82. // prevent refresh from aborting file operations and hosing file
  83. ignore_user_abort(true);
  84. // Attempt to open the jpeg file - the at symbol supresses the error message about
  85. // not being able to open files. The file_exists would have been used, but it
  86. // does not work with files fetched over http or ftp.
  87. if (is_readable($filename) && is_file($filename) && ($filehnd = fopen($filename, 'rb'))) {
  88. // great
  89. } else {
  90. return false;
  91. }
  92. // Read the first two characters
  93. $data = fread($filehnd, 2);
  94. // Check that the first two characters are 0xFF 0xD8 (SOI - Start of image)
  95. if ($data != "\xFF\xD8")
  96. {
  97. // No SOI (FF D8) at start of file - This probably isn't a JPEG file - close file and return;
  98. echo '<p>This probably is not a JPEG file</p>'."\n";
  99. fclose($filehnd);
  100. return false;
  101. }
  102. // Read the third character
  103. $data = fread($filehnd, 2);
  104. // Check that the third character is 0xFF (Start of first segment header)
  105. if ($data[0] != "\xFF")
  106. {
  107. // NO FF found - close file and return - JPEG is probably corrupted
  108. fclose($filehnd);
  109. return false;
  110. }
  111. // Flag that we havent yet hit the compressed image data
  112. $hit_compressed_image_data = false;
  113. $headerdata = array();
  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|boolean $xmp_data - the string of raw XML text,
  171. * 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 https://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 $xmltext - a string containing the XMP data (XML) to be parsed
  200. * @return array|boolean $xmp_array - an array containing all xmp details retrieved,
  201. * 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. break;
  277. case 'cdata':
  278. case 'close':
  279. break;
  280. }
  281. break;
  282. case 'rdf:ID':
  283. case 'rdf:nodeID':
  284. // Attributes are ignored
  285. break;
  286. case 'rdf:li':
  287. // Property member
  288. if ($xml_elem['type'] == 'complete')
  289. {
  290. if (array_key_exists('attributes', $xml_elem))
  291. {
  292. // If Lang Alt (language alternatives) then ensure we take the default language
  293. if (isset($xml_elem['attributes']['xml:lang']) && ($xml_elem['attributes']['xml:lang'] != 'x-default'))
  294. {
  295. break;
  296. }
  297. }
  298. if ($current_property != '')
  299. {
  300. $xmp_array[$current_property][$container_index] = (isset($xml_elem['value']) ? $xml_elem['value'] : '');
  301. $container_index += 1;
  302. }
  303. //else unidentified attribute!!
  304. }
  305. break;
  306. case 'rdf:Seq':
  307. case 'rdf:Bag':
  308. case 'rdf:Alt':
  309. // Container found
  310. switch ($xml_elem['type'])
  311. {
  312. case 'open':
  313. $container_index = 0;
  314. break;
  315. case 'close':
  316. $container_index = -1;
  317. break;
  318. case 'cdata':
  319. break;
  320. }
  321. break;
  322. default:
  323. // Check whether we want the details from this attribute
  324. // if (in_array($xml_elem['tag'], $GLOBALS['XMP_tag_captions']))
  325. // if (true)
  326. // {
  327. switch ($xml_elem['type'])
  328. {
  329. case 'open':
  330. // open current element
  331. $current_property = $xml_elem['tag'];
  332. break;
  333. case 'close':
  334. // close current element
  335. $current_property = '';
  336. break;
  337. case 'complete':
  338. // store attribute value
  339. $xmp_array[$xml_elem['tag']] = (isset($xml_elem['attributes']) ? $xml_elem['attributes'] : (isset($xml_elem['value']) ? $xml_elem['value'] : ''));
  340. break;
  341. case 'cdata':
  342. // ignore
  343. break;
  344. }
  345. // }
  346. break;
  347. }
  348. }
  349. return $xmp_array;
  350. }
  351. /**
  352. * Constructor
  353. *
  354. * @param string $sFilename - Name of the image file to access and extract XMP information from.
  355. */
  356. public function __construct($sFilename)
  357. {
  358. $this->_sFilename = $sFilename;
  359. if (is_file($this->_sFilename))
  360. {
  361. // Get XMP data
  362. $xmp_data = $this->_get_XMP_text($sFilename);
  363. if ($xmp_data)
  364. {
  365. $aXMP = $this->read_XMP_array_from_text($xmp_data);
  366. if ($aXMP !== false) {
  367. $this->_aXMP = (array) $aXMP;
  368. $this->_bXMPParse = true;
  369. }
  370. }
  371. }
  372. }
  373. }
  374. /**
  375. * Global Variable: XMP_tag_captions
  376. *
  377. * The Property names of all known XMP fields.
  378. * Note: this is a full list with unrequired properties commented out.
  379. */
  380. /*
  381. $GLOBALS['XMP_tag_captions'] = array(
  382. // IPTC Core
  383. 'Iptc4xmpCore:CiAdrCity',
  384. 'Iptc4xmpCore:CiAdrCtry',
  385. 'Iptc4xmpCore:CiAdrExtadr',
  386. 'Iptc4xmpCore:CiAdrPcode',
  387. 'Iptc4xmpCore:CiAdrRegion',
  388. 'Iptc4xmpCore:CiEmailWork',
  389. 'Iptc4xmpCore:CiTelWork',
  390. 'Iptc4xmpCore:CiUrlWork',
  391. 'Iptc4xmpCore:CountryCode',
  392. 'Iptc4xmpCore:CreatorContactInfo',
  393. 'Iptc4xmpCore:IntellectualGenre',
  394. 'Iptc4xmpCore:Location',
  395. 'Iptc4xmpCore:Scene',
  396. 'Iptc4xmpCore:SubjectCode',
  397. // Dublin Core Schema
  398. 'dc:contributor',
  399. 'dc:coverage',
  400. 'dc:creator',
  401. 'dc:date',
  402. 'dc:description',
  403. 'dc:format',
  404. 'dc:identifier',
  405. 'dc:language',
  406. 'dc:publisher',
  407. 'dc:relation',
  408. 'dc:rights',
  409. 'dc:source',
  410. 'dc:subject',
  411. 'dc:title',
  412. 'dc:type',
  413. // XMP Basic Schema
  414. 'xmp:Advisory',
  415. 'xmp:BaseURL',
  416. 'xmp:CreateDate',
  417. 'xmp:CreatorTool',
  418. 'xmp:Identifier',
  419. 'xmp:Label',
  420. 'xmp:MetadataDate',
  421. 'xmp:ModifyDate',
  422. 'xmp:Nickname',
  423. 'xmp:Rating',
  424. 'xmp:Thumbnails',
  425. 'xmpidq:Scheme',
  426. // XMP Rights Management Schema
  427. 'xmpRights:Certificate',
  428. 'xmpRights:Marked',
  429. 'xmpRights:Owner',
  430. 'xmpRights:UsageTerms',
  431. 'xmpRights:WebStatement',
  432. // These are not in spec but Photoshop CS seems to use them
  433. 'xap:Advisory',
  434. 'xap:BaseURL',
  435. 'xap:CreateDate',
  436. 'xap:CreatorTool',
  437. 'xap:Identifier',
  438. 'xap:MetadataDate',
  439. 'xap:ModifyDate',
  440. 'xap:Nickname',
  441. 'xap:Rating',
  442. 'xap:Thumbnails',
  443. 'xapidq:Scheme',
  444. 'xapRights:Certificate',
  445. 'xapRights:Copyright',
  446. 'xapRights:Marked',
  447. 'xapRights:Owner',
  448. 'xapRights:UsageTerms',
  449. 'xapRights:WebStatement',
  450. // XMP Media Management Schema
  451. 'xapMM:DerivedFrom',
  452. 'xapMM:DocumentID',
  453. 'xapMM:History',
  454. 'xapMM:InstanceID',
  455. 'xapMM:ManagedFrom',
  456. 'xapMM:Manager',
  457. 'xapMM:ManageTo',
  458. 'xapMM:ManageUI',
  459. 'xapMM:ManagerVariant',
  460. 'xapMM:RenditionClass',
  461. 'xapMM:RenditionParams',
  462. 'xapMM:VersionID',
  463. 'xapMM:Versions',
  464. 'xapMM:LastURL',
  465. 'xapMM:RenditionOf',
  466. 'xapMM:SaveID',
  467. // XMP Basic Job Ticket Schema
  468. 'xapBJ:JobRef',
  469. // XMP Paged-Text Schema
  470. 'xmpTPg:MaxPageSize',
  471. 'xmpTPg:NPages',
  472. 'xmpTPg:Fonts',
  473. 'xmpTPg:Colorants',
  474. 'xmpTPg:PlateNames',
  475. // Adobe PDF Schema
  476. 'pdf:Keywords',
  477. 'pdf:PDFVersion',
  478. 'pdf:Producer',
  479. // Photoshop Schema
  480. 'photoshop:AuthorsPosition',
  481. 'photoshop:CaptionWriter',
  482. 'photoshop:Category',
  483. 'photoshop:City',
  484. 'photoshop:Country',
  485. 'photoshop:Credit',
  486. 'photoshop:DateCreated',
  487. 'photoshop:Headline',
  488. 'photoshop:History',
  489. // Not in XMP spec
  490. 'photoshop:Instructions',
  491. 'photoshop:Source',
  492. 'photoshop:State',
  493. 'photoshop:SupplementalCategories',
  494. 'photoshop:TransmissionReference',
  495. 'photoshop:Urgency',
  496. // EXIF Schemas
  497. 'tiff:ImageWidth',
  498. 'tiff:ImageLength',
  499. 'tiff:BitsPerSample',
  500. 'tiff:Compression',
  501. 'tiff:PhotometricInterpretation',
  502. 'tiff:Orientation',
  503. 'tiff:SamplesPerPixel',
  504. 'tiff:PlanarConfiguration',
  505. 'tiff:YCbCrSubSampling',
  506. 'tiff:YCbCrPositioning',
  507. 'tiff:XResolution',
  508. 'tiff:YResolution',
  509. 'tiff:ResolutionUnit',
  510. 'tiff:TransferFunction',
  511. 'tiff:WhitePoint',
  512. 'tiff:PrimaryChromaticities',
  513. 'tiff:YCbCrCoefficients',
  514. 'tiff:ReferenceBlackWhite',
  515. 'tiff:DateTime',
  516. 'tiff:ImageDescription',
  517. 'tiff:Make',
  518. 'tiff:Model',
  519. 'tiff:Software',
  520. 'tiff:Artist',
  521. 'tiff:Copyright',
  522. 'exif:ExifVersion',
  523. 'exif:FlashpixVersion',
  524. 'exif:ColorSpace',
  525. 'exif:ComponentsConfiguration',
  526. 'exif:CompressedBitsPerPixel',
  527. 'exif:PixelXDimension',
  528. 'exif:PixelYDimension',
  529. 'exif:MakerNote',
  530. 'exif:UserComment',
  531. 'exif:RelatedSoundFile',
  532. 'exif:DateTimeOriginal',
  533. 'exif:DateTimeDigitized',
  534. 'exif:ExposureTime',
  535. 'exif:FNumber',
  536. 'exif:ExposureProgram',
  537. 'exif:SpectralSensitivity',
  538. 'exif:ISOSpeedRatings',
  539. 'exif:OECF',
  540. 'exif:ShutterSpeedValue',
  541. 'exif:ApertureValue',
  542. 'exif:BrightnessValue',
  543. 'exif:ExposureBiasValue',
  544. 'exif:MaxApertureValue',
  545. 'exif:SubjectDistance',
  546. 'exif:MeteringMode',
  547. 'exif:LightSource',
  548. 'exif:Flash',
  549. 'exif:FocalLength',
  550. 'exif:SubjectArea',
  551. 'exif:FlashEnergy',
  552. 'exif:SpatialFrequencyResponse',
  553. 'exif:FocalPlaneXResolution',
  554. 'exif:FocalPlaneYResolution',
  555. 'exif:FocalPlaneResolutionUnit',
  556. 'exif:SubjectLocation',
  557. 'exif:SensingMethod',
  558. 'exif:FileSource',
  559. 'exif:SceneType',
  560. 'exif:CFAPattern',
  561. 'exif:CustomRendered',
  562. 'exif:ExposureMode',
  563. 'exif:WhiteBalance',
  564. 'exif:DigitalZoomRatio',
  565. 'exif:FocalLengthIn35mmFilm',
  566. 'exif:SceneCaptureType',
  567. 'exif:GainControl',
  568. 'exif:Contrast',
  569. 'exif:Saturation',
  570. 'exif:Sharpness',
  571. 'exif:DeviceSettingDescription',
  572. 'exif:SubjectDistanceRange',
  573. 'exif:ImageUniqueID',
  574. 'exif:GPSVersionID',
  575. 'exif:GPSLatitude',
  576. 'exif:GPSLongitude',
  577. 'exif:GPSAltitudeRef',
  578. 'exif:GPSAltitude',
  579. 'exif:GPSTimeStamp',
  580. 'exif:GPSSatellites',
  581. 'exif:GPSStatus',
  582. 'exif:GPSMeasureMode',
  583. 'exif:GPSDOP',
  584. 'exif:GPSSpeedRef',
  585. 'exif:GPSSpeed',
  586. 'exif:GPSTrackRef',
  587. 'exif:GPSTrack',
  588. 'exif:GPSImgDirectionRef',
  589. 'exif:GPSImgDirection',
  590. 'exif:GPSMapDatum',
  591. 'exif:GPSDestLatitude',
  592. 'exif:GPSDestLongitude',
  593. 'exif:GPSDestBearingRef',
  594. 'exif:GPSDestBearing',
  595. 'exif:GPSDestDistanceRef',
  596. 'exif:GPSDestDistance',
  597. 'exif:GPSProcessingMethod',
  598. 'exif:GPSAreaInformation',
  599. 'exif:GPSDifferential',
  600. 'stDim:w',
  601. 'stDim:h',
  602. 'stDim:unit',
  603. 'xapGImg:height',
  604. 'xapGImg:width',
  605. 'xapGImg:format',
  606. 'xapGImg:image',
  607. 'stEvt:action',
  608. 'stEvt:instanceID',
  609. 'stEvt:parameters',
  610. 'stEvt:softwareAgent',
  611. 'stEvt:when',
  612. 'stRef:instanceID',
  613. 'stRef:documentID',
  614. 'stRef:versionID',
  615. 'stRef:renditionClass',
  616. 'stRef:renditionParams',
  617. 'stRef:manager',
  618. 'stRef:managerVariant',
  619. 'stRef:manageTo',
  620. 'stRef:manageUI',
  621. 'stVer:comments',
  622. 'stVer:event',
  623. 'stVer:modifyDate',
  624. 'stVer:modifier',
  625. 'stVer:version',
  626. 'stJob:name',
  627. 'stJob:id',
  628. 'stJob:url',
  629. // Exif Flash
  630. 'exif:Fired',
  631. 'exif:Return',
  632. 'exif:Mode',
  633. 'exif:Function',
  634. 'exif:RedEyeMode',
  635. // Exif OECF/SFR
  636. 'exif:Columns',
  637. 'exif:Rows',
  638. 'exif:Names',
  639. 'exif:Values',
  640. // Exif CFAPattern
  641. 'exif:Columns',
  642. 'exif:Rows',
  643. 'exif:Values',
  644. // Exif DeviceSettings
  645. 'exif:Columns',
  646. 'exif:Rows',
  647. 'exif:Settings',
  648. );
  649. */
  650. /**
  651. * Global Variable: JPEG_Segment_Names
  652. *
  653. * The names of the JPEG segment markers, indexed by their marker number
  654. */
  655. $GLOBALS['JPEG_Segment_Names'] = array(
  656. 0x01 => 'TEM',
  657. 0x02 => 'RES',
  658. 0xC0 => 'SOF0',
  659. 0xC1 => 'SOF1',
  660. 0xC2 => 'SOF2',
  661. 0xC3 => 'SOF4',
  662. 0xC4 => 'DHT',
  663. 0xC5 => 'SOF5',
  664. 0xC6 => 'SOF6',
  665. 0xC7 => 'SOF7',
  666. 0xC8 => 'JPG',
  667. 0xC9 => 'SOF9',
  668. 0xCA => 'SOF10',
  669. 0xCB => 'SOF11',
  670. 0xCC => 'DAC',
  671. 0xCD => 'SOF13',
  672. 0xCE => 'SOF14',
  673. 0xCF => 'SOF15',
  674. 0xD0 => 'RST0',
  675. 0xD1 => 'RST1',
  676. 0xD2 => 'RST2',
  677. 0xD3 => 'RST3',
  678. 0xD4 => 'RST4',
  679. 0xD5 => 'RST5',
  680. 0xD6 => 'RST6',
  681. 0xD7 => 'RST7',
  682. 0xD8 => 'SOI',
  683. 0xD9 => 'EOI',
  684. 0xDA => 'SOS',
  685. 0xDB => 'DQT',
  686. 0xDC => 'DNL',
  687. 0xDD => 'DRI',
  688. 0xDE => 'DHP',
  689. 0xDF => 'EXP',
  690. 0xE0 => 'APP0',
  691. 0xE1 => 'APP1',
  692. 0xE2 => 'APP2',
  693. 0xE3 => 'APP3',
  694. 0xE4 => 'APP4',
  695. 0xE5 => 'APP5',
  696. 0xE6 => 'APP6',
  697. 0xE7 => 'APP7',
  698. 0xE8 => 'APP8',
  699. 0xE9 => 'APP9',
  700. 0xEA => 'APP10',
  701. 0xEB => 'APP11',
  702. 0xEC => 'APP12',
  703. 0xED => 'APP13',
  704. 0xEE => 'APP14',
  705. 0xEF => 'APP15',
  706. 0xF0 => 'JPG0',
  707. 0xF1 => 'JPG1',
  708. 0xF2 => 'JPG2',
  709. 0xF3 => 'JPG3',
  710. 0xF4 => 'JPG4',
  711. 0xF5 => 'JPG5',
  712. 0xF6 => 'JPG6',
  713. 0xF7 => 'JPG7',
  714. 0xF8 => 'JPG8',
  715. 0xF9 => 'JPG9',
  716. 0xFA => 'JPG10',
  717. 0xFB => 'JPG11',
  718. 0xFC => 'JPG12',
  719. 0xFD => 'JPG13',
  720. 0xFE => 'COM',
  721. );