99 $resolutionunit = !isset( $tags[
'ResolutionUnit'] ) || $tags[
'ResolutionUnit'] == 2 ? 2 : 3;
100 unset( $tags[
'ResolutionUnit'] );
103 unset( $tags[
'HasExtendedXMP'] );
104 unset( $tags[
'AuthorsPosition'] );
105 unset( $tags[
'LocationCreated'] );
106 unset( $tags[
'LocationShown'] );
107 unset( $tags[
'GPSAltitudeRef'] );
109 foreach ( $tags as $tag => &$vals ) {
112 if ( !is_array( $vals ) ) {
117 if ( isset( $vals[
'_type'] ) ) {
118 $type = $vals[
'_type'];
119 unset( $vals[
'_type'] );
126 if ( isset( $tags[$tag][
'_formatted'] ) ) {
128 $tags[$tag][
'_formatted'], $type
134 if ( $tag ===
'GPSTimeStamp' && count( $vals ) === 3 ) {
137 $h = explode(
'/', $vals[0], 2 );
138 $m = explode(
'/', $vals[1], 2 );
139 $s = explode(
'/', $vals[2], 2 );
154 $vals = str_pad( (
string)( (
int)$h[0] / (
int)$h[1] ), 2,
'0', STR_PAD_LEFT )
155 .
':' . str_pad( (
string)( (
int)$m[0] / (
int)$m[1] ), 2,
'0', STR_PAD_LEFT )
156 .
':' . str_pad( (
string)( (
int)$s[0] / (
int)$s[1] ), 2,
'0', STR_PAD_LEFT );
158 $time =
wfTimestamp( TS_MW,
'1971:01:01 ' . $vals );
160 if ( $time && (
int)$time > 0 ) {
169 if ( $tag ===
'Contact' || $tag ===
'CreatorContactInfo' ) {
174 foreach ( $vals as &$val ) {
189 $val = $this->exifMsg( $tag, $val );
198 case 'PhotometricInterpretation':
212 $val = $this->exifMsg( $tag, $val );
231 $val = $this->exifMsg( $tag, $val );
240 case 'PlanarConfiguration':
244 $val = $this->exifMsg( $tag, $val );
254 case 'YCbCrPositioning':
258 $val = $this->exifMsg( $tag, $val );
269 switch ( $resolutionunit ) {
271 $val = $this->exifMsg(
'XYResolution',
'i', $this->formatNum( $val ) );
274 $val = $this->exifMsg(
'XYResolution',
'c', $this->formatNum( $val ) );
290 case 'FlashPixVersion':
293 case 'FlashpixVersion':
294 $val = $this->
literal( (
int)$val / 100 );
301 $val = $this->exifMsg( $tag, $val );
310 case 'ComponentsConfiguration':
319 $val = $this->exifMsg( $tag, $val );
329 case 'DateTimeOriginal':
330 case 'DateTimeDigitized':
331 case 'DateTimeReleased':
332 case 'DateTimeExpires':
335 case 'DateTimeMetadata':
336 case 'FirstPhotoDate':
337 case 'LastPhotoDate':
338 if ( $val ===
null ) {
345 if ( $val ===
'0000:00:00 00:00:00' || $val ===
' : : : : ' ) {
346 $val = $this->
msg(
'exif-unknowndate' )->text();
350 '/^(?:\d{4}):(?:\d\d):(?:\d\d) (?:\d\d):(?:\d\d):(?:\d\d)$/D',
355 if ( $time && (
int)$time > 0 ) {
359 } elseif ( preg_match(
'/^(?:\d{4}):(?:\d\d):(?:\d\d) (?:\d\d):(?:\d\d)$/D', $val ) ) {
364 if ( $time && (
int)$time > 0 ) {
368 } elseif ( preg_match(
'/^(?:\d{4}):(?:\d\d):(?:\d\d)$/D', $val ) ) {
371 . substr( $val, 5, 2 )
372 . substr( $val, 8, 2 )
374 if ( $time && (
int)$time > 0 ) {
383 case 'ExposureProgram':
394 $val = $this->exifMsg( $tag, $val );
403 case 'SubjectDistance':
404 $val = $this->exifMsg( $tag,
'', $this->formatNum( $val ) );
418 $val = $this->exifMsg( $tag, $val );
450 $val = $this->exifMsg( $tag, $val );
464 'fired' => $val & 0b00000001,
465 'return' => ( $val & 0b00000110 ) >> 1,
466 'mode' => ( $val & 0b00011000 ) >> 3,
467 'function' => ( $val & 0b00100000 ) >> 5,
468 'redeye' => ( $val & 0b01000000 ) >> 6,
472 # We do not need to handle unknown values since all are used.
473 foreach ( $flashDecode as $subTag => $subValue ) {
474 # We do not need any message for zeroed values.
475 if ( $subTag !==
'fired' && $subValue === 0 ) {
478 $fullTag = $tag .
'-' . $subTag;
479 $flashMsgs[] = $this->exifMsg( $fullTag, $subValue );
481 $val = $this->
getLanguage()->commaList( $flashMsgs );
484 case 'FocalPlaneResolutionUnit':
487 $val = $this->exifMsg( $tag, $val );
496 case 'SensingMethod':
505 $val = $this->exifMsg( $tag, $val );
517 $val = $this->exifMsg( $tag, $val );
529 $val = $this->exifMsg( $tag, $val );
538 case 'CustomRendered':
550 $val = $this->exifMsg( $tag, $val );
564 $val = $this->exifMsg( $tag, $val );
576 $val = $this->exifMsg( $tag, $val );
585 case 'SceneCaptureType':
591 $val = $this->exifMsg( $tag, $val );
607 $val = $this->exifMsg( $tag, $val );
621 $val = $this->exifMsg( $tag, $val );
635 $val = $this->exifMsg( $tag, $val );
649 $val = $this->exifMsg( $tag, $val );
658 case 'SubjectDistanceRange':
664 $val = $this->exifMsg( $tag, $val );
674 case 'GPSLatitudeRef':
675 case 'GPSDestLatitudeRef':
679 $val = $this->exifMsg(
'GPSLatitude', $val );
688 case 'GPSLongitudeRef':
689 case 'GPSDestLongitudeRef':
693 $val = $this->exifMsg(
'GPSLongitude', $val );
704 $val = $this->exifMsg(
'GPSAltitude',
'below-sealevel', $this->formatNum( -$val, 3 ) );
706 $val = $this->exifMsg(
'GPSAltitude',
'above-sealevel', $this->formatNum( $val, 3 ) );
714 $val = $this->exifMsg( $tag, $val );
723 case 'GPSMeasureMode':
727 $val = $this->exifMsg( $tag, $val );
737 case 'GPSImgDirectionRef':
738 case 'GPSDestBearingRef':
742 $val = $this->exifMsg(
'GPSDirection', $val );
752 case 'GPSDestLatitude':
753 $val = $this->formatCoords( $val,
'latitude' );
756 case 'GPSDestLongitude':
757 $val = $this->formatCoords( $val,
'longitude' );
765 $val = $this->exifMsg(
'GPSSpeed', $val );
774 case 'GPSDestDistanceRef':
779 $val = $this->exifMsg(
'GPSDestDistance', $val );
791 $val = $this->exifMsg( $tag,
'excellent', $this->formatNum( $val ) );
792 } elseif ( $val <= 5 ) {
793 $val = $this->exifMsg( $tag,
'good', $this->formatNum( $val ) );
794 } elseif ( $val <= 10 ) {
795 $val = $this->exifMsg( $tag,
'moderate', $this->formatNum( $val ) );
796 } elseif ( $val <= 20 ) {
797 $val = $this->exifMsg( $tag,
'fair', $this->formatNum( $val ) );
799 $val = $this->exifMsg( $tag,
'poor', $this->formatNum( $val ) );
808 $val = $this->exifMsg( $tag,
'', $this->
literal( $val ) );
812 if ( is_array( $val ) ) {
813 if ( count( $val ) > 1 ) {
816 'exif-software-version-value',
822 $val = $this->exifMsg( $tag,
'', $this->
literal( $val[0] ) );
825 $val = $this->exifMsg( $tag,
'', $this->
literal( $val ) );
831 $val = $this->
msg(
'exif-exposuretime-format',
832 $this->formatFraction( $val ), $this->formatNum( $val ) )->text();
834 case 'ISOSpeedRatings':
838 if ( $val ===
'65535' ) {
839 $val = $this->exifMsg( $tag,
'overflow' );
841 $val = $this->formatNum( $val );
845 $val = $this->
msg(
'exif-fnumber-format',
846 $this->formatNum( $val ) )->text();
850 case 'FocalLengthIn35mmFilm':
851 $val = $this->
msg(
'exif-focallength-format',
852 $this->formatNum( $val ) )->text();
855 case 'MaxApertureValue':
856 if ( str_contains( $val,
'/' ) ) {
858 [ $n, $d ] = explode(
'/', $val, 2 );
859 if ( is_numeric( $n ) && is_numeric( $d ) ) {
860 $val = (int)$n / (
int)$d;
863 if ( is_numeric( $val ) ) {
864 $fNumber = 2 ** ( $val / 2 );
865 if ( is_finite( $fNumber ) ) {
866 $val = $this->
msg(
'exif-maxaperturevalue-value',
867 $this->formatNum( $val ),
868 $this->formatNum( $fNumber, 2 )
877 switch ( strtolower( $val ) ) {
897 $val = $this->exifMsg(
906 case 'SubjectNewsCode':
912 $val = $this->convertNewsCode( $val );
918 if ( $val === 0 || $val === 9 ) {
920 } elseif ( $val < 5 && $val > 1 ) {
922 } elseif ( $val === 5 ) {
924 } elseif ( $val <= 8 && $val > 5 ) {
928 if ( $urgency !==
'' ) {
929 $val = $this->exifMsg(
'urgency',
930 $urgency, $this->
literal( $val )
936 case 'DigitalSourceType':
939 if ( str_starts_with( $val,
'http://cv.iptc.org/newscodes/digitalsourcetype/' ) ) {
940 $code = substr( $val, 47 );
941 $msg = $this->
msg(
'exif-digitalsourcetype-' . strtolower( $code ) );
942 if ( !$msg->isDisabled() ) {
950 case 'OriginalImageHeight':
951 case 'OriginalImageWidth':
952 case 'PixelXDimension':
953 case 'PixelYDimension':
956 $val = $this->formatNum( $val ) .
' ' . $this->
msg(
'unit-pixel' )->text();
966 case 'ImageDescription':
970 case 'RelatedSoundFile':
971 case 'ImageUniqueID':
972 case 'SpectralSensitivity':
973 case 'GPSSatellites':
977 case 'WorldRegionDest':
979 case 'CountryCodeDest':
980 case 'ProvinceOrStateDest':
982 case 'SublocationDest':
983 case 'WorldRegionCreated':
984 case 'CountryCreated':
985 case 'CountryCodeCreated':
986 case 'ProvinceOrStateCreated':
988 case 'SublocationCreated':
990 case 'SpecialInstructions':
995 case 'FixtureIdentifier':
997 case 'LocationDestCode':
999 case 'JPEGFileComment':
1000 case 'iimSupplementalCategory':
1001 case 'OriginalTransmissionRef':
1003 case 'dc-contributor':
1005 case 'dc-publisher':
1011 case 'SerialNumber':
1012 case 'CameraOwnerName':
1015 case 'RightsCertificate':
1016 case 'CopyrightOwner':
1018 case 'WebStatement':
1019 case 'OriginalDocumentID':
1021 case 'MorePermissionsUrl':
1022 case 'AttributionUrl':
1023 case 'PreferredAttributionName':
1024 case 'PNGFileComment':
1026 case 'ContentWarning':
1027 case 'GIFFileComment':
1029 case 'IntellectualGenre':
1031 case 'OrganisationInImage':
1032 case 'PersonInImage':
1033 case 'CaptureSoftware':
1034 case 'GPSAreaInformation':
1035 case 'GPSProcessingMethod':
1036 case 'StitchingSoftware':
1038 case 'SubSecTimeOriginal':
1039 case 'SubSecTimeDigitized':
1040 $val = $this->
literal( $val );
1043 case 'ProjectionType':
1045 case 'equirectangular':
1046 $val = $this->exifMsg( $tag, $val );
1049 $val = $this->
literal( $val );
1058 $val = $this->exifMsg( $tag, $val );
1061 $val = $this->
literal( $val );
1066 case 'UsePanoramaViewer':
1067 case 'ExposureLockUsed':
1071 $val = $this->exifMsg( $tag, $val );
1074 $val = $this->
literal( $val );
1079 if ( $val ===
'-1' ) {
1080 $val = $this->exifMsg( $tag,
'rejected' );
1082 $val = $this->formatNum( $val );
1086 case 'LanguageCode':
1087 $lang = MediaWikiServices::getInstance()
1088 ->getLanguageNameUtils()
1089 ->getLanguageName( strtolower( $val ), $this->
getLanguage()->getCode() );
1090 $val = $this->
literal( $lang ?: $val );
1094 $val = $this->formatNum( $val,
false, $tag );