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
return true;
}
-
/**
* Extracts the width/height if the image will be scaled before rotating
*
* 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 ) {
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.
- *
- * @param File $image
- * @return int
- */
- function getImageArea( $image ) {
- return $image->getWidth() * $image->getHeight();
- }
-
/**
* @param $image File
* @param $dstPath
# 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
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
# Transform functions and binaries need a FS source file
$scalerParams['srcPath'] = $image->getLocalRefPath();
+ if ( $scalerParams['srcPath'] === false ) { // Failed to get local copy
+ wfDebugLog( 'thumbnail',
+ sprintf( 'Thumbnail failed on %s: could not get local copy of "%s"',
+ wfHostname(), $image->getName() ) );
+ return new MediaTransformError( 'thumbnail_error',
+ $scalerParams['clientWidth'], $scalerParams['clientHeight'] );
+ }
# Try a hook
$mto = null;
* client side
*
* @param $image File File associated with this thumbnail
- * @param $scalerParams array Array with scaler params
+ * @param array $scalerParams Array with scaler params
* @return ThumbnailImage
*
* @todo fixme: no rotation support
* 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
*/
$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.
" -depth 8 $sharpen " .
" -rotate -$rotation " .
" {$animation_post} " .
- wfEscapeShellArg( $this->escapeMagickOutput( $params['dstPath'] ) ) . " 2>&1";
+ wfEscapeShellArg( $this->escapeMagickOutput( $params['dstPath'] ) );
wfDebug( __METHOD__ . ": running ImageMagick: $cmd\n" );
wfProfileIn( 'convert' );
$retval = 0;
- $err = wfShellExec( $cmd, $retval, $env );
+ $err = wfShellExecWithStderr( $cmd, $retval, $env );
wfProfileOut( 'convert' );
if ( $retval !== 0 ) {
* 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
*/
$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 ) {
* 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
*/
wfDebug( __METHOD__ . ": Running custom convert command $cmd\n" );
wfProfileIn( 'convert' );
$retval = 0;
- $err = wfShellExec( $cmd, $retval );
+ $err = wfShellExecWithStderr( $cmd, $retval );
wfProfileOut( 'convert' );
if ( $retval !== 0 ) {
/**
* 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 ) {
* 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
*/
* 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 string $path The file path
* @param bool|string $scene The scene specification, or false if there is none
* @throws MWException
* @return string
* Armour a string against ImageMagick's GetPathComponent(). This is a
* helper function for escapeMagickInput() and escapeMagickOutput().
*
- * @param $path string The file path
+ * @param string $path The file path
* @param bool|string $scene The scene specification, or false if there is none
* @throws MWException
* @return string
imagejpeg( $dst_image, $thumbPath, 95 );
}
- /**
- * On supporting image formats, try to read out the low-level orientation
- * of the file and return the angle that the file needs to be rotated to
- * be viewed.
- *
- * This information is only useful when manipulating the original file;
- * the width and height we normally work with is logical, and will match
- * any produced output views.
- *
- * The base BitmapHandler doesn't understand any metadata formats, so this
- * is left up to child classes to implement.
- *
- * @param $file File
- * @return int 0, 90, 180 or 270
- */
- public function getRotation( $file ) {
- return 0;
- }
-
/**
* Returns whether the current scaler supports rotation (im and gd do)
*
}
}
+ /**
+ * @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'] ) );
+ wfDebug( __METHOD__ . ": running ImageMagick: $cmd\n" );
+ wfProfileIn( 'convert' );
+ $retval = 0;
+ $err = wfShellExecWithStderr( $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.