1<?php
2/**
3 * Definitions for Reader class.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 * http://www.gnu.org/copyleft/gpl.html
19 *
20 * @file
21 * @ingroup Media
22 */
23
24namespace Wikimedia\XMPReader;
25
26/**
27 * This class is just a container for a big array
28 * used by Reader to determine which XMP items to
29 * extract.
30 */
31class Info {
32	/** Get the items array
33	 * @return array XMP item configuration array.
34	 */
35	public static function getItems() {
36		return self::$items;
37	}
38
39	/**
40	 * XMPInfo::$items keeps a list of all the items
41	 * we are interested to extract, as well as
42	 * information about the item like what type
43	 * it is.
44	 *
45	 * Format is an array of namespaces,
46	 * each containing an array of tags
47	 * each tag is an array of information about the
48	 * tag, including:
49	 *   * map_group - What group (used for precedence during conflicts in
50	 *     accordance with http://www.metadataworkinggroup.org/pdf/mwg_guidance.pdf )
51	 *   * mode - What type of item (self::MODE_SIMPLE usually, see above for
52	 *     all values).
53	 *   * validate - Method to validate input. Could also post-process the
54	 *     input. A string value is assumed to be a method of
55	 *     XMPValidate. Can also take a array( 'className', 'methodName' ).
56	 *   * choices - Array of potential values (format of 'value' => true ).
57	 *     Only used with validateClosed.
58	 *   * rangeLow and rangeHigh - Alternative to choices for numeric ranges.
59	 *     Again for validateClosed only.
60	 *   * children - For MODE_STRUCT items, allowed children.
61	 *   * structPart - Indicates that this element can only appear as a member
62	 *     of a structure.
63	 *
64	 * Currently this just has a bunch of EXIF values as this class is only half-done.
65	 */
66	private static $items = [
67		'http://ns.adobe.com/exif/1.0/' => [
68			'ApertureValue' => [
69				'map_group' => 'exif',
70				'mode' => Reader::MODE_SIMPLE,
71				'validate' => 'validateRational'
72			],
73			'BrightnessValue' => [
74				'map_group' => 'exif',
75				'mode' => Reader::MODE_SIMPLE,
76				'validate' => 'validateRational'
77			],
78			'CompressedBitsPerPixel' => [
79				'map_group' => 'exif',
80				'mode' => Reader::MODE_SIMPLE,
81				'validate' => 'validateRational'
82			],
83			'DigitalZoomRatio' => [
84				'map_group' => 'exif',
85				'mode' => Reader::MODE_SIMPLE,
86				'validate' => 'validateRational'
87			],
88			'ExposureBiasValue' => [
89				'map_group' => 'exif',
90				'mode' => Reader::MODE_SIMPLE,
91				'validate' => 'validateRational'
92			],
93			'ExposureIndex' => [
94				'map_group' => 'exif',
95				'mode' => Reader::MODE_SIMPLE,
96				'validate' => 'validateRational'
97			],
98			'ExposureTime' => [
99				'map_group' => 'exif',
100				'mode' => Reader::MODE_SIMPLE,
101				'validate' => 'validateRational'
102			],
103			'FlashEnergy' => [
104				'map_group' => 'exif',
105				'mode' => Reader::MODE_SIMPLE,
106				'validate' => 'validateRational',
107			],
108			'FNumber' => [
109				'map_group' => 'exif',
110				'mode' => Reader::MODE_SIMPLE,
111				'validate' => 'validateRational'
112			],
113			'FocalLength' => [
114				'map_group' => 'exif',
115				'mode' => Reader::MODE_SIMPLE,
116				'validate' => 'validateRational'
117			],
118			'FocalPlaneXResolution' => [
119				'map_group' => 'exif',
120				'mode' => Reader::MODE_SIMPLE,
121				'validate' => 'validateRational'
122			],
123			'FocalPlaneYResolution' => [
124				'map_group' => 'exif',
125				'mode' => Reader::MODE_SIMPLE,
126				'validate' => 'validateRational'
127			],
128			'GPSAltitude' => [
129				'map_group' => 'exif',
130				'mode' => Reader::MODE_SIMPLE,
131				'validate' => 'validateRational',
132			],
133			'GPSDestBearing' => [
134				'map_group' => 'exif',
135				'mode' => Reader::MODE_SIMPLE,
136				'validate' => 'validateRational'
137			],
138			'GPSDestDistance' => [
139				'map_group' => 'exif',
140				'mode' => Reader::MODE_SIMPLE,
141				'validate' => 'validateRational'
142			],
143			'GPSDOP' => [
144				'map_group' => 'exif',
145				'mode' => Reader::MODE_SIMPLE,
146				'validate' => 'validateRational'
147			],
148			'GPSImgDirection' => [
149				'map_group' => 'exif',
150				'mode' => Reader::MODE_SIMPLE,
151				'validate' => 'validateRational'
152			],
153			'GPSSpeed' => [
154				'map_group' => 'exif',
155				'mode' => Reader::MODE_SIMPLE,
156				'validate' => 'validateRational'
157			],
158			'GPSTrack' => [
159				'map_group' => 'exif',
160				'mode' => Reader::MODE_SIMPLE,
161				'validate' => 'validateRational'
162			],
163			'MaxApertureValue' => [
164				'map_group' => 'exif',
165				'mode' => Reader::MODE_SIMPLE,
166				'validate' => 'validateRational'
167			],
168			'ShutterSpeedValue' => [
169				'map_group' => 'exif',
170				'mode' => Reader::MODE_SIMPLE,
171				'validate' => 'validateRational'
172			],
173			'SubjectDistance' => [
174				'map_group' => 'exif',
175				'mode' => Reader::MODE_SIMPLE,
176				'validate' => 'validateRational'
177			],
178			/* Flash */
179			'Flash' => [
180				'mode' => Reader::MODE_STRUCT,
181				'children' => [
182					'Fired' => true,
183					'Function' => true,
184					'Mode' => true,
185					'RedEyeMode' => true,
186					'Return' => true,
187				],
188				'validate' => 'validateFlash',
189				'map_group' => 'exif',
190			],
191			'Fired' => [
192				'map_group' => 'exif',
193				'validate' => 'validateBoolean',
194				'mode' => Reader::MODE_SIMPLE,
195				'structPart' => true,
196			],
197			'Function' => [
198				'map_group' => 'exif',
199				'validate' => 'validateBoolean',
200				'mode' => Reader::MODE_SIMPLE,
201				'structPart' => true,
202			],
203			'Mode' => [
204				'map_group' => 'exif',
205				'validate' => 'validateClosed',
206				'mode' => Reader::MODE_SIMPLE,
207				'choices' => [ '0' => true, '1' => true,
208					'2' => true, '3' => true ],
209				'structPart' => true,
210			],
211			'Return' => [
212				'map_group' => 'exif',
213				'validate' => 'validateClosed',
214				'mode' => Reader::MODE_SIMPLE,
215				'choices' => [ '0' => true,
216					'2' => true, '3' => true ],
217				'structPart' => true,
218			],
219			'RedEyeMode' => [
220				'map_group' => 'exif',
221				'validate' => 'validateBoolean',
222				'mode' => Reader::MODE_SIMPLE,
223				'structPart' => true,
224			],
225			/* End Flash */
226			'ISOSpeedRatings' => [
227				'map_group' => 'exif',
228				'mode' => Reader::MODE_SEQ,
229				'validate' => 'validateInteger'
230			],
231			/* end rational things */
232			'ColorSpace' => [
233				'map_group' => 'exif',
234				'mode' => Reader::MODE_SIMPLE,
235				'validate' => 'validateClosed',
236				'choices' => [ '1' => true, '65535' => true ],
237			],
238			'ComponentsConfiguration' => [
239				'map_group' => 'exif',
240				'mode' => Reader::MODE_SEQ,
241				'validate' => 'validateClosed',
242				'choices' => [ '1' => true, '2' => true, '3' => true, '4' => true,
243					'5' => true, '6' => true ]
244			],
245			'Contrast' => [
246				'map_group' => 'exif',
247				'mode' => Reader::MODE_SIMPLE,
248				'validate' => 'validateClosed',
249				'choices' => [ '0' => true, '1' => true, '2' => true ]
250			],
251			'CustomRendered' => [
252				'map_group' => 'exif',
253				'mode' => Reader::MODE_SIMPLE,
254				'validate' => 'validateClosed',
255				'choices' => [ '0' => true, '1' => true ]
256			],
257			'DateTimeOriginal' => [
258				'map_group' => 'exif',
259				'mode' => Reader::MODE_SIMPLE,
260				'validate' => 'validateDate',
261			],
262			'DateTimeDigitized' => [
263				/* xmp:CreateDate */
264				'map_group' => 'exif',
265				'mode' => Reader::MODE_SIMPLE,
266				'validate' => 'validateDate',
267			],
268			/* todo: there might be interesting information in
269			 * exif:DeviceSettingDescription, but need to find an
270			 * example
271			 */
272			'ExifVersion' => [
273				'map_group' => 'exif',
274				'mode' => Reader::MODE_SIMPLE,
275			],
276			'ExposureMode' => [
277				'map_group' => 'exif',
278				'mode' => Reader::MODE_SIMPLE,
279				'validate' => 'validateClosed',
280				'rangeLow' => 0,
281				'rangeHigh' => 2,
282			],
283			'ExposureProgram' => [
284				'map_group' => 'exif',
285				'mode' => Reader::MODE_SIMPLE,
286				'validate' => 'validateClosed',
287				'rangeLow' => 0,
288				'rangeHigh' => 8,
289			],
290			'FileSource' => [
291				'map_group' => 'exif',
292				'mode' => Reader::MODE_SIMPLE,
293				'validate' => 'validateClosed',
294				'choices' => [ '3' => true ]
295			],
296			// PHP likes to be the odd one out with casing of FlashPixVersion;
297			// https://www.exif.org/Exif2-2.PDF#page=32 and
298			// https://www.digitalgalen.net/Documents/External/XMP/XMPSpecificationPart2.pdf#page=51
299			// both use FlashpixVersion. However, since at least 2002, PHP has used FlashPixVersion at
300			// https://github.com/php/php-src/blame/master/ext/exif/exif.c#L725
301			'FlashpixVersion' => [
302				'map_group' => 'exif',
303				'mode' => Reader::MODE_SIMPLE,
304			],
305			'FocalLengthIn35mmFilm' => [
306				'map_group' => 'exif',
307				'mode' => Reader::MODE_SIMPLE,
308				'validate' => 'validateInteger',
309			],
310			'FocalPlaneResolutionUnit' => [
311				'map_group' => 'exif',
312				'mode' => Reader::MODE_SIMPLE,
313				'validate' => 'validateClosed',
314				'choices' => [ '2' => true, '3' => true ],
315			],
316			'GainControl' => [
317				'map_group' => 'exif',
318				'mode' => Reader::MODE_SIMPLE,
319				'validate' => 'validateClosed',
320				'rangeLow' => 0,
321				'rangeHigh' => 4,
322			],
323			/* this value is post-processed out later */
324			'GPSAltitudeRef' => [
325				'map_group' => 'exif',
326				'mode' => Reader::MODE_SIMPLE,
327				'validate' => 'validateClosed',
328				'choices' => [ '0' => true, '1' => true ],
329			],
330			'GPSAreaInformation' => [
331				'map_group' => 'exif',
332				'mode' => Reader::MODE_SIMPLE,
333			],
334			'GPSDestBearingRef' => [
335				'map_group' => 'exif',
336				'mode' => Reader::MODE_SIMPLE,
337				'validate' => 'validateClosed',
338				'choices' => [ 'T' => true, 'M' => true ],
339			],
340			'GPSDestDistanceRef' => [
341				'map_group' => 'exif',
342				'mode' => Reader::MODE_SIMPLE,
343				'validate' => 'validateClosed',
344				'choices' => [ 'K' => true, 'M' => true,
345					'N' => true ],
346			],
347			'GPSDestLatitude' => [
348				'map_group' => 'exif',
349				'mode' => Reader::MODE_SIMPLE,
350				'validate' => 'validateGPS',
351			],
352			'GPSDestLongitude' => [
353				'map_group' => 'exif',
354				'mode' => Reader::MODE_SIMPLE,
355				'validate' => 'validateGPS',
356			],
357			'GPSDifferential' => [
358				'map_group' => 'exif',
359				'mode' => Reader::MODE_SIMPLE,
360				'validate' => 'validateClosed',
361				'choices' => [ '0' => true, '1' => true ],
362			],
363			'GPSImgDirectionRef' => [
364				'map_group' => 'exif',
365				'mode' => Reader::MODE_SIMPLE,
366				'validate' => 'validateClosed',
367				'choices' => [ 'T' => true, 'M' => true ],
368			],
369			'GPSLatitude' => [
370				'map_group' => 'exif',
371				'mode' => Reader::MODE_SIMPLE,
372				'validate' => 'validateGPS',
373			],
374			'GPSLongitude' => [
375				'map_group' => 'exif',
376				'mode' => Reader::MODE_SIMPLE,
377				'validate' => 'validateGPS',
378			],
379			'GPSMapDatum' => [
380				'map_group' => 'exif',
381				'mode' => Reader::MODE_SIMPLE,
382			],
383			'GPSMeasureMode' => [
384				'map_group' => 'exif',
385				'mode' => Reader::MODE_SIMPLE,
386				'validate' => 'validateClosed',
387				'choices' => [ '2' => true, '3' => true ]
388			],
389			'GPSProcessingMethod' => [
390				'map_group' => 'exif',
391				'mode' => Reader::MODE_SIMPLE,
392			],
393			'GPSSatellites' => [
394				'map_group' => 'exif',
395				'mode' => Reader::MODE_SIMPLE,
396			],
397			'GPSSpeedRef' => [
398				'map_group' => 'exif',
399				'mode' => Reader::MODE_SIMPLE,
400				'validate' => 'validateClosed',
401				'choices' => [ 'K' => true, 'M' => true,
402					'N' => true ],
403			],
404			'GPSStatus' => [
405				'map_group' => 'exif',
406				'mode' => Reader::MODE_SIMPLE,
407				'validate' => 'validateClosed',
408				'choices' => [ 'A' => true, 'V' => true ]
409			],
410			'GPSTimeStamp' => [
411				'map_group' => 'exif',
412				// Note: in exif, GPSDateStamp does not include
413				// the time, where here it does.
414				'map_name' => 'GPSDateStamp',
415				'mode' => Reader::MODE_SIMPLE,
416				'validate' => 'validateDate',
417			],
418			'GPSTrackRef' => [
419				'map_group' => 'exif',
420				'mode' => Reader::MODE_SIMPLE,
421				'validate' => 'validateClosed',
422				'choices' => [ 'T' => true, 'M' => true ]
423			],
424			'GPSVersionID' => [
425				'map_group' => 'exif',
426				'mode' => Reader::MODE_SIMPLE,
427			],
428			'ImageUniqueID' => [
429				'map_group' => 'exif',
430				'mode' => Reader::MODE_SIMPLE,
431			],
432			'LightSource' => [
433				'map_group' => 'exif',
434				'mode' => Reader::MODE_SIMPLE,
435				'validate' => 'validateClosed',
436				/* can't use a range, as it skips... */
437				'choices' => [ '0' => true, '1' => true,
438					'2' => true, '3' => true, '4' => true,
439					'9' => true, '10' => true, '11' => true,
440					'12' => true, '13' => true,
441					'14' => true, '15' => true,
442					'17' => true, '18' => true,
443					'19' => true, '20' => true,
444					'21' => true, '22' => true,
445					'23' => true, '24' => true,
446					'255' => true,
447				],
448			],
449			'MeteringMode' => [
450				'map_group' => 'exif',
451				'mode' => Reader::MODE_SIMPLE,
452				'validate' => 'validateClosed',
453				'rangeLow' => 0,
454				'rangeHigh' => 6,
455				'choices' => [ '255' => true ],
456			],
457			/* Pixel(X|Y)Dimension are rather useless, but for
458			 * completeness since we do it with exif.
459			 */
460			'PixelXDimension' => [
461				'map_group' => 'exif',
462				'mode' => Reader::MODE_SIMPLE,
463				'validate' => 'validateInteger',
464			],
465			'PixelYDimension' => [
466				'map_group' => 'exif',
467				'mode' => Reader::MODE_SIMPLE,
468				'validate' => 'validateInteger',
469			],
470			'Saturation' => [
471				'map_group' => 'exif',
472				'mode' => Reader::MODE_SIMPLE,
473				'validate' => 'validateClosed',
474				'rangeLow' => 0,
475				'rangeHigh' => 2,
476			],
477			'SceneCaptureType' => [
478				'map_group' => 'exif',
479				'mode' => Reader::MODE_SIMPLE,
480				'validate' => 'validateClosed',
481				'rangeLow' => 0,
482				'rangeHigh' => 3,
483			],
484			'SceneType' => [
485				'map_group' => 'exif',
486				'mode' => Reader::MODE_SIMPLE,
487				'validate' => 'validateClosed',
488				'choices' => [ '1' => true ],
489			],
490			// Note, 6 is not valid SensingMethod.
491			'SensingMethod' => [
492				'map_group' => 'exif',
493				'mode' => Reader::MODE_SIMPLE,
494				'validate' => 'validateClosed',
495				'rangeLow' => 1,
496				'rangeHigh' => 5,
497				'choices' => [ '7' => true, 8 => true ],
498			],
499			'Sharpness' => [
500				'map_group' => 'exif',
501				'mode' => Reader::MODE_SIMPLE,
502				'validate' => 'validateClosed',
503				'rangeLow' => 0,
504				'rangeHigh' => 2,
505			],
506			'SpectralSensitivity' => [
507				'map_group' => 'exif',
508				'mode' => Reader::MODE_SIMPLE,
509			],
510			// This tag should perhaps be displayed to user better.
511			'SubjectArea' => [
512				'map_group' => 'exif',
513				'mode' => Reader::MODE_SEQ,
514				'validate' => 'validateInteger',
515			],
516			'SubjectDistanceRange' => [
517				'map_group' => 'exif',
518				'mode' => Reader::MODE_SIMPLE,
519				'validate' => 'validateClosed',
520				'rangeLow' => 0,
521				'rangeHigh' => 3,
522			],
523			'SubjectLocation' => [
524				'map_group' => 'exif',
525				'mode' => Reader::MODE_SEQ,
526				'validate' => 'validateInteger',
527			],
528			'UserComment' => [
529				'map_group' => 'exif',
530				'mode' => Reader::MODE_LANG,
531			],
532			'WhiteBalance' => [
533				'map_group' => 'exif',
534				'mode' => Reader::MODE_SIMPLE,
535				'validate' => 'validateClosed',
536				'choices' => [ '0' => true, '1' => true ]
537			],
538		],
539		'http://ns.adobe.com/tiff/1.0/' => [
540			'Artist' => [
541				'map_group' => 'exif',
542				'mode' => Reader::MODE_SIMPLE,
543			],
544			'BitsPerSample' => [
545				'map_group' => 'exif',
546				'mode' => Reader::MODE_SEQ,
547				'validate' => 'validateInteger',
548			],
549			'Compression' => [
550				'map_group' => 'exif',
551				'mode' => Reader::MODE_SIMPLE,
552				'validate' => 'validateClosed',
553				'choices' => [ '1' => true, '6' => true ],
554			],
555			/* this prop should not be used in XMP. dc:rights is the correct prop */
556			'Copyright' => [
557				'map_group' => 'exif',
558				'mode' => Reader::MODE_LANG,
559			],
560			'DateTime' => [
561				/* proper prop is xmp:ModifyDate */
562				'map_group' => 'exif',
563				'mode' => Reader::MODE_SIMPLE,
564				'validate' => 'validateDate',
565			],
566			'ImageDescription' => [
567				/* proper one is dc:description */
568				'map_group' => 'exif',
569				'mode' => Reader::MODE_LANG,
570			],
571			'ImageLength' => [
572				'map_group' => 'exif',
573				'mode' => Reader::MODE_SIMPLE,
574				'validate' => 'validateInteger',
575			],
576			'ImageWidth' => [
577				'map_group' => 'exif',
578				'mode' => Reader::MODE_SIMPLE,
579				'validate' => 'validateInteger',
580			],
581			'Make' => [
582				'map_group' => 'exif',
583				'mode' => Reader::MODE_SIMPLE,
584			],
585			'Model' => [
586				'map_group' => 'exif',
587				'mode' => Reader::MODE_SIMPLE,
588			],
589			/** Do not extract this property
590			 * It interferes with auto exif rotation.
591			 * 'Orientation'       => array(
592			 *    'map_group' => 'exif',
593			 *    'mode'      => Reader::MODE_SIMPLE,
594			 *    'validate'  => 'validateClosed',
595			 *    'choices'   => array( '1' => true, '2' => true, '3' => true, '4' => true, 5 => true,
596			 *            '6' => true, '7' => true, '8' => true ),
597			 * ),
598			 */
599			'PhotometricInterpretation' => [
600				'map_group' => 'exif',
601				'mode' => Reader::MODE_SIMPLE,
602				'validate' => 'validateClosed',
603				'choices' => [ '2' => true, '6' => true ],
604			],
605			'PlanerConfiguration' => [
606				'map_group' => 'exif',
607				'mode' => Reader::MODE_SIMPLE,
608				'validate' => 'validateClosed',
609				'choices' => [ '1' => true, '2' => true ],
610			],
611			'PrimaryChromaticities' => [
612				'map_group' => 'exif',
613				'mode' => Reader::MODE_SEQ,
614				'validate' => 'validateRational',
615			],
616			'ReferenceBlackWhite' => [
617				'map_group' => 'exif',
618				'mode' => Reader::MODE_SEQ,
619				'validate' => 'validateRational',
620			],
621			'ResolutionUnit' => [
622				'map_group' => 'exif',
623				'mode' => Reader::MODE_SIMPLE,
624				'validate' => 'validateClosed',
625				'choices' => [ '2' => true, '3' => true ],
626			],
627			'SamplesPerPixel' => [
628				'map_group' => 'exif',
629				'mode' => Reader::MODE_SIMPLE,
630				'validate' => 'validateInteger',
631			],
632			'Software' => [
633				/* see xmp:CreatorTool */
634				'map_group' => 'exif',
635				'mode' => Reader::MODE_SIMPLE,
636			],
637			/* ignore TransferFunction */
638			'WhitePoint' => [
639				'map_group' => 'exif',
640				'mode' => Reader::MODE_SEQ,
641				'validate' => 'validateRational',
642			],
643			'XResolution' => [
644				'map_group' => 'exif',
645				'mode' => Reader::MODE_SIMPLE,
646				'validate' => 'validateRational',
647			],
648			'YResolution' => [
649				'map_group' => 'exif',
650				'mode' => Reader::MODE_SIMPLE,
651				'validate' => 'validateRational',
652			],
653			'YCbCrCoefficients' => [
654				'map_group' => 'exif',
655				'mode' => Reader::MODE_SEQ,
656				'validate' => 'validateRational',
657			],
658			'YCbCrPositioning' => [
659				'map_group' => 'exif',
660				'mode' => Reader::MODE_SIMPLE,
661				'validate' => 'validateClosed',
662				'choices' => [ '1' => true, '2' => true ],
663			],
664			/**
665			 * Disable extracting this property (T33944)
666			 * Several files have a string instead of a Seq
667			 * for this property. Reader doesn't handle
668			 * mismatched types very gracefully (it marks
669			 * the entire file as invalid, instead of just
670			 * the relavent prop). Since this prop
671			 * doesn't communicate all that useful information
672			 * just disable this prop for now, until such
673			 * Reader is more graceful (T34172)
674			 * 'YCbCrSubSampling'  => array(
675			 *    'map_group' => 'exif',
676			 *    'mode'      => Reader::MODE_SEQ,
677			 *    'validate'  => 'validateClosed',
678			 *    'choices'   => array( '1' => true, '2' => true ),
679			 * ),
680			 */
681		],
682		'http://ns.adobe.com/exif/1.0/aux/' => [
683			'Lens' => [
684				'map_group' => 'exif',
685				'mode' => Reader::MODE_SIMPLE,
686			],
687			'SerialNumber' => [
688				'map_group' => 'exif',
689				'mode' => Reader::MODE_SIMPLE,
690			],
691			'OwnerName' => [
692				'map_group' => 'exif',
693				'map_name' => 'CameraOwnerName',
694				'mode' => Reader::MODE_SIMPLE,
695			],
696		],
697		'http://purl.org/dc/elements/1.1/' => [
698			'title' => [
699				'map_group' => 'general',
700				'map_name' => 'ObjectName',
701				'mode' => Reader::MODE_LANG
702			],
703			'description' => [
704				'map_group' => 'general',
705				'map_name' => 'ImageDescription',
706				'mode' => Reader::MODE_LANG
707			],
708			'contributor' => [
709				'map_group' => 'general',
710				'map_name' => 'dc-contributor',
711				'mode' => Reader::MODE_BAG
712			],
713			'coverage' => [
714				'map_group' => 'general',
715				'map_name' => 'dc-coverage',
716				'mode' => Reader::MODE_SIMPLE,
717			],
718			'creator' => [
719				'map_group' => 'general',
720				// map with exif Artist, iptc byline (2:80)
721				'map_name' => 'Artist',
722				'mode' => Reader::MODE_SEQ,
723			],
724			'date' => [
725				'map_group' => 'general',
726				// Note, not mapped with other date properties, as this type of date is
727				// non-specific: "A point or period of time associated with an event in
728				// the lifecycle of the resource"
729				'map_name' => 'dc-date',
730				'mode' => Reader::MODE_SEQ,
731				'validate' => 'validateDate',
732			],
733			/* Do not extract dc:format, as we've got better ways to determine MIME type */
734			'identifier' => [
735				'map_group' => 'deprecated',
736				'map_name' => 'Identifier',
737				'mode' => Reader::MODE_SIMPLE,
738			],
739			'language' => [
740				'map_group' => 'general',
741				/* mapped with iptc 2:135 */
742				'map_name' => 'LanguageCode',
743				'mode' => Reader::MODE_BAG,
744				'validate' => 'validateLangCode',
745			],
746			'publisher' => [
747				'map_group' => 'general',
748				'map_name' => 'dc-publisher',
749				'mode' => Reader::MODE_BAG,
750			],
751			// for related images/resources
752			'relation' => [
753				'map_group' => 'general',
754				'map_name' => 'dc-relation',
755				'mode' => Reader::MODE_BAG,
756			],
757			'rights' => [
758				'map_group' => 'general',
759				'map_name' => 'Copyright',
760				'mode' => Reader::MODE_LANG,
761			],
762			// Note: source is not mapped with iptc source, since iptc
763			// source describes the source of the image in terms of a person
764			// who provided the image, where this is to describe an image that the
765			// current one is based on.
766			'source' => [
767				'map_group' => 'general',
768				'map_name' => 'dc-source',
769				'mode' => Reader::MODE_SIMPLE,
770			],
771			'subject' => [
772				'map_group' => 'general',
773				/* maps to iptc 2:25 */
774				'map_name' => 'Keywords',
775				'mode' => Reader::MODE_BAG,
776			],
777			'type' => [
778				'map_group' => 'general',
779				'map_name' => 'dc-type',
780				'mode' => Reader::MODE_BAG,
781			],
782		],
783		'http://ns.adobe.com/xap/1.0/' => [
784			'CreateDate' => [
785				'map_group' => 'general',
786				'map_name' => 'DateTimeDigitized',
787				'mode' => Reader::MODE_SIMPLE,
788				'validate' => 'validateDate',
789			],
790			'CreatorTool' => [
791				'map_group' => 'general',
792				'map_name' => 'Software',
793				'mode' => Reader::MODE_SIMPLE
794			],
795			'Identifier' => [
796				'map_group' => 'general',
797				'mode' => Reader::MODE_BAG,
798			],
799			'Label' => [
800				'map_group' => 'general',
801				'mode' => Reader::MODE_SIMPLE,
802			],
803			'ModifyDate' => [
804				'map_group' => 'general',
805				'mode' => Reader::MODE_SIMPLE,
806				'map_name' => 'DateTime',
807				'validate' => 'validateDate',
808			],
809			'MetadataDate' => [
810				'map_group' => 'general',
811				'mode' => Reader::MODE_SIMPLE,
812				// map_name to be consistent with other date names.
813				'map_name' => 'DateTimeMetadata',
814				'validate' => 'validateDate',
815			],
816			'Nickname' => [
817				'map_group' => 'general',
818				'mode' => Reader::MODE_SIMPLE,
819			],
820			'Rating' => [
821				'map_group' => 'general',
822				'mode' => Reader::MODE_SIMPLE,
823				'validate' => 'validateRating',
824			],
825		],
826		'http://ns.adobe.com/xap/1.0/rights/' => [
827			'Certificate' => [
828				'map_group' => 'general',
829				'map_name' => 'RightsCertificate',
830				'mode' => Reader::MODE_SIMPLE,
831			],
832			'Marked' => [
833				'map_group' => 'general',
834				'map_name' => 'Copyrighted',
835				'mode' => Reader::MODE_SIMPLE,
836				'validate' => 'validateBoolean',
837			],
838			'Owner' => [
839				'map_group' => 'general',
840				'map_name' => 'CopyrightOwner',
841				'mode' => Reader::MODE_BAG,
842			],
843			// this seems similar to dc:rights.
844			'UsageTerms' => [
845				'map_group' => 'general',
846				'mode' => Reader::MODE_LANG,
847			],
848			'WebStatement' => [
849				'map_group' => 'general',
850				'mode' => Reader::MODE_SIMPLE,
851			],
852		],
853		// XMP media management.
854		'http://ns.adobe.com/xap/1.0/mm/' => [
855			// if we extract the exif UniqueImageID, might
856			// as well do this too.
857			'OriginalDocumentID' => [
858				'map_group' => 'general',
859				'mode' => Reader::MODE_SIMPLE,
860			],
861			// It might also be useful to do xmpMM:LastURL
862			// and xmpMM:DerivedFrom as you can potentially,
863			// get the url of this document/source for this
864			// document. However whats more likely is you'd
865			// get a file:// url for the path of the doc,
866			// which is somewhat of a privacy issue.
867		],
868		'http://creativecommons.org/ns#' => [
869			'license' => [
870				'map_name' => 'LicenseUrl',
871				'map_group' => 'general',
872				'mode' => Reader::MODE_SIMPLE,
873			],
874			'morePermissions' => [
875				'map_name' => 'MorePermissionsUrl',
876				'map_group' => 'general',
877				'mode' => Reader::MODE_SIMPLE,
878			],
879			'attributionURL' => [
880				'map_group' => 'general',
881				'map_name' => 'AttributionUrl',
882				'mode' => Reader::MODE_SIMPLE,
883			],
884			'attributionName' => [
885				'map_group' => 'general',
886				'map_name' => 'PreferredAttributionName',
887				'mode' => Reader::MODE_SIMPLE,
888			],
889		],
890		// Note, this property affects how jpeg metadata is extracted.
891		'http://ns.adobe.com/xmp/note/' => [
892			'HasExtendedXMP' => [
893				'map_group' => 'special',
894				'mode' => Reader::MODE_SIMPLE,
895			],
896		],
897		/* Note, in iptc schemas, the legacy properties are denoted
898		 * as deprecated, since other properties should used instead,
899		 * and properties marked as deprecated in the standard are
900		 * are marked as general here as they don't have replacements
901		 */
902		'http://ns.adobe.com/photoshop/1.0/' => [
903			'City' => [
904				'map_group' => 'deprecated',
905				'mode' => Reader::MODE_SIMPLE,
906				'map_name' => 'CityDest',
907			],
908			'Country' => [
909				'map_group' => 'deprecated',
910				'mode' => Reader::MODE_SIMPLE,
911				'map_name' => 'CountryDest',
912			],
913			'State' => [
914				'map_group' => 'deprecated',
915				'mode' => Reader::MODE_SIMPLE,
916				'map_name' => 'ProvinceOrStateDest',
917			],
918			'DateCreated' => [
919				'map_group' => 'deprecated',
920				// marking as deprecated as the xmp prop preferred
921				'mode' => Reader::MODE_SIMPLE,
922				'map_name' => 'DateTimeOriginal',
923				'validate' => 'validateDate',
924				// note this prop is an XMP, not IPTC date
925			],
926			'CaptionWriter' => [
927				'map_group' => 'general',
928				'mode' => Reader::MODE_SIMPLE,
929				'map_name' => 'Writer',
930			],
931			'Instructions' => [
932				'map_group' => 'general',
933				'mode' => Reader::MODE_SIMPLE,
934				'map_name' => 'SpecialInstructions',
935			],
936			'TransmissionReference' => [
937				'map_group' => 'general',
938				'mode' => Reader::MODE_SIMPLE,
939				'map_name' => 'OriginalTransmissionRef',
940			],
941			'AuthorsPosition' => [
942				/* This corresponds with 2:85
943				 * By-line Title, which needs to be
944				 * handled weirdly to correspond
945				 * with iptc/exif. */
946				'map_group' => 'special',
947				'mode' => Reader::MODE_SIMPLE
948			],
949			'Credit' => [
950				'map_group' => 'general',
951				'mode' => Reader::MODE_SIMPLE,
952			],
953			'Source' => [
954				'map_group' => 'general',
955				'mode' => Reader::MODE_SIMPLE,
956			],
957			'Urgency' => [
958				'map_group' => 'general',
959				'mode' => Reader::MODE_SIMPLE,
960			],
961			'Category' => [
962				// Note, this prop is deprecated, but in general
963				// group since it doesn't have a replacement.
964				'map_group' => 'general',
965				'mode' => Reader::MODE_SIMPLE,
966				'map_name' => 'iimCategory',
967			],
968			'SupplementalCategories' => [
969				'map_group' => 'general',
970				'mode' => Reader::MODE_BAG,
971				'map_name' => 'iimSupplementalCategory',
972			],
973			'Headline' => [
974				'map_group' => 'general',
975				'mode' => Reader::MODE_SIMPLE
976			],
977		],
978		'http://iptc.org/std/Iptc4xmpCore/1.0/xmlns/' => [
979			'CountryCode' => [
980				'map_group' => 'deprecated',
981				'mode' => Reader::MODE_SIMPLE,
982				'map_name' => 'CountryCodeDest',
983			],
984			'IntellectualGenre' => [
985				'map_group' => 'general',
986				'mode' => Reader::MODE_SIMPLE,
987			],
988			// Note, this is a six digit code.
989			// See: http://cv.iptc.org/newscodes/scene/
990			// Since these aren't really all that common,
991			// we just show the number.
992			'Scene' => [
993				'map_group' => 'general',
994				'mode' => Reader::MODE_BAG,
995				'validate' => 'validateInteger',
996				'map_name' => 'SceneCode',
997			],
998			/* Note: SubjectCode should be an 8 ascii digits.
999			 * it is not really an integer (has leading 0's,
1000			 * cannot have a +/- sign), but validateInteger
1001			 * will let it through.
1002			 */
1003			'SubjectCode' => [
1004				'map_group' => 'general',
1005				'mode' => Reader::MODE_BAG,
1006				'map_name' => 'SubjectNewsCode',
1007				'validate' => 'validateInteger'
1008			],
1009			'Location' => [
1010				'map_group' => 'deprecated',
1011				'mode' => Reader::MODE_SIMPLE,
1012				'map_name' => 'SublocationDest',
1013			],
1014			'CreatorContactInfo' => [
1015				/* Note this maps to 2:118 in iim
1016				 * (Contact) field. However those field
1017				 * types are slightly different - 2:118
1018				 * is free form text field, where this
1019				 * is more structured.
1020				 */
1021				'map_group' => 'general',
1022				'mode' => Reader::MODE_STRUCT,
1023				'map_name' => 'Contact',
1024				'children' => [
1025					'CiAdrExtadr' => true,
1026					'CiAdrCity' => true,
1027					'CiAdrCtry' => true,
1028					'CiEmailWork' => true,
1029					'CiTelWork' => true,
1030					'CiAdrPcode' => true,
1031					'CiAdrRegion' => true,
1032					'CiUrlWork' => true,
1033				],
1034			],
1035			'CiAdrExtadr' => [
1036				/* address */
1037				'map_group' => 'general',
1038				'mode' => Reader::MODE_SIMPLE,
1039				'structPart' => true,
1040			],
1041			'CiAdrCity' => [
1042				/* city */
1043				'map_group' => 'general',
1044				'mode' => Reader::MODE_SIMPLE,
1045				'structPart' => true,
1046			],
1047			'CiAdrCtry' => [
1048				/* country */
1049				'map_group' => 'general',
1050				'mode' => Reader::MODE_SIMPLE,
1051				'structPart' => true,
1052			],
1053			'CiEmailWork' => [
1054				/* email (possibly separated by ',') */
1055				'map_group' => 'general',
1056				'mode' => Reader::MODE_SIMPLE,
1057				'structPart' => true,
1058			],
1059			'CiTelWork' => [
1060				/* telephone */
1061				'map_group' => 'general',
1062				'mode' => Reader::MODE_SIMPLE,
1063				'structPart' => true,
1064			],
1065			'CiAdrPcode' => [
1066				/* postal code */
1067				'map_group' => 'general',
1068				'mode' => Reader::MODE_SIMPLE,
1069				'structPart' => true,
1070			],
1071			'CiAdrRegion' => [
1072				/* province/state */
1073				'map_group' => 'general',
1074				'mode' => Reader::MODE_SIMPLE,
1075				'structPart' => true,
1076			],
1077			'CiUrlWork' => [
1078				/* url. Multiple may be separated by comma. */
1079				'map_group' => 'general',
1080				'mode' => Reader::MODE_SIMPLE,
1081				'structPart' => true,
1082			],
1083			/* End contact info struct properties */
1084		],
1085		'http://iptc.org/std/Iptc4xmpExt/2008-02-29/' => [
1086			'Event' => [
1087				'map_group' => 'general',
1088				'mode' => Reader::MODE_SIMPLE,
1089			],
1090			'OrganisationInImageName' => [
1091				'map_group' => 'general',
1092				'mode' => Reader::MODE_BAG,
1093				'map_name' => 'OrganisationInImage'
1094			],
1095			'PersonInImage' => [
1096				'map_group' => 'general',
1097				'mode' => Reader::MODE_BAG,
1098			],
1099			'MaxAvailHeight' => [
1100				'map_group' => 'general',
1101				'mode' => Reader::MODE_SIMPLE,
1102				'validate' => 'validateInteger',
1103				'map_name' => 'OriginalImageHeight',
1104			],
1105			'MaxAvailWidth' => [
1106				'map_group' => 'general',
1107				'mode' => Reader::MODE_SIMPLE,
1108				'validate' => 'validateInteger',
1109				'map_name' => 'OriginalImageWidth',
1110			],
1111			// LocationShown and LocationCreated are handled
1112			// specially because they are hierarchical, but we
1113			// also want to merge with the old non-hierarchical.
1114			'LocationShown' => [
1115				'map_group' => 'special',
1116				'mode' => Reader::MODE_BAGSTRUCT,
1117				'children' => [
1118					'WorldRegion' => true,
1119					/* iso code */
1120					'CountryCode' => true,
1121					'CountryName' => true,
1122					'ProvinceState' => true,
1123					'City' => true,
1124					'Sublocation' => true,
1125				],
1126			],
1127			'LocationCreated' => [
1128				'map_group' => 'special',
1129				'mode' => Reader::MODE_BAGSTRUCT,
1130				'children' => [
1131					'WorldRegion' => true,
1132					/* iso code */
1133					'CountryCode' => true,
1134					'CountryName' => true,
1135					'ProvinceState' => true,
1136					'City' => true,
1137					'Sublocation' => true,
1138				],
1139			],
1140			'WorldRegion' => [
1141				'map_group' => 'special',
1142				'mode' => Reader::MODE_SIMPLE,
1143				'structPart' => true,
1144			],
1145			'CountryCode' => [
1146				'map_group' => 'special',
1147				'mode' => Reader::MODE_SIMPLE,
1148				'structPart' => true,
1149			],
1150			'CountryName' => [
1151				'map_group' => 'special',
1152				'mode' => Reader::MODE_SIMPLE,
1153				'structPart' => true,
1154				'map_name' => 'Country',
1155			],
1156			'ProvinceState' => [
1157				'map_group' => 'special',
1158				'mode' => Reader::MODE_SIMPLE,
1159				'structPart' => true,
1160				'map_name' => 'ProvinceOrState',
1161			],
1162			'City' => [
1163				'map_group' => 'special',
1164				'mode' => Reader::MODE_SIMPLE,
1165				'structPart' => true,
1166			],
1167			'Sublocation' => [
1168				'map_group' => 'special',
1169				'mode' => Reader::MODE_SIMPLE,
1170				'structPart' => true,
1171			],
1172
1173			/* Other props that might be interesting but
1174			 * Not currently extracted:
1175			 * ArtworkOrObject, (info about objects in picture)
1176			 * DigitalSourceType
1177			 * RegistryId
1178			 */
1179		],
1180		'http://ns.google.com/photos/1.0/panorama/' => [
1181			// https://developers.google.com/streetview/spherical-metadata
1182			'UsePanoramaViewer' => [
1183				'map_group' => 'general',
1184				'mode' => Reader::MODE_SIMPLE,
1185				'validate' => 'validateBoolean',
1186			],
1187			'CaptureSoftware' => [
1188				'map_group' => 'general',
1189				'mode' => Reader::MODE_SIMPLE,
1190			],
1191			'StitchingSoftware' => [
1192				'map_group' => 'general',
1193				'mode' => Reader::MODE_SIMPLE,
1194			],
1195			'ProjectionType' => [
1196				'map_group' => 'general',
1197				'mode' => Reader::MODE_SIMPLE,
1198				'validate' => 'validateClosed',
1199				'choices' => [
1200					'equirectangular' => true,
1201				]
1202			],
1203			'PoseHeadingDegrees' => [
1204				'map_group' => 'general',
1205				'mode' => Reader::MODE_SIMPLE,
1206				'validate' => 'validateReal',
1207				'rangeLow' => 0,
1208				'rangeHigh' => 360,
1209			],
1210			'PosePitchDegrees' => [
1211				'map_group' => 'general',
1212				'mode' => Reader::MODE_SIMPLE,
1213				'validate' => 'validateReal',
1214				'rangeLow' => -90,
1215				'rangeHigh' => 90,
1216			],
1217			'PoseRollDegrees' => [
1218				'map_group' => 'general',
1219				'mode' => Reader::MODE_SIMPLE,
1220				'validate' => 'validateReal',
1221				'rangeLow' => -180,
1222				'rangeHigh' => 180,
1223			],
1224			'InitialViewHeadingDegrees' => [
1225				'map_group' => 'general',
1226				'mode' => Reader::MODE_SIMPLE,
1227				'validate' => 'validateInteger',
1228			],
1229			'InitialViewRollDegrees' => [
1230				'map_group' => 'general',
1231				'mode' => Reader::MODE_SIMPLE,
1232				'validate' => 'validateInteger',
1233			],
1234			'InitialViewRollDegrees' => [
1235				'map_group' => 'general',
1236				'mode' => Reader::MODE_SIMPLE,
1237				'validate' => 'validateInteger',
1238			],
1239			'InitialHorizontalFOVDegrees' => [
1240				'map_group' => 'general',
1241				'mode' => Reader::MODE_SIMPLE,
1242				'validate' => 'validateReal',
1243				'rangeLow' => 0,
1244				'rangeHigh' => 360,
1245			],
1246			'InitialVerticalFOVDegrees' => [
1247				'map_group' => 'general',
1248				'mode' => Reader::MODE_SIMPLE,
1249				'validate' => 'validateReal',
1250				'rangeLow' => 0,
1251				'rangeHigh' => 360,
1252			],
1253			'FirstPhotoDate' => [
1254				'map_group' => 'general',
1255				'mode' => Reader::MODE_SIMPLE,
1256				'validate' => 'validateDate',
1257			],
1258			'LastPhotoDate' => [
1259				'map_group' => 'general',
1260				'mode' => Reader::MODE_SIMPLE,
1261				'validate' => 'validateDate',
1262			],
1263			'SourcePhotosCount' => [
1264				'map_group' => 'general',
1265				'mode' => Reader::MODE_SIMPLE,
1266				'validate' => 'validateInteger',
1267			],
1268			'ExposureLockUsed' => [
1269				'map_group' => 'general',
1270				'mode' => Reader::MODE_SIMPLE,
1271				'validate' => 'validateBoolean',
1272			],
1273			'CroppedAreaImageWidthPixels' => [
1274				'map_group' => 'general',
1275				'mode' => Reader::MODE_SIMPLE,
1276				'validate' => 'validateInteger',
1277			],
1278			'CroppedAreaImageHeightPixels' => [
1279				'map_group' => 'general',
1280				'mode' => Reader::MODE_SIMPLE,
1281				'validate' => 'validateInteger',
1282			],
1283			'FullPanoWidthPixels' => [
1284				'map_group' => 'general',
1285				'mode' => Reader::MODE_SIMPLE,
1286				'validate' => 'validateInteger',
1287			],
1288			'FullPanoHeightPixels' => [
1289				'map_group' => 'general',
1290				'mode' => Reader::MODE_SIMPLE,
1291				'validate' => 'validateInteger',
1292			],
1293			'CroppedAreaLeftPixels' => [
1294				'map_group' => 'general',
1295				'mode' => Reader::MODE_SIMPLE,
1296				'validate' => 'validateInteger',
1297			],
1298			'CroppedAreaTopPixels' => [
1299				'map_group' => 'general',
1300				'mode' => Reader::MODE_SIMPLE,
1301				'validate' => 'validateInteger',
1302			],
1303			'InitialCameraDolly' => [
1304				'map_group' => 'general',
1305				'mode' => Reader::MODE_SIMPLE,
1306				'validate' => 'validateReal',
1307				'rangeLow' => -1,
1308				'rangeHigh' => 1,
1309			],
1310		]
1311
1312		/* Plus props we might want to consider:
1313		 * (Note: some of these have unclear/incomplete definitions
1314		 * from the iptc4xmp standard).
1315		 * ImageSupplier (kind of like iptc source field)
1316		 * ImageSupplierId (id code for image from supplier)
1317		 * CopyrightOwner
1318		 * ImageCreator
1319		 * Licensor
1320		 * Various model release fields
1321		 * Property release fields.
1322		 */
1323	];
1324}
1325