(bug 14706) Added support for the Imagick PHP extension. Based on patch by Leslie...
authorBryan Tong Minh <btongminh@users.mediawiki.org>
Sat, 12 Mar 2011 19:32:39 +0000 (19:32 +0000)
committerBryan Tong Minh <btongminh@users.mediawiki.org>
Sat, 12 Mar 2011 19:32:39 +0000 (19:32 +0000)
Scaler type is "imext". Rotation is supported.
Logic mostly copied from transformImagemagick() and ported to Imagick calls.
Resizing animated gifs is broken; it only shows the first frame and I can't find out why it does not work, but otherwise it is fully working.

CREDITS
RELEASE-NOTES
includes/media/Bitmap.php

diff --git a/CREDITS b/CREDITS
index a13c0f4..463b744 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -34,6 +34,7 @@ following names for their contribution to the product.
 * Jon Harald Søby
 * Juliano F. Ravasi
 * Leon Weber
+* Leslie Hoare
 * Marco Schuster
 * Matěj Grabovský
 * Matt Johnston
index 15c2083..7cd82ef 100644 (file)
@@ -102,6 +102,7 @@ PHP if you have not done so prior to upgrading MediaWiki.
   several wikis.
 * When $wgAllowMicrodataAttributes is true, all itemtypes are allowed, not just
   the three that were defined in the original specification.
+* (bug 14706) Added support for the Imagick PHP extension.
 
 === Bug fixes in 1.18 ===
 * (bug 23119) WikiError class and subclasses are now marked as deprecated
index cc7b052..74be0ba 100644 (file)
@@ -143,6 +143,8 @@ class BitmapHandler extends ImageHandler {
                        case 'custom':
                                $err = $this->transformCustom( $image, $scalerParams );
                                break;
+                       case 'imext':
+                               $err = $this->transformImageMagickExt( $image, $scalerParams );
                        case 'gd':
                        default:
                                $err = $this->transformGd( $image, $scalerParams );
@@ -184,6 +186,8 @@ class BitmapHandler extends ImageHandler {
                        $scaler = 'custom';
                } elseif ( function_exists( 'imagecreatetruecolor' ) ) {
                        $scaler = 'gd';
+               } elseif ( class_exists( 'Imagick' ) ) {
+                       $scaler = 'imext';
                } else {
                        $scaler = 'client';
                }
@@ -209,7 +213,7 @@ class BitmapHandler extends ImageHandler {
                return new ThumbnailImage( $image, $image->getURL(),
                                $params['clientWidth'], $params['clientHeight'], $params['srcPath'] );
        }
-
+       
        /**
         * Transform an image using ImageMagick
         *
@@ -301,6 +305,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
@@ -703,6 +792,9 @@ class BitmapHandler extends ImageHandler {
                        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