46 if ( !parent::normaliseParams( $image, $params ) ) {
50 # Obtain the source, pre-rotation dimensions
51 $srcWidth = $image->getWidth( $params[
'page'] );
52 $srcHeight = $image->getHeight( $params[
'page'] );
54 # Don't make an image bigger than the source
55 if ( $params[
'physicalWidth'] >= $srcWidth ) {
56 $params[
'physicalWidth'] = $srcWidth;
57 $params[
'physicalHeight'] = $srcHeight;
59 # Skip scaling limit checks if no scaling is required
60 # due to requested size being bigger than source.
61 if ( !$image->mustRender() ) {
82 if ( $rotation == 90 || $rotation == 270 ) {
83 # We'll resize before rotation, so swap the dimensions again
84 $width = $params[
'physicalHeight'];
85 $height = $params[
'physicalWidth'];
87 $width = $params[
'physicalWidth'];
88 $height = $params[
'physicalHeight'];
91 return [ $width, $height ];
107 function doTransform( $image, $dstPath, $dstUrl, $params, $flags = 0 ) {
112 # Create a parameter array to pass to the scaler
114 # The size to which the image will be resized
115 'physicalWidth' => $params[
'physicalWidth'],
116 'physicalHeight' => $params[
'physicalHeight'],
117 'physicalDimensions' =>
"{$params['physicalWidth']}x{$params['physicalHeight']}",
118 # The size of the image on the page
119 'clientWidth' => $params[
'width'],
120 'clientHeight' => $params[
'height'],
121 # Comment as will be added to the Exif of the thumbnail
122 'comment' => isset( $params[
'descriptionUrl'] )
123 ?
"File source: {$params['descriptionUrl']}"
125 # Properties of the original image
126 'srcWidth' => $image->getWidth(),
127 'srcHeight' => $image->getHeight(),
128 'mimeType' => $image->getMimeType(),
129 'dstPath' => $dstPath,
131 'interlace' => $params[
'interlace'] ??
false,
134 if ( isset( $params[
'quality'] ) && $params[
'quality'] ===
'low' ) {
135 $scalerParams[
'quality'] = 30;
139 if ( $image->isMultipage() && isset( $params[
'page'] ) ) {
140 $scalerParams[
'page'] = intval( $params[
'page'] );
143 # Determine scaler type
146 if ( is_array( $scaler ) ) {
147 $scalerName = get_class( $scaler[0] );
149 $scalerName = $scaler;
152 wfDebug( __METHOD__ .
": creating {$scalerParams['physicalDimensions']} " .
153 "thumbnail at $dstPath using scaler $scalerName\n" );
155 if ( !$image->mustRender() &&
156 $scalerParams[
'physicalWidth'] == $scalerParams[
'srcWidth']
157 && $scalerParams[
'physicalHeight'] == $scalerParams[
'srcHeight']
158 && !isset( $scalerParams[
'quality'] )
160 # normaliseParams (or the user) wants us to return the unscaled image
161 wfDebug( __METHOD__ .
": returning unscaled image\n" );
166 if ( $scaler ==
'client' ) {
167 # Client-side image scaling, use the source URL
168 # Using the destination URL in a TRANSFORM_LATER request would be incorrect
172 if ( $image->isTransformedLocally() && !$this->isImageAreaOkForThumbnaling( $image, $params ) ) {
177 if ( $flags & self::TRANSFORM_LATER ) {
178 wfDebug( __METHOD__ .
": Transforming later per flags.\n" );
180 'width' => $scalerParams[
'clientWidth'],
181 'height' => $scalerParams[
'clientHeight']
183 if ( isset( $params[
'quality'] ) ) {
184 $newParams[
'quality'] = $params[
'quality'];
186 if ( isset( $params[
'page'] ) && $params[
'page'] ) {
187 $newParams[
'page'] = $params[
'page'];
192 # Try to make a target path for the thumbnail
194 wfDebug( __METHOD__ .
": Unable to create thumbnail destination " .
195 "directory, falling back to client scaling\n" );
200 # Transform functions and binaries need a FS source file
204 if ( $scalerParams[
'srcWidth'] != $thumbnailSource[
'width']
205 || $scalerParams[
'srcHeight'] != $thumbnailSource[
'height'] ) {
206 $scalerParams[
'disableRotation'] =
true;
209 $scalerParams[
'srcPath'] = $thumbnailSource[
'path'];
210 $scalerParams[
'srcWidth'] = $thumbnailSource[
'width'];
211 $scalerParams[
'srcHeight'] = $thumbnailSource[
'height'];
213 if ( $scalerParams[
'srcPath'] ===
false ) {
215 sprintf(
'Thumbnail failed on %s: could not get local copy of "%s"',
219 $scalerParams[
'clientWidth'], $scalerParams[
'clientHeight'],
224 # Try a hook. Called "Bitmap" for historical reasons.
227 Hooks::run(
'BitmapHandlerTransform', [ $this, $image, &$scalerParams, &$mto ] );
228 if ( !is_null( $mto ) ) {
229 wfDebug( __METHOD__ .
": Hook to BitmapHandlerTransform created an mto\n" );
230 $scaler =
'hookaborted';
236 if ( is_array( $scaler ) && is_callable( $scaler ) ) {
238 $err = call_user_func( $scaler, $image, $scalerParams );
242 # Handled by the hook above
243 $err = $mto->isError() ? $mto :
false;
256 $err = $this->
transformGd( $image, $scalerParams );
261 # Remove the file if a zero-byte thumbnail was created, or if there was an error
264 # transform returned MediaTransforError
266 } elseif ( $removed ) {
267 # Thumbnail was zero-byte and had to be removed
269 $scalerParams[
'clientWidth'], $scalerParams[
'clientHeight'],
276 'width' => $scalerParams[
'clientWidth'],
277 'height' => $scalerParams[
'clientHeight']
279 if ( isset( $params[
'quality'] ) ) {
280 $newParams[
'quality'] = $params[
'quality'];
282 if ( isset( $params[
'page'] ) && $params[
'page'] ) {
283 $newParams[
'page'] = $params[
'page'];
285 return new ThumbnailImage( $image, $dstUrl, $dstPath, $newParams );
297 return $file->getThumbnailSource( $params );
321 abstract protected function getScalerType( $dstPath, $checkDstPath =
true );
335 'width' => $scalerParams[
'clientWidth'],
336 'height' => $scalerParams[
'clientHeight']
339 return new ThumbnailImage( $image, $image->getUrl(),
null, $params );
393 $params[
'clientHeight'], $errMsg );
418 $s = str_replace(
'\\',
'\\\\',
$s );
420 $s = str_replace(
'%',
'%%',
$s );
422 if ( strlen(
$s ) > 0 && (
$s[0] ===
'-' ||
$s[0] ===
'@' ) ) {
447 # Die on initial metacharacters (caller should prepend path)
448 $firstChar = substr(
$path, 0, 1 );
449 if ( $firstChar ===
'~' || $firstChar ===
'@' ) {
450 throw new MWException( __METHOD__ .
': cannot escape this path name' );
454 $path = preg_replace(
'/[*?\[\]{}]/',
'\\\\\0',
$path );
482 # Die on format specifiers (other than drive letters). The regex is
483 # meant to match all the formats you get from "convert -list format"
484 if ( preg_match(
'/^([a-zA-Z0-9-]+):/',
$path, $m ) ) {
489 throw new MWException( __METHOD__ .
': unexpected colon character in path name' );
493 # If there are square brackets, add a do-nothing scene specification
494 # to force a literal interpretation
495 if ( $scene ===
false ) {
496 if ( strpos(
$path,
'[' ) !==
false ) {
513 $cache = MediaWikiServices::getInstance()->getLocalServerObjectCache();
514 $method = __METHOD__;
515 return $cache->getWithSetCallback(
516 $cache->makeGlobalKey(
'imagemagick-version' ),
518 function () use ( $method ) {
522 wfDebug( $method .
": Running convert -version\n" );
526 '/Version: ImageMagick ([0-9]*\.[0-9]*\.[0-9]*)/', $return,
$matches
529 wfDebug( $method .
": ImageMagick version check failed\n" );
572 static::class .
' rotation not implemented' );
599 # For historical reasons, hook starts with BitmapHandler
600 $checkImageAreaHookResult =
null;
602 'BitmapHandlerCheckImageArea',
603 [
$file, &$params, &$checkImageAreaHookResult ]
606 if ( !is_null( $checkImageAreaHookResult ) ) {
608 return (
bool)$checkImageAreaHookResult;
611 $srcWidth =
$file->getWidth( $params[
'page'] );
612 $srcHeight =
$file->getHeight( $params[
'page'] );
615 && !(
$file->getMimeType() ==
'image/jpeg'
616 && $this->getScalerType(
false,
false ) ==
'im' )
618 # Only ImageMagick can efficiently downsize jpg images without loading
619 # the entire file in memory
$wgMaxImageArea
The maximum number of pixels a source image can have if it is to be scaled down by a scaler that requ...
$wgImageMagickConvertCommand
The convert command shipped with ImageMagick.
wfDebug( $text, $dest='all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
wfHostname()
Get host name of the current machine, for use in error reporting.
wfShellExecWithStderr( $cmd, &$retval=null, $environ=[], $limits=[])
Execute a shell command, returning both stdout and stderr.
wfDebugLog( $logGroup, $text, $dest='all', array $context=[])
Send a line to a supplementary debug log file, if configured, or main debug log if not.
wfIsWindows()
Check if the operating system is Windows.
wfMkdirParents( $dir, $mode=null, $caller=null)
Make directory, and make all parent directories if they don't exist.
wfMessage( $key,... $params)
This is the function for getting translated interface messages.
Media handler abstract base class for images.
Media transform output for images.
if(PHP_SAPI !='cli-server') if(!isset( $_SERVER['SCRIPT_FILENAME'])) $file
Item class for a filearchive table row.