MediaWiki  master
BitmapHandler.php
Go to the documentation of this file.
1 <?php
26 
34 
44  protected function getScalerType( $dstPath, $checkDstPath = true ) {
45  $mainConfig = MediaWikiServices::getInstance()->getMainConfig();
46  $useImageResize = $mainConfig->get( 'UseImageResize' );
47  $useImageMagick = $mainConfig->get( 'UseImageMagick' );
48  $customConvertCommand = $mainConfig->get( 'CustomConvertCommand' );
49  if ( !$dstPath && $checkDstPath ) {
50  # No output path available, client side scaling only
51  $scaler = 'client';
52  } elseif ( !$useImageResize ) {
53  $scaler = 'client';
54  } elseif ( $useImageMagick ) {
55  $scaler = 'im';
56  } elseif ( $customConvertCommand ) {
57  $scaler = 'custom';
58  } elseif ( function_exists( 'imagecreatetruecolor' ) ) {
59  $scaler = 'gd';
60  } elseif ( class_exists( 'Imagick' ) ) {
61  $scaler = 'imext';
62  } else {
63  $scaler = 'client';
64  }
65 
66  return $scaler;
67  }
68 
73  public function makeParamString( $params ) {
74  $res = parent::makeParamString( $params );
75  if ( isset( $params['interlace'] ) && $params['interlace'] ) {
76  return "interlaced-{$res}";
77  } else {
78  return $res;
79  }
80  }
81 
86  public function parseParamString( $str ) {
87  $remainder = preg_replace( '/^interlaced-/', '', $str );
88  $params = parent::parseParamString( $remainder );
89  if ( $params === false ) {
90  return false;
91  }
92  $params['interlace'] = $str !== $remainder;
93  return $params;
94  }
95 
100  public function validateParam( $name, $value ) {
101  if ( $name === 'interlace' ) {
102  return $value === false || $value === true;
103  } else {
104  return parent::validateParam( $name, $value );
105  }
106  }
107 
114  public function normaliseParams( $image, &$params ) {
115  $maxInterlacingAreas = MediaWikiServices::getInstance()->getMainConfig()->get( 'MaxInterlacingAreas' );
116  if ( !parent::normaliseParams( $image, $params ) ) {
117  return false;
118  }
119  $mimeType = $image->getMimeType();
120  $interlace = isset( $params['interlace'] ) && $params['interlace']
121  && isset( $maxInterlacingAreas[$mimeType] )
122  && $this->getImageArea( $image ) <= $maxInterlacingAreas[$mimeType];
123  $params['interlace'] = $interlace;
124  return true;
125  }
126 
133  protected function imageMagickSubsampling( $pixelFormat ) {
134  switch ( $pixelFormat ) {
135  case 'yuv444':
136  return [ '1x1', '1x1', '1x1' ];
137  case 'yuv422':
138  return [ '2x1', '1x1', '1x1' ];
139  case 'yuv420':
140  return [ '2x2', '1x1', '1x1' ];
141  default:
142  throw new MWException( 'Invalid pixel format for JPEG output' );
143  }
144  }
145 
155  protected function transformImageMagick( $image, $params ) {
156  # use ImageMagick
157  $mainConfig = MediaWikiServices::getInstance()->getMainConfig();
158  $sharpenReductionThreshold = $mainConfig->get( 'SharpenReductionThreshold' );
159  $sharpenParameter = $mainConfig->get( 'SharpenParameter' );
160  $maxAnimatedGifArea = $mainConfig->get( 'MaxAnimatedGifArea' );
161  $imageMagickTempDir = $mainConfig->get( 'ImageMagickTempDir' );
162  $imageMagickConvertCommand = $mainConfig->get( 'ImageMagickConvertCommand' );
163  $jpegPixelFormat = $mainConfig->get( 'JpegPixelFormat' );
164  $jpegQuality = $mainConfig->get( 'JpegQuality' );
165  $quality = [];
166  $sharpen = [];
167  $scene = false;
168  $animation_pre = [];
169  $animation_post = [];
170  $decoderHint = [];
171  $subsampling = [];
172 
173  if ( $params['mimeType'] == 'image/jpeg' ) {
174  $qualityVal = isset( $params['quality'] ) ? (string)$params['quality'] : null;
175  $quality = [ '-quality', $qualityVal ?: (string)$jpegQuality ]; // 80% by default
176  if ( $params['interlace'] ) {
177  $animation_post = [ '-interlace', 'JPEG' ];
178  }
179  # Sharpening, see T8193
180  if ( ( $params['physicalWidth'] + $params['physicalHeight'] )
181  / ( $params['srcWidth'] + $params['srcHeight'] )
182  < $sharpenReductionThreshold
183  ) {
184  $sharpen = [ '-sharpen', $sharpenParameter ];
185  }
186 
187  // JPEG decoder hint to reduce memory, available since IM 6.5.6-2
188  $decoderHint = [ '-define', "jpeg:size={$params['physicalDimensions']}" ];
189 
190  if ( $jpegPixelFormat ) {
191  $factors = $this->imageMagickSubsampling( $jpegPixelFormat );
192  $subsampling = [ '-sampling-factor', implode( ',', $factors ) ];
193  }
194  } elseif ( $params['mimeType'] == 'image/png' ) {
195  $quality = [ '-quality', '95' ]; // zlib 9, adaptive filtering
196  if ( $params['interlace'] ) {
197  $animation_post = [ '-interlace', 'PNG' ];
198  }
199  } elseif ( $params['mimeType'] == 'image/webp' ) {
200  $quality = [ '-quality', '95' ]; // zlib 9, adaptive filtering
201  } elseif ( $params['mimeType'] == 'image/gif' ) {
202  if ( $this->getImageArea( $image ) > $maxAnimatedGifArea ) {
203  // Extract initial frame only; we're so big it'll
204  // be a total drag. :P
205  $scene = 0;
206  } elseif ( $this->isAnimatedImage( $image ) ) {
207  // Coalesce is needed to scale animated GIFs properly (T3017).
208  $animation_pre = [ '-coalesce' ];
209 
210  // We optimize the output, but -optimize is broken,
211  // use optimizeTransparency instead (T13822). Version >= IM 6.3.5
212  $animation_post = [ '-fuzz', '5%', '-layers', 'optimizeTransparency' ];
213  }
214  if ( $params['interlace'] && !$this->isAnimatedImage( $image ) ) {
215  // Version >= IM 6.3.4
216  // interlacing animated GIFs is a bad idea
217  $animation_post[] = '-interlace';
218  $animation_post[] = 'GIF';
219  }
220  } elseif ( $params['mimeType'] == 'image/x-xcf' ) {
221  // Before merging layers, we need to set the background
222  // to be transparent to preserve alpha, as -layers merge
223  // merges all layers on to a canvas filled with the
224  // background colour. After merging we reset the background
225  // to be white for the default background colour setting
226  // in the PNG image (which is used in old IE)
227  $animation_pre = [
228  '-background', 'transparent',
229  '-layers', 'merge',
230  '-background', 'white',
231  ];
232  }
233 
234  // Use one thread only, to avoid deadlock bugs on OOM
235  $env = [ 'OMP_NUM_THREADS' => 1 ];
236  if ( strval( $imageMagickTempDir ) !== '' ) {
237  $env['MAGICK_TMPDIR'] = $imageMagickTempDir;
238  }
239 
240  $rotation = isset( $params['disableRotation'] ) ? 0 : $this->getRotation( $image );
241  list( $width, $height ) = $this->extractPreRotationDimensions( $params, $rotation );
242 
243  $cmd = Shell::escape( ...array_merge(
244  [ $imageMagickConvertCommand ],
245  $quality,
246  // Specify white background color, will be used for transparent images
247  // in Internet Explorer/Windows instead of default black.
248  [ '-background', 'white' ],
249  $decoderHint,
250  [ $this->escapeMagickInput( $params['srcPath'], $scene ) ],
251  $animation_pre,
252  // For the -thumbnail option a "!" is needed to force exact size,
253  // or ImageMagick may decide your ratio is wrong and slice off
254  // a pixel.
255  [ '-thumbnail', "{$width}x{$height}!" ],
256  // Add the source url as a comment to the thumb, but don't add the flag if there's no comment
257  ( $params['comment'] !== ''
258  ? [ '-set', 'comment', $this->escapeMagickProperty( $params['comment'] ) ]
259  : [] ),
260  // T108616: Avoid exposure of local file path
261  [ '+set', 'Thumb::URI' ],
262  [ '-depth', 8 ],
263  $sharpen,
264  [ '-rotate', "-$rotation" ],
265  $subsampling,
266  $animation_post,
267  [ $this->escapeMagickOutput( $params['dstPath'] ) ] ) );
268 
269  wfDebug( __METHOD__ . ": running ImageMagick: $cmd" );
270  $retval = 0;
271  $err = wfShellExecWithStderr( $cmd, $retval, $env );
272 
273  if ( $retval !== 0 ) {
274  $this->logErrorForExternalProcess( $retval, $err, $cmd );
275 
276  return $this->getMediaTransformError( $params, "$err\nError code: $retval" );
277  }
278 
279  return false; # No error
280  }
281 
290  protected function transformImageMagickExt( $image, $params ) {
291  $mainConfig = MediaWikiServices::getInstance()->getMainConfig();
292  $sharpenReductionThreshold = $mainConfig->get( 'SharpenReductionThreshold' );
293  $sharpenParameter = $mainConfig->get( 'SharpenParameter' );
294  $maxAnimatedGifArea = $mainConfig->get( 'MaxAnimatedGifArea' );
295  $jpegPixelFormat = $mainConfig->get( 'JpegPixelFormat' );
296  $jpegQuality = $mainConfig->get( 'JpegQuality' );
297  try {
298  $im = new Imagick();
299  $im->readImage( $params['srcPath'] );
300 
301  if ( $params['mimeType'] == 'image/jpeg' ) {
302  // Sharpening, see T8193
303  if ( ( $params['physicalWidth'] + $params['physicalHeight'] )
304  / ( $params['srcWidth'] + $params['srcHeight'] )
305  < $sharpenReductionThreshold
306  ) {
307  // Hack, since $wgSharpenParameter is written specifically for the command line convert
308  list( $radius, $sigma ) = explode( 'x', $sharpenParameter );
309  $im->sharpenImage( $radius, $sigma );
310  }
311  $qualityVal = isset( $params['quality'] ) ? (string)$params['quality'] : null;
312  $im->setCompressionQuality( $qualityVal ?: $jpegQuality );
313  if ( $params['interlace'] ) {
314  $im->setInterlaceScheme( Imagick::INTERLACE_JPEG );
315  }
316  if ( $jpegPixelFormat ) {
317  $factors = $this->imageMagickSubsampling( $jpegPixelFormat );
318  $im->setSamplingFactors( $factors );
319  }
320  } elseif ( $params['mimeType'] == 'image/png' ) {
321  $im->setCompressionQuality( 95 );
322  if ( $params['interlace'] ) {
323  $im->setInterlaceScheme( Imagick::INTERLACE_PNG );
324  }
325  } elseif ( $params['mimeType'] == 'image/gif' ) {
326  if ( $this->getImageArea( $image ) > $maxAnimatedGifArea ) {
327  // Extract initial frame only; we're so big it'll
328  // be a total drag. :P
329  $im->setImageScene( 0 );
330  } elseif ( $this->isAnimatedImage( $image ) ) {
331  // Coalesce is needed to scale animated GIFs properly (T3017).
332  $im = $im->coalesceImages();
333  }
334  // GIF interlacing is only available since 6.3.4
335  if ( $params['interlace'] ) {
336  $im->setInterlaceScheme( Imagick::INTERLACE_GIF );
337  }
338  }
339 
340  $rotation = isset( $params['disableRotation'] ) ? 0 : $this->getRotation( $image );
341  list( $width, $height ) = $this->extractPreRotationDimensions( $params, $rotation );
342 
343  $im->setImageBackgroundColor( new ImagickPixel( 'white' ) );
344 
345  // Call Imagick::thumbnailImage on each frame
346  foreach ( $im as $i => $frame ) {
347  if ( !$frame->thumbnailImage( $width, $height, /* fit */ false ) ) {
348  return $this->getMediaTransformError( $params, "Error scaling frame $i" );
349  }
350  }
351  $im->setImageDepth( 8 );
352 
353  if ( $rotation && !$im->rotateImage( new ImagickPixel( 'white' ), 360 - $rotation ) ) {
354  return $this->getMediaTransformError( $params, "Error rotating $rotation degrees" );
355  }
356 
357  if ( $this->isAnimatedImage( $image ) ) {
358  wfDebug( __METHOD__ . ": Writing animated thumbnail" );
359  // This is broken somehow... can't find out how to fix it
360  $result = $im->writeImages( $params['dstPath'], true );
361  } else {
362  $result = $im->writeImage( $params['dstPath'] );
363  }
364  if ( !$result ) {
365  return $this->getMediaTransformError( $params,
366  "Unable to write thumbnail to {$params['dstPath']}" );
367  }
368  } catch ( ImagickException $e ) {
369  return $this->getMediaTransformError( $params, $e->getMessage() );
370  }
371 
372  return false;
373  }
374 
383  protected function transformCustom( $image, $params ) {
384  # Use a custom convert command
385  $customConvertCommand = MediaWikiServices::getInstance()->getMainConfig()->get( 'CustomConvertCommand' );
386 
387  # Variables: %s %d %w %h
388  $src = Shell::escape( $params['srcPath'] );
389  $dst = Shell::escape( $params['dstPath'] );
390  $cmd = $customConvertCommand;
391  $cmd = str_replace( '%s', $src, str_replace( '%d', $dst, $cmd ) ); # Filenames
392  $cmd = str_replace( '%h', Shell::escape( $params['physicalHeight'] ),
393  str_replace( '%w', Shell::escape( $params['physicalWidth'] ), $cmd ) ); # Size
394  wfDebug( __METHOD__ . ": Running custom convert command $cmd" );
395  $retval = 0;
396  $err = wfShellExecWithStderr( $cmd, $retval );
397 
398  if ( $retval !== 0 ) {
399  $this->logErrorForExternalProcess( $retval, $err, $cmd );
400 
401  return $this->getMediaTransformError( $params, $err );
402  }
403 
404  return false; # No error
405  }
406 
415  protected function transformGd( $image, $params ) {
416  # Use PHP's builtin GD library functions.
417  # First find out what kind of file this is, and select the correct
418  # input routine for this.
419 
420  $typemap = [
421  'image/gif' => [ 'imagecreatefromgif', 'palette', false, 'imagegif' ],
422  'image/jpeg' => [ 'imagecreatefromjpeg', 'truecolor', true,
423  [ __CLASS__, 'imageJpegWrapper' ] ],
424  'image/png' => [ 'imagecreatefrompng', 'bits', false, 'imagepng' ],
425  'image/vnd.wap.wbmp' => [ 'imagecreatefromwbmp', 'palette', false, 'imagewbmp' ],
426  'image/xbm' => [ 'imagecreatefromxbm', 'palette', false, 'imagexbm' ],
427  ];
428 
429  if ( !isset( $typemap[$params['mimeType']] ) ) {
430  $err = 'Image type not supported';
431  wfDebug( $err );
432  $errMsg = wfMessage( 'thumbnail_image-type' )->text();
433 
434  return $this->getMediaTransformError( $params, $errMsg );
435  }
436  list( $loader, $colorStyle, $useQuality, $saveType ) = $typemap[$params['mimeType']];
437 
438  if ( !function_exists( $loader ) ) {
439  $err = "Incomplete GD library configuration: missing function $loader";
440  wfDebug( $err );
441  $errMsg = wfMessage( 'thumbnail_gd-library', $loader )->text();
442 
443  return $this->getMediaTransformError( $params, $errMsg );
444  }
445 
446  if ( !file_exists( $params['srcPath'] ) ) {
447  $err = "File seems to be missing: {$params['srcPath']}";
448  wfDebug( $err );
449  $errMsg = wfMessage( 'thumbnail_image-missing', $params['srcPath'] )->text();
450 
451  return $this->getMediaTransformError( $params, $errMsg );
452  }
453 
454  if ( filesize( $params['srcPath'] ) === 0 ) {
455  $err = "Image file size seems to be zero.";
456  wfDebug( $err );
457  $errMsg = wfMessage( 'thumbnail_image-size-zero', $params['srcPath'] )->text();
458 
459  return $this->getMediaTransformError( $params, $errMsg );
460  }
461 
462  $src_image = $loader( $params['srcPath'] );
463 
464  $rotation = function_exists( 'imagerotate' ) && !isset( $params['disableRotation'] ) ?
465  $this->getRotation( $image ) :
466  0;
467  list( $width, $height ) = $this->extractPreRotationDimensions( $params, $rotation );
468  $dst_image = imagecreatetruecolor( $width, $height );
469 
470  // Initialise the destination image to transparent instead of
471  // the default solid black, to support PNG and GIF transparency nicely
472  $background = imagecolorallocate( $dst_image, 0, 0, 0 );
473  imagecolortransparent( $dst_image, $background );
474  imagealphablending( $dst_image, false );
475 
476  if ( $colorStyle == 'palette' ) {
477  // Don't resample for paletted GIF images.
478  // It may just uglify them, and completely breaks transparency.
479  imagecopyresized( $dst_image, $src_image,
480  0, 0, 0, 0,
481  $width, $height,
482  imagesx( $src_image ), imagesy( $src_image ) );
483  } else {
484  imagecopyresampled( $dst_image, $src_image,
485  0, 0, 0, 0,
486  $width, $height,
487  imagesx( $src_image ), imagesy( $src_image ) );
488  }
489 
490  if ( $rotation % 360 != 0 && $rotation % 90 == 0 ) {
491  $rot_image = imagerotate( $dst_image, $rotation, 0 );
492  imagedestroy( $dst_image );
493  $dst_image = $rot_image;
494  }
495 
496  imagesavealpha( $dst_image, true );
497 
498  $funcParams = [ $dst_image, $params['dstPath'] ];
499  if ( $useQuality && isset( $params['quality'] ) ) {
500  $funcParams[] = $params['quality'];
501  }
502  $saveType( ...$funcParams );
503 
504  imagedestroy( $dst_image );
505  imagedestroy( $src_image );
506 
507  return false; # No error
508  }
509 
518  public static function imageJpegWrapper( $dst_image, $thumbPath, $quality = null ) {
519  $jpegQuality = MediaWikiServices::getInstance()->getMainConfig()->get( 'JpegQuality' );
520 
521  if ( $quality === null ) {
522  $quality = $jpegQuality;
523  }
524 
525  imageinterlace( $dst_image );
526  imagejpeg( $dst_image, $thumbPath, $quality );
527  }
528 
535  public function canRotate() {
536  $scaler = $this->getScalerType( null, false );
537  switch ( $scaler ) {
538  case 'im':
539  # ImageMagick supports autorotation
540  return true;
541  case 'imext':
542  # Imagick::rotateImage
543  return true;
544  case 'gd':
545  # GD's imagerotate function is used to rotate images, but not
546  # all precompiled PHP versions have that function
547  return function_exists( 'imagerotate' );
548  default:
549  # Other scalers don't support rotation
550  return false;
551  }
552  }
553 
559  public function autoRotateEnabled() {
560  $enableAutoRotation = MediaWikiServices::getInstance()->getMainConfig()->get( 'EnableAutoRotation' );
561 
562  if ( $enableAutoRotation === null ) {
563  // Only enable auto-rotation when we actually can
564  return $this->canRotate();
565  }
566 
567  return $enableAutoRotation;
568  }
569 
578  public function rotate( $file, $params ) {
579  $imageMagickConvertCommand = MediaWikiServices::getInstance()
580  ->getMainConfig()->get( 'ImageMagickConvertCommand' );
581 
582  $rotation = ( $params['rotation'] + $this->getRotation( $file ) ) % 360;
583  $scene = false;
584 
585  $scaler = $this->getScalerType( null, false );
586  switch ( $scaler ) {
587  case 'im':
588  $cmd = Shell::escape( $imageMagickConvertCommand ) . " " .
589  Shell::escape( $this->escapeMagickInput( $params['srcPath'], $scene ) ) .
590  " -rotate " . Shell::escape( "-$rotation" ) . " " .
591  Shell::escape( $this->escapeMagickOutput( $params['dstPath'] ) );
592  wfDebug( __METHOD__ . ": running ImageMagick: $cmd" );
593  $retval = 0;
594  $err = wfShellExecWithStderr( $cmd, $retval );
595  if ( $retval !== 0 ) {
596  $this->logErrorForExternalProcess( $retval, $err, $cmd );
597 
598  return new MediaTransformError( 'thumbnail_error', 0, 0, $err );
599  }
600 
601  return false;
602  case 'imext':
603  $im = new Imagick();
604  $im->readImage( $params['srcPath'] );
605  if ( !$im->rotateImage( new ImagickPixel( 'white' ), 360 - $rotation ) ) {
606  return new MediaTransformError( 'thumbnail_error', 0, 0,
607  "Error rotating $rotation degrees" );
608  }
609  $result = $im->writeImage( $params['dstPath'] );
610  if ( !$result ) {
611  return new MediaTransformError( 'thumbnail_error', 0, 0,
612  "Unable to write image to {$params['dstPath']}" );
613  }
614 
615  return false;
616  default:
617  return new MediaTransformError( 'thumbnail_error', 0, 0,
618  "$scaler rotation not implemented" );
619  }
620  }
621 }
MediaWiki\Shell\Shell
Executes shell commands.
Definition: Shell.php:45
BitmapHandler\parseParamString
parseParamString( $str)
Parse a param string made with makeParamString back into an array.The parameter string without file n...
Definition: BitmapHandler.php:86
MediaTransformError
Basic media transform error class.
Definition: MediaTransformError.php:31
BitmapHandler\validateParam
validateParam( $name, $value)
Validate a thumbnail parameter at parse time.Return true to accept the parameter, and false to reject...
Definition: BitmapHandler.php:100
BitmapHandler\transformImageMagickExt
transformImageMagickExt( $image, $params)
Transform an image using the Imagick PHP extension.
Definition: BitmapHandler.php:290
MediaWiki\MediaWikiServices
MediaWikiServices is the service locator for the application scope of MediaWiki.
Definition: MediaWikiServices.php:203
TransformationalImageHandler\getMediaTransformError
getMediaTransformError( $params, $errMsg)
Get a MediaTransformError with error 'thumbnail_error'.
Definition: TransformationalImageHandler.php:401
BitmapHandler\imageJpegWrapper
static imageJpegWrapper( $dst_image, $thumbPath, $quality=null)
Callback for transformGd when transforming jpeg images.
Definition: BitmapHandler.php:518
TransformationalImageHandler\escapeMagickOutput
escapeMagickOutput( $path, $scene=false)
Escape a string for ImageMagick's output filename.
Definition: TransformationalImageHandler.php:476
BitmapHandler\rotate
rotate( $file, $params)
Definition: BitmapHandler.php:578
TransformationalImageHandler\escapeMagickProperty
escapeMagickProperty( $s)
Escape a string for ImageMagick's property input (e.g.
Definition: TransformationalImageHandler.php:426
$file
if(PHP_SAPI !='cli-server') if(!isset( $_SERVER['SCRIPT_FILENAME'])) $file
Item class for a filearchive table row.
Definition: router.php:42
wfMessage
wfMessage( $key,... $params)
This is the function for getting translated interface messages.
Definition: GlobalFunctions.php:1167
TransformationalImageHandler
Handler for images that need to be transformed.
Definition: TransformationalImageHandler.php:40
$res
$res
Definition: testCompression.php:57
BitmapHandler\transformCustom
transformCustom( $image, $params)
Transform an image using a custom command.
Definition: BitmapHandler.php:383
MWException
MediaWiki exception.
Definition: MWException.php:29
BitmapHandler
Generic handler for bitmap images.
Definition: BitmapHandler.php:33
TransformationalImageHandler\extractPreRotationDimensions
extractPreRotationDimensions( $params, $rotation)
Extracts the width/height if the image will be scaled before rotating.
Definition: TransformationalImageHandler.php:85
TransformationalImageHandler\escapeMagickInput
escapeMagickInput( $path, $scene=false)
Escape a string for ImageMagick's input filenames.
Definition: TransformationalImageHandler.php:456
BitmapHandler\canRotate
canRotate()
Returns whether the current scaler supports rotation (im and gd do)
Definition: BitmapHandler.php:535
wfDebug
wfDebug( $text, $dest='all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
Definition: GlobalFunctions.php:894
BitmapHandler\makeParamString
makeParamString( $params)
Merge a parameter array into a string appropriate for inclusion in filenames.Array of parameters that...
Definition: BitmapHandler.php:73
BitmapHandler\imageMagickSubsampling
imageMagickSubsampling( $pixelFormat)
Get ImageMagick subsampling factors for the target JPEG pixel format.
Definition: BitmapHandler.php:133
BitmapHandler\transformGd
transformGd( $image, $params)
Transform an image using the built in GD library.
Definition: BitmapHandler.php:415
BitmapHandler\autoRotateEnabled
autoRotateEnabled()
Definition: BitmapHandler.php:559
BitmapHandler\normaliseParams
normaliseParams( $image, &$params)
Definition: BitmapHandler.php:114
BitmapHandler\transformImageMagick
transformImageMagick( $image, $params)
Transform an image using ImageMagick.
Definition: BitmapHandler.php:155
MediaHandler\logErrorForExternalProcess
logErrorForExternalProcess( $retval, $err, $cmd)
Log an error that occurred in an external process.
Definition: MediaHandler.php:1008
MediaHandler\isAnimatedImage
isAnimatedImage( $file)
The material is an image, and is animated.
Definition: MediaHandler.php:562
BitmapHandler\getScalerType
getScalerType( $dstPath, $checkDstPath=true)
Returns which scaler type should be used.
Definition: BitmapHandler.php:44
ImageHandler\getImageArea
getImageArea( $image)
Function that returns the number of pixels to be thumbnailed.
Definition: ImageHandler.php:258
MediaHandler\getRotation
getRotation( $file)
On supporting image formats, try to read out the low-level orientation of the file and return the ang...
Definition: MediaHandler.php:993
wfShellExecWithStderr
wfShellExecWithStderr( $cmd, &$retval=null, $environ=[], $limits=[])
Execute a shell command, returning both stdout and stderr.
Definition: GlobalFunctions.php:1947