$params['physicalWidth'] = $srcWidth;
$params['physicalHeight'] = $srcHeight;
# Skip scaling limit checks if no scaling is required
- if( !$image->mustRender() )
+ if ( !$image->mustRender() )
return true;
}
return true;
}
-
-
+
+
// Function that returns the number of pixels to be thumbnailed.
// Intended for animated GIFs to multiply by the number of frames.
function getImageArea( $image, $width, $height ) {
'clientWidth' => $params['width'],
'clientHeight' => $params['height'],
# Comment as will be added to the EXIF of the thumbnail
- 'comment' => isset( $params['descriptionUrl'] ) ?
+ 'comment' => isset( $params['descriptionUrl'] ) ?
"File source: {$params['descriptionUrl']}" : '',
# Properties of the original image
'srcWidth' => $image->getWidth(),
wfDebug( __METHOD__ . ": creating {$scalerParams['physicalSize']} thumbnail at $dstPath\n" );
- if ( !$image->mustRender() &&
+ if ( !$image->mustRender() &&
$scalerParams['physicalWidth'] == $scalerParams['srcWidth']
&& $scalerParams['physicalHeight'] == $scalerParams['srcHeight'] ) {
-
+
# normaliseParams (or the user) wants us to return the unscaled image
wfDebug( __METHOD__ . ": returning unscaled image\n" );
return $this->getClientScalingThumbnailImage( $image, $scalerParams );
if ( !$dstPath ) {
# No output path available, client side scaling only
$scaler = 'client';
- } elseif( !$wgUseImageResize ) {
+ } elseif ( !$wgUseImageResize ) {
$scaler = 'client';
} elseif ( $wgUseImageMagick ) {
$scaler = 'im';
if ( $flags & self::TRANSFORM_LATER ) {
wfDebug( __METHOD__ . ": Transforming later per flags.\n" );
- return new ThumbnailImage( $image, $dstUrl, $scalerParams['clientWidth'],
+ return new ThumbnailImage( $image, $dstUrl, $scalerParams['clientWidth'],
$scalerParams['clientHeight'], $dstPath );
}
# Try to make a target path for the thumbnail
if ( !wfMkdirParents( dirname( $dstPath ) ) ) {
- wfDebug( __METHOD__.": Unable to create thumbnail destination directory, falling back to client scaling\n" );
+ wfDebug( __METHOD__ . ": Unable to create thumbnail destination directory, falling back to client scaling\n" );
return $this->getClientScalingThumbnailImage( $image, $scalerParams );
}
$err = $this->transformGd( $image, $scalerParams );
break;
}
-
+
# Remove the file if a zero-byte thumbnail was created, or if there was an error
$removed = $this->removeBadFile( $dstPath, (bool)$err );
if ( $err ) {
return $err;
} elseif ( $removed ) {
# Thumbnail was zero-byte and had to be removed
- return new MediaTransformError( 'thumbnail_error',
+ return new MediaTransformError( 'thumbnail_error',
$scalerParams['clientWidth'], $scalerParams['clientHeight'] );
} else {
- return new ThumbnailImage( $image, $dstUrl, $scalerParams['clientWidth'],
+ return new ThumbnailImage( $image, $dstUrl, $scalerParams['clientWidth'],
$scalerParams['clientHeight'], $dstPath );
}
}
-
+
/**
* Get a ThumbnailImage that respresents an image that will be scaled
* client side
- *
+ *
* @param $image File File associated with this thumbnail
* @param $params array Array with scaler params
* @return ThumbnailImage
*/
protected function getClientScalingThumbnailImage( $image, $params ) {
- return new ThumbnailImage( $image, $image->getURL(),
+ return new ThumbnailImage( $image, $image->getURL(),
$params['clientWidth'], $params['clientHeight'], $params['srcPath'] );
}
/**
* Transform an image using ImageMagick
- *
+ *
* @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 transformImageMagick( $image, $params ) {
- # use ImageMagick
- global $wgSharpenReductionThreshold, $wgSharpenParameter,
- $wgMaxAnimatedGifArea,
- $wgImageMagickTempDir, $wgImageMagickConvertCommand;
-
- $quality = '';
- $sharpen = '';
- $scene = false;
- $animation_pre = '';
- $animation_post = '';
- $decoderHint = '';
- if ( $params['mimeType'] == 'image/jpeg' ) {
- $quality = "-quality 80"; // 80%
- # Sharpening, see bug 6193
- if ( ( $params['physicalWidth'] + $params['physicalHeight'] )
- / ( $params['srcWidth'] + $params['srcHeight'] )
- < $wgSharpenReductionThreshold ) {
- $sharpen = "-sharpen " . wfEscapeShellArg( $wgSharpenParameter );
- }
- // JPEG decoder hint to reduce memory, available since IM 6.5.6-2
- $decoderHint = "-define jpeg:size={$params['physicalSize']}";
-
- } elseif ( $params['mimeType'] == 'image/png' ) {
- $quality = "-quality 95"; // zlib 9, adaptive filtering
-
- } 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
- $scene = 0;
-
- } elseif( $this->isAnimatedImage( $image ) ) {
- // Coalesce is needed to scale animated GIFs properly (bug 1017).
- $animation_pre = '-coalesce';
- // We optimize the output, but -optimize is broken,
- // use optimizeTransparency instead (bug 11822)
- if( version_compare( $this->getMagickVersion(), "6.3.5" ) >= 0 ) {
- $animation_post = '-fuzz 5% -layers optimizeTransparency +map';
- }
+ # use ImageMagick
+ global $wgSharpenReductionThreshold, $wgSharpenParameter,
+ $wgMaxAnimatedGifArea,
+ $wgImageMagickTempDir, $wgImageMagickConvertCommand;
+
+ $quality = '';
+ $sharpen = '';
+ $scene = false;
+ $animation_pre = '';
+ $animation_post = '';
+ $decoderHint = '';
+ if ( $params['mimeType'] == 'image/jpeg' ) {
+ $quality = "-quality 80"; // 80%
+ # Sharpening, see bug 6193
+ if ( ( $params['physicalWidth'] + $params['physicalHeight'] )
+ / ( $params['srcWidth'] + $params['srcHeight'] )
+ < $wgSharpenReductionThreshold ) {
+ $sharpen = "-sharpen " . wfEscapeShellArg( $wgSharpenParameter );
+ }
+ // JPEG decoder hint to reduce memory, available since IM 6.5.6-2
+ $decoderHint = "-define jpeg:size={$params['physicalSize']}";
+
+ } elseif ( $params['mimeType'] == 'image/png' ) {
+ $quality = "-quality 95"; // zlib 9, adaptive filtering
+
+ } 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
+ $scene = 0;
+
+ } elseif ( $this->isAnimatedImage( $image ) ) {
+ // Coalesce is needed to scale animated GIFs properly (bug 1017).
+ $animation_pre = '-coalesce';
+ // We optimize the output, but -optimize is broken,
+ // use optimizeTransparency instead (bug 11822)
+ if ( version_compare( $this->getMagickVersion(), "6.3.5" ) >= 0 ) {
+ $animation_post = '-fuzz 5% -layers optimizeTransparency +map';
}
}
+ }
- // Use one thread only, to avoid deadlock bugs on OOM
- $env = array( 'OMP_NUM_THREADS' => 1 );
- if ( strval( $wgImageMagickTempDir ) !== '' ) {
- $env['MAGICK_TMPDIR'] = $wgImageMagickTempDir;
- }
+ // Use one thread only, to avoid deadlock bugs on OOM
+ $env = array( 'OMP_NUM_THREADS' => 1 );
+ if ( strval( $wgImageMagickTempDir ) !== '' ) {
+ $env['MAGICK_TMPDIR'] = $wgImageMagickTempDir;
+ }
- $cmd =
- wfEscapeShellArg( $wgImageMagickConvertCommand ) .
- // Specify white background color, will be used for transparent images
- // in Internet Explorer/Windows instead of default black.
- " {$quality} -background white".
- " {$decoderHint} " .
- wfEscapeShellArg( $this->escapeMagickInput( $params['srcPath'], $scene ) ) .
- " {$animation_pre}" .
- // For the -thumbnail option a "!" is needed to force exact size,
- // or ImageMagick may decide your ratio is wrong and slice off
- // a pixel.
- " -thumbnail " . wfEscapeShellArg( "{$params['physicalSize']}!" ) .
- // Add the source url as a comment to the thumb.
- " -set comment " . wfEscapeShellArg( $this->escapeMagickProperty( $params['comment'] ) ) .
- " -depth 8 $sharpen" .
- " {$animation_post} " .
- 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 $this->getMediaTransformError( $params, $err );
- }
-
- return false; # No error
+ $cmd =
+ wfEscapeShellArg( $wgImageMagickConvertCommand ) .
+ // Specify white background color, will be used for transparent images
+ // in Internet Explorer/Windows instead of default black.
+ " {$quality} -background white" .
+ " {$decoderHint} " .
+ wfEscapeShellArg( $this->escapeMagickInput( $params['srcPath'], $scene ) ) .
+ " {$animation_pre}" .
+ // For the -thumbnail option a "!" is needed to force exact size,
+ // or ImageMagick may decide your ratio is wrong and slice off
+ // a pixel.
+ " -thumbnail " . wfEscapeShellArg( "{$params['physicalSize']}!" ) .
+ // Add the source url as a comment to the thumb.
+ " -set comment " . wfEscapeShellArg( $this->escapeMagickProperty( $params['comment'] ) ) .
+ " -depth 8 $sharpen" .
+ " {$animation_post} " .
+ 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 $this->getMediaTransformError( $params, $err );
+ }
+
+ return false; # No error
}
-
+
/**
* Transform an image using a custom command
- *
+ *
* @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 transformCustom( $image, $params ) {
- # Use a custom convert command
- global $wgCustomConvertCommand;
-
- # Variables: %s %d %w %h
- $src = wfEscapeShellArg( $params['srcPath'] );
- $dst = wfEscapeShellArg( $params['dstPath'] );
- $cmd = $wgCustomConvertCommand;
- $cmd = str_replace( '%s', $src, str_replace( '%d', $dst, $cmd ) ); # Filenames
- $cmd = str_replace( '%h', $params['physicalHeight'],
- str_replace( '%w', $params['physicalWidth'], $cmd ) ); # Size
- wfDebug( __METHOD__.": Running custom convert command $cmd\n" );
- wfProfileIn( 'convert' );
- $retval = 0;
- $err = wfShellExec( $cmd, $retval );
- wfProfileOut( 'convert' );
-
- if ( $retval !== 0 ) {
- $this->logErrorForExternalProcess( $retval, $err, $cmd );
- return $this->getMediaTransformError( $params, $err );
- }
- return false; # No error
+ # Use a custom convert command
+ global $wgCustomConvertCommand;
+
+ # Variables: %s %d %w %h
+ $src = wfEscapeShellArg( $params['srcPath'] );
+ $dst = wfEscapeShellArg( $params['dstPath'] );
+ $cmd = $wgCustomConvertCommand;
+ $cmd = str_replace( '%s', $src, str_replace( '%d', $dst, $cmd ) ); # Filenames
+ $cmd = str_replace( '%h', $params['physicalHeight'],
+ str_replace( '%w', $params['physicalWidth'], $cmd ) ); # Size
+ wfDebug( __METHOD__ . ": Running custom convert command $cmd\n" );
+ wfProfileIn( 'convert' );
+ $retval = 0;
+ $err = wfShellExec( $cmd, $retval );
+ wfProfileOut( 'convert' );
+
+ if ( $retval !== 0 ) {
+ $this->logErrorForExternalProcess( $retval, $err, $cmd );
+ return $this->getMediaTransformError( $params, $err );
+ }
+ return false; # No error
}
-
+
/**
* Log an error that occured in an external process
- *
+ *
* @param $retval int
* @param $err int
* @param $cmd string
wfHostname(), $retval, trim( $err ), $cmd ) );
}
/**
- *
+ *
*/
protected function getMediaTransformError( $params, $errMsg ) {
- return new MediaTransformError( 'thumbnail_error', $params['clientWidth'],
+ return new MediaTransformError( 'thumbnail_error', $params['clientWidth'],
$params['clientHeight'], $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
- *
+ *
* @return MediaTransformError Error object if error occured, false (=no error) otherwise
*/
protected function transformGd( $image, $params ) {
- # Use PHP's builtin GD library functions.
- #
- # First find out what kind of file this is, and select the correct
- # input routine for this.
-
- $typemap = array(
- 'image/gif' => array( 'imagecreatefromgif', 'palette', 'imagegif' ),
- 'image/jpeg' => array( 'imagecreatefromjpeg', 'truecolor', array( __CLASS__, 'imageJpegWrapper' ) ),
- 'image/png' => array( 'imagecreatefrompng', 'bits', 'imagepng' ),
- 'image/vnd.wap.wbmp' => array( 'imagecreatefromwbmp', 'palette', 'imagewbmp' ),
- 'image/xbm' => array( 'imagecreatefromxbm', 'palette', 'imagexbm' ),
- );
- if( !isset( $typemap[$params['mimeType']] ) ) {
- $err = 'Image type not supported';
- wfDebug( "$err\n" );
- $errMsg = wfMsg ( 'thumbnail_image-type' );
- return $this->getMediaTransformError( $params, $errMsg );
- }
- list( $loader, $colorStyle, $saveType ) = $typemap[$params['mimeType']];
+ # Use PHP's builtin GD library functions.
+ #
+ # First find out what kind of file this is, and select the correct
+ # input routine for this.
+
+ $typemap = array(
+ 'image/gif' => array( 'imagecreatefromgif', 'palette', 'imagegif' ),
+ 'image/jpeg' => array( 'imagecreatefromjpeg', 'truecolor', array( __CLASS__, 'imageJpegWrapper' ) ),
+ 'image/png' => array( 'imagecreatefrompng', 'bits', 'imagepng' ),
+ 'image/vnd.wap.wbmp' => array( 'imagecreatefromwbmp', 'palette', 'imagewbmp' ),
+ 'image/xbm' => array( 'imagecreatefromxbm', 'palette', 'imagexbm' ),
+ );
+ if ( !isset( $typemap[$params['mimeType']] ) ) {
+ $err = 'Image type not supported';
+ wfDebug( "$err\n" );
+ $errMsg = wfMsg ( 'thumbnail_image-type' );
+ return $this->getMediaTransformError( $params, $errMsg );
+ }
+ list( $loader, $colorStyle, $saveType ) = $typemap[$params['mimeType']];
- if( !function_exists( $loader ) ) {
- $err = "Incomplete GD library configuration: missing function $loader";
- wfDebug( "$err\n" );
- $errMsg = wfMsg ( 'thumbnail_gd-library', $loader );
- return $this->getMediaTransformError( $params, $errMsg );
- }
+ if ( !function_exists( $loader ) ) {
+ $err = "Incomplete GD library configuration: missing function $loader";
+ wfDebug( "$err\n" );
+ $errMsg = wfMsg ( 'thumbnail_gd-library', $loader );
+ 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'] );
- 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'] );
+ return $this->getMediaTransformError( $params, $errMsg );
+ }
- $src_image = call_user_func( $loader, $params['srcPath'] );
- $dst_image = imagecreatetruecolor( $params['physicalWidth'],
- $params['physicalHeight'] );
-
- // Initialise the destination image to transparent instead of
- // the default solid black, to support PNG and GIF transparency nicely
- $background = imagecolorallocate( $dst_image, 0, 0, 0 );
- imagecolortransparent( $dst_image, $background );
- imagealphablending( $dst_image, false );
-
- if ( $colorStyle == 'palette' ) {
- // Don't resample for paletted GIF images.
- // It may just uglify them, and completely breaks transparency.
- imagecopyresized( $dst_image, $src_image,
- 0,0,0,0,
- $params['physicalWidth'], $params['physicalHeight'],
- imagesx( $src_image ), imagesy( $src_image ) );
- } else {
- imagecopyresampled( $dst_image, $src_image,
- 0,0,0,0,
- $params['physicalWidth'], $params['physicalHeight'],
- imagesx( $src_image ), imagesy( $src_image ) );
- }
+ $src_image = call_user_func( $loader, $params['srcPath'] );
+ $dst_image = imagecreatetruecolor( $params['physicalWidth'],
+ $params['physicalHeight'] );
+
+ // Initialise the destination image to transparent instead of
+ // the default solid black, to support PNG and GIF transparency nicely
+ $background = imagecolorallocate( $dst_image, 0, 0, 0 );
+ imagecolortransparent( $dst_image, $background );
+ imagealphablending( $dst_image, false );
+
+ if ( $colorStyle == 'palette' ) {
+ // Don't resample for paletted GIF images.
+ // It may just uglify them, and completely breaks transparency.
+ imagecopyresized( $dst_image, $src_image,
+ 0, 0, 0, 0,
+ $params['physicalWidth'], $params['physicalHeight'],
+ imagesx( $src_image ), imagesy( $src_image ) );
+ } else {
+ imagecopyresampled( $dst_image, $src_image,
+ 0, 0, 0, 0,
+ $params['physicalWidth'], $params['physicalHeight'],
+ imagesx( $src_image ), imagesy( $src_image ) );
+ }
+
+ imagesavealpha( $dst_image, true );
- imagesavealpha( $dst_image, true );
+ call_user_func( $saveType, $dst_image, $params['dstPath'] );
+ imagedestroy( $dst_image );
+ imagedestroy( $src_image );
- call_user_func( $saveType, $dst_image, $params['dstPath'] );
- imagedestroy( $dst_image );
- imagedestroy( $src_image );
-
- return false; # No error
+ return false; # No error
}
/**
}
/**
- * Escape a string for ImageMagick's input filenames. See ExpandFilenames()
+ * Escape a string for ImageMagick's input filenames. See ExpandFilenames()
* and GetPathComponent() in magick/utility.c.
*
* This won't work with an initial ~ or @, so input files should be prefixed
- * with the directory name.
+ * with the directory name.
*
* Glob character unescaping is broken in ImageMagick before 6.6.1-5, but
- * it's broken in a way that doesn't involve trying to convert every file
+ * it's broken in a way that doesn't involve trying to convert every file
* in a directory, so we're better off escaping and waiting for the bugfix
* to filter down to users.
*
# Die on initial metacharacters (caller should prepend path)
$firstChar = substr( $path, 0, 1 );
if ( $firstChar === '~' || $firstChar === '@' ) {
- throw new MWException( __METHOD__.': cannot escape this path name' );
+ throw new MWException( __METHOD__ . ': cannot escape this path name' );
}
# Escape glob chars
}
/**
- * Escape a string for ImageMagick's output filename. See
+ * Escape a string for ImageMagick's output filename. See
* InterpretImageFilename() in magick/image.c.
*/
function escapeMagickOutput( $path, $scene = false ) {
}
/**
- * Armour a string against ImageMagick's GetPathComponent(). This is a
+ * Armour a string against ImageMagick's GetPathComponent(). This is a
* helper function for escapeMagickInput() and escapeMagickOutput().
*
* @param $path string The file path
// OK, it's a drive letter
// ImageMagick has a similar exception, see IsMagickConflict()
} else {
- throw new MWException( __METHOD__.': unexpected colon character in path name' );
+ throw new MWException( __METHOD__ . ': unexpected colon character in path name' );
}
}
- # If there are square brackets, add a do-nothing scene specification
+ # If there are square brackets, add a do-nothing scene specification
# to force a literal interpretation
if ( $scene === false ) {
if ( strpos( $path, '[' ) !== false ) {
global $wgMemc;
$cache = $wgMemc->get( "imagemagick-version" );
- if( !$cache ) {
+ if ( !$cache ) {
global $wgImageMagickConvertCommand;
$cmd = wfEscapeShellArg( $wgImageMagickConvertCommand ) . ' -version';
- wfDebug( __METHOD__.": Running convert -version\n" );
+ wfDebug( __METHOD__ . ": Running convert -version\n" );
$retval = '';
$return = wfShellExec( $cmd, $retval );
- $x = preg_match('/Version: ImageMagick ([0-9]*\.[0-9]*\.[0-9]*)/', $return, $matches);
- if( $x != 1 ) {
- wfDebug( __METHOD__.": ImageMagick version check failed\n" );
+ $x = preg_match( '/Version: ImageMagick ([0-9]*\.[0-9]*\.[0-9]*)/', $return, $matches );
+ if ( $x != 1 ) {
+ wfDebug( __METHOD__ . ": ImageMagick version check failed\n" );
return null;
}
$wgMemc->set( "imagemagick-version", $matches[1], 3600 );
function getMetadata( $image, $filename ) {
global $wgShowEXIF;
- if( $wgShowEXIF && file_exists( $filename ) ) {
+ if ( $wgShowEXIF && file_exists( $filename ) ) {
$exif = new Exif( $filename );
$data = $exif->getFilteredData();
if ( $data ) {
$exif['MEDIAWIKI_EXIF_VERSION'] != Exif::version() )
{
# Wrong version
- wfDebug( __METHOD__.": wrong version\n" );
+ wfDebug( __METHOD__ . ": wrong version\n" );
return false;
}
return true;
function visibleMetadataFields() {
$fields = array();
$lines = explode( "\n", wfMsgForContent( 'metadata-fields' ) );
- foreach( $lines as $line ) {
+ foreach ( $lines as $line ) {
$matches = array();
- if( preg_match( '/^\\*\s*(.*?)\s*$/', $line, $matches ) ) {
+ if ( preg_match( '/^\\*\s*(.*?)\s*$/', $line, $matches ) ) {
$fields[] = $matches[1];
}
}