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