Merge "Allow postEdit hook to be triggered asynchronously"
[lhc/web/wiklou.git] / includes / media / Bitmap.php
index 0f30c6f..9f7a09c 100644 (file)
@@ -29,7 +29,7 @@
 class BitmapHandler extends ImageHandler {
        /**
         * @param $image File
-        * @param $params array Transform parameters. Entries with the keys 'width'
+        * @param array $params Transform parameters. Entries with the keys 'width'
         * and 'height' are the respective screen width and height, while the keys
         * 'physicalWidth' and 'physicalHeight' indicate the thumbnail dimensions.
         * @return bool
@@ -75,7 +75,6 @@ class BitmapHandler extends ImageHandler {
                return true;
        }
 
-
        /**
         * Extracts the width/height if the image will be scaled before rotating
         *
@@ -84,8 +83,8 @@ class BitmapHandler extends ImageHandler {
         * stored as raw landscape with 90-degress rotation, the resulting size
         * will be wider than it is tall.
         *
-        * @param $params array Parameters as returned by normaliseParams
-        * @param $rotation int The rotation angle that will be applied
+        * @param array $params Parameters as returned by normaliseParams
+        * @param int $rotation The rotation angle that will be applied
         * @return array ($width, $height) array
         */
        public function extractPreRotationDimensions( $params, $rotation ) {
@@ -100,7 +99,6 @@ class BitmapHandler extends ImageHandler {
                return array( $width, $height );
        }
 
-
        /**
         * Function that returns the number of pixels to be thumbnailed.
         * Intended for animated GIFs to multiply by the number of frames.
@@ -133,7 +131,7 @@ class BitmapHandler extends ImageHandler {
                        # The size of the image on the page
                        'clientWidth' => $params['width'],
                        'clientHeight' => $params['height'],
-                       # Comment as will be added to the EXIF of the thumbnail
+                       # Comment as will be added to the Exif of the thumbnail
                        'comment' => isset( $params['descriptionUrl'] ) ?
                                "File source: {$params['descriptionUrl']}" : '',
                        # Properties of the original image
@@ -158,7 +156,6 @@ class BitmapHandler extends ImageHandler {
                        return $this->getClientScalingThumbnailImage( $image, $scalerParams );
                }
 
-
                if ( $scaler == 'client' ) {
                        # Client-side image scaling, use the source URL
                        # Using the destination URL in a TRANSFORM_LATER request would be incorrect
@@ -167,8 +164,11 @@ class BitmapHandler extends ImageHandler {
 
                if ( $flags & self::TRANSFORM_LATER ) {
                        wfDebug( __METHOD__ . ": Transforming later per flags.\n" );
-                       return new ThumbnailImage( $image, $dstUrl, $scalerParams['clientWidth'],
-                               $scalerParams['clientHeight'], false );
+                       $params = array(
+                               'width' => $scalerParams['clientWidth'],
+                               'height' => $scalerParams['clientHeight']
+                       );
+                       return new ThumbnailImage( $image, $dstUrl, false, $params );
                }
 
                # Try to make a target path for the thumbnail
@@ -220,8 +220,11 @@ class BitmapHandler extends ImageHandler {
                } elseif ( $mto ) {
                        return $mto;
                } else {
-                       return new ThumbnailImage( $image, $dstUrl, $scalerParams['clientWidth'],
-                               $scalerParams['clientHeight'], $dstPath );
+                       $params = array(
+                               'width' => $scalerParams['clientWidth'],
+                               'height' => $scalerParams['clientHeight']
+                       );
+                       return new ThumbnailImage( $image, $dstUrl, $dstPath, $params );
                }
        }
 
@@ -258,21 +261,24 @@ class BitmapHandler extends ImageHandler {
         * client side
         *
         * @param $image File File associated with this thumbnail
-        * @param $params array Array with scaler params
+        * @param array $scalerParams Array with scaler params
         * @return ThumbnailImage
         *
         * @todo fixme: no rotation support
         */
-       protected function getClientScalingThumbnailImage( $image, $params ) {
-               return new ThumbnailImage( $image, $image->getURL(),
-                       $params['clientWidth'], $params['clientHeight'], null );
+       protected function getClientScalingThumbnailImage( $image, $scalerParams ) {
+               $params = array(
+                       'width' => $scalerParams['clientWidth'],
+                       'height' => $scalerParams['clientHeight']
+               );
+               return new ThumbnailImage( $image, $image->getURL(), null, $params );
        }
 
        /**
         * Transform an image using ImageMagick
         *
         * @param $image File File associated with this thumbnail
-        * @param $params array Array with scaler params
+        * @param array $params Array with scaler params
         *
         * @return MediaTransformError Error object if error occurred, false (=no error) otherwise
         */
@@ -332,7 +338,7 @@ class BitmapHandler extends ImageHandler {
                $rotation = $this->getRotation( $image );
                list( $width, $height ) = $this->extractPreRotationDimensions( $params, $rotation );
 
-               $cmd  =
+               $cmd =
                        wfEscapeShellArg( $wgImageMagickConvertCommand ) .
                        // Specify white background color, will be used for transparent images
                        // in Internet Explorer/Windows instead of default black.
@@ -371,7 +377,7 @@ class BitmapHandler extends ImageHandler {
         * Transform an image using the Imagick PHP extension
         *
         * @param $image File File associated with this thumbnail
-        * @param $params array Array with scaler params
+        * @param array $params Array with scaler params
         *
         * @return MediaTransformError Error object if error occurred, false (=no error) otherwise
         */
@@ -392,7 +398,7 @@ class BitmapHandler extends ImageHandler {
                                        $im->sharpenImage( $radius, $sigma );
                                }
                                $im->setCompressionQuality( 80 );
-                       } elseif( $params['mimeType'] == 'image/png' ) {
+                       } elseif ( $params['mimeType'] == 'image/png' ) {
                                $im->setCompressionQuality( 95 );
                        } elseif ( $params['mimeType'] == 'image/gif' ) {
                                if ( $this->getImageArea( $image ) > $wgMaxAnimatedGifArea ) {
@@ -448,7 +454,7 @@ class BitmapHandler extends ImageHandler {
         * Transform an image using a custom command
         *
         * @param $image File File associated with this thumbnail
-        * @param $params array Array with scaler params
+        * @param array $params Array with scaler params
         *
         * @return MediaTransformError Error object if error occurred, false (=no error) otherwise
         */
@@ -491,8 +497,8 @@ class BitmapHandler extends ImageHandler {
        /**
         * Get a MediaTransformError with error 'thumbnail_error'
         *
-        * @param $params array Parameter array as passed to the transform* functions
-        * @param $errMsg string Error message
+        * @param array $params Parameter array as passed to the transform* functions
+        * @param string $errMsg Error message
         * @return MediaTransformError
         */
        public function getMediaTransformError( $params, $errMsg ) {
@@ -504,7 +510,7 @@ class BitmapHandler extends ImageHandler {
         * Transform an image using the built in GD library
         *
         * @param $image File File associated with this thumbnail
-        * @param $params array Array with scaler params
+        * @param array $params Array with scaler params
         *
         * @return MediaTransformError Error object if error occurred, false (=no error) otherwise
         */
@@ -524,7 +530,7 @@ class BitmapHandler extends ImageHandler {
                if ( !isset( $typemap[$params['mimeType']] ) ) {
                        $err = 'Image type not supported';
                        wfDebug( "$err\n" );
-                       $errMsg = wfMsg( 'thumbnail_image-type' );
+                       $errMsg = wfMessage( 'thumbnail_image-type' )->text();
                        return $this->getMediaTransformError( $params, $errMsg );
                }
                list( $loader, $colorStyle, $saveType ) = $typemap[$params['mimeType']];
@@ -532,14 +538,14 @@ class BitmapHandler extends ImageHandler {
                if ( !function_exists( $loader ) ) {
                        $err = "Incomplete GD library configuration: missing function $loader";
                        wfDebug( "$err\n" );
-                       $errMsg = wfMsg( 'thumbnail_gd-library', $loader );
+                       $errMsg = wfMessage( 'thumbnail_gd-library', $loader )->text();
                        return $this->getMediaTransformError( $params, $errMsg );
                }
 
                if ( !file_exists( $params['srcPath'] ) ) {
                        $err = "File seems to be missing: {$params['srcPath']}";
                        wfDebug( "$err\n" );
-                       $errMsg = wfMsg( 'thumbnail_image-missing', $params['srcPath'] );
+                       $errMsg = wfMessage( 'thumbnail_image-missing', $params['srcPath'] )->text();
                        return $this->getMediaTransformError( $params, $errMsg );
                }
 
@@ -613,8 +619,9 @@ class BitmapHandler extends ImageHandler {
         * in a directory, so we're better off escaping and waiting for the bugfix
         * to filter down to users.
         *
-        * @param $path string The file path
-        * @param $scene string The scene specification, or false if there is none
+        * @param string $path The file path
+        * @param bool|string $scene The scene specification, or false if there is none
+        * @throws MWException
         * @return string
         */
        function escapeMagickInput( $path, $scene = false ) {
@@ -644,8 +651,9 @@ class BitmapHandler extends ImageHandler {
         * Armour a string against ImageMagick's GetPathComponent(). This is a
         * helper function for escapeMagickInput() and escapeMagickOutput().
         *
-        * @param $path string The file path
-        * @param $scene string The scene specification, or false if there is none
+        * @param string $path The file path
+        * @param bool|string $scene The scene specification, or false if there is none
+        * @throws MWException
         * @return string
         */
        protected function escapeMagickPath( $path, $scene = false ) {
@@ -747,6 +755,55 @@ class BitmapHandler extends ImageHandler {
                }
        }
 
+       /**
+        * @param $file File
+        * @param array $params Rotate parameters.
+        *      'rotation' clockwise rotation in degrees, allowed are multiples of 90
+        * @since 1.21
+        * @return bool
+        */
+       public function rotate( $file, $params ) {
+               global $wgImageMagickConvertCommand;
+
+               $rotation = ( $params['rotation'] + $this->getRotation( $file ) ) % 360;
+               $scene = false;
+
+               $scaler = self::getScalerType( null, false );
+               switch ( $scaler ) {
+                       case 'im':
+                               $cmd = wfEscapeShellArg( $wgImageMagickConvertCommand ) . " " .
+                                       wfEscapeShellArg( $this->escapeMagickInput( $params['srcPath'], $scene ) ) .
+                                       " -rotate -$rotation " .
+                                       wfEscapeShellArg( $this->escapeMagickOutput( $params['dstPath'] ) ) . " 2>&1";
+                               wfDebug( __METHOD__ . ": running ImageMagick: $cmd\n" );
+                               wfProfileIn( 'convert' );
+                               $retval = 0;
+                               $err = wfShellExec( $cmd, $retval, $env );
+                               wfProfileOut( 'convert' );
+                               if ( $retval !== 0 ) {
+                                       $this->logErrorForExternalProcess( $retval, $err, $cmd );
+                                       return new MediaTransformError( 'thumbnail_error', 0, 0, $err );
+                               }
+                               return false;
+                       case 'imext':
+                               $im = new Imagick();
+                               $im->readImage( $params['srcPath'] );
+                               if ( !$im->rotateImage( new ImagickPixel( 'white' ), 360 - $rotation ) ) {
+                                       return new MediaTransformError( 'thumbnail_error', 0, 0,
+                                               "Error rotating $rotation degrees" );
+                               }
+                               $result = $im->writeImage( $params['dstPath'] );
+                               if ( !$result ) {
+                                       return new MediaTransformError( 'thumbnail_error', 0, 0,
+                                               "Unable to write image to {$params['dstPath']}" );
+                               }
+                               return false;
+                       default:
+                               return new MediaTransformError( 'thumbnail_error', 0, 0,
+                                       "$scaler rotation not implemented" );
+               }
+       }
+
        /**
         * Rerurns whether the file needs to be rendered. Returns true if the
         * file requires rotation and we are able to rotate it.