Fix switch fail in r83778: add missing break.
[lhc/web/wiklou.git] / includes / media / Bitmap.php
index 5d4de7e..0c717f7 100644 (file)
  * @ingroup Media
  */
 class BitmapHandler extends ImageHandler {
+
+       /**
+        * @param $image File
+        * @param  $params
+        * @return bool
+        */
        function normaliseParams( $image, &$params ) {
                global $wgMaxImageArea;
                if ( !parent::normaliseParams( $image, $params ) ) {
@@ -22,10 +28,10 @@ class BitmapHandler extends ImageHandler {
                $srcWidth = $image->getWidth( $params['page'] );
                $srcHeight = $image->getHeight( $params['page'] );
                
-               if ( $this->canRotate() ) {
+               if ( self::canRotate() ) {
                        $rotation = $this->getRotation( $image );
                        if ( $rotation == 90 || $rotation == 270 ) {
-                               wfDebug( __METHOD__ . ": Swapping width and height because the file will be rotation $rotation degrees\n" );
+                               wfDebug( __METHOD__ . ": Swapping width and height because the file will be rotated $rotation degrees\n" );
                                
                                $width = $params['width'];
                                $params['width'] = $params['height'];
@@ -65,9 +71,15 @@ class BitmapHandler extends ImageHandler {
                return $width * $height;
        }
 
+       /**
+        * @param $image File
+        * @param  $dstPath
+        * @param  $dstUrl
+        * @param  $params
+        * @param int $flags
+        * @return MediaTransformError|ThumbnailImage|TransformParameterError
+        */
        function doTransform( $image, $dstPath, $dstUrl, $params, $flags = 0 ) {
-               global $wgCustomConvertCommand;
-
                if ( !$this->normaliseParams( $image, $params ) ) {
                        return new TransformParameterError( $params );
                }
@@ -103,7 +115,7 @@ class BitmapHandler extends ImageHandler {
                }
 
                # Determine scaler type
-               $scaler = $this->getScalerType( $dstPath );
+               $scaler = self::getScalerType( $dstPath );
                wfDebug( __METHOD__ . ": scaler $scaler\n" );
 
                if ( $scaler == 'client' ) {
@@ -131,6 +143,9 @@ class BitmapHandler extends ImageHandler {
                        case 'custom':
                                $err = $this->transformCustom( $image, $scalerParams );
                                break;
+                       case 'imext':
+                               $err = $this->transformImageMagickExt( $image, $scalerParams );
+                               break;
                        case 'gd':
                        default:
                                $err = $this->transformGd( $image, $scalerParams );
@@ -158,7 +173,7 @@ class BitmapHandler extends ImageHandler {
         * 
         * @return string client,im,custom,gd
         */
-       protected function getScalerType( $dstPath, $checkDstPath = true ) {
+       protected static function getScalerType( $dstPath, $checkDstPath = true ) {
                global $wgUseImageResize, $wgUseImageMagick, $wgCustomConvertCommand;
                
                if ( !$dstPath && $checkDstPath ) {
@@ -172,6 +187,8 @@ class BitmapHandler extends ImageHandler {
                        $scaler = 'custom';
                } elseif ( function_exists( 'imagecreatetruecolor' ) ) {
                        $scaler = 'gd';
+               } elseif ( class_exists( 'Imagick' ) ) {
+                       $scaler = 'imext';
                } else {
                        $scaler = 'client';
                }
@@ -197,7 +214,7 @@ class BitmapHandler extends ImageHandler {
                return new ThumbnailImage( $image, $image->getURL(),
                                $params['clientWidth'], $params['clientHeight'], $params['srcPath'] );
        }
-
+       
        /**
         * Transform an image using ImageMagick
         *
@@ -289,6 +306,91 @@ class BitmapHandler extends ImageHandler {
 
                return false; # No error
        }
+       
+       /**
+        * Transform an image using the Imagick PHP extension
+        * 
+        * @param $image File File associated with this thumbnail
+        * @param $params array Array with scaler params
+        *
+        * @return MediaTransformError Error object if error occured, false (=no error) otherwise
+        */
+       protected function transformImageMagickExt( $image, $params ) {
+               global $wgSharpenReductionThreshold, $wgSharpenParameter, $wgMaxAnimatedGifArea;
+               
+               try {
+                       $im = new Imagick();
+                       $im->readImage( $params['srcPath'] );
+       
+                       if ( $params['mimeType'] == 'image/jpeg' ) {
+                               // Sharpening, see bug 6193
+                               if ( ( $params['physicalWidth'] + $params['physicalHeight'] )
+                                               / ( $params['srcWidth'] + $params['srcHeight'] )
+                                               < $wgSharpenReductionThreshold ) {
+                                       // Hack, since $wgSharpenParamater is written specifically for the command line convert
+                                       list( $radius, $sigma ) = explode( 'x', $wgSharpenParameter );
+                                       $im->sharpenImage( $radius, $sigma );
+                               }
+                               $im->setCompressionQuality( 80 );
+                       } elseif( $params['mimeType'] == 'image/png' ) {
+                               $im->setCompressionQuality( 95 );
+                       } elseif ( $params['mimeType'] == 'image/gif' ) {
+                               if ( $this->getImageArea( $image, $params['srcWidth'],
+                                               $params['srcHeight'] ) > $wgMaxAnimatedGifArea ) {
+                                       // Extract initial frame only; we're so big it'll
+                                       // be a total drag. :P
+                                       $im->setImageScene( 0 );
+                               } elseif ( $this->isAnimatedImage( $image ) ) {
+                                       // Coalesce is needed to scale animated GIFs properly (bug 1017).
+                                       $im = $im->coalesceImages();
+                               }
+                       }
+                       
+                       $rotation = $this->getRotation( $image );
+                       if ( $rotation == 90 || $rotation == 270 ) {
+                               // We'll resize before rotation, so swap the dimensions again
+                               $width = $params['physicalHeight'];
+                               $height = $params['physicalWidth'];
+                       } else {
+                               $width = $params['physicalWidth'];
+                               $height = $params['physicalHeight'];                    
+                       }
+                       
+                       $im->setImageBackgroundColor( new ImagickPixel( 'white' ) );
+                       
+                       // Call Imagick::thumbnailImage on each frame
+                       foreach ( $im as $i => $frame ) {
+                               if ( !$frame->thumbnailImage( $width, $height, /* fit */ false ) ) {
+                                       return $this->getMediaTransformError( $params, "Error scaling frame $i" );
+                               }
+                       }
+                       $im->setImageDepth( 8 );
+                       
+                       if ( $rotation ) {
+                               if ( !$im->rotateImage( new ImagickPixel( 'white' ), $rotation ) ) {
+                                       return $this->getMediaTransformError( $params, "Error rotating $rotation degrees" );
+                               }
+                       }
+       
+                       if ( $this->isAnimatedImage( $image ) ) {
+                               wfDebug( __METHOD__ . ": Writing animated thumbnail\n" );
+                               // This is broken somehow... can't find out how to fix it
+                               $result = $im->writeImages( $params['dstPath'], true );
+                       } else {
+                               $result = $im->writeImage( $params['dstPath'] );
+                       }
+                       if ( !$result ) {
+                               return $this->getMediaTransformError( $params, 
+                                       "Unable to write thumbnail to {$params['dstPath']}" );
+                       }
+
+               } catch ( ImagickException $e ) {
+                       return $this->getMediaTransformError( $params, $e->getMessage() ); 
+               }
+               
+               return false;
+               
+       }
 
        /**
         * Transform an image using a custom command
@@ -390,7 +492,8 @@ class BitmapHandler extends ImageHandler {
                }
 
                $src_image = call_user_func( $loader, $params['srcPath'] );
-               $rotation = $this->getRotation( $image );
+               
+               $rotation = function_exists( 'imagerotate' ) ? $this->getRotation( $image ) : 0;
                if ( $rotation == 90 || $rotation == 270 ) {
                        # We'll resize before rotation, so swap the dimensions again
                        $width = $params['physicalHeight'];
@@ -616,6 +719,10 @@ class BitmapHandler extends ImageHandler {
                return $fields;
        }
 
+       /**
+        * @param $image File
+        * @return array|bool
+        */
        function formatMetadata( $image ) {
                $result = array(
                        'visible' => array(),
@@ -680,9 +787,23 @@ class BitmapHandler extends ImageHandler {
         * 
         * @return bool
         */
-       public function canRotate() {
-               $scaler = $this->getScalerType( null, false );
-               return $scaler == 'im' || $scaler == 'gd';
+       public static function canRotate() {
+               $scaler = self::getScalerType( null, false );
+               switch ( $scaler ) {
+                       case 'im':
+                               # ImageMagick supports autorotation
+                               return true;
+                       case 'imext':
+                               # Imagick::rotateImage
+                               return true;
+                       case 'gd':
+                               # GD's imagerotate function is used to rotate images, but not
+                               # all precompiled PHP versions have that function
+                               return function_exists( 'imagerotate' );
+                       default:
+                               # Other scalers don't support rotation
+                               return false;
+               }
        }
        
        /**
@@ -693,6 +814,6 @@ class BitmapHandler extends ImageHandler {
         * @return bool
         */
        public function mustRender( $file ) {
-               return $this->canRotate() && $this->getRotation( $file ) != 0;
+               return self::canRotate() && $this->getRotation( $file ) != 0;
        }
 }