Merge "Stop doing $that = $this in includes/libs"
[lhc/web/wiklou.git] / includes / media / Bitmap.php
index faf40b3..c2b82d8 100644 (file)
@@ -59,6 +59,51 @@ class BitmapHandler extends TransformationalImageHandler {
                return $scaler;
        }
 
+       function makeParamString( $params ) {
+               $res = parent::makeParamString( $params );
+               if ( isset( $params['interlace'] ) && $params['interlace'] ) {
+                       return "interlaced-{$res}";
+               } else {
+                       return $res;
+               }
+       }
+
+       function parseParamString( $str ) {
+               $remainder = preg_replace( '/^interlaced-/', '', $str );
+               $params = parent::parseParamString( $remainder );
+               if ( $params === false ) {
+                       return false;
+               }
+               $params['interlace'] = $str !== $remainder;
+               return $params;
+       }
+
+       function validateParam( $name, $value ) {
+               if ( $name === 'interlace' ) {
+                       return $value === false || $value === true;
+               } else {
+                       return parent::validateParam( $name, $value );
+               }
+       }
+
+       /**
+        * @param File $image
+        * @param array $params
+        * @return bool
+        */
+       function normaliseParams( $image, &$params ) {
+               global $wgMaxInterlacingAreas;
+               if ( !parent::normaliseParams( $image, $params ) ) {
+                       return false;
+               }
+               $mimeType = $image->getMimeType();
+               $interlace = isset( $params['interlace'] ) && $params['interlace']
+                       && isset( $wgMaxInterlacingAreas[$mimeType] )
+                       && $this->getImageArea( $image ) <= $wgMaxInterlacingAreas[$mimeType];
+               $params['interlace'] = $interlace;
+               return true;
+       }
+
        /**
         * Transform an image using ImageMagick
         *
@@ -70,7 +115,7 @@ class BitmapHandler extends TransformationalImageHandler {
        protected function transformImageMagick( $image, $params ) {
                # use ImageMagick
                global $wgSharpenReductionThreshold, $wgSharpenParameter, $wgMaxAnimatedGifArea,
-                       $wgImageMagickTempDir, $wgImageMagickConvertCommand;
+                       $wgImageMagickTempDir, $wgImageMagickConvertCommand, $wgMaxInterlacingAreas;
 
                $quality = array();
                $sharpen = array();
@@ -78,9 +123,13 @@ class BitmapHandler extends TransformationalImageHandler {
                $animation_pre = array();
                $animation_post = array();
                $decoderHint = array();
+
                if ( $params['mimeType'] == 'image/jpeg' ) {
                        $qualityVal = isset( $params['quality'] ) ? (string)$params['quality'] : null;
                        $quality = array( '-quality', $qualityVal ?: '80' ); // 80%
+                       if ( $params['interlace'] ) {
+                               $animation_post = array( '-interlace', 'JPEG' );
+                       }
                        # Sharpening, see bug 6193
                        if ( ( $params['physicalWidth'] + $params['physicalHeight'] )
                                / ( $params['srcWidth'] + $params['srcHeight'] )
@@ -92,7 +141,12 @@ class BitmapHandler extends TransformationalImageHandler {
                                // JPEG decoder hint to reduce memory, available since IM 6.5.6-2
                                $decoderHint = array( '-define', "jpeg:size={$params['physicalDimensions']}" );
                        }
-               } elseif ( $params['mimeType'] == 'image/png' || $params['mimeType'] == 'image/webp' ) {
+               } elseif ( $params['mimeType'] == 'image/png' ) {
+                       $quality = array( '-quality', '95' ); // zlib 9, adaptive filtering
+                       if ( $params['interlace'] ) {
+                               $animation_post = array( '-interlace', 'PNG' );
+                       }
+               } elseif ( $params['mimeType'] == 'image/webp' ) {
                        $quality = array( '-quality', '95' ); // zlib 9, adaptive filtering
                } elseif ( $params['mimeType'] == 'image/gif' ) {
                        if ( $this->getImageArea( $image ) > $wgMaxAnimatedGifArea ) {
@@ -108,6 +162,11 @@ class BitmapHandler extends TransformationalImageHandler {
                                        $animation_post = array( '-fuzz', '5%', '-layers', 'optimizeTransparency' );
                                }
                        }
+                       if ( $params['interlace'] && version_compare( $this->getMagickVersion(), "6.3.4" ) >= 0
+                               && !$this->isAnimatedImage( $image ) ) { // interlacing animated GIFs is a bad idea
+                               $animation_post[] = '-interlace';
+                               $animation_post[] = 'GIF';
+                       }
                } elseif ( $params['mimeType'] == 'image/x-xcf' ) {
                        // Before merging layers, we need to set the background
                        // to be transparent to preserve alpha, as -layers merge
@@ -191,7 +250,8 @@ class BitmapHandler extends TransformationalImageHandler {
         * @return MediaTransformError Error object if error occurred, false (=no error) otherwise
         */
        protected function transformImageMagickExt( $image, $params ) {
-               global $wgSharpenReductionThreshold, $wgSharpenParameter, $wgMaxAnimatedGifArea;
+               global $wgSharpenReductionThreshold, $wgSharpenParameter, $wgMaxAnimatedGifArea,
+                       $wgMaxInterlacingAreas;
 
                try {
                        $im = new Imagick();
@@ -209,8 +269,14 @@ class BitmapHandler extends TransformationalImageHandler {
                                }
                                $qualityVal = isset( $params['quality'] ) ? (string)$params['quality'] : null;
                                $im->setCompressionQuality( $qualityVal ?: 80 );
+                               if ( $params['interlace'] ) {
+                                       $im->setInterlaceScheme( Imagick::INTERLACE_JPEG );
+                               }
                        } elseif ( $params['mimeType'] == 'image/png' ) {
                                $im->setCompressionQuality( 95 );
+                               if ( $params['interlace'] ) {
+                                       $im->setInterlaceScheme( Imagick::INTERLACE_PNG );
+                               }
                        } elseif ( $params['mimeType'] == 'image/gif' ) {
                                if ( $this->getImageArea( $image ) > $wgMaxAnimatedGifArea ) {
                                        // Extract initial frame only; we're so big it'll
@@ -220,6 +286,13 @@ class BitmapHandler extends TransformationalImageHandler {
                                        // Coalesce is needed to scale animated GIFs properly (bug 1017).
                                        $im = $im->coalesceImages();
                                }
+                               // GIF interlacing is only available since 6.3.4
+                               $v = Imagick::getVersion();
+                               preg_match( '/ImageMagick ([0-9]+\.[0-9]+\.[0-9]+)/', $v['versionString'], $v );
+
+                               if ( $params['interlace'] && version_compare( $v[1], '6.3.4' ) >= 0 ) {
+                                       $im->setInterlaceScheme( Imagick::INTERLACE_GIF );
+                               }
                        }
 
                        $rotation = isset( $params['disableRotation'] ) ? 0 : $this->getRotation( $image );