This should be my last commit of unit tests for the media metadata stuff (hopefully).
greyscale-na-png.png, rgb-png.png, Xmp-exif-multilingual_test.jpg
greyscale-png.png, 1bit-png.png, Png-native-test.png, rgb-na-png.png,
test.tiff, test.jpg, jpeg-comment-multiple.jpg, jpeg-comment-utf.jpg,
-jpeg-comment-iso8859-1.jpg, jpeg-comment-binary.jpg
+jpeg-comment-iso8859-1.jpg, jpeg-comment-binary.jpg, jpeg-xmp-psir.jpg,
+jpeg-xmp-alt.jpg, animated.gif, exif-user-comment.jpg, animated-xmp.gif,
+iptc-timetest-invalid.jpg, jpeg-iptc-bad-hash.jpg, iptc-timetest.jpg,
+xmp.png, nonanimated.gif, exif-gps.jpg, jpeg-xmp-psir.xmp, jpeg-iptc-good-hash.jpg
Are all by Bawolff. I don't think they contain enough originality to
claim copyright, but on the off chance they do, feel free to use them
however you feel fit, without restriction.
--- /dev/null
+<?xpacket begin='' id='W5M0MpCehiHzreSzNTczkc9d'?>
+<x:xmpmeta xmlns:x='adobe:ns:meta/' x:xmptk='Image::ExifTool 7.30'>
+<rdf:RDF xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'>
+
+ <rdf:Description rdf:about=''
+ xmlns:dc='http://purl.org/dc/elements/1.1/'>
+ <dc:identifier>jpeg-xmp-psir.jpg</dc:identifier>
+ </rdf:Description>
+</rdf:RDF>
+</x:xmpmeta>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<?xpacket end='w'?>
\ No newline at end of file
--- /dev/null
+<?php
+
+$result = array( 'xmp-exif' =>
+ array(
+ 'DigitalZoomRatio' => '0/10',
+ 'Flash' => '9'
+ )
+);
--- /dev/null
+<?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?> <x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core
+ 4.1.3-c001 49.282696, Mon Apr 02 2007 21:16:10 ">
+<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+<rdf:Description
+ rdf:about=""
+ xmlns:exif="http://ns.adobe.com/exif/1.0/"
+ exif:DigitalZoomRatio="0/10">
+<exif:Flash rdf:parseType='Resource'>
+<exif:Fired>True</exif:Fired> <exif:Return>0</exif:Return> <exif:Mode>1</exif:Mode> <exif:Function>False</exif:Function> <exif:RedEyeMode>False</exif:RedEyeMode></exif:Flash> </rdf:Description> </rdf:RDF> </x:xmpmeta>
+
+<?xpacket end="w"?>
--- /dev/null
+<?php
+
+$result = array( 'xmp-exif' =>
+ array(
+ 'DigitalZoomRatio' => '0/10',
+ 'Flash' => '9'
+ )
+);
--- /dev/null
+<?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?> <x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core
+ 4.1.3-c001 49.282696, Mon Apr 02 2007 21:16:10 ">
+<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+<rdf:Description
+ rdf:about=""
+ xmlns:exif="http://ns.adobe.com/exif/1.0/"
+ exif:DigitalZoomRatio="0/10">
+<exif:Flash>
+<rdf:Description exif:Return="0">
+<exif:Fired>True</exif:Fired> <exif:Mode>1</exif:Mode> <exif:Function>False</exif:Function> <exif:RedEyeMode>False</exif:RedEyeMode></rdf:Description></exif:Flash> </rdf:Description> </rdf:RDF> </x:xmpmeta>
+
+<?xpacket end="w"?>
--- /dev/null
+<?php
+
+$result = array( 'xmp-exif' =>
+ array(
+ 'DigitalZoomRatio' => '0/10',
+ )
+);
--- /dev/null
+<?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?> <x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core
+ 4.1.3-c001 49.282696, Mon Apr 02 2007 21:16:10 ">
+<!--
+This file has an invalid flash compoenent (one of the values are a qualifier)
+-->
+<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+<rdf:Description
+ rdf:about=""
+ xmlns:exif="http://ns.adobe.com/exif/1.0/"
+>
+<exif:DigitalZoomRatio>
+
+<rdf:Description>
+<rdf:value>
+0/10
+</rdf:value>
+<exif:foobarbaz>fred</exif:foobarbaz>
+
+</rdf:Description>
+
+</exif:DigitalZoomRatio>
+
+<exif:Flash>
+<rdf:Description exif:Return="0">
+<exif:Mode><rdf:Description>
+<rdf:value>1</rdf:value>
+<exif:Fired>False</exif:Fired> <!-- qualifier. should be ignored-->
+</rdf:Description>
+</exif:Mode> <exif:Function>False</exif:Function> <exif:RedEyeMode>False</exif:RedEyeMode></rdf:Description></exif:Flash> </rdf:Description> </rdf:RDF> </x:xmpmeta>
+
+<?xpacket end="w"?>
--- /dev/null
+<?php
+
+$result = array( 'xmp-exif' =>
+ array(
+ 'DigitalZoomRatio' => '0/10',
+ 'Flash' => '9'
+ )
+);
--- /dev/null
+<?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?> <x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core
+ 4.1.3-c001 49.282696, Mon Apr 02 2007 21:16:10 ">
+<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+<rdf:Description
+ rdf:about=""
+ xmlns:exif="http://ns.adobe.com/exif/1.0/"
+>
+<exif:DigitalZoomRatio>
+
+<rdf:Description>
+<rdf:value>
+0/10
+</rdf:value>
+<exif:foobarbaz>fred</exif:foobarbaz>
+
+</rdf:Description>
+
+</exif:DigitalZoomRatio>
+
+<exif:Flash>
+<rdf:Description exif:Return="0">
+<exif:Fired>True</exif:Fired>
+<exif:Mode><rdf:Description>
+<rdf:value>1</rdf:value>
+<exif:Fired>False</exif:Fired> <!-- qualifier. should be ignored-->
+</rdf:Description>
+</exif:Mode> <exif:Function>False</exif:Function> <exif:RedEyeMode>False</exif:RedEyeMode></rdf:Description></exif:Flash> </rdf:Description> </rdf:RDF> </x:xmpmeta>
+
+<?xpacket end="w"?>
--- /dev/null
+<?php
+
+$result = array( 'xmp-exif' =>
+ array(
+ 'DigitalZoomRatio' => '0/10',
+ )
+);
--- /dev/null
+<?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?> <x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core
+ 4.1.3-c001 49.282696, Mon Apr 02 2007 21:16:10 ">
+<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+<!-- Valid output is just the DigitalZoomRatio
+as the flash is a qualifier
+-->
+<rdf:Description
+ rdf:about=""
+ xmlns:exif="http://ns.adobe.com/exif/1.0/">
+ <exif:DigitalZoomRatio>
+<rdf:Description>
+<rdf:value>
+0/10
+</rdf:value>
+<exif:Flash rdf:parseType='Resource'>
+<exif:Fired>True</exif:Fired> <exif:Return>0</exif:Return> <exif:Mode>1</exif:Mode> <exif:Function>False</exif:Function> <exif:RedEyeMode>False</exif:RedEyeMode></exif:Flash>
+</rdf:Description>
+</exif:DigitalZoomRatio>
+</rdf:Description> </rdf:RDF> </x:xmpmeta>
+
+
+<?xpacket end="w"?>
--- /dev/null
+<?php
+
+$result = array( 'xmp-exif' =>
+ array(
+ 'DigitalZoomRatio' => '0/10',
+ )
+);
--- /dev/null
+<?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?> <x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core
+ 4.1.3-c001 49.282696, Mon Apr 02 2007 21:16:10 ">
+<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+<rdf:Description
+ rdf:about=""
+ xmlns:exif="http://ns.adobe.com/exif/1.0/">
+ <exif:DigitalZoomRatio>
+<rdf:Description rdf:value="0/10">
+<exif:Flash rdf:parseType='Resource'>
+<exif:Fired>True</exif:Fired> <exif:Return>0</exif:Return> <exif:Mode>1</exif:Mode> <exif:Function>False</exif:Function> <exif:RedEyeMode>False</exif:RedEyeMode></exif:Flash>
+</rdf:Description>
+</exif:DigitalZoomRatio>
+</rdf:Description> </rdf:RDF> </x:xmpmeta>
+
+
+<?xpacket end="w"?>
--- /dev/null
+<?php
+
+$result = array( 'xmp-exif' =>
+ array(
+ 'DigitalZoomRatio' => '0/10',
+ 'Flash' => '9'
+ )
+);
--- /dev/null
+<?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?> <x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core
+ 4.1.3-c001 49.282696, Mon Apr 02 2007 21:16:10 ">
+<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+<rdf:Description
+ rdf:about=""
+ xmlns:exif="http://ns.adobe.com/exif/1.0/">
+<exif:DigitalZoomRatio>
+0/10
+</exif:DigitalZoomRatio>
+</rdf:Description>
+<rdf:Description
+ rdf:about=""
+ xmlns:exif="http://ns.adobe.com/exif/1.0/">
+
+<exif:Flash rdf:parseType='Resource'>
+<exif:Fired>True</exif:Fired> <exif:Return>0</exif:Return> <exif:Mode>1</exif:Mode> <exif:Function>False</exif:Function> <exif:RedEyeMode>False</exif:RedEyeMode></exif:Flash> </rdf:Description> </rdf:RDF> </x:xmpmeta>
+
+<?xpacket end="w"?>
--- /dev/null
+<?php
+$result = array (
+ 'xmp-exif' =>
+ array (
+ 'CameraOwnerName' => 'Me!',
+ ),
+ 'xmp-general' =>
+ array (
+ 'LicenseUrl' => 'http://creativecommons.com/cc-by-2.9',
+ 'ImageDescription' =>
+ array (
+ 'x-default' => 'Test image for the cc: xmp: xmpRights: namespaces in xmp',
+ '_type' => 'lang',
+ ),
+ 'ObjectName' =>
+ array (
+ 'x-default' => 'xmp core/xmp rights/cc ns test',
+ '_type' => 'lang',
+ ),
+ 'DateTimeDigitized' => '2005:04:03',
+ 'Software' => 'The one true editor: Vi (ok i used gimp)',
+ 'Identifier' =>
+ array (
+ 0 => 'http://example.com/identifierurl',
+ 1 => 'urn:sha1:342524abcdef',
+ '_type' => 'ul',
+ ),
+ 'Label' => 'Test image',
+ 'DateTimeMetadata' => '2011:05:12',
+ 'DateTime' => '2007:03:04 06:34:10',
+ 'Nickname' => 'My little xmp test image',
+ 'Rating' => '5',
+ 'RightsCertificate' => 'http://example.com/rights-certificate/',
+ 'Copyrighted' => 'True',
+ 'CopyrightOwner' =>
+ array (
+ 0 => 'Bawolff is copyright owner',
+ '_type' => 'ul',
+ ),
+ 'UsageTerms' =>
+ array (
+ 'x-default' => 'do whatever you want',
+ 'en-gb' => 'Do whatever you want in british english',
+ '_type' => 'lang',
+ ),
+ 'WebStatement' => 'http://example.com/web_statement',
+ ),
+ 'xmp-deprecated' =>
+ array (
+ 'Identifier' => 'http://example.com/identifierurl/wrong',
+ ),
+);
--- /dev/null
+<?xpacket begin='' id='W5M0MpCehiHzreSzNTczkc9d'?>
+<x:xmpmeta xmlns:x='adobe:ns:meta/' x:xmptk='Image::ExifTool 7.30'>
+<rdf:RDF xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'>
+
+ <rdf:Description rdf:about=''
+ xmlns:aux='http://ns.adobe.com/exif/1.0/aux/'>
+ <aux:OwnerName>Me!</aux:OwnerName>
+ </rdf:Description>
+
+ <rdf:Description rdf:about=''
+ xmlns:cc='http://creativecommons.org/ns#'>
+ <cc:license>http://creativecommons.com/cc-by-2.9</cc:license>
+ </rdf:Description>
+
+ <rdf:Description rdf:about=''
+ xmlns:dc='http://purl.org/dc/elements/1.1/'>
+ <dc:description>
+ <rdf:Alt>
+ <rdf:li xml:lang='x-default'>Test image for the cc: xmp: xmpRights: namespaces in xmp</rdf:li>
+ </rdf:Alt>
+ </dc:description>
+ <dc:identifier>http://example.com/identifierurl/wrong</dc:identifier>
+ <dc:title>
+ <rdf:Alt>
+ <rdf:li xml:lang='x-default'>xmp core/xmp rights/cc ns test</rdf:li>
+ </rdf:Alt>
+ </dc:title>
+ </rdf:Description>
+
+ <rdf:Description rdf:about=''
+ xmlns:xmp='http://ns.adobe.com/xap/1.0/'>
+ <xmp:CreateDate>2005-04-03</xmp:CreateDate>
+ <xmp:CreatorTool>The one true editor: Vi (ok i used gimp)</xmp:CreatorTool>
+ <xmp:Identifier>
+ <rdf:Bag>
+ <rdf:li>http://example.com/identifierurl
+</rdf:li>
+ <rdf:li>urn:sha1:342524abcdef</rdf:li>
+ </rdf:Bag>
+ </xmp:Identifier>
+ <xmp:Label>Test image</xmp:Label>
+ <xmp:MetadataDate>2011-05-12</xmp:MetadataDate>
+ <xmp:ModifyDate>2007-03-04T12:34:10-06:00</xmp:ModifyDate>
+ <xmp:Nickname>My little xmp test image</xmp:Nickname>
+ <xmp:Rating>7</xmp:Rating>
+ </rdf:Description>
+
+ <rdf:Description rdf:about=''
+ xmlns:xmpRights='http://ns.adobe.com/xap/1.0/rights/'>
+ <xmpRights:Certificate>http://example.com/rights-certificate/</xmpRights:Certificate>
+ <xmpRights:Marked>True</xmpRights:Marked>
+ <xmpRights:Owner>
+ <rdf:Bag>
+ <rdf:li>Bawolff is copyright owner</rdf:li>
+ </rdf:Bag>
+ </xmpRights:Owner>
+ <xmpRights:UsageTerms>
+ <rdf:Alt>
+ <rdf:li xml:lang='x-default'>do whatever you want</rdf:li>
+ <rdf:li xml:lang='en-GB'>Do whatever you want in british english</rdf:li>
+ </rdf:Alt>
+ </xmpRights:UsageTerms>
+ <xmpRights:WebStatement>http://example.com/web_statement</xmpRights:WebStatement>
+ </rdf:Description>
+</rdf:RDF>
+</x:xmpmeta>
+<?xpacket end='r'?>
--- /dev/null
+This directory contains a bunch of XMP files
+as well as a bunch of php files containing what the
+parsed version of the XMP looks like.
--- /dev/null
+<?php
+
+$result = array(
+ 'xmp-general' => array(
+ 'Artist' => array(
+ '_type' => 'ul',
+ 0 => 'The author',
+ )
+ )
+);
--- /dev/null
+<?xpacket begin=""?> <x:xmpmeta xmlns:x="adobe:ns:meta/"> <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> <rdf:Description rdf:about="" xmlns:dc="http://purl.org/dc/elements/1.1/"> <dc:creator> <rdf:Bag> <rdf:li>The author</rdf:li> </rdf:Bag> </dc:creator> </rdf:Description> </rdf:RDF> </x:xmpmeta>
--- /dev/null
+<?php
+
+$result = array( 'xmp-exif' =>
+ array(
+ 'DigitalZoomRatio' => '0/10',
+ 'Flash' => '127'
+ )
+);
--- /dev/null
+<?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?> <x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core
+ 4.1.3-c001 49.282696, Mon Apr 02 2007 21:16:10 ">
+<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+<rdf:Description
+ rdf:about=""
+ xmlns:exif="http://ns.adobe.com/exif/1.0/"
+ exif:DigitalZoomRatio="0/10">
+<exif:Flash rdf:parseType='Resource'>
+<exif:Fired>True</exif:Fired> <exif:Return>3</exif:Return> <exif:Mode>3</exif:Mode> <exif:Function>True</exif:Function> <exif:RedEyeMode>True</exif:RedEyeMode></exif:Flash> </rdf:Description> </rdf:RDF> </x:xmpmeta>
+
+<?xpacket end="w"?>
--- /dev/null
+<?php
+
+$result = array( 'xmp-exif' =>
+ array(
+ 'DigitalZoomRatio' => '0/10',
+ )
+);
--- /dev/null
+<?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?> <x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core
+ 4.1.3-c001 49.282696, Mon Apr 02 2007 21:16:10 ">
+<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+<rdf:Description
+ rdf:about=""
+ xmlns:exif="http://ns.adobe.com/exif/1.0/"
+ exif:DigitalZoomRatio="0/10">
+<exif:Fired>True</exif:Fired> <exif:Return>0</exif:Return> <exif:Mode>1</exif:Mode> <exif:Function>False</exif:Function> <exif:RedEyeMode>False</exif:RedEyeMode>
+
+ </rdf:Description> </rdf:RDF> </x:xmpmeta>
+
+<?xpacket end="w"?>
--- /dev/null
+<?php
+
+$result = array( 'xmp-exif' =>
+ array(
+ 'FNumber' => '28/10',
+ )
+);
--- /dev/null
+<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+<!-- Testing it handles random non-namespaced properties in files ok.
+ Some older photoshop's did not include the rdf: prefix on about. -->
+<rdf:Description
+ about=""
+ rdf:about=""
+ xmlns:exif="http://ns.adobe.com/exif/1.0/"
+ exif:FNumber="28/10">
+</rdf:Description>
+</rdf:RDF>
+<?xpacket end="w"?>
--- /dev/null
+<?php
+$result = array();
--- /dev/null
+<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+<rdf:Description
+ rdf:about=""
+ xmlns:exif="http://ns.adobe.com/exif/1.0/not-exif-namespace"
+ exif:FNumber="2/10">
+</rdf:Description>
+</rdf:RDF>
+<?xpacket end="w"?>
--- /dev/null
+<?php
+
+$result = array(
+ 'xmp-exif' =>
+ array(
+ 'DigitalZoomRatio' => '0/10',
+ ),
+ 'xmp-general' =>
+ array(
+ 'Label' => ''
+ ),
+);
--- /dev/null
+<?php
+
+$result = array(
+ 'xmp-exif' =>
+ array(
+ 'DigitalZoomRatio' => '0/10',
+ ),
+ 'xmp-general' =>
+ array(
+ 'Label' => ''
+ ),
+);
--- /dev/null
+<?php
+
+$result = array(
+ 'xmp-exif' =>
+ array(
+ 'DigitalZoomRatio' => '0/10',
+ ),
+ 'xmp-general' =>
+ array(
+ 'Label' => ''
+ ),
+);
--- /dev/null
+<?php
+
+$result = array(
+ 'xmp-exif' =>
+ array(
+ 'DigitalZoomRatio' => '0/10',
+ ),
+ 'xmp-general' =>
+ array(
+ 'Label' => ''
+ ),
+);
--- /dev/null
+<?php
+
+$result = array( 'xmp-exif' =>
+ array(
+ 'DigitalZoomRatio' => '0/10',
+ 'Flash' => '9'
+ )
+);
--- /dev/null
+<?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?> <x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core
+ 4.1.3-c001 49.282696, Mon Apr 02 2007 21:16:10 ">
+<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+<rdf:Description
+ rdf:about=""
+ xmlns:exif="http://ns.adobe.com/exif/1.0/"
+ xmlns:xmpNote="http://ns.adobe.com/xmp/note/"
+ exif:DigitalZoomRatio="0/10"
+ xmpNote:HasExtendedXMP="28C74E0AC2D796886759006FBE2E57B7">
+<exif:Flash rdf:parseType='Resource'>
+<exif:Fired>True</exif:Fired> <exif:Return>0</exif:Return> <exif:Mode>1</exif:Mode> <exif:Function>False</exif:Function> <exif:RedEyeMode>False</exif:RedEyeMode></exif:Flash> </rdf:Description> </rdf:RDF> </x:xmpmeta>
+
+<?xpacket end="w"?>
--- /dev/null
+<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+<rdf:Description
+ rdf:about=""
+ xmlns:exif="http://ns.adobe.com/exif/1.0/"
+ exif:FNumber="2/10">
+</rdf:Description>
+</rdf:RDF>
+<?xpacket end="w"?>
$this->assertEquals( 'UTF-8 JPEG Comment — ¼',
$meta['JPEGFileComment'][0] );
}
+
+ public function testIPTCDates() {
+ $meta = BitmapMetadataHandler::Jpeg( $this->filePath .
+ 'iptc-timetest.jpg' );
+
+ $this->assertEquals( '2020:07:14 01:36:05', $meta['DateTimeDigitized'] );
+ $this->assertEquals( '1997:03:02 00:01:02', $meta['DateTimeOriginal'] );
+ }
+ /* File has an invalid time (+ one valid but really weird time)
+ * that shouldn't be included
+ */
+ public function testIPTCDatesInvalid() {
+ $meta = BitmapMetadataHandler::Jpeg( $this->filePath .
+ 'iptc-timetest-invalid.jpg' );
+
+ $this->assertEquals( '1845:03:02 00:01:02', $meta['DateTimeOriginal'] );
+ $this->assertFalse( isset( $meta['DateTimeDigitized'] ) );
+ }
+
+ /**
+ * XMP data should take priority over iptc data
+ * when hash has been updated, but not when
+ * the hash is wrong.
+ */
+ public function testMerging() {
+ $merger = new BitmapMetadataHandler();
+ $merger->addMetadata( array( 'foo' => 'xmp' ), 'xmp-general' );
+ $merger->addMetadata( array( 'bar' => 'xmp' ), 'xmp-general' );
+ $merger->addMetadata( array( 'baz' => 'xmp' ), 'xmp-general' );
+ $merger->addMetadata( array( 'fred' => 'xmp' ), 'xmp-general' );
+ $merger->addMetadata( array( 'foo' => 'iptc (hash)' ), 'iptc-good-hash' );
+ $merger->addMetadata( array( 'bar' => 'iptc (bad hash)' ), 'iptc-bad-hash' );
+ $merger->addMetadata( array( 'baz' => 'iptc (bad hash)' ), 'iptc-bad-hash' );
+ $merger->addMetadata( array( 'fred' => 'iptc (no hash)' ), 'iptc-no-hash' );
+ $merger->addMetadata( array( 'baz' => 'exif' ), 'exif' );
+
+ $actual = $merger->getMetadataArray();
+ $expected = array(
+ 'foo' => 'xmp',
+ 'bar' => 'iptc (bad hash)',
+ 'baz' => 'exif',
+ 'fred' => 'xmp',
+ );
+ $this->assertEquals( $expected, $actual );
+ }
+
+ public function testPNGXMP() {
+ $handler = new BitmapMetadataHandler();
+ $result = $handler->png( $this->filePath . 'xmp.png' );
+ $expected = array (
+ 'frameCount' => 0,
+ 'loopCount' => 1,
+ 'duration' => 0,
+ 'bitDepth' => 1,
+ 'colorType' => 'index-coloured',
+ 'metadata' => array (
+ 'SerialNumber' => '123456789',
+ '_MW_PNG_VERSION' => 1,
+ ),
+ );
+ $this->assertEquals( $expected, $result );
+ }
+ public function testPNGNative() {
+ $handler = new BitmapMetadataHandler();
+ $result = $handler->png( $this->filePath . 'Png-native-test.png' );
+ $expected = 'http://example.com/url';
+ $this->assertEquals( $expected, $result['metadata']['Identifier']['x-default'] );
+ }
+ public function testTiffByteOrder() {
+ $handler = new BitmapMetadataHandler();
+ $res = $handler->getTiffByteOrder( $this->filePath . 'test.tiff' );
+ $this->assertEquals( 'LE', $res );
+ }
+
}
global $wgShowEXIF;
$this->showExif = $wgShowEXIF;
$wgShowEXIF = true;
+ $this->handler = new ExifBitmapHandler;
}
public function tearDown() {
if ( !wfDl( 'exif' ) ) {
$this->markTestIncomplete( "This test needs the exif extension." );
}
- $handler = new ExifBitmapHandler;
- $res = $handler->isMetadataValid( null, ExifBitmapHandler::OLD_BROKEN_FILE );
+ $res = $this->handler->isMetadataValid( null, ExifBitmapHandler::OLD_BROKEN_FILE );
$this->assertEquals( ExifBitmapHandler::METADATA_COMPATIBLE, $res );
}
public function testIsBrokenFile() {
if ( !wfDl( 'exif' ) ) {
$this->markTestIncomplete( "This test needs the exif extension." );
}
- $handler = new ExifBitmapHandler;
- $res = $handler->isMetadataValid( null, ExifBitmapHandler::BROKEN_FILE );
+ $res = $this->handler->isMetadataValid( null, ExifBitmapHandler::BROKEN_FILE );
$this->assertEquals( ExifBitmapHandler::METADATA_GOOD, $res );
}
public function testIsInvalid() {
if ( !wfDl( 'exif' ) ) {
$this->markTestIncomplete( "This test needs the exif extension." );
}
- $handler = new ExifBitmapHandler;
- $res = $handler->isMetadataValid( null, 'Something Invalid Here.' );
+ $res = $this->handler->isMetadataValid( null, 'Something Invalid Here.' );
$this->assertEquals( ExifBitmapHandler::METADATA_BAD, $res );
}
public function testGoodMetadata() {
if ( !wfDl( 'exif' ) ) {
$this->markTestIncomplete( "This test needs the exif extension." );
}
- $handler = new ExifBitmapHandler;
$meta = 'a:16:{s:10:"ImageWidth";i:20;s:11:"ImageLength";i:20;s:13:"BitsPerSample";a:3:{i:0;i:8;i:1;i:8;i:2;i:8;}s:11:"Compression";i:5;s:25:"PhotometricInterpretation";i:2;s:16:"ImageDescription";s:17:"Created with GIMP";s:12:"StripOffsets";i:8;s:11:"Orientation";i:1;s:15:"SamplesPerPixel";i:3;s:12:"RowsPerStrip";i:64;s:15:"StripByteCounts";i:238;s:11:"XResolution";s:19:"1207959552/16777216";s:11:"YResolution";s:19:"1207959552/16777216";s:19:"PlanarConfiguration";i:1;s:14:"ResolutionUnit";i:2;s:22:"MEDIAWIKI_EXIF_VERSION";i:2;}';
- $res = $handler->isMetadataValid( null, $meta );
+ $res = $this->handler->isMetadataValid( null, $meta );
$this->assertEquals( ExifBitmapHandler::METADATA_GOOD, $res );
}
public function testIsOldGood() {
if ( !wfDl( 'exif' ) ) {
$this->markTestIncomplete( "This test needs the exif extension." );
}
- $handler = new ExifBitmapHandler;
$meta = 'a:16:{s:10:"ImageWidth";i:20;s:11:"ImageLength";i:20;s:13:"BitsPerSample";a:3:{i:0;i:8;i:1;i:8;i:2;i:8;}s:11:"Compression";i:5;s:25:"PhotometricInterpretation";i:2;s:16:"ImageDescription";s:17:"Created with GIMP";s:12:"StripOffsets";i:8;s:11:"Orientation";i:1;s:15:"SamplesPerPixel";i:3;s:12:"RowsPerStrip";i:64;s:15:"StripByteCounts";i:238;s:11:"XResolution";s:19:"1207959552/16777216";s:11:"YResolution";s:19:"1207959552/16777216";s:19:"PlanarConfiguration";i:1;s:14:"ResolutionUnit";i:2;s:22:"MEDIAWIKI_EXIF_VERSION";i:1;}';
- $res = $handler->isMetadataValid( null, $meta );
+ $res = $this->handler->isMetadataValid( null, $meta );
$this->assertEquals( ExifBitmapHandler::METADATA_COMPATIBLE, $res );
}
// Handle metadata from paged tiff handler (gotten via instant commons)
if ( !wfDl( 'exif' ) ) {
$this->markTestIncomplete( "This test needs the exif extension." );
}
- $handler = new ExifBitmapHandler;
$meta = 'a:6:{s:9:"page_data";a:1:{i:1;a:5:{s:5:"width";i:643;s:6:"height";i:448;s:5:"alpha";s:4:"true";s:4:"page";i:1;s:6:"pixels";i:288064;}}s:10:"page_count";i:1;s:10:"first_page";i:1;s:9:"last_page";i:1;s:4:"exif";a:9:{s:10:"ImageWidth";i:643;s:11:"ImageLength";i:448;s:11:"Compression";i:5;s:25:"PhotometricInterpretation";i:2;s:11:"Orientation";i:1;s:15:"SamplesPerPixel";i:4;s:12:"RowsPerStrip";i:50;s:19:"PlanarConfiguration";i:1;s:22:"MEDIAWIKI_EXIF_VERSION";i:1;}s:21:"TIFF_METADATA_VERSION";s:3:"1.4";}';
- $res = $handler->isMetadataValid( null, $meta );
+ $res = $this->handler->isMetadataValid( null, $meta );
$this->assertEquals( ExifBitmapHandler::METADATA_BAD, $res );
}
+
+ function testConvertMetadataLatest() {
+ $metadata = array(
+ 'foo' => array( 'First', 'Second', '_type' => 'ol' ),
+ 'MEDIAWIKI_EXIF_VERSION' => 2
+ );
+ $res = $this->handler->convertMetadataVersion( $metadata, 2 );
+ $this->assertEquals( $metadata, $res );
+ }
+ function testConvertMetadataToOld() {
+ $metadata = array(
+ 'foo' => array( 'First', 'Second', '_type' => 'ol' ),
+ 'bar' => array( 'First', 'Second', '_type' => 'ul' ),
+ 'baz' => array( 'First', 'Second' ),
+ 'fred' => 'Single',
+ 'MEDIAWIKI_EXIF_VERSION' => 2,
+ );
+ $expected = array(
+ 'foo' => "\n#First\n#Second",
+ 'bar' => "\n*First\n*Second",
+ 'baz' => "\n*First\n*Second",
+ 'fred' => 'Single',
+ 'MEDIAWIKI_EXIF_VERSION' => 1,
+ );
+ $res = $this->handler->convertMetadataVersion( $metadata, 1 );
+ $this->assertEquals( $expected, $res );
+ }
+ function testConvertMetadataSoftware() {
+ $metadata = array(
+ 'Software' => array( array('GIMP', '1.1' ) ),
+ 'MEDIAWIKI_EXIF_VERSION' => 2,
+ );
+ $expected = array(
+ 'Software' => 'GIMP (Version 1.1)',
+ 'MEDIAWIKI_EXIF_VERSION' => 1,
+ );
+ $res = $this->handler->convertMetadataVersion( $metadata, 1 );
+ $this->assertEquals( $expected, $res );
+ }
+ function testConvertMetadataSoftwareNormal() {
+ $metadata = array(
+ 'Software' => array( "GIMP 1.2", "vim" ),
+ 'MEDIAWIKI_EXIF_VERSION' => 2,
+ );
+ $expected = array(
+ 'Software' => "\n*GIMP 1.2\n*vim",
+ 'MEDIAWIKI_EXIF_VERSION' => 1,
+ );
+ $res = $this->handler->convertMetadataVersion( $metadata, 1 );
+ $this->assertEquals( $expected, $res );
+ }
}
--- /dev/null
+<?php
+class ExifTest extends MediaWikiTestCase {
+
+ public function setUp() {
+ $this->mediaPath = dirname( __FILE__ ) . '/../../data/media/';
+
+ global $wgShowEXIF;
+ $this->showExif = $wgShowEXIF;
+ $wgShowEXIF = true;
+ }
+ public function tearDown() {
+ global $wgShowEXIF;
+ $wgShowEXIF = $this->showExif;
+ }
+
+ public function testGPSExtraction() {
+ if ( !wfDl( 'exif' ) ) {
+ $this->markTestIncomplete( "This test needs the exif extension." );
+ }
+
+ $filename = $this->mediaPath . 'exif-gps.jpg';
+ $seg = JpegMetadataExtractor::segmentSplitter( $filename );
+ $exif = new Exif( $filename, $seg['byteOrder'] );
+ $data = $exif->getFilteredData();
+ $expected = array(
+ 'GPSLatitude' => 88.5180555556,
+ 'GPSLongitude' => -21.12357,
+ 'GPSAltitude' => -200,
+ 'GPSDOP' => '5/1',
+ 'GPSVersionID' => '2.2.0.0',
+ );
+ $this->assertEquals( $expected, $data, '', 0.0000000001 );
+ }
+ public function testUnicodeUserComment() {
+ if ( !wfDl( 'exif' ) ) {
+ $this->markTestIncomplete( "This test needs the exif extension." );
+ }
+
+ $filename = $this->mediaPath . 'exif-user-comment.jpg';
+ $seg = JpegMetadataExtractor::segmentSplitter( $filename );
+ $exif = new Exif( $filename, $seg['byteOrder'] );
+ $data = $exif->getFilteredData();
+
+ $expected = array(
+ 'UserComment' => 'test⁔comment'
+ );
+ $this->assertEquals( $expected, $data );
+ }
+
+
+}
--- /dev/null
+<?php
+class GIFMetadataExtractorTest extends MediaWikiTestCase {
+
+ public function setUp() {
+ $this->mediaPath = dirname( __FILE__ ) . '/../../data/media/';
+ }
+ /**
+ * Put in a file, and see if the metadata coming out is as expected.
+ * @param $filename String
+ * @param $expected Array The extracted metadata.
+ * @dataProvider dataGetMetadata
+ */
+ public function testGetMetadata( $filename, $expected ) {
+ $actual = GIFMetadataExtractor::getMetadata( $this->mediaPath . $filename );
+ $this->assertEquals( $expected, $actual );
+ }
+ public function dataGetMetadata() {
+
+ $xmpNugget = <<<EOF
+<?xpacket begin='' id='W5M0MpCehiHzreSzNTczkc9d'?>
+<x:xmpmeta xmlns:x='adobe:ns:meta/' x:xmptk='Image::ExifTool 7.30'>
+<rdf:RDF xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'>
+
+ <rdf:Description rdf:about=''
+ xmlns:Iptc4xmpCore='http://iptc.org/std/Iptc4xmpCore/1.0/xmlns/'>
+ <Iptc4xmpCore:Location>The interwebs</Iptc4xmpCore:Location>
+ </rdf:Description>
+
+ <rdf:Description rdf:about=''
+ xmlns:tiff='http://ns.adobe.com/tiff/1.0/'>
+ <tiff:Artist>Bawolff</tiff:Artist>
+ <tiff:ImageDescription>
+ <rdf:Alt>
+ <rdf:li xml:lang='x-default'>A file to test GIF</rdf:li>
+ </rdf:Alt>
+ </tiff:ImageDescription>
+ </rdf:Description>
+</rdf:RDF>
+</x:xmpmeta>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<?xpacket end='w'?>
+EOF;
+
+ return array(
+ array( 'nonanimated.gif', array(
+ 'comment' => array( 'GIF test file ⁕ Created with GIMP' ),
+ 'duration' => 0.1,
+ 'frameCount' => 1,
+ 'looped' => false,
+ 'xmp' => '',
+ )
+ ),
+ array( 'animated.gif', array(
+ 'comment' => array( 'GIF test file . Created with GIMP' ),
+ 'duration' => 2.4,
+ 'frameCount' => 4,
+ 'looped' => true,
+ 'xmp' => '',
+ )
+ ),
+
+ array( 'animated-xmp.gif', array(
+ 'xmp' => $xmpNugget,
+ 'duration' => 2.4,
+ 'frameCount' => 4,
+ 'looped' => true,
+ 'comment' => array( 'GIƒ·test·file' ),
+ )
+ ),
+ );
+ }
+}
--- /dev/null
+<?php
+class GIFHandlerTest extends MediaWikiTestCase {
+
+ public function setUp() {
+ $this->filePath = dirname( __FILE__ ) . '/../../data/media/';
+ $this->handler = new GIFHandler();
+ }
+
+ public function testInvalidFile() {
+ $res = $this->handler->getMetadata( null, $this->filePath . 'README' );
+ $this->assertEquals( GIFHandler::BROKEN_FILE, $res );
+ }
+ /**
+ * @param $filename String basename of the file to check
+ * @param $expected boolean Expected result.
+ * @dataProvider dataIsAnimated
+ */
+ public function testIsAnimanted( $filename, $expected ) {
+ $file = UnregisteredLocalFile::newFromPath( $this->filePath . $filename,
+ 'image/gif' );
+ $actual = $this->handler->isAnimatedImage( $file );
+ $this->assertEquals( $expected, $actual );
+ }
+ public function dataIsAnimated() {
+ return array(
+ array( 'animated.gif', true ),
+ array( 'nonanimated.gif', false ),
+ );
+ }
+
+ /**
+ * @param $filename String
+ * @param $expected Integer Total image area
+ * @dataProvider dataGetImageArea
+ */
+ public function testGetImageArea( $filename, $expected ) {
+ $file = UnregisteredLocalFile::newFromPath( $this->filePath . $filename,
+ 'image/gif' );
+ $actual = $this->handler->getImageArea( $file, $file->getWidth(), $file->getHeight() );
+ $this->assertEquals( $expected, $actual );
+ }
+ public function dataGetImageArea() {
+ return array(
+ array( 'animated.gif', 5400 ),
+ array( 'nonanimated.gif', 1350 ),
+ );
+ }
+
+ /**
+ * @param $metadata String Serialized metadata
+ * @param $expected Integer One of the class constants of GIFHandler
+ * @dataProvider dataIsMetadataValid
+ */
+ public function testIsMetadataValid( $metadata, $expected ) {
+ $actual = $this->handler->isMetadataValid( null, $metadata );
+ $this->assertEquals( $expected, $actual );
+ }
+ public function dataIsMetadataValid() {
+ return array(
+ array( GIFHandler::BROKEN_FILE, GIFHandler::METADATA_GOOD ),
+ array( '', GIFHandler::METADATA_BAD ),
+ array( null, GIFHandler::METADATA_BAD ),
+ array( 'Something invalid!', GIFHandler::METADATA_BAD ),
+ array( 'a:4:{s:10:"frameCount";i:1;s:6:"looped";b:0;s:8:"duration";d:0.1000000000000000055511151231257827021181583404541015625;s:8:"metadata";a:2:{s:14:"GIFFileComment";a:1:{i:0;s:35:"GIF test file ⁕ Created with GIMP";}s:15:"_MW_GIF_VERSION";i:1;}}', GIFHandler::METADATA_GOOD ),
+ );
+ }
+
+ /**
+ * @param $filename String
+ * @param $expected String Serialized array
+ * @dataProvider dataGetMetadata
+ */
+ public function testGetMetadata( $filename, $expected ) {
+ $file = UnregisteredLocalFile::newFromPath( $this->filePath . $filename,
+ 'image/gif' );
+ $actual = $this->handler->getMetadata( $file, $this->filePath . $filename );
+ $this->assertEquals( unserialize( $expected ), unserialize( $actual ) );
+ }
+ public function dataGetMetadata() {
+ return array(
+ array( 'nonanimated.gif', 'a:4:{s:10:"frameCount";i:1;s:6:"looped";b:0;s:8:"duration";d:0.1000000000000000055511151231257827021181583404541015625;s:8:"metadata";a:2:{s:14:"GIFFileComment";a:1:{i:0;s:35:"GIF test file ⁕ Created with GIMP";}s:15:"_MW_GIF_VERSION";i:1;}}' ),
+ array( 'animated-xmp.gif', 'a:4:{s:10:"frameCount";i:4;s:6:"looped";b:1;s:8:"duration";d:2.399999999999999911182158029987476766109466552734375;s:8:"metadata";a:5:{s:6:"Artist";s:7:"Bawolff";s:16:"ImageDescription";a:2:{s:9:"x-default";s:18:"A file to test GIF";s:5:"_type";s:4:"lang";}s:15:"SublocationDest";s:13:"The interwebs";s:14:"GIFFileComment";a:1:{i:0;s:16:"GIƒ·test·file";}s:15:"_MW_GIF_VERSION";i:1;}}' ),
+ );
+ }
+}
--- /dev/null
+<?php
+class IPTCTest extends MediaWikiTestCase {
+ public function testRecognizeUtf8() {
+ // utf-8 is the only one used in practise.
+ $res = IPTC::getCharset( "\x1b%G" );
+ $this->assertEquals( 'UTF-8', $res );
+ }
+
+ public function testIPTCParseNoCharset88591() {
+ // basically IPTC for keyword with value of 0xBC which is 1/4 in iso-8859-1
+ // This data doesn't specify a charset. We're supposed to guess
+ // (which basically means utf-8 if valid, windows 1252 (iso 8859-1) if not)
+ $iptcData = "Photoshop 3.0\08BIM\4\4\0\0\0\0\0\x06\x1c\x02\x19\x00\x01\xBC";
+ $res = IPTC::Parse( $iptcData );
+ $this->assertEquals( array( '¼' ), $res['Keywords'] );
+ }
+ /* This one contains a sequence that's valid iso 8859-1 but not valid utf8 */
+ /* \xC3 = Ã, \xB8 = ¸ */
+ public function testIPTCParseNoCharset88591b() {
+ $iptcData = "Photoshop 3.0\08BIM\4\4\0\0\0\0\0\x09\x1c\x02\x19\x00\x04\xC3\xC3\xC3\xB8";
+ $res = IPTC::Parse( $iptcData );
+ $this->assertEquals( array( 'ÃÃø' ), $res['Keywords'] );
+ }
+ /* Same as testIPTCParseNoCharset88591b, but forcing the charset to utf-8.
+ * What should happen is the first "\xC3\xC3" should be dropped as invalid,
+ * leaving \xC3\xB8, which is ø
+ */
+ public function testIPTCParseForcedUTFButInvalid() {
+ $iptcData = "Photoshop 3.0\08BIM\4\4\0\0\0\0\0\x11\x1c\x02\x19\x00\x04\xC3\xC3\xC3\xB8"
+ . "\x1c\x01\x5A\x00\x03\x1B\x25\x47";
+ $res = IPTC::Parse( $iptcData );
+ $this->assertEquals( array( 'ø' ), $res['Keywords'] );
+ }
+ public function testIPTCParseNoCharsetUTF8() {
+ $iptcData = "Photoshop 3.0\08BIM\4\4\0\0\0\0\0\x07\x1c\x02\x19\x00\x02¼";
+ $res = IPTC::Parse( $iptcData );
+ $this->assertEquals( array( '¼' ), $res['Keywords'] );
+ }
+ // Testing something that has 2 values for keyword
+ public function testIPTCParseMulti() {
+ $iptcData = /* identifier */ "Photoshop 3.0\08BIM\4\4"
+ /* length */ . "\0\0\0\0\0\x0D"
+ . "\x1c\x02\x19" . "\x00\x01" . "\xBC"
+ . "\x1c\x02\x19" . "\x00\x02" . "\xBC\xBD";
+ $res = IPTC::Parse( $iptcData );
+ $this->assertEquals( array( '¼', '¼½' ), $res['Keywords'] );
+ }
+ public function testIPTCParseUTF8() {
+ // This has the magic "\x1c\x01\x5A\x00\x03\x1B\x25\x47" which marks content as UTF8.
+ $iptcData = "Photoshop 3.0\08BIM\4\4\0\0\0\0\0\x0F\x1c\x02\x19\x00\x02¼\x1c\x01\x5A\x00\x03\x1B\x25\x47";
+ $res = IPTC::Parse( $iptcData );
+ $this->assertEquals( array( '¼' ), $res['Keywords'] );
+ }
+
+}
<?php
+/*
+ * @todo Could use a test of extended XMP segments. Hard to find programs that
+ * create example files, and creating my own in vim propbably wouldn't
+ * serve as a very good "test". (Adobe photoshop probably creates such files
+ * but it costs money). The implementation of it currently in MediaWiki is based
+ * solely on reading the standard, without any real world test files.
+ */
class JpegMetadataExtractorTest extends MediaWikiTestCase {
public function setUp() {
$res = JpegMetadataExtractor::segmentSplitter( $this->filePath . 'jpeg-comment-multiple.jpg' );
$this->assertEquals( array( 'foo', 'bar' ), $res['COM'] );
}
+ public function testXMPExtraction() {
+ $res = JpegMetadataExtractor::segmentSplitter( $this->filePath . 'jpeg-xmp-psir.jpg' );
+ $expected = file_get_contents( $this->filePath . 'jpeg-xmp-psir.xmp' );
+ $this->assertEquals( $expected, $res['XMP'] );
+ }
+ public function testPSIRExtraction() {
+ $res = JpegMetadataExtractor::segmentSplitter( $this->filePath . 'jpeg-xmp-psir.jpg' );
+ $expected = '50686f746f73686f7020332e30003842494d04040000000000181c02190004746573741c02190003666f6f1c020000020004';
+ $this->assertEquals( $expected, bin2hex( $res['PSIR'] ) );
+ }
+ public function testXMPExtractionAltAppId() {
+ $res = JpegMetadataExtractor::segmentSplitter( $this->filePath . 'jpeg-xmp-alt.jpg' );
+ $expected = file_get_contents( $this->filePath . 'jpeg-xmp-psir.xmp' );
+ $this->assertEquals( $expected, $res['XMP'] );
+ }
+
+
+ public function testIPTCHashComparisionNoHash() {
+ $segments = JpegMetadataExtractor::segmentSplitter( $this->filePath . 'jpeg-xmp-psir.jpg' );
+ $res = JpegMetadataExtractor::doPSIR( $segments['PSIR'] );
+
+ $this->assertEquals( 'iptc-no-hash', $res );
+ }
+ public function testIPTCHashComparisionBadHash() {
+ $segments = JpegMetadataExtractor::segmentSplitter( $this->filePath . 'jpeg-iptc-bad-hash.jpg' );
+ $res = JpegMetadataExtractor::doPSIR( $segments['PSIR'] );
+
+ $this->assertEquals( 'iptc-bad-hash', $res );
+ }
+ public function testIPTCHashComparisionGoodHash() {
+ $segments = JpegMetadataExtractor::segmentSplitter( $this->filePath . 'jpeg-iptc-good-hash.jpg' );
+ $res = JpegMetadataExtractor::doPSIR( $segments['PSIR'] );
+
+ $this->assertEquals( 'iptc-good-hash', $res );
+ }
+ public function testExifByteOrder() {
+ $res = JpegMetadataExtractor::segmentSplitter( $this->filePath . 'exif-user-comment.jpg' );
+ $expected = 'BE';
+ $this->assertEquals( $expected, $res['byteOrder'] );
+ }
}
$this->assertEquals( 'greyscale', $meta['colorType'] );
}
-
}
--- /dev/null
+<?php
+class PNGHandlerTest extends MediaWikiTestCase {
+
+ public function setUp() {
+ $this->filePath = dirname( __FILE__ ) . '/../../data/media/';
+ $this->handler = new PNGHandler();
+ }
+
+ public function testInvalidFile() {
+ $res = $this->handler->getMetadata( null, $this->filePath . 'README' );
+ $this->assertEquals( PNGHandler::BROKEN_FILE, $res );
+ }
+ /**
+ * @param $filename String basename of the file to check
+ * @param $expected boolean Expected result.
+ * @dataProvider dataIsAnimated
+ */
+ public function testIsAnimanted( $filename, $expected ) {
+ $file = UnregisteredLocalFile::newFromPath( $this->filePath . $filename,
+ 'image/png' );
+ $actual = $this->handler->isAnimatedImage( $file );
+ $this->assertEquals( $expected, $actual );
+ }
+ public function dataIsAnimated() {
+ return array(
+ array( 'Animated_PNG_example_bouncing_beach_ball.png', true ),
+ array( '1bit-png.png', false ),
+ );
+ }
+
+ /**
+ * @param $filename String
+ * @param $expected Integer Total image area
+ * @dataProvider dataGetImageArea
+ */
+ public function testGetImageArea( $filename, $expected ) {
+ $file = UnregisteredLocalFile::newFromPath( $this->filePath . $filename,
+ 'image/png' );
+ $actual = $this->handler->getImageArea( $file, $file->getWidth(), $file->getHeight() );
+ $this->assertEquals( $expected, $actual );
+ }
+ public function dataGetImageArea() {
+ return array(
+ array( '1bit-png.png', 2500 ),
+ array( 'greyscale-png.png', 2500 ),
+ array( 'Png-native-test.png', 126000 ),
+ array( 'Animated_PNG_example_bouncing_beach_ball.png', 10000 ),
+ );
+ }
+
+ /**
+ * @param $metadata String Serialized metadata
+ * @param $expected Integer One of the class constants of PNGHandler
+ * @dataProvider dataIsMetadataValid
+ */
+ public function testIsMetadataValid( $metadata, $expected ) {
+ $actual = $this->handler->isMetadataValid( null, $metadata );
+ $this->assertEquals( $expected, $actual );
+ }
+ public function dataIsMetadataValid() {
+ return array(
+ array( PNGHandler::BROKEN_FILE, PNGHandler::METADATA_GOOD ),
+ array( '', PNGHandler::METADATA_BAD ),
+ array( null, PNGHandler::METADATA_BAD ),
+ array( 'Something invalid!', PNGHandler::METADATA_BAD ),
+ array( 'a:6:{s:10:"frameCount";i:0;s:9:"loopCount";i:1;s:8:"duration";d:0;s:8:"bitDepth";i:8;s:9:"colorType";s:10:"truecolour";s:8:"metadata";a:1:{s:15:"_MW_PNG_VERSION";i:1;}}', PNGHandler::METADATA_GOOD ),
+ );
+ }
+
+ /**
+ * @param $filename String
+ * @param $expected String Serialized array
+ * @dataProvider dataGetMetadata
+ */
+ public function testGetMetadata( $filename, $expected ) {
+ $file = UnregisteredLocalFile::newFromPath( $this->filePath . $filename,
+ 'image/png' );
+ $actual = $this->handler->getMetadata( $file, $this->filePath . $filename );
+// $this->assertEquals( unserialize( $expected ), unserialize( $actual ) );
+ $this->assertEquals( ( $expected ), ( $actual ) );
+ }
+ public function dataGetMetadata() {
+ return array(
+ array( 'rgb-na-png.png', 'a:6:{s:10:"frameCount";i:0;s:9:"loopCount";i:1;s:8:"duration";d:0;s:8:"bitDepth";i:8;s:9:"colorType";s:10:"truecolour";s:8:"metadata";a:1:{s:15:"_MW_PNG_VERSION";i:1;}}' ),
+ array( 'xmp.png', 'a:6:{s:10:"frameCount";i:0;s:9:"loopCount";i:1;s:8:"duration";d:0;s:8:"bitDepth";i:1;s:9:"colorType";s:14:"index-coloured";s:8:"metadata";a:2:{s:12:"SerialNumber";s:9:"123456789";s:15:"_MW_PNG_VERSION";i:1;}}' ),
+ );
+ }
+}
$this->showExif = $wgShowEXIF;
$wgShowEXIF = true;
$this->filePath = dirname( __FILE__ ) . '/../../data/media/';
+ $this->handler = new TiffHandler;
}
public function tearDown() {
if ( !wfDl( 'exif' ) ) {
$this->markTestIncomplete( "This test needs the exif extension." );
}
- $tiff = new TiffHandler;
- $res = $tiff->getMetadata( null, $this->filePath . 'README' );
+ $res = $this->handler->getMetadata( null, $this->filePath . 'README' );
$this->assertEquals( ExifBitmapHandler::BROKEN_FILE, $res );
}
if ( !wfDl( 'exif' ) ) {
$this->markTestIncomplete( "This test needs the exif extension." );
}
- $tiff = new TiffHandler;
- $res = $tiff->getMetadata( null, $this->filePath . 'test.tiff' );
+ $res = $this->handler->getMetadata( null, $this->filePath . 'test.tiff' );
$expected = 'a:16:{s:10:"ImageWidth";i:20;s:11:"ImageLength";i:20;s:13:"BitsPerSample";a:3:{i:0;i:8;i:1;i:8;i:2;i:8;}s:11:"Compression";i:5;s:25:"PhotometricInterpretation";i:2;s:16:"ImageDescription";s:17:"Created with GIMP";s:12:"StripOffsets";i:8;s:11:"Orientation";i:1;s:15:"SamplesPerPixel";i:3;s:12:"RowsPerStrip";i:64;s:15:"StripByteCounts";i:238;s:11:"XResolution";s:19:"1207959552/16777216";s:11:"YResolution";s:19:"1207959552/16777216";s:19:"PlanarConfiguration";i:1;s:14:"ResolutionUnit";i:2;s:22:"MEDIAWIKI_EXIF_VERSION";i:2;}';
// Re-unserialize in case there are subtle differences between how versions
// of php serialize stuff.
--- /dev/null
+<?php
+class XMPTest extends MediaWikiTestCase {
+
+ /**
+ * Put XMP in, compare what comes out...
+ *
+ * @param $xmp String the actual xml data.
+ * @param $expected Array expected result of parsing the xmp.
+ * @param $info String Short sentence on what's being tested.
+ *
+ * @dataProvider dataXMPParse
+ */
+ public function testXMPParse( $xmp, $expected, $info ) {
+ if ( !function_exists( 'xml_parser_create_ns' ) ) {
+ $this->markIncomplete( 'Requires libxml to do XMP parsing' );
+ }
+ if ( !is_string( $xmp ) || !is_array( $expected ) ) {
+ throw new Exception( "Invalid data provided to " . __METHOD__ );
+ }
+ $reader = new XMPReader;
+ $reader->parse( $xmp );
+ $this->assertEquals( $expected, $reader->getResults(), $info );
+ }
+
+ public function dataXMPParse() {
+ $xmpPath = dirname( __FILE__ ) . '/../../data/xmp/' ;
+ $data = array();
+
+ // $xmpFiles format: array of arrays with first arg file base name,
+ // with the actual file having .xmp on the end for the xmp
+ // and .result.php on the end for a php file containing the result
+ // array. Second argument is some info on what's being tested.
+ $xmpFiles = array(
+ array( '1', 'parseType=Resource test' ),
+ array( '2', 'Structure with mixed attribute and element props' ),
+ array( '3', 'Extra qualifiers (that should be ignored)' ),
+ array( '3-invalid', 'Test ignoring qualifiers that look like normal props' ),
+ array( '4', 'Flash as qualifier' ),
+ array( '5', 'Flash as qualifier 2' ),
+ array( '6', 'Multiple rdf:Description' ),
+ array( '7', 'Generic test of several property types' ),
+ array( 'flash', 'Test of Flash property' ),
+ array( 'invalid-child-not-struct', 'Test child props not in struct or ignored' ),
+ array( 'no-recognized-props', 'Test namespace and no recognized props' ),
+ array( 'no-namespace', 'Test non-namespaced attributes are ignored' ),
+ array( 'bag-for-seq', "Allow bag's instead of seq's. (bug 27105)" ),
+ array( 'utf16BE', 'UTF-16BE encoding' ),
+ array( 'utf16LE', 'UTF-16LE encoding' ),
+ array( 'utf32BE', 'UTF-32BE encoding' ),
+ array( 'utf32LE', 'UTF-32LE encoding' ),
+ array( 'xmpExt', 'Extended XMP missing second part' ),
+ );
+ foreach( $xmpFiles as $file ) {
+ $xmp = file_get_contents( $xmpPath . $file[0] . '.xmp' );
+ // I'm not sure if this is the best way to handle getting the
+ // result array, but it seems kind of big to put directly in the test
+ // file.
+ $result = null;
+ include( $xmpPath . $file[0] . '.result.php' );
+ $data[] = array( $xmp, $result, '[' . $file[0] . '.xmp] ' . $file[1] );
+ }
+ return $data;
+ }
+
+ /** Test ExtendedXMP block support. (Used when the XMP has to be split
+ * over multiple jpeg segments, due to 64k size limit on jpeg segments.
+ *
+ * @todo This is based on what the standard says. Need to find a real
+ * world example file to double check the support for this is right.
+ */
+ function testExtendedXMP() {
+ $xmpPath = dirname( __FILE__ ) . '/../../data/xmp/';
+ $standardXMP = file_get_contents( $xmpPath . 'xmpExt.xmp' );
+ $extendedXMP = file_get_contents( $xmpPath . 'xmpExt2.xmp' );
+
+ $md5sum = '28C74E0AC2D796886759006FBE2E57B7'; // of xmpExt2.xmp
+ $length = pack( 'N', strlen( $extendedXMP ) );
+ $offset = pack( 'N', 0 );
+ $extendedPacket = $md5sum . $length . $offset . $extendedXMP;
+
+ $reader = new XMPReader();
+ $reader->parse( $standardXMP );
+ $reader->parseExtended( $extendedPacket );
+ $actual = $reader->getResults();
+
+ $expected = array( 'xmp-exif' =>
+ array(
+ 'DigitalZoomRatio' => '0/10',
+ 'Flash' => 9,
+ 'FNumber' => '2/10',
+ )
+ );
+
+ $this->assertEquals( $expected, $actual );
+ }
+
+ /**
+ * This test has an extended XMP block with a wrong guid (md5sum)
+ * and thus should only return the StandardXMP, not the ExtendedXMP.
+ */
+ function testExtendedXMPWithWrongGUID() {
+ $xmpPath = dirname( __FILE__ ) . '/../../data/xmp/';
+ $standardXMP = file_get_contents( $xmpPath . 'xmpExt.xmp' );
+ $extendedXMP = file_get_contents( $xmpPath . 'xmpExt2.xmp' );
+
+ $md5sum = '28C74E0AC2D796886759006FBE2E57B9'; // Note last digit.
+ $length = pack( 'N', strlen( $extendedXMP ) );
+ $offset = pack( 'N', 0 );
+ $extendedPacket = $md5sum . $length . $offset . $extendedXMP;
+
+ $reader = new XMPReader();
+ $reader->parse( $standardXMP );
+ $reader->parseExtended( $extendedPacket );
+ $actual = $reader->getResults();
+
+ $expected = array( 'xmp-exif' =>
+ array(
+ 'DigitalZoomRatio' => '0/10',
+ 'Flash' => 9,
+ )
+ );
+
+ $this->assertEquals( $expected, $actual );
+ }
+ /**
+ * Have a high offset to simulate a missing packet,
+ * which should cause it to ignore the ExtendedXMP packet.
+ */
+ function testExtendedXMPMissingPacket() {
+ $xmpPath = dirname( __FILE__ ) . '/../../data/xmp/';
+ $standardXMP = file_get_contents( $xmpPath . 'xmpExt.xmp' );
+ $extendedXMP = file_get_contents( $xmpPath . 'xmpExt2.xmp' );
+
+ $md5sum = '28C74E0AC2D796886759006FBE2E57B7'; // of xmpExt2.xmp
+ $length = pack( 'N', strlen( $extendedXMP ) );
+ $offset = pack( 'N', 2048 );
+ $extendedPacket = $md5sum . $length . $offset . $extendedXMP;
+
+ $reader = new XMPReader();
+ $reader->parse( $standardXMP );
+ $reader->parseExtended( $extendedPacket );
+ $actual = $reader->getResults();
+
+ $expected = array( 'xmp-exif' =>
+ array(
+ 'DigitalZoomRatio' => '0/10',
+ 'Flash' => 9,
+ )
+ );
+
+ $this->assertEquals( $expected, $actual );
+ }
+
+}