PageRenderTime 72ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 0ms

/getid3/module.tag.xmp.php

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