Whitelist existing violations, but enable the sniff to prevent
any new occurrences.
-->
- <exclude-pattern>*/includes/media/XCF\.php</exclude-pattern>
<exclude-pattern>*/includes/Feed\.php</exclude-pattern>
<exclude-pattern>*/includes/libs/xmp/XMP\.php</exclude-pattern>
<exclude-pattern>*/includes/jobqueue/JobSpecification\.php</exclude-pattern>
'WithoutInterwikiPage' => __DIR__ . '/includes/specials/SpecialWithoutinterwiki.php',
'WordLevelDiff' => __DIR__ . '/includes/diff/WordLevelDiff.php',
'WrapOldPasswords' => __DIR__ . '/maintenance/wrapOldPasswords.php',
- 'XCFHandler' => __DIR__ . '/includes/media/XCF.php',
+ 'XCFHandler' => __DIR__ . '/includes/media/XCFHandler.php',
'XMLRCFeedFormatter' => __DIR__ . '/includes/rcfeed/XMLRCFeedFormatter.php',
'XMPInfo' => __DIR__ . '/includes/compat/XMPReader.php',
'XMPReader' => __DIR__ . '/includes/compat/XMPReader.php',
+++ /dev/null
-<?php
-/**
- * Handler for the Gimp's native file format (XCF)
- *
- * Overview:
- * https://en.wikipedia.org/wiki/XCF_(file_format)
- * Specification in Gnome repository:
- * http://svn.gnome.org/viewvc/gimp/trunk/devel-docs/xcf.txt?view=markup
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- * @ingroup Media
- */
-
-/**
- * Handler for the Gimp's native file format; getimagesize() doesn't
- * support these files
- *
- * @ingroup Media
- */
-class XCFHandler extends BitmapHandler {
- /**
- * @param File $file
- * @return bool
- */
- public function mustRender( $file ) {
- return true;
- }
-
- /**
- * Render files as PNG
- *
- * @param string $ext
- * @param string $mime
- * @param array|null $params
- * @return array
- */
- function getThumbType( $ext, $mime, $params = null ) {
- return [ 'png', 'image/png' ];
- }
-
- /**
- * Get width and height from the XCF header.
- *
- * @param File|FSFile $image
- * @param string $filename
- * @return array
- */
- function getImageSize( $image, $filename ) {
- $header = self::getXCFMetaData( $filename );
- if ( !$header ) {
- return false;
- }
-
- # Forge a return array containing metadata information just like getimagesize()
- # See PHP documentation at: https://secure.php.net/getimagesize
- return [
- 0 => $header['width'],
- 1 => $header['height'],
- 2 => null, # IMAGETYPE constant, none exist for XCF.
- 3 => "height=\"{$header['height']}\" width=\"{$header['width']}\"",
- 'mime' => 'image/x-xcf',
- 'channels' => null,
- 'bits' => 8, # Always 8-bits per color
- ];
- }
-
- /**
- * Metadata for a given XCF file
- *
- * Will return false if file magic signature is not recognized
- * @author Hexmode
- * @author Hashar
- *
- * @param string $filename Full path to a XCF file
- * @return bool|array Metadata Array just like PHP getimagesize()
- */
- static function getXCFMetaData( $filename ) {
- # Decode master structure
- $f = fopen( $filename, 'rb' );
- if ( !$f ) {
- return false;
- }
- # The image structure always starts at offset 0 in the XCF file.
- # So we just read it :-)
- $binaryHeader = fread( $f, 26 );
- fclose( $f );
-
- /**
- * Master image structure:
- *
- * byte[9] "gimp xcf " File type magic
- * byte[4] version XCF version
- * "file" - version 0
- * "v001" - version 1
- * "v002" - version 2
- * byte 0 Zero-terminator for version tag
- * uint32 width With of canvas
- * uint32 height Height of canvas
- * uint32 base_type Color mode of the image; one of
- * 0: RGB color
- * 1: Grayscale
- * 2: Indexed color
- * (enum GimpImageBaseType in libgimpbase/gimpbaseenums.h)
- */
- try {
- $header = wfUnpack(
- "A9magic" . # A: space padded
- "/a5version" . # a: zero padded
- "/Nwidth" . # \
- "/Nheight" . # N: unsigned long 32bit big endian
- "/Nbase_type", # /
- $binaryHeader
- );
- } catch ( Exception $mwe ) {
- return false;
- }
-
- # Check values
- if ( $header['magic'] !== 'gimp xcf' ) {
- wfDebug( __METHOD__ . " '$filename' has invalid magic signature.\n" );
-
- return false;
- }
- # TODO: we might want to check for sane values of width and height
-
- wfDebug( __METHOD__ .
- ": canvas size of '$filename' is {$header['width']} x {$header['height']} px\n" );
-
- return $header;
- }
-
- /**
- * Store the channel type
- *
- * Greyscale files need different command line options.
- *
- * @param File|FSFile $file The image object, or false if there isn't one.
- * Warning, FSFile::getPropsFromPath might pass an (object)array() instead (!)
- * @param string $filename
- * @return string
- */
- public function getMetadata( $file, $filename ) {
- $header = self::getXCFMetaData( $filename );
- $metadata = [];
- if ( $header ) {
- // Try to be consistent with the names used by PNG files.
- // Unclear from base media type if it has an alpha layer,
- // so just assume that it does since it "potentially" could.
- switch ( $header['base_type'] ) {
- case 0:
- $metadata['colorType'] = 'truecolour-alpha';
- break;
- case 1:
- $metadata['colorType'] = 'greyscale-alpha';
- break;
- case 2:
- $metadata['colorType'] = 'index-coloured';
- break;
- default:
- $metadata['colorType'] = 'unknown';
- }
- } else {
- // Marker to prevent repeated attempted extraction
- $metadata['error'] = true;
- }
- return serialize( $metadata );
- }
-
- /**
- * Should we refresh the metadata
- *
- * @param File $file The file object for the file in question
- * @param string $metadata Serialized metadata
- * @return bool One of the self::METADATA_(BAD|GOOD|COMPATIBLE) constants
- */
- public function isMetadataValid( $file, $metadata ) {
- if ( !$metadata ) {
- // Old metadata when we just put an empty string in there
- return self::METADATA_BAD;
- } else {
- return self::METADATA_GOOD;
- }
- }
-
- /**
- * Must use "im" for XCF
- *
- * @param string $dstPath
- * @param bool $checkDstPath
- * @return string
- */
- protected function getScalerType( $dstPath, $checkDstPath = true ) {
- return "im";
- }
-
- /**
- * Can we render this file?
- *
- * Image magick doesn't support indexed xcf files as of current
- * writing (as of 6.8.9-3)
- * @param File $file
- * @return bool
- */
- public function canRender( $file ) {
- Wikimedia\suppressWarnings();
- $xcfMeta = unserialize( $file->getMetadata() );
- Wikimedia\restoreWarnings();
- if ( isset( $xcfMeta['colorType'] ) && $xcfMeta['colorType'] === 'index-coloured' ) {
- return false;
- }
- return parent::canRender( $file );
- }
-}
--- /dev/null
+<?php
+/**
+ * Handler for the Gimp's native file format (XCF)
+ *
+ * Overview:
+ * https://en.wikipedia.org/wiki/XCF_(file_format)
+ * Specification in Gnome repository:
+ * http://svn.gnome.org/viewvc/gimp/trunk/devel-docs/xcf.txt?view=markup
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Media
+ */
+
+/**
+ * Handler for the Gimp's native file format; getimagesize() doesn't
+ * support these files
+ *
+ * @ingroup Media
+ */
+class XCFHandler extends BitmapHandler {
+ /**
+ * @param File $file
+ * @return bool
+ */
+ public function mustRender( $file ) {
+ return true;
+ }
+
+ /**
+ * Render files as PNG
+ *
+ * @param string $ext
+ * @param string $mime
+ * @param array|null $params
+ * @return array
+ */
+ function getThumbType( $ext, $mime, $params = null ) {
+ return [ 'png', 'image/png' ];
+ }
+
+ /**
+ * Get width and height from the XCF header.
+ *
+ * @param File|FSFile $image
+ * @param string $filename
+ * @return array
+ */
+ function getImageSize( $image, $filename ) {
+ $header = self::getXCFMetaData( $filename );
+ if ( !$header ) {
+ return false;
+ }
+
+ # Forge a return array containing metadata information just like getimagesize()
+ # See PHP documentation at: https://secure.php.net/getimagesize
+ return [
+ 0 => $header['width'],
+ 1 => $header['height'],
+ 2 => null, # IMAGETYPE constant, none exist for XCF.
+ 3 => "height=\"{$header['height']}\" width=\"{$header['width']}\"",
+ 'mime' => 'image/x-xcf',
+ 'channels' => null,
+ 'bits' => 8, # Always 8-bits per color
+ ];
+ }
+
+ /**
+ * Metadata for a given XCF file
+ *
+ * Will return false if file magic signature is not recognized
+ * @author Hexmode
+ * @author Hashar
+ *
+ * @param string $filename Full path to a XCF file
+ * @return bool|array Metadata Array just like PHP getimagesize()
+ */
+ static function getXCFMetaData( $filename ) {
+ # Decode master structure
+ $f = fopen( $filename, 'rb' );
+ if ( !$f ) {
+ return false;
+ }
+ # The image structure always starts at offset 0 in the XCF file.
+ # So we just read it :-)
+ $binaryHeader = fread( $f, 26 );
+ fclose( $f );
+
+ /**
+ * Master image structure:
+ *
+ * byte[9] "gimp xcf " File type magic
+ * byte[4] version XCF version
+ * "file" - version 0
+ * "v001" - version 1
+ * "v002" - version 2
+ * byte 0 Zero-terminator for version tag
+ * uint32 width With of canvas
+ * uint32 height Height of canvas
+ * uint32 base_type Color mode of the image; one of
+ * 0: RGB color
+ * 1: Grayscale
+ * 2: Indexed color
+ * (enum GimpImageBaseType in libgimpbase/gimpbaseenums.h)
+ */
+ try {
+ $header = wfUnpack(
+ "A9magic" . # A: space padded
+ "/a5version" . # a: zero padded
+ "/Nwidth" . # \
+ "/Nheight" . # N: unsigned long 32bit big endian
+ "/Nbase_type", # /
+ $binaryHeader
+ );
+ } catch ( Exception $mwe ) {
+ return false;
+ }
+
+ # Check values
+ if ( $header['magic'] !== 'gimp xcf' ) {
+ wfDebug( __METHOD__ . " '$filename' has invalid magic signature.\n" );
+
+ return false;
+ }
+ # TODO: we might want to check for sane values of width and height
+
+ wfDebug( __METHOD__ .
+ ": canvas size of '$filename' is {$header['width']} x {$header['height']} px\n" );
+
+ return $header;
+ }
+
+ /**
+ * Store the channel type
+ *
+ * Greyscale files need different command line options.
+ *
+ * @param File|FSFile $file The image object, or false if there isn't one.
+ * Warning, FSFile::getPropsFromPath might pass an (object)array() instead (!)
+ * @param string $filename
+ * @return string
+ */
+ public function getMetadata( $file, $filename ) {
+ $header = self::getXCFMetaData( $filename );
+ $metadata = [];
+ if ( $header ) {
+ // Try to be consistent with the names used by PNG files.
+ // Unclear from base media type if it has an alpha layer,
+ // so just assume that it does since it "potentially" could.
+ switch ( $header['base_type'] ) {
+ case 0:
+ $metadata['colorType'] = 'truecolour-alpha';
+ break;
+ case 1:
+ $metadata['colorType'] = 'greyscale-alpha';
+ break;
+ case 2:
+ $metadata['colorType'] = 'index-coloured';
+ break;
+ default:
+ $metadata['colorType'] = 'unknown';
+ }
+ } else {
+ // Marker to prevent repeated attempted extraction
+ $metadata['error'] = true;
+ }
+ return serialize( $metadata );
+ }
+
+ /**
+ * Should we refresh the metadata
+ *
+ * @param File $file The file object for the file in question
+ * @param string $metadata Serialized metadata
+ * @return bool One of the self::METADATA_(BAD|GOOD|COMPATIBLE) constants
+ */
+ public function isMetadataValid( $file, $metadata ) {
+ if ( !$metadata ) {
+ // Old metadata when we just put an empty string in there
+ return self::METADATA_BAD;
+ } else {
+ return self::METADATA_GOOD;
+ }
+ }
+
+ /**
+ * Must use "im" for XCF
+ *
+ * @param string $dstPath
+ * @param bool $checkDstPath
+ * @return string
+ */
+ protected function getScalerType( $dstPath, $checkDstPath = true ) {
+ return "im";
+ }
+
+ /**
+ * Can we render this file?
+ *
+ * Image magick doesn't support indexed xcf files as of current
+ * writing (as of 6.8.9-3)
+ * @param File $file
+ * @return bool
+ */
+ public function canRender( $file ) {
+ Wikimedia\suppressWarnings();
+ $xcfMeta = unserialize( $file->getMetadata() );
+ Wikimedia\restoreWarnings();
+ if ( isset( $xcfMeta['colorType'] ) && $xcfMeta['colorType'] === 'index-coloured' ) {
+ return false;
+ }
+ return parent::canRender( $file );
+ }
+}
--- /dev/null
+<?php
+
+/**
+ * @group Media
+ */
+class GIFHandlerTest extends MediaWikiMediaTestCase {
+
+ /** @var GIFHandler */
+ protected $handler;
+
+ protected function setUp() {
+ parent::setUp();
+
+ $this->handler = new GIFHandler();
+ }
+
+ /**
+ * @covers GIFHandler::getMetadata
+ */
+ public function testInvalidFile() {
+ $res = $this->handler->getMetadata( null, $this->filePath . '/README' );
+ $this->assertEquals( GIFHandler::BROKEN_FILE, $res );
+ }
+
+ /**
+ * @param string $filename Basename of the file to check
+ * @param bool $expected Expected result.
+ * @dataProvider provideIsAnimated
+ * @covers GIFHandler::isAnimatedImage
+ */
+ public function testIsAnimanted( $filename, $expected ) {
+ $file = $this->dataFile( $filename, 'image/gif' );
+ $actual = $this->handler->isAnimatedImage( $file );
+ $this->assertEquals( $expected, $actual );
+ }
+
+ public static function provideIsAnimated() {
+ return [
+ [ 'animated.gif', true ],
+ [ 'nonanimated.gif', false ],
+ ];
+ }
+
+ /**
+ * @param string $filename
+ * @param int $expected Total image area
+ * @dataProvider provideGetImageArea
+ * @covers GIFHandler::getImageArea
+ */
+ public function testGetImageArea( $filename, $expected ) {
+ $file = $this->dataFile( $filename, 'image/gif' );
+ $actual = $this->handler->getImageArea( $file, $file->getWidth(), $file->getHeight() );
+ $this->assertEquals( $expected, $actual );
+ }
+
+ public static function provideGetImageArea() {
+ return [
+ [ 'animated.gif', 5400 ],
+ [ 'nonanimated.gif', 1350 ],
+ ];
+ }
+
+ /**
+ * @param string $metadata Serialized metadata
+ * @param int $expected One of the class constants of GIFHandler
+ * @dataProvider provideIsMetadataValid
+ * @covers GIFHandler::isMetadataValid
+ */
+ public function testIsMetadataValid( $metadata, $expected ) {
+ $actual = $this->handler->isMetadataValid( null, $metadata );
+ $this->assertEquals( $expected, $actual );
+ }
+
+ public static function provideIsMetadataValid() {
+ // phpcs:disable Generic.Files.LineLength
+ return [
+ [ GIFHandler::BROKEN_FILE, GIFHandler::METADATA_GOOD ],
+ [ '', GIFHandler::METADATA_BAD ],
+ [ null, GIFHandler::METADATA_BAD ],
+ [ 'Something invalid!', GIFHandler::METADATA_BAD ],
+ [
+ '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
+ ],
+ ];
+ // phpcs:enable
+ }
+
+ /**
+ * @param string $filename
+ * @param string $expected Serialized array
+ * @dataProvider provideGetMetadata
+ * @covers GIFHandler::getMetadata
+ */
+ public function testGetMetadata( $filename, $expected ) {
+ $file = $this->dataFile( $filename, 'image/gif' );
+ $actual = $this->handler->getMetadata( $file, "$this->filePath/$filename" );
+ $this->assertEquals( unserialize( $expected ), unserialize( $actual ) );
+ }
+
+ public static function provideGetMetadata() {
+ // phpcs:disable Generic.Files.LineLength
+ return [
+ [
+ '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;}}'
+ ],
+ [
+ '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;}}'
+ ],
+ ];
+ // phpcs:enable
+ }
+
+ /**
+ * @param string $filename
+ * @param string $expected Serialized array
+ * @dataProvider provideGetIndependentMetaArray
+ * @covers GIFHandler::getCommonMetaArray
+ */
+ public function testGetIndependentMetaArray( $filename, $expected ) {
+ $file = $this->dataFile( $filename, 'image/gif' );
+ $actual = $this->handler->getCommonMetaArray( $file );
+ $this->assertEquals( $expected, $actual );
+ }
+
+ public static function provideGetIndependentMetaArray() {
+ return [
+ [ 'nonanimated.gif', [
+ 'GIFFileComment' => [
+ 'GIF test file ⁕ Created with GIMP',
+ ],
+ ] ],
+ [ 'animated-xmp.gif',
+ [
+ 'Artist' => 'Bawolff',
+ 'ImageDescription' => [
+ 'x-default' => 'A file to test GIF',
+ '_type' => 'lang',
+ ],
+ 'SublocationDest' => 'The interwebs',
+ 'GIFFileComment' =>
+ [
+ 'GIƒ·test·file',
+ ],
+ ]
+ ],
+ ];
+ }
+
+ /**
+ * @param string $filename
+ * @param float $expectedLength
+ * @dataProvider provideGetLength
+ * @covers GIFHandler::getLength
+ */
+ public function testGetLength( $filename, $expectedLength ) {
+ $file = $this->dataFile( $filename, 'image/gif' );
+ $actualLength = $file->getLength();
+ $this->assertEquals( $expectedLength, $actualLength, '', 0.00001 );
+ }
+
+ public function provideGetLength() {
+ return [
+ [ 'animated.gif', 2.4 ],
+ [ 'animated-xmp.gif', 2.4 ],
+ [ 'nonanimated', 0.0 ],
+ [ 'Bishzilla_blink.gif', 1.4 ],
+ ];
+ }
+}
+++ /dev/null
-<?php
-
-/**
- * @group Media
- */
-class GIFHandlerTest extends MediaWikiMediaTestCase {
-
- /** @var GIFHandler */
- protected $handler;
-
- protected function setUp() {
- parent::setUp();
-
- $this->handler = new GIFHandler();
- }
-
- /**
- * @covers GIFHandler::getMetadata
- */
- public function testInvalidFile() {
- $res = $this->handler->getMetadata( null, $this->filePath . '/README' );
- $this->assertEquals( GIFHandler::BROKEN_FILE, $res );
- }
-
- /**
- * @param string $filename Basename of the file to check
- * @param bool $expected Expected result.
- * @dataProvider provideIsAnimated
- * @covers GIFHandler::isAnimatedImage
- */
- public function testIsAnimanted( $filename, $expected ) {
- $file = $this->dataFile( $filename, 'image/gif' );
- $actual = $this->handler->isAnimatedImage( $file );
- $this->assertEquals( $expected, $actual );
- }
-
- public static function provideIsAnimated() {
- return [
- [ 'animated.gif', true ],
- [ 'nonanimated.gif', false ],
- ];
- }
-
- /**
- * @param string $filename
- * @param int $expected Total image area
- * @dataProvider provideGetImageArea
- * @covers GIFHandler::getImageArea
- */
- public function testGetImageArea( $filename, $expected ) {
- $file = $this->dataFile( $filename, 'image/gif' );
- $actual = $this->handler->getImageArea( $file, $file->getWidth(), $file->getHeight() );
- $this->assertEquals( $expected, $actual );
- }
-
- public static function provideGetImageArea() {
- return [
- [ 'animated.gif', 5400 ],
- [ 'nonanimated.gif', 1350 ],
- ];
- }
-
- /**
- * @param string $metadata Serialized metadata
- * @param int $expected One of the class constants of GIFHandler
- * @dataProvider provideIsMetadataValid
- * @covers GIFHandler::isMetadataValid
- */
- public function testIsMetadataValid( $metadata, $expected ) {
- $actual = $this->handler->isMetadataValid( null, $metadata );
- $this->assertEquals( $expected, $actual );
- }
-
- public static function provideIsMetadataValid() {
- // phpcs:disable Generic.Files.LineLength
- return [
- [ GIFHandler::BROKEN_FILE, GIFHandler::METADATA_GOOD ],
- [ '', GIFHandler::METADATA_BAD ],
- [ null, GIFHandler::METADATA_BAD ],
- [ 'Something invalid!', GIFHandler::METADATA_BAD ],
- [
- '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
- ],
- ];
- // phpcs:enable
- }
-
- /**
- * @param string $filename
- * @param string $expected Serialized array
- * @dataProvider provideGetMetadata
- * @covers GIFHandler::getMetadata
- */
- public function testGetMetadata( $filename, $expected ) {
- $file = $this->dataFile( $filename, 'image/gif' );
- $actual = $this->handler->getMetadata( $file, "$this->filePath/$filename" );
- $this->assertEquals( unserialize( $expected ), unserialize( $actual ) );
- }
-
- public static function provideGetMetadata() {
- // phpcs:disable Generic.Files.LineLength
- return [
- [
- '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;}}'
- ],
- [
- '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;}}'
- ],
- ];
- // phpcs:enable
- }
-
- /**
- * @param string $filename
- * @param string $expected Serialized array
- * @dataProvider provideGetIndependentMetaArray
- * @covers GIFHandler::getCommonMetaArray
- */
- public function testGetIndependentMetaArray( $filename, $expected ) {
- $file = $this->dataFile( $filename, 'image/gif' );
- $actual = $this->handler->getCommonMetaArray( $file );
- $this->assertEquals( $expected, $actual );
- }
-
- public static function provideGetIndependentMetaArray() {
- return [
- [ 'nonanimated.gif', [
- 'GIFFileComment' => [
- 'GIF test file ⁕ Created with GIMP',
- ],
- ] ],
- [ 'animated-xmp.gif',
- [
- 'Artist' => 'Bawolff',
- 'ImageDescription' => [
- 'x-default' => 'A file to test GIF',
- '_type' => 'lang',
- ],
- 'SublocationDest' => 'The interwebs',
- 'GIFFileComment' =>
- [
- 'GIƒ·test·file',
- ],
- ]
- ],
- ];
- }
-
- /**
- * @param string $filename
- * @param float $expectedLength
- * @dataProvider provideGetLength
- * @covers GIFHandler::getLength
- */
- public function testGetLength( $filename, $expectedLength ) {
- $file = $this->dataFile( $filename, 'image/gif' );
- $actualLength = $file->getLength();
- $this->assertEquals( $expectedLength, $actualLength, '', 0.00001 );
- }
-
- public function provideGetLength() {
- return [
- [ 'animated.gif', 2.4 ],
- [ 'animated-xmp.gif', 2.4 ],
- [ 'nonanimated', 0.0 ],
- [ 'Bishzilla_blink.gif', 1.4 ],
- ];
- }
-}
--- /dev/null
+<?php
+
+/**
+ * @group Media
+ */
+class PNGHandlerTest extends MediaWikiMediaTestCase {
+
+ /** @var PNGHandler */
+ protected $handler;
+
+ protected function setUp() {
+ parent::setUp();
+ $this->handler = new PNGHandler();
+ }
+
+ /**
+ * @covers PNGHandler::getMetadata
+ */
+ public function testInvalidFile() {
+ $res = $this->handler->getMetadata( null, $this->filePath . '/README' );
+ $this->assertEquals( PNGHandler::BROKEN_FILE, $res );
+ }
+
+ /**
+ * @param string $filename Basename of the file to check
+ * @param bool $expected Expected result.
+ * @dataProvider provideIsAnimated
+ * @covers PNGHandler::isAnimatedImage
+ */
+ public function testIsAnimanted( $filename, $expected ) {
+ $file = $this->dataFile( $filename, 'image/png' );
+ $actual = $this->handler->isAnimatedImage( $file );
+ $this->assertEquals( $expected, $actual );
+ }
+
+ public static function provideIsAnimated() {
+ return [
+ [ 'Animated_PNG_example_bouncing_beach_ball.png', true ],
+ [ '1bit-png.png', false ],
+ ];
+ }
+
+ /**
+ * @param string $filename
+ * @param int $expected Total image area
+ * @dataProvider provideGetImageArea
+ * @covers PNGHandler::getImageArea
+ */
+ public function testGetImageArea( $filename, $expected ) {
+ $file = $this->dataFile( $filename, 'image/png' );
+ $actual = $this->handler->getImageArea( $file, $file->getWidth(), $file->getHeight() );
+ $this->assertEquals( $expected, $actual );
+ }
+
+ public static function provideGetImageArea() {
+ return [
+ [ '1bit-png.png', 2500 ],
+ [ 'greyscale-png.png', 2500 ],
+ [ 'Png-native-test.png', 126000 ],
+ [ 'Animated_PNG_example_bouncing_beach_ball.png', 10000 ],
+ ];
+ }
+
+ /**
+ * @param string $metadata Serialized metadata
+ * @param int $expected One of the class constants of PNGHandler
+ * @dataProvider provideIsMetadataValid
+ * @covers PNGHandler::isMetadataValid
+ */
+ public function testIsMetadataValid( $metadata, $expected ) {
+ $actual = $this->handler->isMetadataValid( null, $metadata );
+ $this->assertEquals( $expected, $actual );
+ }
+
+ public static function provideIsMetadataValid() {
+ // phpcs:disable Generic.Files.LineLength
+ return [
+ [ PNGHandler::BROKEN_FILE, PNGHandler::METADATA_GOOD ],
+ [ '', PNGHandler::METADATA_BAD ],
+ [ null, PNGHandler::METADATA_BAD ],
+ [ 'Something invalid!', PNGHandler::METADATA_BAD ],
+ [
+ '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
+ ],
+ ];
+ // phpcs:enable
+ }
+
+ /**
+ * @param string $filename
+ * @param string $expected Serialized array
+ * @dataProvider provideGetMetadata
+ * @covers PNGHandler::getMetadata
+ */
+ public function testGetMetadata( $filename, $expected ) {
+ $file = $this->dataFile( $filename, 'image/png' );
+ $actual = $this->handler->getMetadata( $file, "$this->filePath/$filename" );
+// $this->assertEquals( unserialize( $expected ), unserialize( $actual ) );
+ $this->assertEquals( ( $expected ), ( $actual ) );
+ }
+
+ public static function provideGetMetadata() {
+ // phpcs:disable Generic.Files.LineLength
+ return [
+ [
+ '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;}}'
+ ],
+ [
+ '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;}}'
+ ],
+ ];
+ // phpcs:enable
+ }
+
+ /**
+ * @param string $filename
+ * @param array $expected Expected standard metadata
+ * @dataProvider provideGetIndependentMetaArray
+ * @covers PNGHandler::getCommonMetaArray
+ */
+ public function testGetIndependentMetaArray( $filename, $expected ) {
+ $file = $this->dataFile( $filename, 'image/png' );
+ $actual = $this->handler->getCommonMetaArray( $file );
+ $this->assertEquals( $expected, $actual );
+ }
+
+ public static function provideGetIndependentMetaArray() {
+ return [
+ [ 'rgb-na-png.png', [] ],
+ [ 'xmp.png',
+ [
+ 'SerialNumber' => '123456789',
+ ]
+ ],
+ ];
+ }
+
+ /**
+ * @param string $filename
+ * @param float $expectedLength
+ * @dataProvider provideGetLength
+ * @covers PNGHandler::getLength
+ */
+ public function testGetLength( $filename, $expectedLength ) {
+ $file = $this->dataFile( $filename, 'image/png' );
+ $actualLength = $file->getLength();
+ $this->assertEquals( $expectedLength, $actualLength, '', 0.00001 );
+ }
+
+ public function provideGetLength() {
+ return [
+ [ 'Animated_PNG_example_bouncing_beach_ball.png', 1.5 ],
+ [ 'Png-native-test.png', 0.0 ],
+ [ 'greyscale-png.png', 0.0 ],
+ [ '1bit-png.png', 0.0 ],
+ ];
+ }
+}
+++ /dev/null
-<?php
-
-/**
- * @group Media
- */
-class PNGHandlerTest extends MediaWikiMediaTestCase {
-
- /** @var PNGHandler */
- protected $handler;
-
- protected function setUp() {
- parent::setUp();
- $this->handler = new PNGHandler();
- }
-
- /**
- * @covers PNGHandler::getMetadata
- */
- public function testInvalidFile() {
- $res = $this->handler->getMetadata( null, $this->filePath . '/README' );
- $this->assertEquals( PNGHandler::BROKEN_FILE, $res );
- }
-
- /**
- * @param string $filename Basename of the file to check
- * @param bool $expected Expected result.
- * @dataProvider provideIsAnimated
- * @covers PNGHandler::isAnimatedImage
- */
- public function testIsAnimanted( $filename, $expected ) {
- $file = $this->dataFile( $filename, 'image/png' );
- $actual = $this->handler->isAnimatedImage( $file );
- $this->assertEquals( $expected, $actual );
- }
-
- public static function provideIsAnimated() {
- return [
- [ 'Animated_PNG_example_bouncing_beach_ball.png', true ],
- [ '1bit-png.png', false ],
- ];
- }
-
- /**
- * @param string $filename
- * @param int $expected Total image area
- * @dataProvider provideGetImageArea
- * @covers PNGHandler::getImageArea
- */
- public function testGetImageArea( $filename, $expected ) {
- $file = $this->dataFile( $filename, 'image/png' );
- $actual = $this->handler->getImageArea( $file, $file->getWidth(), $file->getHeight() );
- $this->assertEquals( $expected, $actual );
- }
-
- public static function provideGetImageArea() {
- return [
- [ '1bit-png.png', 2500 ],
- [ 'greyscale-png.png', 2500 ],
- [ 'Png-native-test.png', 126000 ],
- [ 'Animated_PNG_example_bouncing_beach_ball.png', 10000 ],
- ];
- }
-
- /**
- * @param string $metadata Serialized metadata
- * @param int $expected One of the class constants of PNGHandler
- * @dataProvider provideIsMetadataValid
- * @covers PNGHandler::isMetadataValid
- */
- public function testIsMetadataValid( $metadata, $expected ) {
- $actual = $this->handler->isMetadataValid( null, $metadata );
- $this->assertEquals( $expected, $actual );
- }
-
- public static function provideIsMetadataValid() {
- // phpcs:disable Generic.Files.LineLength
- return [
- [ PNGHandler::BROKEN_FILE, PNGHandler::METADATA_GOOD ],
- [ '', PNGHandler::METADATA_BAD ],
- [ null, PNGHandler::METADATA_BAD ],
- [ 'Something invalid!', PNGHandler::METADATA_BAD ],
- [
- '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
- ],
- ];
- // phpcs:enable
- }
-
- /**
- * @param string $filename
- * @param string $expected Serialized array
- * @dataProvider provideGetMetadata
- * @covers PNGHandler::getMetadata
- */
- public function testGetMetadata( $filename, $expected ) {
- $file = $this->dataFile( $filename, 'image/png' );
- $actual = $this->handler->getMetadata( $file, "$this->filePath/$filename" );
-// $this->assertEquals( unserialize( $expected ), unserialize( $actual ) );
- $this->assertEquals( ( $expected ), ( $actual ) );
- }
-
- public static function provideGetMetadata() {
- // phpcs:disable Generic.Files.LineLength
- return [
- [
- '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;}}'
- ],
- [
- '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;}}'
- ],
- ];
- // phpcs:enable
- }
-
- /**
- * @param string $filename
- * @param array $expected Expected standard metadata
- * @dataProvider provideGetIndependentMetaArray
- * @covers PNGHandler::getCommonMetaArray
- */
- public function testGetIndependentMetaArray( $filename, $expected ) {
- $file = $this->dataFile( $filename, 'image/png' );
- $actual = $this->handler->getCommonMetaArray( $file );
- $this->assertEquals( $expected, $actual );
- }
-
- public static function provideGetIndependentMetaArray() {
- return [
- [ 'rgb-na-png.png', [] ],
- [ 'xmp.png',
- [
- 'SerialNumber' => '123456789',
- ]
- ],
- ];
- }
-
- /**
- * @param string $filename
- * @param float $expectedLength
- * @dataProvider provideGetLength
- * @covers PNGHandler::getLength
- */
- public function testGetLength( $filename, $expectedLength ) {
- $file = $this->dataFile( $filename, 'image/png' );
- $actualLength = $file->getLength();
- $this->assertEquals( $expectedLength, $actualLength, '', 0.00001 );
- }
-
- public function provideGetLength() {
- return [
- [ 'Animated_PNG_example_bouncing_beach_ball.png', 1.5 ],
- [ 'Png-native-test.png', 0.0 ],
- [ 'greyscale-png.png', 0.0 ],
- [ '1bit-png.png', 0.0 ],
- ];
- }
-}
--- /dev/null
+<?php
+
+/**
+ * @covers WebPHandler
+ */
+class WebPHandlerTest extends MediaWikiTestCase {
+ public function setUp() {
+ parent::setUp();
+ // Allocated file for testing
+ $this->tempFileName = tempnam( wfTempDir(), 'WEBP' );
+ }
+
+ public function tearDown() {
+ parent::tearDown();
+ unlink( $this->tempFileName );
+ }
+
+ /**
+ * @dataProvider provideTestExtractMetaData
+ */
+ public function testExtractMetaData( $header, $expectedResult ) {
+ // Put header into file
+ file_put_contents( $this->tempFileName, $header );
+
+ $this->assertEquals( $expectedResult, WebPHandler::extractMetadata( $this->tempFileName ) );
+ }
+
+ public function provideTestExtractMetaData() {
+ // phpcs:disable Generic.Files.LineLength
+ return [
+ // Files from https://developers.google.com/speed/webp/gallery2
+ [ "\x52\x49\x46\x46\x90\x68\x01\x00\x57\x45\x42\x50\x56\x50\x38\x4C\x83\x68\x01\x00\x2F\x8F\x01\x4B\x10\x8D\x38\x6C\xDB\x46\x92\xE0\xE0\x82\x7B\x6C",
+ [ 'compression' => 'lossless', 'width' => 400, 'height' => 301 ] ],
+ [ "\x52\x49\x46\x46\x64\x5B\x00\x00\x57\x45\x42\x50\x56\x50\x38\x58\x0A\x00\x00\x00\x10\x00\x00\x00\x8F\x01\x00\x2C\x01\x00\x41\x4C\x50\x48\xE5\x0E",
+ [ 'compression' => 'unknown', 'animated' => false, 'transparency' => true, 'width' => 400, 'height' => 301 ] ],
+ [ "\x52\x49\x46\x46\xA8\x72\x00\x00\x57\x45\x42\x50\x56\x50\x38\x4C\x9B\x72\x00\x00\x2F\x81\x81\x62\x10\x8D\x40\x8C\x24\x39\x6E\x73\x73\x38\x01\x96",
+ [ 'compression' => 'lossless', 'width' => 386, 'height' => 395 ] ],
+ [ "\x52\x49\x46\x46\xE0\x42\x00\x00\x57\x45\x42\x50\x56\x50\x38\x58\x0A\x00\x00\x00\x10\x00\x00\x00\x81\x01\x00\x8A\x01\x00\x41\x4C\x50\x48\x56\x10",
+ [ 'compression' => 'unknown', 'animated' => false, 'transparency' => true, 'width' => 386, 'height' => 395 ] ],
+ [ "\x52\x49\x46\x46\x70\x61\x02\x00\x57\x45\x42\x50\x56\x50\x38\x4C\x63\x61\x02\x00\x2F\x1F\xC3\x95\x10\x8D\xC8\x72\xDB\xC8\x92\x24\xD8\x91\xD9\x91",
+ [ 'compression' => 'lossless', 'width' => 800, 'height' => 600 ] ],
+ [ "\x52\x49\x46\x46\x1C\x1D\x01\x00\x57\x45\x42\x50\x56\x50\x38\x58\x0A\x00\x00\x00\x10\x00\x00\x00\x1F\x03\x00\x57\x02\x00\x41\x4C\x50\x48\x25\x8B",
+ [ 'compression' => 'unknown', 'animated' => false, 'transparency' => true, 'width' => 800, 'height' => 600 ] ],
+ [ "\x52\x49\x46\x46\xFA\xC5\x00\x00\x57\x45\x42\x50\x56\x50\x38\x4C\xEE\xC5\x00\x00\x2F\xA4\x81\x28\x10\x8D\x40\x68\x24\xC9\x91\xA4\xAE\xF3\x97\x75",
+ [ 'compression' => 'lossless', 'width' => 421, 'height' => 163 ] ],
+ [ "\x52\x49\x46\x46\xF6\x5D\x00\x00\x57\x45\x42\x50\x56\x50\x38\x58\x0A\x00\x00\x00\x10\x00\x00\x00\xA4\x01\x00\xA2\x00\x00\x41\x4C\x50\x48\x38\x1A",
+ [ 'compression' => 'unknown', 'animated' => false, 'transparency' => true, 'width' => 421, 'height' => 163 ] ],
+ [ "\x52\x49\x46\x46\xC4\x96\x01\x00\x57\x45\x42\x50\x56\x50\x38\x4C\xB8\x96\x01\x00\x2F\x2B\xC1\x4A\x10\x11\x87\x6D\xDB\x48\x12\xFC\x60\xB0\x83\x24",
+ [ 'compression' => 'lossless', 'width' => 300, 'height' => 300 ] ],
+ [ "\x52\x49\x46\x46\x0A\x11\x01\x00\x57\x45\x42\x50\x56\x50\x38\x58\x0A\x00\x00\x00\x10\x00\x00\x00\x2B\x01\x00\x2B\x01\x00\x41\x4C\x50\x48\x67\x6E",
+ [ 'compression' => 'unknown', 'animated' => false, 'transparency' => true, 'width' => 300, 'height' => 300 ] ],
+
+ // Lossy files from https://developers.google.com/speed/webp/gallery1
+ [ "\x52\x49\x46\x46\x68\x76\x00\x00\x57\x45\x42\x50\x56\x50\x38\x20\x5C\x76\x00\x00\xD2\xBE\x01\x9D\x01\x2A\x26\x02\x70\x01\x3E\xD5\x4E\x97\x43\xA2",
+ [ 'compression' => 'lossy', 'width' => 550, 'height' => 368 ] ],
+ [ "\x52\x49\x46\x46\xB0\xEC\x00\x00\x57\x45\x42\x50\x56\x50\x38\x20\xA4\xEC\x00\x00\xB2\x4B\x02\x9D\x01\x2A\x26\x02\x94\x01\x3E\xD1\x50\x96\x46\x26",
+ [ 'compression' => 'lossy', 'width' => 550, 'height' => 404 ] ],
+ [ "\x52\x49\x46\x46\x7A\x19\x03\x00\x57\x45\x42\x50\x56\x50\x38\x20\x6E\x19\x03\x00\xB2\xF8\x09\x9D\x01\x2A\x00\x05\xD0\x02\x3E\xAD\x46\x99\x4A\xA5",
+ [ 'compression' => 'lossy', 'width' => 1280, 'height' => 720 ] ],
+ [ "\x52\x49\x46\x46\x44\xB3\x02\x00\x57\x45\x42\x50\x56\x50\x38\x20\x38\xB3\x02\x00\x52\x57\x06\x9D\x01\x2A\x00\x04\x04\x03\x3E\xA5\x44\x96\x49\x26",
+ [ 'compression' => 'lossy', 'width' => 1024, 'height' => 772 ] ],
+ [ "\x52\x49\x46\x46\x02\x43\x01\x00\x57\x45\x42\x50\x56\x50\x38\x20\xF6\x42\x01\x00\x12\xC0\x05\x9D\x01\x2A\x00\x04\xF0\x02\x3E\x79\x34\x93\x47\xA4",
+ [ 'compression' => 'lossy', 'width' => 1024, 'height' => 752 ] ],
+
+ // Animated file from https://groups.google.com/a/chromium.org/d/topic/blink-dev/Y8tRC4mdQz8/discussion
+ [ "\x52\x49\x46\x46\xD0\x0B\x02\x00\x57\x45\x42\x50\x56\x50\x38\x58\x0A\x00\x00\x00\x12\x00\x00\x00\x3F\x01\x00\x3F\x01\x00\x41\x4E",
+ [ 'compression' => 'unknown', 'animated' => true, 'transparency' => true, 'width' => 320, 'height' => 320 ] ],
+
+ // Error cases
+ [ '', false ],
+ [ ' ', false ],
+ [ 'RIFF ', false ],
+ [ 'RIFF1234WEBP ', false ],
+ [ 'RIFF1234WEBPVP8 ', false ],
+ [ 'RIFF1234WEBPVP8L ', false ],
+ ];
+ // phpcs:enable
+ }
+
+ /**
+ * @dataProvider provideTestWithFileExtractMetaData
+ */
+ public function testWithFileExtractMetaData( $filename, $expectedResult ) {
+ $this->assertEquals( $expectedResult, WebPHandler::extractMetadata( $filename ) );
+ }
+
+ public function provideTestWithFileExtractMetaData() {
+ return [
+ [ __DIR__ . '/../../data/media/2_webp_ll.webp',
+ [
+ 'compression' => 'lossless',
+ 'width' => 386,
+ 'height' => 395
+ ]
+ ],
+ [ __DIR__ . '/../../data/media/2_webp_a.webp',
+ [
+ 'compression' => 'lossy',
+ 'animated' => false,
+ 'transparency' => true,
+ 'width' => 386,
+ 'height' => 395
+ ]
+ ],
+ ];
+ }
+
+ /**
+ * @dataProvider provideTestGetImageSize
+ */
+ public function testGetImageSize( $path, $expectedResult ) {
+ $handler = new WebPHandler();
+ $this->assertEquals( $expectedResult, $handler->getImageSize( null, $path ) );
+ }
+
+ public function provideTestGetImageSize() {
+ return [
+ // Public domain files from https://developers.google.com/speed/webp/gallery2
+ [ __DIR__ . '/../../data/media/2_webp_a.webp', [ 386, 395 ] ],
+ [ __DIR__ . '/../../data/media/2_webp_ll.webp', [ 386, 395 ] ],
+ [ __DIR__ . '/../../data/media/webp_animated.webp', [ 300, 225 ] ],
+
+ // Error cases
+ [ __FILE__, false ],
+ ];
+ }
+
+ /**
+ * Tests the WebP MIME detection. This should really be a separate test, but sticking it
+ * here for now.
+ *
+ * @dataProvider provideTestGetMimeType
+ */
+ public function testGuessMimeType( $path ) {
+ $mime = MediaWiki\MediaWikiServices::getInstance()->getMimeAnalyzer();
+ $this->assertEquals( 'image/webp', $mime->guessMimeType( $path, false ) );
+ }
+
+ public function provideTestGetMimeType() {
+ return [
+ // Public domain files from https://developers.google.com/speed/webp/gallery2
+ [ __DIR__ . '/../../data/media/2_webp_a.webp' ],
+ [ __DIR__ . '/../../data/media/2_webp_ll.webp' ],
+ [ __DIR__ . '/../../data/media/webp_animated.webp' ],
+ ];
+ }
+}
+
+/* Python code to extract a header and convert to PHP format:
+ * print '"%s"' % ''.implode( '\\x%02X' % ord(c) for c in urllib.urlopen(url).read(36) )
+ */
+++ /dev/null
-<?php
-
-/**
- * @covers WebPHandler
- */
-class WebPHandlerTest extends MediaWikiTestCase {
- public function setUp() {
- parent::setUp();
- // Allocated file for testing
- $this->tempFileName = tempnam( wfTempDir(), 'WEBP' );
- }
-
- public function tearDown() {
- parent::tearDown();
- unlink( $this->tempFileName );
- }
-
- /**
- * @dataProvider provideTestExtractMetaData
- */
- public function testExtractMetaData( $header, $expectedResult ) {
- // Put header into file
- file_put_contents( $this->tempFileName, $header );
-
- $this->assertEquals( $expectedResult, WebPHandler::extractMetadata( $this->tempFileName ) );
- }
-
- public function provideTestExtractMetaData() {
- // phpcs:disable Generic.Files.LineLength
- return [
- // Files from https://developers.google.com/speed/webp/gallery2
- [ "\x52\x49\x46\x46\x90\x68\x01\x00\x57\x45\x42\x50\x56\x50\x38\x4C\x83\x68\x01\x00\x2F\x8F\x01\x4B\x10\x8D\x38\x6C\xDB\x46\x92\xE0\xE0\x82\x7B\x6C",
- [ 'compression' => 'lossless', 'width' => 400, 'height' => 301 ] ],
- [ "\x52\x49\x46\x46\x64\x5B\x00\x00\x57\x45\x42\x50\x56\x50\x38\x58\x0A\x00\x00\x00\x10\x00\x00\x00\x8F\x01\x00\x2C\x01\x00\x41\x4C\x50\x48\xE5\x0E",
- [ 'compression' => 'unknown', 'animated' => false, 'transparency' => true, 'width' => 400, 'height' => 301 ] ],
- [ "\x52\x49\x46\x46\xA8\x72\x00\x00\x57\x45\x42\x50\x56\x50\x38\x4C\x9B\x72\x00\x00\x2F\x81\x81\x62\x10\x8D\x40\x8C\x24\x39\x6E\x73\x73\x38\x01\x96",
- [ 'compression' => 'lossless', 'width' => 386, 'height' => 395 ] ],
- [ "\x52\x49\x46\x46\xE0\x42\x00\x00\x57\x45\x42\x50\x56\x50\x38\x58\x0A\x00\x00\x00\x10\x00\x00\x00\x81\x01\x00\x8A\x01\x00\x41\x4C\x50\x48\x56\x10",
- [ 'compression' => 'unknown', 'animated' => false, 'transparency' => true, 'width' => 386, 'height' => 395 ] ],
- [ "\x52\x49\x46\x46\x70\x61\x02\x00\x57\x45\x42\x50\x56\x50\x38\x4C\x63\x61\x02\x00\x2F\x1F\xC3\x95\x10\x8D\xC8\x72\xDB\xC8\x92\x24\xD8\x91\xD9\x91",
- [ 'compression' => 'lossless', 'width' => 800, 'height' => 600 ] ],
- [ "\x52\x49\x46\x46\x1C\x1D\x01\x00\x57\x45\x42\x50\x56\x50\x38\x58\x0A\x00\x00\x00\x10\x00\x00\x00\x1F\x03\x00\x57\x02\x00\x41\x4C\x50\x48\x25\x8B",
- [ 'compression' => 'unknown', 'animated' => false, 'transparency' => true, 'width' => 800, 'height' => 600 ] ],
- [ "\x52\x49\x46\x46\xFA\xC5\x00\x00\x57\x45\x42\x50\x56\x50\x38\x4C\xEE\xC5\x00\x00\x2F\xA4\x81\x28\x10\x8D\x40\x68\x24\xC9\x91\xA4\xAE\xF3\x97\x75",
- [ 'compression' => 'lossless', 'width' => 421, 'height' => 163 ] ],
- [ "\x52\x49\x46\x46\xF6\x5D\x00\x00\x57\x45\x42\x50\x56\x50\x38\x58\x0A\x00\x00\x00\x10\x00\x00\x00\xA4\x01\x00\xA2\x00\x00\x41\x4C\x50\x48\x38\x1A",
- [ 'compression' => 'unknown', 'animated' => false, 'transparency' => true, 'width' => 421, 'height' => 163 ] ],
- [ "\x52\x49\x46\x46\xC4\x96\x01\x00\x57\x45\x42\x50\x56\x50\x38\x4C\xB8\x96\x01\x00\x2F\x2B\xC1\x4A\x10\x11\x87\x6D\xDB\x48\x12\xFC\x60\xB0\x83\x24",
- [ 'compression' => 'lossless', 'width' => 300, 'height' => 300 ] ],
- [ "\x52\x49\x46\x46\x0A\x11\x01\x00\x57\x45\x42\x50\x56\x50\x38\x58\x0A\x00\x00\x00\x10\x00\x00\x00\x2B\x01\x00\x2B\x01\x00\x41\x4C\x50\x48\x67\x6E",
- [ 'compression' => 'unknown', 'animated' => false, 'transparency' => true, 'width' => 300, 'height' => 300 ] ],
-
- // Lossy files from https://developers.google.com/speed/webp/gallery1
- [ "\x52\x49\x46\x46\x68\x76\x00\x00\x57\x45\x42\x50\x56\x50\x38\x20\x5C\x76\x00\x00\xD2\xBE\x01\x9D\x01\x2A\x26\x02\x70\x01\x3E\xD5\x4E\x97\x43\xA2",
- [ 'compression' => 'lossy', 'width' => 550, 'height' => 368 ] ],
- [ "\x52\x49\x46\x46\xB0\xEC\x00\x00\x57\x45\x42\x50\x56\x50\x38\x20\xA4\xEC\x00\x00\xB2\x4B\x02\x9D\x01\x2A\x26\x02\x94\x01\x3E\xD1\x50\x96\x46\x26",
- [ 'compression' => 'lossy', 'width' => 550, 'height' => 404 ] ],
- [ "\x52\x49\x46\x46\x7A\x19\x03\x00\x57\x45\x42\x50\x56\x50\x38\x20\x6E\x19\x03\x00\xB2\xF8\x09\x9D\x01\x2A\x00\x05\xD0\x02\x3E\xAD\x46\x99\x4A\xA5",
- [ 'compression' => 'lossy', 'width' => 1280, 'height' => 720 ] ],
- [ "\x52\x49\x46\x46\x44\xB3\x02\x00\x57\x45\x42\x50\x56\x50\x38\x20\x38\xB3\x02\x00\x52\x57\x06\x9D\x01\x2A\x00\x04\x04\x03\x3E\xA5\x44\x96\x49\x26",
- [ 'compression' => 'lossy', 'width' => 1024, 'height' => 772 ] ],
- [ "\x52\x49\x46\x46\x02\x43\x01\x00\x57\x45\x42\x50\x56\x50\x38\x20\xF6\x42\x01\x00\x12\xC0\x05\x9D\x01\x2A\x00\x04\xF0\x02\x3E\x79\x34\x93\x47\xA4",
- [ 'compression' => 'lossy', 'width' => 1024, 'height' => 752 ] ],
-
- // Animated file from https://groups.google.com/a/chromium.org/d/topic/blink-dev/Y8tRC4mdQz8/discussion
- [ "\x52\x49\x46\x46\xD0\x0B\x02\x00\x57\x45\x42\x50\x56\x50\x38\x58\x0A\x00\x00\x00\x12\x00\x00\x00\x3F\x01\x00\x3F\x01\x00\x41\x4E",
- [ 'compression' => 'unknown', 'animated' => true, 'transparency' => true, 'width' => 320, 'height' => 320 ] ],
-
- // Error cases
- [ '', false ],
- [ ' ', false ],
- [ 'RIFF ', false ],
- [ 'RIFF1234WEBP ', false ],
- [ 'RIFF1234WEBPVP8 ', false ],
- [ 'RIFF1234WEBPVP8L ', false ],
- ];
- // phpcs:enable
- }
-
- /**
- * @dataProvider provideTestWithFileExtractMetaData
- */
- public function testWithFileExtractMetaData( $filename, $expectedResult ) {
- $this->assertEquals( $expectedResult, WebPHandler::extractMetadata( $filename ) );
- }
-
- public function provideTestWithFileExtractMetaData() {
- return [
- [ __DIR__ . '/../../data/media/2_webp_ll.webp',
- [
- 'compression' => 'lossless',
- 'width' => 386,
- 'height' => 395
- ]
- ],
- [ __DIR__ . '/../../data/media/2_webp_a.webp',
- [
- 'compression' => 'lossy',
- 'animated' => false,
- 'transparency' => true,
- 'width' => 386,
- 'height' => 395
- ]
- ],
- ];
- }
-
- /**
- * @dataProvider provideTestGetImageSize
- */
- public function testGetImageSize( $path, $expectedResult ) {
- $handler = new WebPHandler();
- $this->assertEquals( $expectedResult, $handler->getImageSize( null, $path ) );
- }
-
- public function provideTestGetImageSize() {
- return [
- // Public domain files from https://developers.google.com/speed/webp/gallery2
- [ __DIR__ . '/../../data/media/2_webp_a.webp', [ 386, 395 ] ],
- [ __DIR__ . '/../../data/media/2_webp_ll.webp', [ 386, 395 ] ],
- [ __DIR__ . '/../../data/media/webp_animated.webp', [ 300, 225 ] ],
-
- // Error cases
- [ __FILE__, false ],
- ];
- }
-
- /**
- * Tests the WebP MIME detection. This should really be a separate test, but sticking it
- * here for now.
- *
- * @dataProvider provideTestGetMimeType
- */
- public function testGuessMimeType( $path ) {
- $mime = MediaWiki\MediaWikiServices::getInstance()->getMimeAnalyzer();
- $this->assertEquals( 'image/webp', $mime->guessMimeType( $path, false ) );
- }
-
- public function provideTestGetMimeType() {
- return [
- // Public domain files from https://developers.google.com/speed/webp/gallery2
- [ __DIR__ . '/../../data/media/2_webp_a.webp' ],
- [ __DIR__ . '/../../data/media/2_webp_ll.webp' ],
- [ __DIR__ . '/../../data/media/webp_animated.webp' ],
- ];
- }
-}
-
-/* Python code to extract a header and convert to PHP format:
- * print '"%s"' % ''.implode( '\\x%02X' % ord(c) for c in urllib.urlopen(url).read(36) )
- */
--- /dev/null
+<?php
+
+/**
+ * @group Media
+ */
+class XCFHandlerTest extends MediaWikiMediaTestCase {
+
+ /** @var XCFHandler */
+ protected $handler;
+
+ protected function setUp() {
+ parent::setUp();
+ $this->handler = new XCFHandler();
+ }
+
+ /**
+ * @param string $filename
+ * @param int $expectedWidth Width
+ * @param int $expectedHeight Height
+ * @dataProvider provideGetImageSize
+ * @covers XCFHandler::getImageSize
+ */
+ public function testGetImageSize( $filename, $expectedWidth, $expectedHeight ) {
+ $file = $this->dataFile( $filename, 'image/x-xcf' );
+ $actual = $this->handler->getImageSize( $file, $file->getLocalRefPath() );
+ $this->assertEquals( $expectedWidth, $actual[0] );
+ $this->assertEquals( $expectedHeight, $actual[1] );
+ }
+
+ public static function provideGetImageSize() {
+ return [
+ [ '80x60-2layers.xcf', 80, 60 ],
+ [ '80x60-RGB.xcf', 80, 60 ],
+ [ '80x60-Greyscale.xcf', 80, 60 ],
+ ];
+ }
+
+ /**
+ * @param string $metadata Serialized metadata
+ * @param int $expected One of the class constants of XCFHandler
+ * @dataProvider provideIsMetadataValid
+ * @covers XCFHandler::isMetadataValid
+ */
+ public function testIsMetadataValid( $metadata, $expected ) {
+ $actual = $this->handler->isMetadataValid( null, $metadata );
+ $this->assertEquals( $expected, $actual );
+ }
+
+ public static function provideIsMetadataValid() {
+ return [
+ [ '', XCFHandler::METADATA_BAD ],
+ [ serialize( [ 'error' => true ] ), XCFHandler::METADATA_GOOD ],
+ [ false, XCFHandler::METADATA_BAD ],
+ [ serialize( [ 'colorType' => 'greyscale-alpha' ] ), XCFHandler::METADATA_GOOD ],
+ ];
+ }
+
+ /**
+ * @param string $filename
+ * @param string $expected Serialized array
+ * @dataProvider provideGetMetadata
+ * @covers XCFHandler::getMetadata
+ */
+ public function testGetMetadata( $filename, $expected ) {
+ $file = $this->dataFile( $filename, 'image/png' );
+ $actual = $this->handler->getMetadata( $file, "$this->filePath/$filename" );
+ $this->assertEquals( $expected, $actual );
+ }
+
+ public static function provideGetMetadata() {
+ return [
+ [ '80x60-2layers.xcf',
+ 'a:1:{s:9:"colorType";s:16:"truecolour-alpha";}'
+ ],
+ [ '80x60-RGB.xcf',
+ 'a:1:{s:9:"colorType";s:16:"truecolour-alpha";}'
+ ],
+ [ '80x60-Greyscale.xcf',
+ 'a:1:{s:9:"colorType";s:15:"greyscale-alpha";}'
+ ],
+ ];
+ }
+}
+++ /dev/null
-<?php
-
-/**
- * @group Media
- */
-class XCFHandlerTest extends MediaWikiMediaTestCase {
-
- /** @var XCFHandler */
- protected $handler;
-
- protected function setUp() {
- parent::setUp();
- $this->handler = new XCFHandler();
- }
-
- /**
- * @param string $filename
- * @param int $expectedWidth Width
- * @param int $expectedHeight Height
- * @dataProvider provideGetImageSize
- * @covers XCFHandler::getImageSize
- */
- public function testGetImageSize( $filename, $expectedWidth, $expectedHeight ) {
- $file = $this->dataFile( $filename, 'image/x-xcf' );
- $actual = $this->handler->getImageSize( $file, $file->getLocalRefPath() );
- $this->assertEquals( $expectedWidth, $actual[0] );
- $this->assertEquals( $expectedHeight, $actual[1] );
- }
-
- public static function provideGetImageSize() {
- return [
- [ '80x60-2layers.xcf', 80, 60 ],
- [ '80x60-RGB.xcf', 80, 60 ],
- [ '80x60-Greyscale.xcf', 80, 60 ],
- ];
- }
-
- /**
- * @param string $metadata Serialized metadata
- * @param int $expected One of the class constants of XCFHandler
- * @dataProvider provideIsMetadataValid
- * @covers XCFHandler::isMetadataValid
- */
- public function testIsMetadataValid( $metadata, $expected ) {
- $actual = $this->handler->isMetadataValid( null, $metadata );
- $this->assertEquals( $expected, $actual );
- }
-
- public static function provideIsMetadataValid() {
- return [
- [ '', XCFHandler::METADATA_BAD ],
- [ serialize( [ 'error' => true ] ), XCFHandler::METADATA_GOOD ],
- [ false, XCFHandler::METADATA_BAD ],
- [ serialize( [ 'colorType' => 'greyscale-alpha' ] ), XCFHandler::METADATA_GOOD ],
- ];
- }
-
- /**
- * @param string $filename
- * @param string $expected Serialized array
- * @dataProvider provideGetMetadata
- * @covers XCFHandler::getMetadata
- */
- public function testGetMetadata( $filename, $expected ) {
- $file = $this->dataFile( $filename, 'image/png' );
- $actual = $this->handler->getMetadata( $file, "$this->filePath/$filename" );
- $this->assertEquals( $expected, $actual );
- }
-
- public static function provideGetMetadata() {
- return [
- [ '80x60-2layers.xcf',
- 'a:1:{s:9:"colorType";s:16:"truecolour-alpha";}'
- ],
- [ '80x60-RGB.xcf',
- 'a:1:{s:9:"colorType";s:16:"truecolour-alpha";}'
- ],
- [ '80x60-Greyscale.xcf',
- 'a:1:{s:9:"colorType";s:15:"greyscale-alpha";}'
- ],
- ];
- }
-}