Completed
Branch master (9259dd)
by
unknown
27:26
created

TransformationalImageHandler::doTransform()   F

Complexity

Conditions 39
Paths 7489

Size

Total Lines 182
Code Lines 111

Duplication

Lines 16
Ratio 8.79 %

Importance

Changes 0
Metric Value
cc 39
eloc 111
nc 7489
nop 5
dl 16
loc 182
rs 2
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * Base class for handlers which require transforming images in a
4
 * similar way as BitmapHandler does.
5
 *
6
 * This was split from BitmapHandler on the basis that some extensions
7
 * might want to work in a similar way to BitmapHandler, but for
8
 * different formats.
9
 *
10
 * This program is free software; you can redistribute it and/or modify
11
 * it under the terms of the GNU General Public License as published by
12
 * the Free Software Foundation; either version 2 of the License, or
13
 * (at your option) any later version.
14
 *
15
 * This program is distributed in the hope that it will be useful,
16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
 * GNU General Public License for more details.
19
 *
20
 * You should have received a copy of the GNU General Public License along
21
 * with this program; if not, write to the Free Software Foundation, Inc.,
22
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23
 * http://www.gnu.org/copyleft/gpl.html
24
 *
25
 * @file
26
 * @ingroup Media
27
 */
28
29
/**
30
 * Handler for images that need to be transformed
31
 *
32
 * @since 1.24
33
 * @ingroup Media
34
 */
35
abstract class TransformationalImageHandler extends ImageHandler {
36
	/**
37
	 * @param File $image
38
	 * @param array $params Transform parameters. Entries with the keys 'width'
39
	 * and 'height' are the respective screen width and height, while the keys
40
	 * 'physicalWidth' and 'physicalHeight' indicate the thumbnail dimensions.
41
	 * @return bool
42
	 */
43
	function normaliseParams( $image, &$params ) {
44
		if ( !parent::normaliseParams( $image, $params ) ) {
45
			return false;
46
		}
47
48
		# Obtain the source, pre-rotation dimensions
49
		$srcWidth = $image->getWidth( $params['page'] );
50
		$srcHeight = $image->getHeight( $params['page'] );
51
52
		# Don't make an image bigger than the source
53
		if ( $params['physicalWidth'] >= $srcWidth ) {
54
			$params['physicalWidth'] = $srcWidth;
55
			$params['physicalHeight'] = $srcHeight;
56
57
			# Skip scaling limit checks if no scaling is required
58
			# due to requested size being bigger than source.
59
			if ( !$image->mustRender() ) {
60
				return true;
61
			}
62
		}
63
64
		return true;
65
	}
66
67
	/**
68
	 * Extracts the width/height if the image will be scaled before rotating
69
	 *
70
	 * This will match the physical size/aspect ratio of the original image
71
	 * prior to application of the rotation -- so for a portrait image that's
72
	 * stored as raw landscape with 90-degress rotation, the resulting size
73
	 * will be wider than it is tall.
74
	 *
75
	 * @param array $params Parameters as returned by normaliseParams
76
	 * @param int $rotation The rotation angle that will be applied
77
	 * @return array ($width, $height) array
78
	 */
79
	public function extractPreRotationDimensions( $params, $rotation ) {
80
		if ( $rotation == 90 || $rotation == 270 ) {
81
			# We'll resize before rotation, so swap the dimensions again
82
			$width = $params['physicalHeight'];
83
			$height = $params['physicalWidth'];
84
		} else {
85
			$width = $params['physicalWidth'];
86
			$height = $params['physicalHeight'];
87
		}
88
89
		return [ $width, $height ];
90
	}
91
92
	/**
93
	 * Create a thumbnail.
94
	 *
95
	 * This sets up various parameters, and then calls a helper method
96
	 * based on $this->getScalerType in order to scale the image.
97
	 *
98
	 * @param File $image
99
	 * @param string $dstPath
100
	 * @param string $dstUrl
101
	 * @param array $params
102
	 * @param int $flags
103
	 * @return MediaTransformError|ThumbnailImage|TransformParameterError
104
	 */
105
	function doTransform( $image, $dstPath, $dstUrl, $params, $flags = 0 ) {
106
		if ( !$this->normaliseParams( $image, $params ) ) {
107
			return new TransformParameterError( $params );
108
		}
109
110
		# Create a parameter array to pass to the scaler
111
		$scalerParams = [
112
			# The size to which the image will be resized
113
			'physicalWidth' => $params['physicalWidth'],
114
			'physicalHeight' => $params['physicalHeight'],
115
			'physicalDimensions' => "{$params['physicalWidth']}x{$params['physicalHeight']}",
116
			# The size of the image on the page
117
			'clientWidth' => $params['width'],
118
			'clientHeight' => $params['height'],
119
			# Comment as will be added to the Exif of the thumbnail
120
			'comment' => isset( $params['descriptionUrl'] )
121
				? "File source: {$params['descriptionUrl']}"
122
				: '',
123
			# Properties of the original image
124
			'srcWidth' => $image->getWidth(),
125
			'srcHeight' => $image->getHeight(),
126
			'mimeType' => $image->getMimeType(),
127
			'dstPath' => $dstPath,
128
			'dstUrl' => $dstUrl,
129
			'interlace' => isset( $params['interlace'] ) ? $params['interlace'] : false,
130
		];
131
132
		if ( isset( $params['quality'] ) && $params['quality'] === 'low' ) {
133
			$scalerParams['quality'] = 30;
134
		}
135
136
		// For subclasses that might be paged.
137
		if ( $image->isMultipage() && isset( $params['page'] ) ) {
138
			$scalerParams['page'] = intval( $params['page'] );
139
		}
140
141
		# Determine scaler type
142
		$scaler = $this->getScalerType( $dstPath );
143
144
		if ( is_array( $scaler ) ) {
145
			$scalerName = get_class( $scaler[0] );
146
		} else {
147
			$scalerName = $scaler;
148
		}
149
150
		wfDebug( __METHOD__ . ": creating {$scalerParams['physicalDimensions']} " .
151
			"thumbnail at $dstPath using scaler $scalerName\n" );
152
153
		if ( !$image->mustRender() &&
154
			$scalerParams['physicalWidth'] == $scalerParams['srcWidth']
155
			&& $scalerParams['physicalHeight'] == $scalerParams['srcHeight']
156
			&& !isset( $scalerParams['quality'] )
157
		) {
158
159
			# normaliseParams (or the user) wants us to return the unscaled image
160
			wfDebug( __METHOD__ . ": returning unscaled image\n" );
161
162
			return $this->getClientScalingThumbnailImage( $image, $scalerParams );
163
		}
164
165
		if ( $scaler == 'client' ) {
166
			# Client-side image scaling, use the source URL
167
			# Using the destination URL in a TRANSFORM_LATER request would be incorrect
168
			return $this->getClientScalingThumbnailImage( $image, $scalerParams );
169
		}
170
171
		if ( $image->isTransformedLocally() && !$this->isImageAreaOkForThumbnaling( $image, $params ) ) {
172
			global $wgMaxImageArea;
173
			return new TransformTooBigImageAreaError( $params, $wgMaxImageArea );
174
		}
175
176
		if ( $flags & self::TRANSFORM_LATER ) {
177
			wfDebug( __METHOD__ . ": Transforming later per flags.\n" );
178
			$newParams = [
179
				'width' => $scalerParams['clientWidth'],
180
				'height' => $scalerParams['clientHeight']
181
			];
182
			if ( isset( $params['quality'] ) ) {
183
				$newParams['quality'] = $params['quality'];
184
			}
185 View Code Duplication
			if ( isset( $params['page'] ) && $params['page'] ) {
186
				$newParams['page'] = $params['page'];
187
			}
188
			return new ThumbnailImage( $image, $dstUrl, false, $newParams );
189
		}
190
191
		# Try to make a target path for the thumbnail
192
		if ( !wfMkdirParents( dirname( $dstPath ), null, __METHOD__ ) ) {
193
			wfDebug( __METHOD__ . ": Unable to create thumbnail destination " .
194
				"directory, falling back to client scaling\n" );
195
196
			return $this->getClientScalingThumbnailImage( $image, $scalerParams );
197
		}
198
199
		# Transform functions and binaries need a FS source file
200
		$thumbnailSource = $this->getThumbnailSource( $image, $params );
201
202
		// If the source isn't the original, disable EXIF rotation because it's already been applied
203
		if ( $scalerParams['srcWidth'] != $thumbnailSource['width']
204
			|| $scalerParams['srcHeight'] != $thumbnailSource['height'] ) {
205
			$scalerParams['disableRotation'] = true;
206
		}
207
208
		$scalerParams['srcPath'] = $thumbnailSource['path'];
209
		$scalerParams['srcWidth'] = $thumbnailSource['width'];
210
		$scalerParams['srcHeight'] = $thumbnailSource['height'];
211
212 View Code Duplication
		if ( $scalerParams['srcPath'] === false ) { // Failed to get local copy
213
			wfDebugLog( 'thumbnail',
214
				sprintf( 'Thumbnail failed on %s: could not get local copy of "%s"',
215
					wfHostname(), $image->getName() ) );
216
217
			return new MediaTransformError( 'thumbnail_error',
218
				$scalerParams['clientWidth'], $scalerParams['clientHeight'],
219
				wfMessage( 'filemissing' )->text()
220
			);
221
		}
222
223
		# Try a hook. Called "Bitmap" for historical reasons.
224
		/** @var $mto MediaTransformOutput */
225
		$mto = null;
226
		Hooks::run( 'BitmapHandlerTransform', [ $this, $image, &$scalerParams, &$mto ] );
227
		if ( !is_null( $mto ) ) {
228
			wfDebug( __METHOD__ . ": Hook to BitmapHandlerTransform created an mto\n" );
229
			$scaler = 'hookaborted';
230
		}
231
232
		// $scaler will return a MediaTransformError on failure, or false on success.
233
		// If the scaler is succesful, it will have created a thumbnail at the destination
234
		// path.
235
		if ( is_array( $scaler ) && is_callable( $scaler ) ) {
236
			// Allow subclasses to specify their own rendering methods.
237
			$err = call_user_func( $scaler, $image, $scalerParams );
238
		} else {
239
			switch ( $scaler ) {
240
				case 'hookaborted':
241
					# Handled by the hook above
242
					$err = $mto->isError() ? $mto : false;
243
					break;
244
				case 'im':
245
					$err = $this->transformImageMagick( $image, $scalerParams );
246
					break;
247
				case 'custom':
248
					$err = $this->transformCustom( $image, $scalerParams );
249
					break;
250
				case 'imext':
251
					$err = $this->transformImageMagickExt( $image, $scalerParams );
252
					break;
253
				case 'gd':
254
				default:
255
					$err = $this->transformGd( $image, $scalerParams );
256
					break;
257
			}
258
		}
259
260
		# Remove the file if a zero-byte thumbnail was created, or if there was an error
261
		$removed = $this->removeBadFile( $dstPath, (bool)$err );
262
		if ( $err ) {
263
			# transform returned MediaTransforError
264
			return $err;
265
		} elseif ( $removed ) {
266
			# Thumbnail was zero-byte and had to be removed
267
			return new MediaTransformError( 'thumbnail_error',
268
				$scalerParams['clientWidth'], $scalerParams['clientHeight'],
269
				wfMessage( 'unknown-error' )->text()
270
			);
271
		} elseif ( $mto ) {
272
			return $mto;
273
		} else {
274
			$newParams = [
275
				'width' => $scalerParams['clientWidth'],
276
				'height' => $scalerParams['clientHeight']
277
			];
278
			if ( isset( $params['quality'] ) ) {
279
				$newParams['quality'] = $params['quality'];
280
			}
281 View Code Duplication
			if ( isset( $params['page'] ) && $params['page'] ) {
282
				$newParams['page'] = $params['page'];
283
			}
284
			return new ThumbnailImage( $image, $dstUrl, $dstPath, $newParams );
285
		}
286
	}
287
288
	/**
289
	 * Get the source file for the transform
290
	 *
291
	 * @param File $file
292
	 * @param array $params
293
	 * @return array Array with keys  width, height and path.
294
	 */
295
	protected function getThumbnailSource( $file, $params ) {
296
		return $file->getThumbnailSource( $params );
297
	}
298
299
	/**
300
	 * Returns what sort of scaler type should be used.
301
	 *
302
	 * Values can be one of client, im, custom, gd, imext, or an array
303
	 * of object, method-name to call that specific method.
304
	 *
305
	 * If specifying a custom scaler command with array( Obj, method ),
306
	 * the method in question should take 2 parameters, a File object,
307
	 * and a $scalerParams array with various options (See doTransform
308
	 * for what is in $scalerParams). On error it should return a
309
	 * MediaTransformError object. On success it should return false,
310
	 * and simply make sure the thumbnail file is located at
311
	 * $scalerParams['dstPath'].
312
	 *
313
	 * If there is a problem with the output path, it returns "client"
314
	 * to do client side scaling.
315
	 *
316
	 * @param string $dstPath
317
	 * @param bool $checkDstPath Check that $dstPath is valid
318
	 * @return string|Callable One of client, im, custom, gd, imext, or a Callable array.
319
	 */
320
	abstract protected function getScalerType( $dstPath, $checkDstPath = true );
321
322
	/**
323
	 * Get a ThumbnailImage that respresents an image that will be scaled
324
	 * client side
325
	 *
326
	 * @param File $image File associated with this thumbnail
327
	 * @param array $scalerParams Array with scaler params
328
	 * @return ThumbnailImage
329
	 *
330
	 * @todo FIXME: No rotation support
331
	 */
332
	protected function getClientScalingThumbnailImage( $image, $scalerParams ) {
333
		$params = [
334
			'width' => $scalerParams['clientWidth'],
335
			'height' => $scalerParams['clientHeight']
336
		];
337
338
		return new ThumbnailImage( $image, $image->getUrl(), null, $params );
339
	}
340
341
	/**
342
	 * Transform an image using ImageMagick
343
	 *
344
	 * This is a stub method. The real method is in BitmapHander.
345
	 *
346
	 * @param File $image File associated with this thumbnail
347
	 * @param array $params Array with scaler params
348
	 *
349
	 * @return MediaTransformError Error object if error occurred, false (=no error) otherwise
350
	 */
351
	protected function transformImageMagick( $image, $params ) {
352
		return $this->getMediaTransformError( $params, "Unimplemented" );
353
	}
354
355
	/**
356
	 * Transform an image using the Imagick PHP extension
357
	 *
358
	 * This is a stub method. The real method is in BitmapHander.
359
	 *
360
	 * @param File $image File associated with this thumbnail
361
	 * @param array $params Array with scaler params
362
	 *
363
	 * @return MediaTransformError Error object if error occurred, false (=no error) otherwise
364
	 */
365
	protected function transformImageMagickExt( $image, $params ) {
366
		return $this->getMediaTransformError( $params, "Unimplemented" );
367
	}
368
369
	/**
370
	 * Transform an image using a custom command
371
	 *
372
	 * This is a stub method. The real method is in BitmapHander.
373
	 *
374
	 * @param File $image File associated with this thumbnail
375
	 * @param array $params Array with scaler params
376
	 *
377
	 * @return MediaTransformError Error object if error occurred, false (=no error) otherwise
378
	 */
379
	protected function transformCustom( $image, $params ) {
380
		return $this->getMediaTransformError( $params, "Unimplemented" );
381
	}
382
383
	/**
384
	 * Get a MediaTransformError with error 'thumbnail_error'
385
	 *
386
	 * @param array $params Parameter array as passed to the transform* functions
387
	 * @param string $errMsg Error message
388
	 * @return MediaTransformError
389
	 */
390
	public function getMediaTransformError( $params, $errMsg ) {
391
		return new MediaTransformError( 'thumbnail_error', $params['clientWidth'],
392
			$params['clientHeight'], $errMsg );
393
	}
394
395
	/**
396
	 * Transform an image using the built in GD library
397
	 *
398
	 * This is a stub method. The real method is in BitmapHander.
399
	 *
400
	 * @param File $image File associated with this thumbnail
401
	 * @param array $params Array with scaler params
402
	 *
403
	 * @return MediaTransformError Error object if error occurred, false (=no error) otherwise
404
	 */
405
	protected function transformGd( $image, $params ) {
406
		return $this->getMediaTransformError( $params, "Unimplemented" );
407
	}
408
409
	/**
410
	 * Escape a string for ImageMagick's property input (e.g. -set -comment)
411
	 * See InterpretImageProperties() in magick/property.c
412
	 * @param string $s
413
	 * @return string
414
	 */
415
	function escapeMagickProperty( $s ) {
416
		// Double the backslashes
417
		$s = str_replace( '\\', '\\\\', $s );
418
		// Double the percents
419
		$s = str_replace( '%', '%%', $s );
420
		// Escape initial - or @
421
		if ( strlen( $s ) > 0 && ( $s[0] === '-' || $s[0] === '@' ) ) {
422
			$s = '\\' . $s;
423
		}
424
425
		return $s;
426
	}
427
428
	/**
429
	 * Escape a string for ImageMagick's input filenames. See ExpandFilenames()
430
	 * and GetPathComponent() in magick/utility.c.
431
	 *
432
	 * This won't work with an initial ~ or @, so input files should be prefixed
433
	 * with the directory name.
434
	 *
435
	 * Glob character unescaping is broken in ImageMagick before 6.6.1-5, but
436
	 * it's broken in a way that doesn't involve trying to convert every file
437
	 * in a directory, so we're better off escaping and waiting for the bugfix
438
	 * to filter down to users.
439
	 *
440
	 * @param string $path The file path
441
	 * @param bool|string $scene The scene specification, or false if there is none
442
	 * @throws MWException
443
	 * @return string
444
	 */
445
	function escapeMagickInput( $path, $scene = false ) {
446
		# Die on initial metacharacters (caller should prepend path)
447
		$firstChar = substr( $path, 0, 1 );
448
		if ( $firstChar === '~' || $firstChar === '@' ) {
449
			throw new MWException( __METHOD__ . ': cannot escape this path name' );
450
		}
451
452
		# Escape glob chars
453
		$path = preg_replace( '/[*?\[\]{}]/', '\\\\\0', $path );
454
455
		return $this->escapeMagickPath( $path, $scene );
456
	}
457
458
	/**
459
	 * Escape a string for ImageMagick's output filename. See
460
	 * InterpretImageFilename() in magick/image.c.
461
	 * @param string $path The file path
462
	 * @param bool|string $scene The scene specification, or false if there is none
463
	 * @return string
464
	 */
465
	function escapeMagickOutput( $path, $scene = false ) {
466
		$path = str_replace( '%', '%%', $path );
467
468
		return $this->escapeMagickPath( $path, $scene );
469
	}
470
471
	/**
472
	 * Armour a string against ImageMagick's GetPathComponent(). This is a
473
	 * helper function for escapeMagickInput() and escapeMagickOutput().
474
	 *
475
	 * @param string $path The file path
476
	 * @param bool|string $scene The scene specification, or false if there is none
477
	 * @throws MWException
478
	 * @return string
479
	 */
480
	protected function escapeMagickPath( $path, $scene = false ) {
481
		# Die on format specifiers (other than drive letters). The regex is
482
		# meant to match all the formats you get from "convert -list format"
483
		if ( preg_match( '/^([a-zA-Z0-9-]+):/', $path, $m ) ) {
484
			if ( wfIsWindows() && is_dir( $m[0] ) ) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
485
				// OK, it's a drive letter
486
				// ImageMagick has a similar exception, see IsMagickConflict()
487
			} else {
488
				throw new MWException( __METHOD__ . ': unexpected colon character in path name' );
489
			}
490
		}
491
492
		# If there are square brackets, add a do-nothing scene specification
493
		# to force a literal interpretation
494
		if ( $scene === false ) {
495
			if ( strpos( $path, '[' ) !== false ) {
496
				$path .= '[0--1]';
497
			}
498
		} else {
499
			$path .= "[$scene]";
500
		}
501
502
		return $path;
503
	}
504
505
	/**
506
	 * Retrieve the version of the installed ImageMagick
507
	 * You can use PHPs version_compare() to use this value
508
	 * Value is cached for one hour.
509
	 * @return string|bool Representing the IM version; false on error
510
	 */
511
	protected function getMagickVersion() {
512
		$cache = ObjectCache::getLocalServerInstance( CACHE_NONE );
513
		return $cache->getWithSetCallback(
514
			'imagemagick-version',
515
			$cache::TTL_HOUR,
516
			function () {
517
				global $wgImageMagickConvertCommand;
518
519
				$cmd = wfEscapeShellArg( $wgImageMagickConvertCommand ) . ' -version';
520
				wfDebug( __METHOD__ . ": Running convert -version\n" );
521
				$retval = '';
522
				$return = wfShellExec( $cmd, $retval );
523
				$x = preg_match(
524
					'/Version: ImageMagick ([0-9]*\.[0-9]*\.[0-9]*)/', $return, $matches
525
				);
526
				if ( $x != 1 ) {
527
					wfDebug( __METHOD__ . ": ImageMagick version check failed\n" );
528
					return false;
529
				}
530
531
				return $matches[1];
532
			}
533
		);
534
	}
535
536
	/**
537
	 * Returns whether the current scaler supports rotation.
538
	 *
539
	 * @since 1.24 No longer static
540
	 * @return bool
541
	 */
542
	public function canRotate() {
543
		return false;
544
	}
545
546
	/**
547
	 * Should we automatically rotate an image based on exif
548
	 *
549
	 * @since 1.24 No longer static
550
	 * @see $wgEnableAutoRotation
551
	 * @return bool Whether auto rotation is enabled
552
	 */
553
	public function autoRotateEnabled() {
554
		return false;
555
	}
556
557
	/**
558
	 * Rotate a thumbnail.
559
	 *
560
	 * This is a stub. See BitmapHandler::rotate.
561
	 *
562
	 * @param File $file
563
	 * @param array $params Rotate parameters.
564
	 *   'rotation' clockwise rotation in degrees, allowed are multiples of 90
565
	 * @since 1.24 Is non-static. From 1.21 it was static
566
	 * @return bool
567
	 */
568
	public function rotate( $file, $params ) {
569
		return new MediaTransformError( 'thumbnail_error', 0, 0,
570
			get_class( $this ) . ' rotation not implemented' );
571
	}
572
573
	/**
574
	 * Returns whether the file needs to be rendered. Returns true if the
575
	 * file requires rotation and we are able to rotate it.
576
	 *
577
	 * @param File $file
578
	 * @return bool
579
	 */
580
	public function mustRender( $file ) {
581
		return $this->canRotate() && $this->getRotation( $file ) != 0;
582
	}
583
584
	/**
585
	 * Check if the file is smaller than the maximum image area for thumbnailing.
586
	 *
587
	 * Runs the 'BitmapHandlerCheckImageArea' hook.
588
	 *
589
	 * @param File $file
590
	 * @param array $params
591
	 * @return bool
592
	 * @since 1.25
593
	 */
594
	public function isImageAreaOkForThumbnaling( $file, &$params ) {
595
		global $wgMaxImageArea;
596
597
		# For historical reasons, hook starts with BitmapHandler
598
		$checkImageAreaHookResult = null;
599
		Hooks::run(
600
			'BitmapHandlerCheckImageArea',
601
			[ $file, &$params, &$checkImageAreaHookResult ]
602
		);
603
604
		if ( !is_null( $checkImageAreaHookResult ) ) {
605
			// was set by hook, so return that value
606
			return (bool)$checkImageAreaHookResult;
607
		}
608
609
		$srcWidth = $file->getWidth( $params['page'] );
610
		$srcHeight = $file->getHeight( $params['page'] );
611
612
		if ( $srcWidth * $srcHeight > $wgMaxImageArea
613
			&& !( $file->getMimeType() == 'image/jpeg'
614
				&& $this->getScalerType( false, false ) == 'im' )
615
		) {
616
			# Only ImageMagick can efficiently downsize jpg images without loading
617
			# the entire file in memory
618
			return false;
619
		}
620
		return true;
621
	}
622
}
623