111 $resolutionunit = !isset( $tags[
'ResolutionUnit'] ) || $tags[
'ResolutionUnit'] == 2 ? 2 : 3;
112 unset( $tags[
'ResolutionUnit'] );
115 unset( $tags[
'HasExtendedXMP'] );
116 unset( $tags[
'AuthorsPosition'] );
117 unset( $tags[
'LocationCreated'] );
118 unset( $tags[
'LocationShown'] );
119 unset( $tags[
'GPSAltitudeRef'] );
121 foreach ( $tags as $tag => &$vals ) {
124 if ( !is_array( $vals ) ) {
129 if ( isset( $vals[
'_type'] ) ) {
130 $type = $vals[
'_type'];
131 unset( $vals[
'_type'] );
138 if ( isset( $tags[$tag][
'_formatted'] ) ) {
140 $tags[$tag][
'_formatted'], $type
146 if ( $tag ===
'GPSTimeStamp' && count( $vals ) === 3 ) {
149 $h = explode(
'/', $vals[0], 2 );
150 $m = explode(
'/', $vals[1], 2 );
151 $s = explode(
'/', $vals[2], 2 );
166 $vals = str_pad( (
string)( (
int)$h[0] / (
int)$h[1] ), 2,
'0', STR_PAD_LEFT )
167 .
':' . str_pad( (
string)( (
int)$m[0] / (
int)$m[1] ), 2,
'0', STR_PAD_LEFT )
168 .
':' . str_pad( (
string)( (
int)$s[0] / (
int)$s[1] ), 2,
'0', STR_PAD_LEFT );
170 $time =
wfTimestamp( TS_MW,
'1971:01:01 ' . $vals );
172 if ( $time && (
int)$time > 0 ) {
181 if ( $tag ===
'Contact' || $tag ===
'CreatorContactInfo' ) {
186 foreach ( $vals as &$val ) {
201 $val = $this->exifMsg( $tag, $val );
210 case 'PhotometricInterpretation':
224 $val = $this->exifMsg( $tag, $val );
243 $val = $this->exifMsg( $tag, $val );
252 case 'PlanarConfiguration':
256 $val = $this->exifMsg( $tag, $val );
266 case 'YCbCrPositioning':
270 $val = $this->exifMsg( $tag, $val );
281 switch ( $resolutionunit ) {
283 $val = $this->exifMsg(
'XYResolution',
'i', $this->formatNum( $val ) );
286 $val = $this->exifMsg(
'XYResolution',
'c', $this->formatNum( $val ) );
302 case 'FlashPixVersion':
305 case 'FlashpixVersion':
306 $val = $this->
literal( (
int)$val / 100 );
313 $val = $this->exifMsg( $tag, $val );
322 case 'ComponentsConfiguration':
331 $val = $this->exifMsg( $tag, $val );
341 case 'DateTimeOriginal':
342 case 'DateTimeDigitized':
343 case 'DateTimeReleased':
344 case 'DateTimeExpires':
347 case 'DateTimeMetadata':
348 case 'FirstPhotoDate':
349 case 'LastPhotoDate':
350 if ( $val ===
null ) {
357 if ( $val ===
'0000:00:00 00:00:00' || $val ===
' : : : : ' ) {
358 $val = $this->
msg(
'exif-unknowndate' )->text();
362 '/^(?:\d{4}):(?:\d\d):(?:\d\d) (?:\d\d):(?:\d\d):(?:\d\d)$/D',
367 if ( $time && (
int)$time > 0 ) {
371 } elseif ( preg_match(
'/^(?:\d{4}):(?:\d\d):(?:\d\d) (?:\d\d):(?:\d\d)$/D', $val ) ) {
376 if ( $time && (
int)$time > 0 ) {
380 } elseif ( preg_match(
'/^(?:\d{4}):(?:\d\d):(?:\d\d)$/D', $val ) ) {
383 . substr( $val, 5, 2 )
384 . substr( $val, 8, 2 )
386 if ( $time && (
int)$time > 0 ) {
395 case 'ExposureProgram':
406 $val = $this->exifMsg( $tag, $val );
415 case 'SubjectDistance':
416 $val = $this->exifMsg( $tag,
'', $this->formatNum( $val ) );
430 $val = $this->exifMsg( $tag, $val );
462 $val = $this->exifMsg( $tag, $val );
476 'fired' => $val & 0b00000001,
477 'return' => ( $val & 0b00000110 ) >> 1,
478 'mode' => ( $val & 0b00011000 ) >> 3,
479 'function' => ( $val & 0b00100000 ) >> 5,
480 'redeye' => ( $val & 0b01000000 ) >> 6,
484 # We do not need to handle unknown values since all are used.
485 foreach ( $flashDecode as $subTag => $subValue ) {
486 # We do not need any message for zeroed values.
487 if ( $subTag !==
'fired' && $subValue === 0 ) {
490 $fullTag = $tag .
'-' . $subTag;
491 $flashMsgs[] = $this->exifMsg( $fullTag, $subValue );
493 $val = $this->
getLanguage()->commaList( $flashMsgs );
496 case 'FocalPlaneResolutionUnit':
499 $val = $this->exifMsg( $tag, $val );
508 case 'SensingMethod':
517 $val = $this->exifMsg( $tag, $val );
529 $val = $this->exifMsg( $tag, $val );
541 $val = $this->exifMsg( $tag, $val );
550 case 'CustomRendered':
562 $val = $this->exifMsg( $tag, $val );
576 $val = $this->exifMsg( $tag, $val );
588 $val = $this->exifMsg( $tag, $val );
597 case 'SceneCaptureType':
603 $val = $this->exifMsg( $tag, $val );
619 $val = $this->exifMsg( $tag, $val );
633 $val = $this->exifMsg( $tag, $val );
647 $val = $this->exifMsg( $tag, $val );
661 $val = $this->exifMsg( $tag, $val );
670 case 'SubjectDistanceRange':
676 $val = $this->exifMsg( $tag, $val );
686 case 'GPSLatitudeRef':
687 case 'GPSDestLatitudeRef':
691 $val = $this->exifMsg(
'GPSLatitude', $val );
700 case 'GPSLongitudeRef':
701 case 'GPSDestLongitudeRef':
705 $val = $this->exifMsg(
'GPSLongitude', $val );
716 $val = $this->exifMsg(
'GPSAltitude',
'below-sealevel', $this->formatNum( -$val, 3 ) );
718 $val = $this->exifMsg(
'GPSAltitude',
'above-sealevel', $this->formatNum( $val, 3 ) );
726 $val = $this->exifMsg( $tag, $val );
735 case 'GPSMeasureMode':
739 $val = $this->exifMsg( $tag, $val );
749 case 'GPSImgDirectionRef':
750 case 'GPSDestBearingRef':
754 $val = $this->exifMsg(
'GPSDirection', $val );
764 case 'GPSDestLatitude':
765 $val = $this->formatCoords( $val,
'latitude' );
768 case 'GPSDestLongitude':
769 $val = $this->formatCoords( $val,
'longitude' );
777 $val = $this->exifMsg(
'GPSSpeed', $val );
786 case 'GPSDestDistanceRef':
791 $val = $this->exifMsg(
'GPSDestDistance', $val );
803 $val = $this->exifMsg( $tag,
'excellent', $this->formatNum( $val ) );
804 } elseif ( $val <= 5 ) {
805 $val = $this->exifMsg( $tag,
'good', $this->formatNum( $val ) );
806 } elseif ( $val <= 10 ) {
807 $val = $this->exifMsg( $tag,
'moderate', $this->formatNum( $val ) );
808 } elseif ( $val <= 20 ) {
809 $val = $this->exifMsg( $tag,
'fair', $this->formatNum( $val ) );
811 $val = $this->exifMsg( $tag,
'poor', $this->formatNum( $val ) );
820 $val = $this->exifMsg( $tag,
'', $this->
literal( $val ) );
824 if ( is_array( $val ) ) {
825 if ( count( $val ) > 1 ) {
828 'exif-software-version-value',
834 $val = $this->exifMsg( $tag,
'', $this->
literal( $val[0] ) );
837 $val = $this->exifMsg( $tag,
'', $this->
literal( $val ) );
843 $val = $this->
msg(
'exif-exposuretime-format',
844 $this->formatFraction( $val ), $this->formatNum( $val ) )->text();
846 case 'ISOSpeedRatings':
850 if ( $val ===
'65535' ) {
851 $val = $this->exifMsg( $tag,
'overflow' );
853 $val = $this->formatNum( $val );
857 $val = $this->
msg(
'exif-fnumber-format',
858 $this->formatNum( $val ) )->text();
862 case 'FocalLengthIn35mmFilm':
863 $val = $this->
msg(
'exif-focallength-format',
864 $this->formatNum( $val ) )->text();
867 case 'MaxApertureValue':
868 if ( strpos( $val,
'/' ) !==
false ) {
870 [ $n, $d ] = explode(
'/', $val, 2 );
871 if ( is_numeric( $n ) && is_numeric( $d ) ) {
872 $val = (int)$n / (
int)$d;
875 if ( is_numeric( $val ) ) {
876 $fNumber = 2 ** ( $val / 2 );
877 if ( is_finite( $fNumber ) ) {
878 $val = $this->
msg(
'exif-maxaperturevalue-value',
879 $this->formatNum( $val ),
880 $this->formatNum( $fNumber, 2 )
889 switch ( strtolower( $val ) ) {
909 $val = $this->exifMsg(
918 case 'SubjectNewsCode':
924 $val = $this->convertNewsCode( $val );
930 if ( $val === 0 || $val === 9 ) {
932 } elseif ( $val < 5 && $val > 1 ) {
934 } elseif ( $val === 5 ) {
936 } elseif ( $val <= 8 && $val > 5 ) {
940 if ( $urgency !==
'' ) {
941 $val = $this->exifMsg(
'urgency',
942 $urgency, $this->
literal( $val )
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 );