108 $resolutionunit = !isset( $tags[
'ResolutionUnit'] ) || $tags[
'ResolutionUnit'] == 2 ? 2 : 3;
109 unset( $tags[
'ResolutionUnit'] );
112 unset( $tags[
'HasExtendedXMP'] );
113 unset( $tags[
'AuthorsPosition'] );
114 unset( $tags[
'LocationCreated'] );
115 unset( $tags[
'LocationShown'] );
116 unset( $tags[
'GPSAltitudeRef'] );
118 foreach ( $tags as $tag => &$vals ) {
121 if ( !is_array( $vals ) ) {
126 if ( isset( $vals[
'_type'] ) ) {
127 $type = $vals[
'_type'];
128 unset( $vals[
'_type'] );
135 if ( isset( $tags[$tag][
'_formatted'] ) ) {
137 $tags[$tag][
'_formatted'],
$type
143 if ( $tag ===
'GPSTimeStamp' && count( $vals ) === 3 ) {
146 $h = explode(
'/', $vals[0], 2 );
147 $m = explode(
'/', $vals[1], 2 );
148 $s = explode(
'/', $vals[2], 2 );
163 $vals = str_pad( (
string)( (
int)$h[0] / (
int)$h[1] ), 2,
'0', STR_PAD_LEFT )
164 .
':' . str_pad( (
string)( (
int)$m[0] / (
int)$m[1] ), 2,
'0', STR_PAD_LEFT )
165 .
':' . str_pad( (
string)( (
int)$s[0] / (
int)$s[1] ), 2,
'0', STR_PAD_LEFT );
167 $time =
wfTimestamp( TS_MW,
'1971:01:01 ' . $vals );
169 if ( $time && (
int)$time > 0 ) {
178 if ( $tag ===
'Contact' || $tag ===
'CreatorContactInfo' ) {
183 foreach ( $vals as &$val ) {
198 $val = $this->exifMsg( $tag, $val );
207 case 'PhotometricInterpretation':
221 $val = $this->exifMsg( $tag, $val );
240 $val = $this->exifMsg( $tag, $val );
249 case 'PlanarConfiguration':
253 $val = $this->exifMsg( $tag, $val );
263 case 'YCbCrPositioning':
267 $val = $this->exifMsg( $tag, $val );
278 switch ( $resolutionunit ) {
280 $val = $this->exifMsg(
'XYResolution',
'i', $this->formatNum( $val ) );
283 $val = $this->exifMsg(
'XYResolution',
'c', $this->formatNum( $val ) );
299 case 'FlashPixVersion':
302 case 'FlashpixVersion':
303 $val = $this->
literal( (
int)$val / 100 );
310 $val = $this->exifMsg( $tag, $val );
319 case 'ComponentsConfiguration':
328 $val = $this->exifMsg( $tag, $val );
338 case 'DateTimeOriginal':
339 case 'DateTimeDigitized':
340 case 'DateTimeReleased':
341 case 'DateTimeExpires':
344 case 'DateTimeMetadata':
345 case 'FirstPhotoDate':
346 case 'LastPhotoDate':
347 if ( $val ===
'0000:00:00 00:00:00' || $val ===
' : : : : ' ) {
348 $val = $this->
msg(
'exif-unknowndate' )->text();
352 '/^(?:\d{4}):(?:\d\d):(?:\d\d) (?:\d\d):(?:\d\d):(?:\d\d)$/D',
357 if ( $time && (
int)$time > 0 ) {
361 } elseif ( preg_match(
'/^(?:\d{4}):(?:\d\d):(?:\d\d) (?:\d\d):(?:\d\d)$/D', $val ) ) {
366 if ( $time && (
int)$time > 0 ) {
370 } elseif ( preg_match(
'/^(?:\d{4}):(?:\d\d):(?:\d\d)$/D', $val ) ) {
373 . substr( $val, 5, 2 )
374 . substr( $val, 8, 2 )
376 if ( $time && (
int)$time > 0 ) {
385 case 'ExposureProgram':
396 $val = $this->exifMsg( $tag, $val );
405 case 'SubjectDistance':
406 $val = $this->exifMsg( $tag,
'', $this->formatNum( $val ) );
420 $val = $this->exifMsg( $tag, $val );
452 $val = $this->exifMsg( $tag, $val );
463 'fired' => $val & 0b00000001,
464 'return' => ( $val & 0b00000110 ) >> 1,
465 'mode' => ( $val & 0b00011000 ) >> 3,
466 'function' => ( $val & 0b00100000 ) >> 5,
467 'redeye' => ( $val & 0b01000000 ) >> 6,
471 # We do not need to handle unknown values since all are used.
472 foreach ( $flashDecode as $subTag => $subValue ) {
473 # We do not need any message for zeroed values.
474 if ( $subTag !==
'fired' && $subValue === 0 ) {
477 $fullTag = $tag .
'-' . $subTag;
478 $flashMsgs[] = $this->exifMsg( $fullTag, $subValue );
480 $val = $this->
getLanguage()->commaList( $flashMsgs );
483 case 'FocalPlaneResolutionUnit':
486 $val = $this->exifMsg( $tag, $val );
495 case 'SensingMethod':
504 $val = $this->exifMsg( $tag, $val );
516 $val = $this->exifMsg( $tag, $val );
528 $val = $this->exifMsg( $tag, $val );
537 case 'CustomRendered':
549 $val = $this->exifMsg( $tag, $val );
563 $val = $this->exifMsg( $tag, $val );
575 $val = $this->exifMsg( $tag, $val );
584 case 'SceneCaptureType':
590 $val = $this->exifMsg( $tag, $val );
606 $val = $this->exifMsg( $tag, $val );
620 $val = $this->exifMsg( $tag, $val );
634 $val = $this->exifMsg( $tag, $val );
648 $val = $this->exifMsg( $tag, $val );
657 case 'SubjectDistanceRange':
663 $val = $this->exifMsg( $tag, $val );
673 case 'GPSLatitudeRef':
674 case 'GPSDestLatitudeRef':
678 $val = $this->exifMsg(
'GPSLatitude', $val );
687 case 'GPSLongitudeRef':
688 case 'GPSDestLongitudeRef':
692 $val = $this->exifMsg(
'GPSLongitude', $val );
703 $val = $this->exifMsg(
'GPSAltitude',
'below-sealevel', $this->formatNum( -$val, 3 ) );
705 $val = $this->exifMsg(
'GPSAltitude',
'above-sealevel', $this->formatNum( $val, 3 ) );
713 $val = $this->exifMsg( $tag, $val );
722 case 'GPSMeasureMode':
726 $val = $this->exifMsg( $tag, $val );
736 case 'GPSImgDirectionRef':
737 case 'GPSDestBearingRef':
741 $val = $this->exifMsg(
'GPSDirection', $val );
751 case 'GPSDestLatitude':
752 $val = $this->formatCoords( $val,
'latitude' );
755 case 'GPSDestLongitude':
756 $val = $this->formatCoords( $val,
'longitude' );
764 $val = $this->exifMsg(
'GPSSpeed', $val );
773 case 'GPSDestDistanceRef':
778 $val = $this->exifMsg(
'GPSDestDistance', $val );
790 $val = $this->exifMsg( $tag,
'excellent', $this->formatNum( $val ) );
791 } elseif ( $val <= 5 ) {
792 $val = $this->exifMsg( $tag,
'good', $this->formatNum( $val ) );
793 } elseif ( $val <= 10 ) {
794 $val = $this->exifMsg( $tag,
'moderate', $this->formatNum( $val ) );
795 } elseif ( $val <= 20 ) {
796 $val = $this->exifMsg( $tag,
'fair', $this->formatNum( $val ) );
798 $val = $this->exifMsg( $tag,
'poor', $this->formatNum( $val ) );
807 $val = $this->exifMsg( $tag,
'', $this->
literal( $val ) );
811 if ( is_array( $val ) ) {
812 if ( count( $val ) > 1 ) {
815 'exif-software-version-value',
821 $val = $this->exifMsg( $tag,
'', $this->
literal( $val[0] ) );
824 $val = $this->exifMsg( $tag,
'', $this->
literal( $val ) );
830 $val = $this->
msg(
'exif-exposuretime-format',
831 $this->formatFraction( $val ), $this->formatNum( $val ) )->text();
833 case 'ISOSpeedRatings':
837 if ( $val ===
'65535' ) {
838 $val = $this->exifMsg( $tag,
'overflow' );
840 $val = $this->formatNum( $val );
844 $val = $this->
msg(
'exif-fnumber-format',
845 $this->formatNum( $val ) )->text();
849 case 'FocalLengthIn35mmFilm':
850 $val = $this->
msg(
'exif-focallength-format',
851 $this->formatNum( $val ) )->text();
854 case 'MaxApertureValue':
855 if ( strpos( $val,
'/' ) !==
false ) {
857 [ $n, $d ] = explode(
'/', $val, 2 );
858 if ( is_numeric( $n ) && is_numeric( $d ) ) {
859 $val = (int)$n / (
int)$d;
862 if ( is_numeric( $val ) ) {
863 $fNumber = 2 ** ( $val / 2 );
864 if ( is_finite( $fNumber ) ) {
865 $val = $this->
msg(
'exif-maxaperturevalue-value',
866 $this->formatNum( $val ),
867 $this->formatNum( $fNumber, 2 )
876 switch ( strtolower( $val ) ) {
896 $val = $this->exifMsg(
905 case 'SubjectNewsCode':
911 $val = $this->convertNewsCode( $val );
917 if ( $val === 0 || $val === 9 ) {
919 } elseif ( $val < 5 && $val > 1 ) {
921 } elseif ( $val === 5 ) {
923 } elseif ( $val <= 8 && $val > 5 ) {
927 if ( $urgency !==
'' ) {
928 $val = $this->exifMsg(
'urgency',
929 $urgency, $this->
literal( $val )
937 case 'OriginalImageHeight':
938 case 'OriginalImageWidth':
939 case 'PixelXDimension':
940 case 'PixelYDimension':
943 $val = $this->formatNum( $val ) .
' ' . $this->
msg(
'unit-pixel' )->text();
953 case 'ImageDescription':
957 case 'RelatedSoundFile':
958 case 'ImageUniqueID':
959 case 'SpectralSensitivity':
960 case 'GPSSatellites':
964 case 'WorldRegionDest':
966 case 'CountryCodeDest':
967 case 'ProvinceOrStateDest':
969 case 'SublocationDest':
970 case 'WorldRegionCreated':
971 case 'CountryCreated':
972 case 'CountryCodeCreated':
973 case 'ProvinceOrStateCreated':
975 case 'SublocationCreated':
977 case 'SpecialInstructions':
982 case 'FixtureIdentifier':
984 case 'LocationDestCode':
986 case 'JPEGFileComment':
987 case 'iimSupplementalCategory':
988 case 'OriginalTransmissionRef':
990 case 'dc-contributor':
999 case 'CameraOwnerName':
1002 case 'RightsCertificate':
1003 case 'CopyrightOwner':
1005 case 'WebStatement':
1006 case 'OriginalDocumentID':
1008 case 'MorePermissionsUrl':
1009 case 'AttributionUrl':
1010 case 'PreferredAttributionName':
1011 case 'PNGFileComment':
1013 case 'ContentWarning':
1014 case 'GIFFileComment':
1016 case 'IntellectualGenre':
1018 case 'OrganisationInImage':
1019 case 'PersonInImage':
1020 case 'CaptureSoftware':
1021 case 'GPSAreaInformation':
1022 case 'GPSProcessingMethod':
1023 case 'StitchingSoftware':
1025 case 'SubSecTimeOriginal':
1026 case 'SubSecTimeDigitized':
1027 $val = $this->
literal( $val );
1030 case 'ProjectionType':
1032 case 'equirectangular':
1033 $val = $this->exifMsg( $tag, $val );
1036 $val = $this->
literal( $val );
1045 $val = $this->exifMsg( $tag, $val );
1048 $val = $this->
literal( $val );
1053 case 'UsePanoramaViewer':
1054 case 'ExposureLockUsed':
1058 $val = $this->exifMsg( $tag, $val );
1061 $val = $this->
literal( $val );
1066 if ( $val ===
'-1' ) {
1067 $val = $this->exifMsg( $tag,
'rejected' );
1069 $val = $this->formatNum( $val );
1073 case 'LanguageCode':
1074 $lang = MediaWikiServices::getInstance()
1075 ->getLanguageNameUtils()
1076 ->getLanguageName( strtolower( $val ), $this->
getLanguage()->getCode() );
1081 $val = $this->formatNum( $val,
false, $tag );