From 584a23931854e256eb219483cf5cba8ecc411ee8 Mon Sep 17 00:00:00 2001 From: Gilles Dubuc Date: Mon, 15 Jun 2015 18:23:46 +0200 Subject: [PATCH] TinyRGB support for JPG thumbnails TinyRGB is an ICC profile released by Facebook under CC0. It is designed to be fully compatible with sRGB. It offers the vast advantages of being much smaller than sRGB, as well as being free as in freedom (the sRGB profile found in the majority of JPGs is copyrighted). This change aims to provide the ability to swap sRGB for TinyRGB at the time thumbnails are generated. JPGs that use another ICC profile than sRGB or no profile at all are unaffected. Bug: T100976 Change-Id: I2ae35ddad4e8a82db8b9541974367dc76c884e7a --- includes/DefaultSettings.php | 16 ++++ includes/media/Bitmap.php | 3 +- includes/media/ExifBitmap.php | 70 ++++++++++++++++++ includes/media/Jpeg.php | 2 +- includes/media/tinyrgb.icc | Bin 0 -> 524 bytes maintenance/dictionary/mediawiki.dic | 1 + tests/phpunit/data/media/srgb.jpg | Bin 0 -> 7738 bytes tests/phpunit/data/media/tinyrgb.icc | Bin 0 -> 524 bytes tests/phpunit/data/media/tinyrgb.jpg | Bin 0 -> 5118 bytes .../phpunit/includes/media/ExifBitmapTest.php | 39 +++++++++- 10 files changed, 128 insertions(+), 3 deletions(-) create mode 100644 includes/media/tinyrgb.icc create mode 100644 tests/phpunit/data/media/srgb.jpg create mode 100644 tests/phpunit/data/media/tinyrgb.icc create mode 100644 tests/phpunit/data/media/tinyrgb.jpg diff --git a/includes/DefaultSettings.php b/includes/DefaultSettings.php index 39f739da56..0aba961fb9 100644 --- a/includes/DefaultSettings.php +++ b/includes/DefaultSettings.php @@ -970,6 +970,14 @@ $wgJpegTran = '/usr/bin/jpegtran'; */ $wgExiv2Command = '/usr/bin/exiv2'; + +/** + * Path to exiftool binary. Used for lossless ICC profile swapping. + * + * @since 1.26 + */ +$wgExiftool = '/usr/bin/exiftool'; + /** * Scalable Vector Graphics (SVG) may be uploaded as images. * Since SVG support is not yet standard in browsers, it is @@ -1322,6 +1330,14 @@ $wgUploadThumbnailRenderHttpCustomHost = false; */ $wgUploadThumbnailRenderHttpCustomDomain = false; +/** + * When this variable is true and JPGs use the sRGB ICC profile, swaps it for the more lightweight + * (and free) TinyRGB profile when generating thumbnails. + * + * @since 1.26 + */ +$wgUseTinyRGBForJPGThumbnails = false; + /** * Default parameters for the "" tag */ diff --git a/includes/media/Bitmap.php b/includes/media/Bitmap.php index 09d3807815..5af7fbe1ae 100644 --- a/includes/media/Bitmap.php +++ b/includes/media/Bitmap.php @@ -70,7 +70,8 @@ class BitmapHandler extends TransformationalImageHandler { protected function transformImageMagick( $image, $params ) { # use ImageMagick global $wgSharpenReductionThreshold, $wgSharpenParameter, $wgMaxAnimatedGifArea, - $wgImageMagickTempDir, $wgImageMagickConvertCommand; + $wgImageMagickTempDir, $wgImageMagickConvertCommand, $wgResourceBasePath, + $wgUseTinyRGBForJPGThumbnails; $quality = array(); $sharpen = array(); diff --git a/includes/media/ExifBitmap.php b/includes/media/ExifBitmap.php index bf6f7fcebf..5ba5c68c00 100644 --- a/includes/media/ExifBitmap.php +++ b/includes/media/ExifBitmap.php @@ -30,6 +30,7 @@ class ExifBitmapHandler extends BitmapHandler { const BROKEN_FILE = '-1'; // error extracting metadata const OLD_BROKEN_FILE = '0'; // outdated error extracting metadata. + const SRGB_ICC_PROFILE_NAME = 'IEC 61966-2.1 Default RGB colour space - sRGB'; function convertMetadataVersion( $metadata, $version = 1 ) { // basically flattens arrays. @@ -243,4 +244,73 @@ class ExifBitmapHandler extends BitmapHandler { return 0; } + + protected function transformImageMagick( $image, $params ) { + global $wgUseTinyRGBForJPGThumbnails; + + $ret = parent::transformImageMagick( $image, $params ); + + if ( $ret ) { + return $ret; + } + + if ( $params['mimeType'] === 'image/jpeg' && $wgUseTinyRGBForJPGThumbnails ) { + // T100976 If the profile embedded in the JPG is sRGB, swap it for the smaller + // (and free) TinyRGB + + $this->swapICCProfile( + $params['dstPath'], + self::SRGB_ICC_PROFILE_NAME, + realpath( __DIR__ ) . '/tinyrgb.icc' + ); + } + + return false; + } + + /** + * Swaps an embedded ICC profile for another, if found. Depends on exiftool, no-op if not installed. + * @param string $filepath File to be manipulated (will be overwritten) + * @param string $oldProfileString Exact name of color profile to look for (the one that will be replaced) + * @param string $profileFilepath ICC profile file to apply to the file + * @since 1.26 + * @return bool + */ + public function swapICCProfile( $filepath, $oldProfileString, $profileFilepath ) { + global $wgExiftool; + + if ( !$wgExiftool || !is_executable( $wgExiftool ) ) { + return false; + } + + $cmd = wfEscapeShellArg( $wgExiftool, + '-DeviceModelDesc', + '-S', + '-T', + $filepath + ); + + $output = wfShellExecWithStderr( $cmd, $retval ); + + if ( $retval !== 0 || strcasecmp( trim( $output ), $oldProfileString ) !== 0 ) { + // We can't establish that this file has the expected ICC profile, don't process it + return false; + } + + $cmd = wfEscapeShellArg( $wgExiftool, + '-overwrite_original', + '-icc_profile<=' . $profileFilepath, + $filepath + ); + + $output = wfShellExecWithStderr( $cmd, $retval ); + + if ( $retval !== 0 ) { + $this->logErrorForExternalProcess( $retval, $output, $cmd ); + + return false; + } + + return true; + } } diff --git a/includes/media/Jpeg.php b/includes/media/Jpeg.php index 5463922b14..040ff96e1c 100644 --- a/includes/media/Jpeg.php +++ b/includes/media/Jpeg.php @@ -137,7 +137,7 @@ class JpegHandler extends ExifBitmapHandler { $rotation = ( $params['rotation'] + $this->getRotation( $file ) ) % 360; - if ( $wgJpegTran && is_file( $wgJpegTran ) ) { + if ( $wgJpegTran && is_executable( $wgJpegTran ) ) { $cmd = wfEscapeShellArg( $wgJpegTran ) . " -rotate " . wfEscapeShellArg( $rotation ) . " -outfile " . wfEscapeShellArg( $params['dstPath'] ) . diff --git a/includes/media/tinyrgb.icc b/includes/media/tinyrgb.icc new file mode 100644 index 0000000000000000000000000000000000000000..eab973f57dc6ee32a4832463a8d156f4745a6c26 GIT binary patch literal 524 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 N@d`;#oYMK?zX6GdUFiS- literal 0 HcmV?d00001 diff --git a/tests/phpunit/data/media/tinyrgb.icc b/tests/phpunit/data/media/tinyrgb.icc new file mode 100644 index 0000000000000000000000000000000000000000..eab973f57dc6ee32a4832463a8d156f4745a6c26 GIT binary patch literal 524 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 H%Z2{}yb8S* literal 0 HcmV?d00001 diff --git a/tests/phpunit/includes/media/ExifBitmapTest.php b/tests/phpunit/includes/media/ExifBitmapTest.php index 41330f4182..adbc97757c 100644 --- a/tests/phpunit/includes/media/ExifBitmapTest.php +++ b/tests/phpunit/includes/media/ExifBitmapTest.php @@ -3,7 +3,7 @@ /** * @group Media */ -class ExifBitmapTest extends MediaWikiTestCase { +class ExifBitmapTest extends MediaWikiMediaTestCase { /** * @var ExifBitmapHandler @@ -143,4 +143,41 @@ class ExifBitmapTest extends MediaWikiTestCase { $res = $this->handler->convertMetadataVersion( $metadata, 1 ); $this->assertEquals( $expected, $res ); } + + /** + * @dataProvider provideSwappingICCProfile + * @covers BitmapHandler::swapICCProfile + */ + public function testSwappingICCProfile( $sourceFilename, $controlFilename, $newProfileFilename, $oldProfileName ) { + global $wgExiftool; + + if ( !$wgExiftool || !is_file( $wgExiftool ) ) { + $this->markTestSkipped( "Exiftool not installed, cannot test ICC profile swapping" ); + } + + $this->setMwGlobals( 'wgUseTinyRGBForJPGThumbnails', true ); + + $sourceFilepath = $this->filePath . $sourceFilename; + $controlFilepath = $this->filePath . $controlFilename; + $profileFilepath = $this->filePath . $newProfileFilename; + $filepath = $this->getNewTempFile(); + + copy( $sourceFilepath, $filepath ); + + $file = $this->dataFile( $sourceFilename, 'image/jpeg' ); + $this->handler->swapICCProfile( $filepath, $oldProfileName, $profileFilepath ); + + $this->assertEquals( sha1( file_get_contents( $filepath ) ), sha1( file_get_contents( $controlFilepath ) ) ); + } + + public function provideSwappingICCProfile() { + return array( + // File with sRGB should end up with TinyRGB + array( 'srgb.jpg', 'tinyrgb.jpg', 'tinyrgb.icc', 'IEC 61966-2.1 Default RGB colour space - sRGB' ), + // File with TinyRGB should be left unchanged + array( 'tinyrgb.jpg', 'tinyrgb.jpg', 'tinyrgb.icc', 'IEC 61966-2.1 Default RGB colour space - sRGB' ), + // File with no profile should be left unchanged + array( 'test.jpg', 'test.jpg', 'tinyrgb.icc', 'IEC 61966-2.1 Default RGB colour space - sRGB' ) + ); + } } -- 2.20.1