Index: branches/img_metadata/phase3/maintenance/language/messages.inc |
— | — | @@ -2584,6 +2584,8 @@ |
2585 | 2585 | 'metadata-expand', |
2586 | 2586 | 'metadata-collapse', |
2587 | 2587 | 'metadata-fields', |
| 2588 | + 'metadata-langitem', |
| 2589 | + 'metadata-langitem-default', |
2588 | 2590 | ), |
2589 | 2591 | 'exif' => array( |
2590 | 2592 | 'exif-imagewidth', |
Index: branches/img_metadata/phase3/maintenance/language/messageTypes.inc |
— | — | @@ -364,6 +364,8 @@ |
365 | 365 | 'usermessage-template', |
366 | 366 | 'revisionmove-backlink', |
367 | 367 | 'filepage.css', |
| 368 | + 'metadata-langitem', |
| 369 | + 'metadata-langitem-default', |
368 | 370 | ); |
369 | 371 | |
370 | 372 | /** EXIF messages, which may be set as optional in several checks, but are generally mandatory */ |
Index: branches/img_metadata/phase3/skins/common/shared.css |
— | — | @@ -750,7 +750,7 @@ |
751 | 751 | font-size: 0.8em; |
752 | 752 | margin-left: 0.5em; |
753 | 753 | margin-bottom: 0.5em; |
754 | | - width: 300px; |
| 754 | + width: 400px; |
755 | 755 | } |
756 | 756 | |
757 | 757 | table.mw_metadata caption { |
— | — | @@ -773,8 +773,8 @@ |
774 | 774 | table.mw_metadata td, table.mw_metadata th { |
775 | 775 | text-align: center; |
776 | 776 | border: 1px solid #aaaaaa; |
777 | | - padding-left: 0.1em; |
778 | | - padding-right: 0.1em; |
| 777 | + padding-left: 5px; |
| 778 | + padding-right: 5px; |
779 | 779 | } |
780 | 780 | |
781 | 781 | table.mw_metadata th { |
— | — | @@ -785,6 +785,14 @@ |
786 | 786 | background-color: #fcfcfc; |
787 | 787 | } |
788 | 788 | |
| 789 | +table.mw_metadata ul.metadata-langlist { |
| 790 | + list-style-type: none; |
| 791 | + list-style-image: none; |
| 792 | + padding-right: 5px; |
| 793 | + padding-left: 5px; |
| 794 | + margin: 0; |
| 795 | +} |
| 796 | + |
789 | 797 | /* Galleries */ |
790 | 798 | table.gallery { |
791 | 799 | border: 1px solid #ccc; |
Index: branches/img_metadata/phase3/includes/media/FormatMetadata.php |
— | — | @@ -738,21 +738,61 @@ |
739 | 739 | else { |
740 | 740 | switch( $type ) { |
741 | 741 | case 'lang': |
742 | | - // fixme incomplete |
743 | | - // should place x-default, content language, user language |
744 | | - // first. then the others, hidden by defualt. |
745 | | - // also should use much better markup. |
746 | | - $content = ""; |
747 | | - if ( $vals['x-default'] ) { |
748 | | - $content .= "\n*" . $vals['x-default']; |
| 742 | + global $wgContLang; |
| 743 | + // Display default, followed by ContLang, |
| 744 | + // followed by the rest in no paticular |
| 745 | + // order. |
| 746 | + |
| 747 | + // Todo: hide some items if really long list. |
| 748 | + |
| 749 | + $content = ''; |
| 750 | + |
| 751 | + $cLang = $wgContLang->getCode(); |
| 752 | + $default = false; |
| 753 | + $defaultLang = false; |
| 754 | + |
| 755 | + // If default is set, save it for later, |
| 756 | + // as we don't know if it's equal to |
| 757 | + // one of the lang codes. (In xmp |
| 758 | + // you specify the language for a |
| 759 | + // default property by having both |
| 760 | + // a default prop, and one in the language |
| 761 | + // that are identical) |
| 762 | + if ( isset( $vals['x-default'] ) ) { |
| 763 | + $defaultItem = $vals['x-default']; |
749 | 764 | unset( $vals['x-default'] ); |
750 | 765 | } |
| 766 | + // Do contentLanguage. |
| 767 | + if ( isset( $vals[$cLang] ) ) { |
| 768 | + $isDefault = false; |
| 769 | + if ( $vals[$cLang] === $defaultItem ) { |
| 770 | + $defaultItem = false; |
| 771 | + $isDefault = true; |
| 772 | + } |
| 773 | + $content .= self::langItem( |
| 774 | + $vals[$cLang], $cLang, |
| 775 | + $isDefault ); |
| 776 | + |
| 777 | + unset( $vals[$cLang] ); |
| 778 | + } |
| 779 | + |
| 780 | + // Now do the rest. |
751 | 781 | foreach ( $vals as $lang => $item ) { |
752 | | - global $wgContLang; |
753 | | - $content .= "\n*<span lang=\"$lang\">" |
754 | | - . "'''$lang''' $item</span>"; |
| 782 | + if ( $item === $defaultItem ) { |
| 783 | + $defaultLang = $lang; |
| 784 | + continue; |
| 785 | + } |
| 786 | + $content .= self::langItem( $item, |
| 787 | + $lang ); |
755 | 788 | } |
756 | | - return $content; |
| 789 | + if ( $defaultItem !== false ) { |
| 790 | + $content = self::langItem( $defaultItem, |
| 791 | + $defaultLang, true ) |
| 792 | + . $content; |
| 793 | + } |
| 794 | + return '<ul class="metadata-langlist">' . |
| 795 | + $content . |
| 796 | + '</ul>'; |
757 | 797 | case 'ol': |
758 | 798 | return "<ol><li>" . implode( "</li>\n<li>", $vals ) . '</li></ol>'; |
759 | 799 | case 'ul': |
— | — | @@ -761,6 +801,53 @@ |
762 | 802 | } |
763 | 803 | } |
764 | 804 | } |
| 805 | + /** Helper function for creating lists of translations. |
| 806 | + * |
| 807 | + * @param $value String value (this is not escaped) |
| 808 | + * @param $lang String lang code of item or false |
| 809 | + * @param $default if it is default value. |
| 810 | + * @return language item (Note: despite how this looks, |
| 811 | + * this is treated as wikitext not html). |
| 812 | + */ |
| 813 | + private static function langItem( $value, $lang, $default = false ) { |
| 814 | + global $wgContLang; |
| 815 | + if ( $lang === false && $default === false) { |
| 816 | + throw new MWException('$lang and $default cannot both ' |
| 817 | + . 'be false.'); |
| 818 | + } |
| 819 | + |
| 820 | + $wrappedValue = '<span class="mw-metadata-lang-value">' |
| 821 | + . $value . '</span>'; |
| 822 | + |
| 823 | + if ( $lang === false ) { |
| 824 | + return '<li class="mw-metadata-lang-default">' |
| 825 | + . wfMsg( 'metadata-langitem-default', |
| 826 | + $wrappedValue ) |
| 827 | + . "</li>\n"; |
| 828 | + } |
| 829 | + $langName = $wgContLang->getLanguageName( strtolower( $lang ) ); |
| 830 | + if ( $langName === '' ) { |
| 831 | + //try just the base language name. (aka en-US -> en ). |
| 832 | + list( $langPrefix ) = explode( '-', strtolower( $lang ), |
| 833 | + 2 ); |
| 834 | + $langName = $wgContLang->getLanguageName( $langPrefix ); |
| 835 | + if ( $langName === '' ) { |
| 836 | + // give up. |
| 837 | + $langName = $lang; |
| 838 | + } |
| 839 | + } |
| 840 | + // else we have a language specified |
| 841 | + $item = '<li class="mw-metadata-lang-code-' |
| 842 | + . $lang; |
| 843 | + if ( $default ) { |
| 844 | + $item .= ' mw-metadata-lang-default'; |
| 845 | + } |
| 846 | + $item .= '" lang="' . $lang . '">'; |
| 847 | + $item .= wfMsg( 'metadata-langitem', |
| 848 | + $wrappedValue, $langName, $lang ); |
| 849 | + $item .= "</li>\n"; |
| 850 | + return $item; |
| 851 | + } |
765 | 852 | /** |
766 | 853 | * Convenience function for getFormattedData() |
767 | 854 | * |
Index: branches/img_metadata/phase3/includes/media/IPTC.php |
— | — | @@ -278,6 +278,7 @@ |
279 | 279 | case '2#070': |
280 | 280 | case '2#060': |
281 | 281 | case '2#063': |
| 282 | + case '2#085': |
282 | 283 | //ignore. Handled elsewhere. |
283 | 284 | break; |
284 | 285 | |
Index: branches/img_metadata/phase3/includes/media/XMP.php |
— | — | @@ -11,9 +11,12 @@ |
12 | 12 | * feature. If it comes across properties it doesn't recognize, it should |
13 | 13 | * ignore them. |
14 | 14 | * |
15 | | -* The main methods one would call in this class are |
| 15 | +* The public methods one would call in this class are |
16 | 16 | * - parse( $content ) |
17 | 17 | * Reads in xmp content. |
| 18 | +* Can potentially be called multiple times with partial data each time. |
| 19 | +* - parseExtended( $content ) |
| 20 | +* Reads XMPExtended blocks (jpeg files only). |
18 | 21 | * - getResults |
19 | 22 | * Outputs a results array. |
20 | 23 | * |
— | — | @@ -111,15 +114,29 @@ |
112 | 115 | xml_parser_free( $this->xmlParser ); |
113 | 116 | } |
114 | 117 | |
115 | | - /** Get the result array |
| 118 | + /** Get the result array. Do some post-processing before returning |
| 119 | + * the array. |
| 120 | + * |
116 | 121 | * @return Array array of results as an array of arrays suitable for |
117 | | - * FormatExif. |
| 122 | + * FormatMetadata::getFormattedData(). |
118 | 123 | */ |
119 | 124 | public function getResults() { |
120 | 125 | // xmp-special is for metadata that affects how stuff |
121 | | - // is extracted. For example xmpNote:HasExtendedXMP |
122 | | - unset( $this->results['xmp-special'] ); |
123 | | - return $this->results; |
| 126 | + // is extracted. For example xmpNote:HasExtendedXMP. |
| 127 | + $data = $this->results; |
| 128 | + unset( $data['xmp-special'] ); |
| 129 | + |
| 130 | + // Convert GPSAltitude to negative if below sea level. |
| 131 | + if ( isset( $data['xmp-exif']['GPSAltitudeRef'] ) ) { |
| 132 | + if ( $data['xmp-exif']['GPSAltitudeRef'] == '1' |
| 133 | + && isset( $data['xmp-exif']['GPSAltitude'] ) |
| 134 | + ) { |
| 135 | + $data['xmp-exif']['GPSAltitude'] *= -1; |
| 136 | + } |
| 137 | + unset( $data['xmp-exif']['GPSAltitudeRef'] ); |
| 138 | + } |
| 139 | + |
| 140 | + return $data; |
124 | 141 | } |
125 | 142 | |
126 | 143 | /** |
— | — | @@ -293,11 +310,7 @@ |
294 | 311 | if ( $this->charContent === false ) { |
295 | 312 | $this->charContent = $data; |
296 | 313 | } else { |
297 | | - // I don't think this should happen, |
298 | | - // but just in case. |
299 | 314 | $this->charContent .= $data; |
300 | | - // FIXME |
301 | | - wfDebugLog( 'XMP', 'XMP: Consecuitive CDATA' ); |
302 | 315 | } |
303 | 316 | |
304 | 317 | } |
Index: branches/img_metadata/phase3/includes/media/XMPValidate.php |
— | — | @@ -254,5 +254,55 @@ |
255 | 255 | } |
256 | 256 | |
257 | 257 | } |
| 258 | + /** function to validate, and more importantly |
| 259 | + * translate the XMP DMS form of gps coords to |
| 260 | + * the decimal form we use. |
| 261 | + * |
| 262 | + * @see http://www.adobe.com/devnet/xmp/pdfs/XMPSpecificationPart2.pdf |
| 263 | + * section 1.2.7.4 on page 23 |
| 264 | + * |
| 265 | + * @param $info Array unused (info about prop) |
| 266 | + * @param &$val String GPS string in either DDD,MM,SSk or |
| 267 | + * or DDD,MM.mmk form |
| 268 | + * @param $standalone Boolean if its a simple prop (should always be true) |
| 269 | + */ |
| 270 | + public static function validateGPS ( $info, &$val, $standalone ) { |
| 271 | + if ( !$standalone ) { |
| 272 | + return; |
| 273 | + } |
258 | 274 | |
| 275 | + $m = array(); |
| 276 | + if ( preg_match( |
| 277 | + '/(\d{1,3}),(\d{1,2}),(\d{1,2})([NWSE])/D', |
| 278 | + $val, $m ) |
| 279 | + ) { |
| 280 | + $coord = intval( $m[1] ); |
| 281 | + $coord += intval( $m[2] ) * (1/60); |
| 282 | + $coord += intval( $m[3] ) * (1/3600); |
| 283 | + if ( $m[4] === 'S' || $m[4] === 'W' ) { |
| 284 | + $coord = -$coord; |
| 285 | + } |
| 286 | + $val = $coord; |
| 287 | + return; |
| 288 | + } elseif ( preg_match( |
| 289 | + '/(\d{1,3}),(\d{1,2}(?:.\d*)?)([NWSE])/D', |
| 290 | + $val, $m ) |
| 291 | + ) { |
| 292 | + $coord = intval( $m[1] ); |
| 293 | + $coord += floatval( $m[2] ) * (1/60); |
| 294 | + if ( $m[3] === 'S' || $m[3] === 'W' ) { |
| 295 | + $coord = -$coord; |
| 296 | + } |
| 297 | + $val = $coord; |
| 298 | + return; |
| 299 | + |
| 300 | + } else { |
| 301 | + wfDebugLog( 'XMP', __METHOD__ |
| 302 | + . " Expected GPSCoordinate, but got $val." ); |
| 303 | + $val = null; |
| 304 | + return; |
| 305 | + } |
| 306 | + |
| 307 | + } |
| 308 | + |
259 | 309 | } |
Index: branches/img_metadata/phase3/includes/media/XMPInfo.php |
— | — | @@ -95,7 +95,11 @@ |
96 | 96 | 'mode' => XMPReader::MODE_SIMPLE, |
97 | 97 | 'validate' => 'validateRational' |
98 | 98 | ), |
99 | | - /* FIXME GPSAltitude */ |
| 99 | + 'GPSAltitude' => array( |
| 100 | + 'map_group' => 'exif', |
| 101 | + 'mode' => XMPReader::MODE_SIMPLE, |
| 102 | + 'validate' => 'validateRational', |
| 103 | + ), |
100 | 104 | 'GPSDestBearing' => array( |
101 | 105 | 'map_group' => 'exif', |
102 | 106 | 'mode' => XMPReader::MODE_SIMPLE, |
Index: branches/img_metadata/phase3/includes/media/Jpeg.php |
— | — | @@ -58,7 +58,7 @@ |
59 | 59 | |
60 | 60 | foreach ( $metadata as &$val ) { |
61 | 61 | if ( is_array( $val ) ) { |
62 | | - $val = formatExif::flattenArray( $val ); |
| 62 | + $val = FormatMetadata::flattenArray( $val ); |
63 | 63 | } |
64 | 64 | } |
65 | 65 | $metadata['MEDIAWIKI_EXIF_VERSION'] = 1; |
Index: branches/img_metadata/phase3/languages/messages/MessagesQqq.php |
— | — | @@ -3099,6 +3099,10 @@ |
3100 | 3100 | {{Identical|Metadata}}', |
3101 | 3101 | 'metadata-expand' => 'On an image description page, there is mostly a table containing data (metadata) about the image. The most important data are shown, but if you click on this link, you can see more data and information. For the link to hide back the less important data, see "[[MediaWiki:Metadata-collapse/{{SUBPAGENAME}}|{{int:metadata-collapse}}]]".', |
3102 | 3102 | 'metadata-collapse' => 'On an image description page, there is mostly a table containing data (metadata) about the image. The most important data are shown, but if you click on the link "[[MediaWiki:Metadata-expand/{{SUBPAGENAME}}|{{int:metadata-expand}}]]", you can see more data and information. This message is for the link to hide back the less important data.', |
| 3103 | +'metadata-langitem' => 'This is used for constructing the list of translations when a metadata property is translated into multiple languages. |
| 3104 | + |
| 3105 | +$1 is the value of the property (in one language), $2 is the language name that this translation is for (or language code if language name cannot be determined), $3 is the language code.', |
| 3106 | +'metadata-langitem-default' => 'Similar to "metadata-langitem" but for the case where a multilingual property has a default specified that does not specify what language the default is in. $1 is the value of the property. ', |
3103 | 3107 | 'metadata-fields' => "'''Warning:''' Do not translate list items, only translate the text! So leave \"<tt>* make</tt>\" and the other items exactly as they are. |
3104 | 3108 | |
3105 | 3109 | The sentences are for explanation only and are not shown to the user.", |
Index: branches/img_metadata/phase3/languages/messages/MessagesEn.php |
— | — | @@ -3634,12 +3634,14 @@ |
3635 | 3635 | 'variantname-tg' => 'tg', # only translate this message to other languages if you have to change it |
3636 | 3636 | |
3637 | 3637 | # Metadata |
3638 | | -'metadata' => 'Metadata', |
3639 | | -'metadata-help' => 'This file contains additional information, probably added from the digital camera or scanner used to create or digitize it. |
| 3638 | +'metadata' => 'Metadata', |
| 3639 | +'metadata-help' => 'This file contains additional information, probably added from the digital camera or scanner used to create or digitize it. |
3640 | 3640 | If the file has been modified from its original state, some details may not fully reflect the modified file.', |
3641 | | -'metadata-expand' => 'Show extended details', |
3642 | | -'metadata-collapse' => 'Hide extended details', |
3643 | | -'metadata-fields' => 'EXIF metadata fields listed in this message will be included on image page display when the metadata table is collapsed. |
| 3641 | +'metadata-expand' => 'Show extended details', |
| 3642 | +'metadata-collapse' => 'Hide extended details', |
| 3643 | +'metadata-langitem' => '\'\'\'$2:\'\'\' $1', |
| 3644 | +'metadata-langitem-default' => '$1', |
| 3645 | +'metadata-fields' => 'EXIF metadata fields listed in this message will be included on image page display when the metadata table is collapsed. |
3644 | 3646 | Others will be hidden by default. |
3645 | 3647 | * make |
3646 | 3648 | * model |