Completed
Push — vendor/getid3 ( 2a5d73...44d59b )
by Pauli
03:12
created

Image_XMP::_get_jpeg_header_data()   C

Complexity

Conditions 13
Paths 10

Size

Total Lines 102

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 13
nc 10
nop 1
dl 0
loc 102
rs 5.2933
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/////////////////////////////////////////////////////////////////
4
/// getID3() by James Heinrich <[email protected]>               //
5
//  available at https://github.com/JamesHeinrich/getID3       //
6
//            or https://www.getid3.org                        //
7
//            or http://getid3.sourceforge.net                 //
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
/**************************************************************************************************
25
 * SWISScenter Source                                                              Nigel Barnes
26
 *
27
 * 	Provides functions for reading information from the 'APP1' Extensible Metadata
28
 *	Platform (XMP) segment of JPEG format files.
29
 *	This XMP segment is XML based and contains the Resource Description Framework (RDF)
30
 *	data, which itself can contain the Dublin Core Metadata Initiative (DCMI) information.
31
 *
32
 * 	This code uses segments from the JPEG Metadata Toolkit project by Evan Hunter.
33
 *************************************************************************************************/
34
class Image_XMP
35
{
36
	/**
37
	* @var string
38
	* The name of the image file that contains the XMP fields to extract and modify.
39
	* @see Image_XMP()
40
	*/
41
	public $_sFilename = null;
42
43
	/**
44
	* @var array
45
	* The XMP fields that were extracted from the image or updated by this class.
46
	* @see getAllTags()
47
	*/
48
	public $_aXMP = array();
49
50
	/**
51
	* @var boolean
52
	* True if an APP1 segment was found to contain XMP metadata.
53
	* @see isValid()
54
	*/
55
	public $_bXMPParse = false;
56
57
	/**
58
	* Returns the status of XMP parsing during instantiation
59
	*
60
	* You'll normally want to call this method before trying to get XMP fields.
61
	*
62
	* @return boolean
63
	* Returns true if an APP1 segment was found to contain XMP metadata.
64
	*/
65
	public function isValid()
66
	{
67
		return $this->_bXMPParse;
68
	}
69
70
	/**
71
	* Get a copy of all XMP tags extracted from the image
72
	*
73
	* @return array - An array of XMP fields as it extracted by the XMPparse() function
74
	*/
75
	public function getAllTags()
76
	{
77
		return $this->_aXMP;
78
	}
79
80
	/**
81
	* Reads all the JPEG header segments from an JPEG image file into an array
82
	*
83
	* @param string $filename - the filename of the JPEG file to read
84
	* @return array|false  $headerdata - Array of JPEG header segments,
85
	*                        FALSE - if headers could not be read
86
	*/
87
	public function _get_jpeg_header_data($filename)
88
	{
89
		// prevent refresh from aborting file operations and hosing file
90
		ignore_user_abort(true);
91
92
		// Attempt to open the jpeg file - the at symbol supresses the error message about
93
		// not being able to open files. The file_exists would have been used, but it
94
		// does not work with files fetched over http or ftp.
95
		if (is_readable($filename) && is_file($filename) && ($filehnd = fopen($filename, 'rb'))) {
96
			// great
97
		} else {
98
			return false;
99
		}
100
101
		// Read the first two characters
102
		$data = fread($filehnd, 2);
103
104
		// Check that the first two characters are 0xFF 0xD8  (SOI - Start of image)
105
		if ($data != "\xFF\xD8")
106
		{
107
			// No SOI (FF D8) at start of file - This probably isn't a JPEG file - close file and return;
108
			echo '<p>This probably is not a JPEG file</p>'."\n";
109
			fclose($filehnd);
110
			return false;
111
		}
112
113
		// Read the third character
114
		$data = fread($filehnd, 2);
115
116
		// Check that the third character is 0xFF (Start of first segment header)
117
		if ($data[0] != "\xFF")
118
		{
119
			// NO FF found - close file and return - JPEG is probably corrupted
120
			fclose($filehnd);
121
			return false;
122
		}
123
124
		// Flag that we havent yet hit the compressed image data
125
		$hit_compressed_image_data = false;
126
127
		$headerdata = array();
128
		// Cycle through the file until, one of: 1) an EOI (End of image) marker is hit,
129
		//                                       2) we have hit the compressed image data (no more headers are allowed after data)
130
		//                                       3) or end of file is hit
131
132
		while (($data[1] != "\xD9") && (!$hit_compressed_image_data) && (!feof($filehnd)))
133
		{
134
			// Found a segment to look at.
135
			// Check that the segment marker is not a Restart marker - restart markers don't have size or data after them
136
			if ((ord($data[1]) < 0xD0) || (ord($data[1]) > 0xD7))
137
			{
138
				// Segment isn't a Restart marker
139
				// Read the next two bytes (size)
140
				$sizestr = fread($filehnd, 2);
141
142
				// convert the size bytes to an integer
143
				$decodedsize = unpack('nsize', $sizestr);
144
145
				// Save the start position of the data
146
				$segdatastart = ftell($filehnd);
147
148
				// Read the segment data with length indicated by the previously read size
149
				$segdata = fread($filehnd, $decodedsize['size'] - 2);
150
151
				// Store the segment information in the output array
152
				$headerdata[] = array(
153
					'SegType'      => ord($data[1]),
154
					'SegName'      => $GLOBALS['JPEG_Segment_Names'][ord($data[1])],
155
					'SegDataStart' => $segdatastart,
156
					'SegData'      => $segdata,
157
				);
158
			}
159
160
			// If this is a SOS (Start Of Scan) segment, then there is no more header data - the compressed image data follows
161
			if ($data[1] == "\xDA")
162
			{
163
				// Flag that we have hit the compressed image data - exit loop as no more headers available.
164
				$hit_compressed_image_data = true;
165
			}
166
			else
167
			{
168
				// Not an SOS - Read the next two bytes - should be the segment marker for the next segment
169
				$data = fread($filehnd, 2);
170
171
				// Check that the first byte of the two is 0xFF as it should be for a marker
172
				if ($data[0] != "\xFF")
173
				{
174
					// NO FF found - close file and return - JPEG is probably corrupted
175
					fclose($filehnd);
176
					return false;
177
				}
178
			}
179
		}
180
181
		// Close File
182
		fclose($filehnd);
183
		// Alow the user to abort from now on
184
		ignore_user_abort(false);
185
186
		// Return the header data retrieved
187
		return $headerdata;
188
	}
189
190
191
	/**
192
	* Retrieves XMP information from an APP1 JPEG segment and returns the raw XML text as a string.
193
	*
194
	* @param string $filename - the filename of the JPEG file to read
195
	* @return string|false $xmp_data - the string of raw XML text,
196
	*                        FALSE - if an APP 1 XMP segment could not be found, or if an error occurred
197
	*/
198
	public function _get_XMP_text($filename)
199
	{
200
		//Get JPEG header data
201
		$jpeg_header_data = $this->_get_jpeg_header_data($filename);
202
203
		//Cycle through the header segments
204
		if (is_array($jpeg_header_data) && count($jpeg_header_data) > 0) {
205
			foreach ($jpeg_header_data as $segment) {
206
				// If we find an APP1 header,
207
				if (strcmp($segment['SegName'], 'APP1') === 0) {
208
					// And if it has the Adobe XMP/RDF label (http://ns.adobe.com/xap/1.0/\x00) ,
209
					if (strncmp($segment['SegData'], 'http://ns.adobe.com/xap/1.0/' . "\x00", 29) === 0) {
210
						// Found a XMP/RDF block
211
						// Return the XMP text
212
						$xmp_data = substr($segment['SegData'], 29);
213
214
						// trim() should not be necessary, but some files found in the wild with null-terminated block
215
						// (known samples from Apple Aperture) causes problems elsewhere
216
						// (see https://www.getid3.org/phpBB3/viewtopic.php?f=4&t=1153)
217
						return trim($xmp_data);
218
					}
219
				}
220
			}
221
		}
222
223
		return false;
224
	}
225
226
	/**
227
	* Parses a string containing XMP data (XML), and returns an array
228
	* which contains all the XMP (XML) information.
229
	*
230
	* @param string $xmltext - a string containing the XMP data (XML) to be parsed
231
	* @return array|false $xmp_array - an array containing all xmp details retrieved,
232
	*                       FALSE - couldn't parse the XMP data.
233
	*/
234
	public function read_XMP_array_from_text($xmltext)
235
	{
236
		// Check if there actually is any text to parse
237
		if (trim($xmltext) == '')
238
		{
239
			return false;
240
		}
241
242
		// Create an instance of a xml parser to parse the XML text
243
		$xml_parser = xml_parser_create('UTF-8');
244
245
		// 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
246
247
		// We would like to remove unneccessary white space, but this will also
248
		// remove things like newlines (&#xA;) in the XML values, so white space
249
		// will have to be removed later
250
		if (xml_parser_set_option($xml_parser, XML_OPTION_SKIP_WHITE, 0) == false)
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
251
		{
252
			// Error setting case folding - destroy the parser and return
253
			xml_parser_free($xml_parser);
254
			return false;
255
		}
256
257
		// to use XML code correctly we have to turn case folding
258
		// (uppercasing) off. XML is case sensitive and upper
259
		// casing is in reality XML standards violation
260
		if (xml_parser_set_option($xml_parser, XML_OPTION_CASE_FOLDING, 0) == false)
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
261
		{
262
			// Error setting case folding - destroy the parser and return
263
			xml_parser_free($xml_parser);
264
			return false;
265
		}
266
267
		// Parse the XML text into a array structure
268
		if (xml_parse_into_struct($xml_parser, $xmltext, $values, $tags) == 0)
269
		{
270
			// Error Parsing XML - destroy the parser and return
271
			xml_parser_free($xml_parser);
272
			return false;
273
		}
274
275
		// Destroy the xml parser
276
		xml_parser_free($xml_parser);
277
278
		// Clear the output array
279
		$xmp_array = array();
280
281
		// The XMP data has now been parsed into an array ...
282
283
		// Cycle through each of the array elements
284
		$current_property = ''; // current property being processed
285
		$container_index = -1; // -1 = no container open, otherwise index of container content
286
		foreach ($values as $xml_elem)
287
		{
288
			// Syntax and Class names
289
			switch ($xml_elem['tag'])
290
			{
291
				case 'x:xmpmeta':
292
					// only defined attribute is x:xmptk written by Adobe XMP Toolkit; value is the version of the toolkit
293
					break;
294
295
				case 'rdf:RDF':
296
					// required element immediately within x:xmpmeta; no data here
297
					break;
298
299
				case 'rdf:Description':
300
					switch ($xml_elem['type'])
301
					{
302
						case 'open':
303
						case 'complete':
304
							if (array_key_exists('attributes', $xml_elem))
305
							{
306
								// rdf:Description may contain wanted attributes
307
								foreach (array_keys($xml_elem['attributes']) as $key)
308
								{
309
									// Check whether we want this details from this attribute
310
//									if (in_array($key, $GLOBALS['XMP_tag_captions']))
311
//									if (true)
312
//									{
313
										// Attribute wanted
314
										$xmp_array[$key] = $xml_elem['attributes'][$key];
315
//									}
316
								}
317
							}
318
							break;
319
						case 'cdata':
320
						case 'close':
321
							break;
322
					}
323
					break;
324
325
				case 'rdf:ID':
326
				case 'rdf:nodeID':
327
					// Attributes are ignored
328
					break;
329
330
				case 'rdf:li':
331
					// Property member
332
					if ($xml_elem['type'] == 'complete')
333
					{
334
						if (array_key_exists('attributes', $xml_elem))
335
						{
336
							// If Lang Alt (language alternatives) then ensure we take the default language
337
							if (isset($xml_elem['attributes']['xml:lang']) && ($xml_elem['attributes']['xml:lang'] != 'x-default'))
338
							{
339
								break;
340
							}
341
						}
342
						if ($current_property != '')
343
						{
344
							$xmp_array[$current_property][$container_index] = (isset($xml_elem['value']) ? $xml_elem['value'] : '');
345
							$container_index += 1;
346
						}
347
					//else unidentified attribute!!
348
					}
349
					break;
350
351
				case 'rdf:Seq':
352
				case 'rdf:Bag':
353
				case 'rdf:Alt':
354
					// Container found
355
					switch ($xml_elem['type'])
356
					{
357
						case 'open':
358
 							$container_index = 0;
359
 							break;
360
						case 'close':
361
							$container_index = -1;
362
							break;
363
						case 'cdata':
364
							break;
365
					}
366
					break;
367
368
				default:
369
					// Check whether we want the details from this attribute
370
//					if (in_array($xml_elem['tag'], $GLOBALS['XMP_tag_captions']))
371
//					if (true)
372
//					{
373
						switch ($xml_elem['type'])
374
						{
375
							case 'open':
376
								// open current element
377
								$current_property = $xml_elem['tag'];
378
								break;
379
380
							case 'close':
381
								// close current element
382
								$current_property = '';
383
								break;
384
385
							case 'complete':
386
								// store attribute value
387
								$xmp_array[$xml_elem['tag']] = (isset($xml_elem['attributes']) ? $xml_elem['attributes'] : (isset($xml_elem['value']) ? $xml_elem['value'] : ''));
388
								break;
389
390
							case 'cdata':
391
								// ignore
392
								break;
393
						}
394
//					}
395
					break;
396
			}
397
398
		}
399
		return $xmp_array;
400
	}
401
402
403
	/**
404
	* Constructor
405
	*
406
	* @param string $sFilename - Name of the image file to access and extract XMP information from.
407
	*/
408
	public function __construct($sFilename)
409
	{
410
		$this->_sFilename = $sFilename;
411
412
		if (is_file($this->_sFilename))
413
		{
414
			// Get XMP data
415
			$xmp_data = $this->_get_XMP_text($sFilename);
416
			if ($xmp_data)
0 ignored issues
show
Bug Best Practice introduced by
The expression $xmp_data of type string|false is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
417
			{
418
				$aXMP = $this->read_XMP_array_from_text($xmp_data);
419
				if ($aXMP !== false) {
420
					$this->_aXMP = (array) $aXMP;
421
					$this->_bXMPParse = true;
422
				}
423
			}
424
		}
425
	}
426
427
}
428
429
/**
430
* Global Variable: XMP_tag_captions
431
*
432
* The Property names of all known XMP fields.
433
* Note: this is a full list with unrequired properties commented out.
434
*/
435
/*
436
$GLOBALS['XMP_tag_captions'] = array(
437
// IPTC Core
438
	'Iptc4xmpCore:CiAdrCity',
439
	'Iptc4xmpCore:CiAdrCtry',
440
	'Iptc4xmpCore:CiAdrExtadr',
441
	'Iptc4xmpCore:CiAdrPcode',
442
	'Iptc4xmpCore:CiAdrRegion',
443
	'Iptc4xmpCore:CiEmailWork',
444
	'Iptc4xmpCore:CiTelWork',
445
	'Iptc4xmpCore:CiUrlWork',
446
	'Iptc4xmpCore:CountryCode',
447
	'Iptc4xmpCore:CreatorContactInfo',
448
	'Iptc4xmpCore:IntellectualGenre',
449
	'Iptc4xmpCore:Location',
450
	'Iptc4xmpCore:Scene',
451
	'Iptc4xmpCore:SubjectCode',
452
// Dublin Core Schema
453
	'dc:contributor',
454
	'dc:coverage',
455
	'dc:creator',
456
	'dc:date',
457
	'dc:description',
458
	'dc:format',
459
	'dc:identifier',
460
	'dc:language',
461
	'dc:publisher',
462
	'dc:relation',
463
	'dc:rights',
464
	'dc:source',
465
	'dc:subject',
466
	'dc:title',
467
	'dc:type',
468
// XMP Basic Schema
469
	'xmp:Advisory',
470
	'xmp:BaseURL',
471
	'xmp:CreateDate',
472
	'xmp:CreatorTool',
473
	'xmp:Identifier',
474
	'xmp:Label',
475
	'xmp:MetadataDate',
476
	'xmp:ModifyDate',
477
	'xmp:Nickname',
478
	'xmp:Rating',
479
	'xmp:Thumbnails',
480
	'xmpidq:Scheme',
481
// XMP Rights Management Schema
482
	'xmpRights:Certificate',
483
	'xmpRights:Marked',
484
	'xmpRights:Owner',
485
	'xmpRights:UsageTerms',
486
	'xmpRights:WebStatement',
487
// These are not in spec but Photoshop CS seems to use them
488
	'xap:Advisory',
489
	'xap:BaseURL',
490
	'xap:CreateDate',
491
	'xap:CreatorTool',
492
	'xap:Identifier',
493
	'xap:MetadataDate',
494
	'xap:ModifyDate',
495
	'xap:Nickname',
496
	'xap:Rating',
497
	'xap:Thumbnails',
498
	'xapidq:Scheme',
499
	'xapRights:Certificate',
500
	'xapRights:Copyright',
501
	'xapRights:Marked',
502
	'xapRights:Owner',
503
	'xapRights:UsageTerms',
504
	'xapRights:WebStatement',
505
// XMP Media Management Schema
506
	'xapMM:DerivedFrom',
507
	'xapMM:DocumentID',
508
	'xapMM:History',
509
	'xapMM:InstanceID',
510
	'xapMM:ManagedFrom',
511
	'xapMM:Manager',
512
	'xapMM:ManageTo',
513
	'xapMM:ManageUI',
514
	'xapMM:ManagerVariant',
515
	'xapMM:RenditionClass',
516
	'xapMM:RenditionParams',
517
	'xapMM:VersionID',
518
	'xapMM:Versions',
519
	'xapMM:LastURL',
520
	'xapMM:RenditionOf',
521
	'xapMM:SaveID',
522
// XMP Basic Job Ticket Schema
523
	'xapBJ:JobRef',
524
// XMP Paged-Text Schema
525
	'xmpTPg:MaxPageSize',
526
	'xmpTPg:NPages',
527
	'xmpTPg:Fonts',
528
	'xmpTPg:Colorants',
529
	'xmpTPg:PlateNames',
530
// Adobe PDF Schema
531
	'pdf:Keywords',
532
	'pdf:PDFVersion',
533
	'pdf:Producer',
534
// Photoshop Schema
535
	'photoshop:AuthorsPosition',
536
	'photoshop:CaptionWriter',
537
	'photoshop:Category',
538
	'photoshop:City',
539
	'photoshop:Country',
540
	'photoshop:Credit',
541
	'photoshop:DateCreated',
542
	'photoshop:Headline',
543
	'photoshop:History',
544
// Not in XMP spec
545
	'photoshop:Instructions',
546
	'photoshop:Source',
547
	'photoshop:State',
548
	'photoshop:SupplementalCategories',
549
	'photoshop:TransmissionReference',
550
	'photoshop:Urgency',
551
// EXIF Schemas
552
	'tiff:ImageWidth',
553
	'tiff:ImageLength',
554
	'tiff:BitsPerSample',
555
	'tiff:Compression',
556
	'tiff:PhotometricInterpretation',
557
	'tiff:Orientation',
558
	'tiff:SamplesPerPixel',
559
	'tiff:PlanarConfiguration',
560
	'tiff:YCbCrSubSampling',
561
	'tiff:YCbCrPositioning',
562
	'tiff:XResolution',
563
	'tiff:YResolution',
564
	'tiff:ResolutionUnit',
565
	'tiff:TransferFunction',
566
	'tiff:WhitePoint',
567
	'tiff:PrimaryChromaticities',
568
	'tiff:YCbCrCoefficients',
569
	'tiff:ReferenceBlackWhite',
570
	'tiff:DateTime',
571
	'tiff:ImageDescription',
572
	'tiff:Make',
573
	'tiff:Model',
574
	'tiff:Software',
575
	'tiff:Artist',
576
	'tiff:Copyright',
577
	'exif:ExifVersion',
578
	'exif:FlashpixVersion',
579
	'exif:ColorSpace',
580
	'exif:ComponentsConfiguration',
581
	'exif:CompressedBitsPerPixel',
582
	'exif:PixelXDimension',
583
	'exif:PixelYDimension',
584
	'exif:MakerNote',
585
	'exif:UserComment',
586
	'exif:RelatedSoundFile',
587
	'exif:DateTimeOriginal',
588
	'exif:DateTimeDigitized',
589
	'exif:ExposureTime',
590
	'exif:FNumber',
591
	'exif:ExposureProgram',
592
	'exif:SpectralSensitivity',
593
	'exif:ISOSpeedRatings',
594
	'exif:OECF',
595
	'exif:ShutterSpeedValue',
596
	'exif:ApertureValue',
597
	'exif:BrightnessValue',
598
	'exif:ExposureBiasValue',
599
	'exif:MaxApertureValue',
600
	'exif:SubjectDistance',
601
	'exif:MeteringMode',
602
	'exif:LightSource',
603
	'exif:Flash',
604
	'exif:FocalLength',
605
	'exif:SubjectArea',
606
	'exif:FlashEnergy',
607
	'exif:SpatialFrequencyResponse',
608
	'exif:FocalPlaneXResolution',
609
	'exif:FocalPlaneYResolution',
610
	'exif:FocalPlaneResolutionUnit',
611
	'exif:SubjectLocation',
612
	'exif:SensingMethod',
613
	'exif:FileSource',
614
	'exif:SceneType',
615
	'exif:CFAPattern',
616
	'exif:CustomRendered',
617
	'exif:ExposureMode',
618
	'exif:WhiteBalance',
619
	'exif:DigitalZoomRatio',
620
	'exif:FocalLengthIn35mmFilm',
621
	'exif:SceneCaptureType',
622
	'exif:GainControl',
623
	'exif:Contrast',
624
	'exif:Saturation',
625
	'exif:Sharpness',
626
	'exif:DeviceSettingDescription',
627
	'exif:SubjectDistanceRange',
628
	'exif:ImageUniqueID',
629
	'exif:GPSVersionID',
630
	'exif:GPSLatitude',
631
	'exif:GPSLongitude',
632
	'exif:GPSAltitudeRef',
633
	'exif:GPSAltitude',
634
	'exif:GPSTimeStamp',
635
	'exif:GPSSatellites',
636
	'exif:GPSStatus',
637
	'exif:GPSMeasureMode',
638
	'exif:GPSDOP',
639
	'exif:GPSSpeedRef',
640
	'exif:GPSSpeed',
641
	'exif:GPSTrackRef',
642
	'exif:GPSTrack',
643
	'exif:GPSImgDirectionRef',
644
	'exif:GPSImgDirection',
645
	'exif:GPSMapDatum',
646
	'exif:GPSDestLatitude',
647
	'exif:GPSDestLongitude',
648
	'exif:GPSDestBearingRef',
649
	'exif:GPSDestBearing',
650
	'exif:GPSDestDistanceRef',
651
	'exif:GPSDestDistance',
652
	'exif:GPSProcessingMethod',
653
	'exif:GPSAreaInformation',
654
	'exif:GPSDifferential',
655
	'stDim:w',
656
	'stDim:h',
657
	'stDim:unit',
658
	'xapGImg:height',
659
	'xapGImg:width',
660
	'xapGImg:format',
661
	'xapGImg:image',
662
	'stEvt:action',
663
	'stEvt:instanceID',
664
	'stEvt:parameters',
665
	'stEvt:softwareAgent',
666
	'stEvt:when',
667
	'stRef:instanceID',
668
	'stRef:documentID',
669
	'stRef:versionID',
670
	'stRef:renditionClass',
671
	'stRef:renditionParams',
672
	'stRef:manager',
673
	'stRef:managerVariant',
674
	'stRef:manageTo',
675
	'stRef:manageUI',
676
	'stVer:comments',
677
	'stVer:event',
678
	'stVer:modifyDate',
679
	'stVer:modifier',
680
	'stVer:version',
681
	'stJob:name',
682
	'stJob:id',
683
	'stJob:url',
684
// Exif Flash
685
	'exif:Fired',
686
	'exif:Return',
687
	'exif:Mode',
688
	'exif:Function',
689
	'exif:RedEyeMode',
690
// Exif OECF/SFR
691
	'exif:Columns',
692
	'exif:Rows',
693
	'exif:Names',
694
	'exif:Values',
695
// Exif CFAPattern
696
	'exif:Columns',
697
	'exif:Rows',
698
	'exif:Values',
699
// Exif DeviceSettings
700
	'exif:Columns',
701
	'exif:Rows',
702
	'exif:Settings',
703
);
704
*/
705
706
/**
707
* Global Variable: JPEG_Segment_Names
708
*
709
* The names of the JPEG segment markers, indexed by their marker number
710
*/
711
$GLOBALS['JPEG_Segment_Names'] = array(
712
	0x01 => 'TEM',
713
	0x02 => 'RES',
714
	0xC0 => 'SOF0',
715
	0xC1 => 'SOF1',
716
	0xC2 => 'SOF2',
717
	0xC3 => 'SOF4',
718
	0xC4 => 'DHT',
719
	0xC5 => 'SOF5',
720
	0xC6 => 'SOF6',
721
	0xC7 => 'SOF7',
722
	0xC8 => 'JPG',
723
	0xC9 => 'SOF9',
724
	0xCA => 'SOF10',
725
	0xCB => 'SOF11',
726
	0xCC => 'DAC',
727
	0xCD => 'SOF13',
728
	0xCE => 'SOF14',
729
	0xCF => 'SOF15',
730
	0xD0 => 'RST0',
731
	0xD1 => 'RST1',
732
	0xD2 => 'RST2',
733
	0xD3 => 'RST3',
734
	0xD4 => 'RST4',
735
	0xD5 => 'RST5',
736
	0xD6 => 'RST6',
737
	0xD7 => 'RST7',
738
	0xD8 => 'SOI',
739
	0xD9 => 'EOI',
740
	0xDA => 'SOS',
741
	0xDB => 'DQT',
742
	0xDC => 'DNL',
743
	0xDD => 'DRI',
744
	0xDE => 'DHP',
745
	0xDF => 'EXP',
746
	0xE0 => 'APP0',
747
	0xE1 => 'APP1',
748
	0xE2 => 'APP2',
749
	0xE3 => 'APP3',
750
	0xE4 => 'APP4',
751
	0xE5 => 'APP5',
752
	0xE6 => 'APP6',
753
	0xE7 => 'APP7',
754
	0xE8 => 'APP8',
755
	0xE9 => 'APP9',
756
	0xEA => 'APP10',
757
	0xEB => 'APP11',
758
	0xEC => 'APP12',
759
	0xED => 'APP13',
760
	0xEE => 'APP14',
761
	0xEF => 'APP15',
762
	0xF0 => 'JPG0',
763
	0xF1 => 'JPG1',
764
	0xF2 => 'JPG2',
765
	0xF3 => 'JPG3',
766
	0xF4 => 'JPG4',
767
	0xF5 => 'JPG5',
768
	0xF6 => 'JPG6',
769
	0xF7 => 'JPG7',
770
	0xF8 => 'JPG8',
771
	0xF9 => 'JPG9',
772
	0xFA => 'JPG10',
773
	0xFB => 'JPG11',
774
	0xFC => 'JPG12',
775
	0xFD => 'JPG13',
776
	0xFE => 'COM',
777
);
778