Completed
Push — new-committers ( 29cb6f...bcba16 )
by Sam
12:18 queued 33s
created

GDBackend   D

Complexity

Total Complexity 102

Size/Duplication

Total Lines 575
Duplicated Lines 2.09 %

Coupling/Cohesion

Components 1
Dependencies 7
Metric Value
wmc 102
lcom 1
cbo 7
dl 12
loc 575
rs 4.8717

29 Methods

Rating   Name   Duplication   Size   Complexity  
A set_default_quality() 3 6 4
A setGD() 0 4 1
A getImageResource() 0 3 1
A getGD() 0 4 1
A imageAvailable() 0 3 2
A checkAvailableMemory() 0 20 4
A failedResample() 0 4 2
A setQuality() 0 3 1
A hasImageResource() 0 3 2
A getWidth() 0 3 1
A getHeight() 0 3 1
A resizeByWidth() 0 4 1
A resizeByHeight() 0 4 1
A makeDir() 0 4 3
C __construct() 0 44 11
A setImageResource() 0 5 1
C croppedResize() 0 46 7
A fittedResize() 0 5 2
A hasGD() 0 5 1
D resize() 0 30 10
A rotate() 0 13 3
C rotatePixelByPixel() 0 31 7
A crop() 0 13 1
A resizeRatio() 5 10 4
A color_web2gd() 3 9 2
C paddedResize() 0 50 7
B greyscale() 0 27 6
F writeTo() 0 38 13
A onBeforeDelete() 0 8 2

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like GDBackend often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use GDBackend, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * A wrapper class for GD-based images, with lots of manipulation functions.
4
 * @package framework
5
 * @subpackage filesystem
6
 */
7
class GDBackend extends Object implements Image_Backend {
8
	protected $gd, $width, $height;
9
	protected $quality;
10
	protected $interlace;
11
	protected $cache, $cacheKey, $manipulation;
12
13
	/**
14
	 * @config
15
	 * @var integer
16
	 */
17
	private static $default_quality = 75;
18
19
	/**
20
	 * @config
21
	 * @var integer
22
	 */
23
	private static $image_interlace = 0;
24
25
	/**
26
	 * Set the default image quality.
27
	 *
28
	 * @deprecated 4.0 Use the "GDBackend.default_quality" config setting instead
29
	 * @param quality int A number from 0 to 100, 100 being the best quality.
30
	 */
31
	public static function set_default_quality($quality) {
32
		Deprecation::notice('4.0', 'Use the "GDBackend.default_quality" config setting instead');
33 View Code Duplication
		if(is_numeric($quality) && (int) $quality >= 0 && (int) $quality <= 100) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
34
			config::inst()->update('GDBackend', 'default_quality', (int) $quality);
35
		}
36
	}
37
38
	public function __construct($filename = null, $args = array()) {
39
		// If we're working with image resampling, things could take a while.  Bump up the time-limit
40
		increase_time_limit_to(300);
41
42
		$this->cache = SS_Cache::factory('GDBackend_Manipulations');
43
44
		if($filename && is_readable($filename)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $filename of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
45
			$this->cacheKey = md5(implode('_', array($filename, filemtime($filename))));
46
			$this->manipulation = implode('|', $args);
47
48
			$cacheData = unserialize($this->cache->load($this->cacheKey));
49
			$cacheData = ($cacheData !== false) ? $cacheData : array();
50
51
			if ($this->imageAvailable($filename, $this->manipulation)) {
52
				$cacheData[$this->manipulation] = true;
53
				$this->cache->save(serialize($cacheData), $this->cacheKey);
54
55
				// We use getimagesize instead of extension checking, because sometimes extensions are wrong.
56
				list($width, $height, $type, $attr) = getimagesize($filename);
0 ignored issues
show
Unused Code introduced by
The assignment to $width is unused. Consider omitting it like so list($first,,$third).

This checks looks for assignemnts to variables using the list(...) function, where not all assigned variables are subsequently used.

Consider the following code example.

<?php

function returnThreeValues() {
    return array('a', 'b', 'c');
}

list($a, $b, $c) = returnThreeValues();

print $a . " - " . $c;

Only the variables $a and $c are used. There was no need to assign $b.

Instead, the list call could have been.

list($a,, $c) = returnThreeValues();
Loading history...
Unused Code introduced by
The assignment to $height is unused. Consider omitting it like so list($first,,$third).

This checks looks for assignemnts to variables using the list(...) function, where not all assigned variables are subsequently used.

Consider the following code example.

<?php

function returnThreeValues() {
    return array('a', 'b', 'c');
}

list($a, $b, $c) = returnThreeValues();

print $a . " - " . $c;

Only the variables $a and $c are used. There was no need to assign $b.

Instead, the list call could have been.

list($a,, $c) = returnThreeValues();
Loading history...
Unused Code introduced by
The assignment to $attr is unused. Consider omitting it like so list($first,,$third).

This checks looks for assignemnts to variables using the list(...) function, where not all assigned variables are subsequently used.

Consider the following code example.

<?php

function returnThreeValues() {
    return array('a', 'b', 'c');
}

list($a, $b, $c) = returnThreeValues();

print $a . " - " . $c;

Only the variables $a and $c are used. There was no need to assign $b.

Instead, the list call could have been.

list($a,, $c) = returnThreeValues();
Loading history...
57
				switch($type) {
58
					case 1:
59
						if(function_exists('imagecreatefromgif'))
60
							$this->setImageResource(imagecreatefromgif($filename));
61
						break;
62
					case 2:
63
						if(function_exists('imagecreatefromjpeg'))
64
							$this->setImageResource(imagecreatefromjpeg($filename));
65
						break;
66
					case 3:
67
						if(function_exists('imagecreatefrompng')) {
68
							$img = imagecreatefrompng($filename);
69
							imagesavealpha($img, true); // save alphablending setting (important)
70
							$this->setImageResource($img);
71
						}
72
						break;
73
				}
74
			}
75
		}
76
77
		parent::__construct();
78
79
		$this->quality = $this->config()->default_quality;
0 ignored issues
show
Documentation introduced by
The property default_quality does not exist on object<Config_ForClass>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
80
		$this->interlace = $this->config()->image_interlace;
0 ignored issues
show
Documentation introduced by
The property image_interlace does not exist on object<Config_ForClass>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
81
	}
82
83
	public function setImageResource($resource) {
84
		$this->gd = $resource;
85
		$this->width = imagesx($resource);
86
		$this->height = imagesy($resource);
87
	}
88
89
	/**
90
	 * @deprecated
91
	 */
92
	public function setGD($gd) {
93
		Deprecation::notice('4.0', 'Use GD::setImageResource instead');
94
		return $this->setImageResource($gd);
95
	}
96
97
	public function getImageResource() {
98
		return $this->gd;
99
	}
100
101
	/**
102
	 * @deprecated
103
	 */
104
	public function getGD() {
105
		Deprecation::notice('4.0', 'GD::getImageResource instead');
106
		return $this->getImageResource();
107
	}
108
109
	/**
110
	 * @param string $filename
111
	 * @param string $manipulation
112
	 * @return boolean
113
	 */
114
	public function imageAvailable($filename, $manipulation) {
115
		return ($this->checkAvailableMemory($filename) && ! $this->failedResample($filename, $manipulation));
116
	}
117
118
	/**
119
	 * Check if we've got enough memory available for resampling this image. This check is rough,
120
	 * so it will not catch all images that are too large - it also won't work accurately on large,
121
	 * animated GIFs as bits per pixel can't be calculated for an animated GIF with a global color
122
	 * table.
123
	 *
124
	 * @param string $filename
125
	 * @return boolean
126
	 */
127
	public function checkAvailableMemory($filename) {
128
		$limit = translate_memstring(ini_get('memory_limit'));
129
130
		if ($limit < 0) return true; // memory_limit == -1
131
132
		$imageInfo = getimagesize($filename);
133
134
		// bits per channel (rounded up, default to 1)
135
		$bits = isset($imageInfo['bits']) ? ($imageInfo['bits'] + 7) / 8 : 1;
136
137
		// channels (default 4 rgba)
138
		$channels = isset($imageInfo['channels']) ? $imageInfo['channels'] : 4;
139
140
		$bytesPerPixel = $bits * $channels;
141
142
		// width * height * bytes per pixel
143
		$memoryRequired = $imageInfo[0] * $imageInfo[1] * $bytesPerPixel;
144
145
		return $memoryRequired + memory_get_usage() < $limit;
146
	}
147
148
	/**
149
	 * Check if this image has previously crashed GD when attempting to open it - if it's opened
150
	 * successfully, the manipulation's cache key is removed.
151
	 *
152
	 * @param string $filename
153
	 * @return boolean
154
	 */
155
	public function failedResample($filename, $manipulation) {
0 ignored issues
show
Unused Code introduced by
The parameter $filename is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
156
		$cacheData = unserialize($this->cache->load($this->cacheKey));
157
		return ($cacheData && array_key_exists($manipulation, $cacheData));
158
	}
159
160
	/**
161
	 * Set the image quality, used when saving JPEGs.
162
	 */
163
	public function setQuality($quality) {
164
		$this->quality = $quality;
165
	}
166
167
	/**
168
	 * Resize an image to cover the given width/height completely, and crop off any overhanging edges.
169
	 */
170
	public function croppedResize($width, $height) {
171
		if(!$this->gd) return;
172
173
		$width = round($width);
174
		$height = round($height);
175
176
		// Check that a resize is actually necessary.
177
		if ($width == $this->width && $height == $this->height) {
178
			return $this;
179
		}
180
181
		$newGD = imagecreatetruecolor($width, $height);
182
183
		// Preserves transparency between images
184
		imagealphablending($newGD, false);
185
		imagesavealpha($newGD, true);
186
187
		$destAR = $width / $height;
188
		if ($this->width > 0 && $this->height > 0 ){
189
			// We can't divide by zero theres something wrong.
190
191
			$srcAR = $this->width / $this->height;
192
193
			// Destination narrower than the source
194
			if($destAR < $srcAR) {
195
				$srcY = 0;
196
				$srcHeight = $this->height;
197
198
				$srcWidth = round( $this->height * $destAR );
199
				$srcX = round( ($this->width - $srcWidth) / 2 );
200
201
			// Destination shorter than the source
202
			} else {
203
				$srcX = 0;
204
				$srcWidth = $this->width;
205
206
				$srcHeight = round( $this->width / $destAR );
207
				$srcY = round( ($this->height - $srcHeight) / 2 );
208
			}
209
210
			imagecopyresampled($newGD, $this->gd, 0,0, $srcX, $srcY, $width, $height, $srcWidth, $srcHeight);
211
		}
212
		$output = clone $this;
213
		$output->setImageResource($newGD);
214
		return $output;
215
	}
216
217
	/**
218
	 * Resizes the image to fit within the given region.
219
	 * Behaves similarly to paddedResize but without the padding.
220
	 * @todo This method isn't very efficent
221
	 */
222
	public function fittedResize($width, $height) {
223
		$gd = $this->resizeByHeight($height);
224
		if($gd->width > $width) $gd = $gd->resizeByWidth($width);
225
		return $gd;
226
	}
227
228
	/**
229
	 * hasImageResource
230
	 *
231
	 * @return boolean
232
	 */
233
	public function hasImageResource() {
234
		return $this->gd ? true : false;
235
	}
236
237
	/**
238
	 * @deprecated
239
	 */
240
	public function hasGD() {
241
		Deprecation::notice('4.0', 'GD::hasImageResource instead',
242
			Deprecation::SCOPE_CLASS);
243
		return $this->hasImageResource();
244
	}
245
246
247
	/**
248
	 * Resize an image, skewing it as necessary.
249
	 */
250
	public function resize($width, $height) {
251
		if(!$this->gd) return;
252
253
		if($width < 0 || $height < 0) throw new InvalidArgumentException("Image resizing dimensions cannot be negative");
254
		if(!$width && !$height) throw new InvalidArgumentException("No dimensions given when resizing image");
255
		if(!$width) throw new InvalidArgumentException("Width not given when resizing image");
256
		if(!$height) throw new InvalidArgumentException("Height not given when resizing image");
257
258
		//use whole numbers, ensuring that size is at least 1x1
259
		$width = max(1, round($width));
260
		$height = max(1, round($height));
261
262
		// Check that a resize is actually necessary.
263
		if ($width == $this->width && $height == $this->height) {
264
			return $this;
265
		}
266
267
268
		$newGD = imagecreatetruecolor($width, $height);
269
270
		// Preserves transparency between images
271
		imagealphablending($newGD, false);
272
		imagesavealpha($newGD, true);
273
274
		imagecopyresampled($newGD, $this->gd, 0,0, 0, 0, $width, $height, $this->width, $this->height);
275
276
		$output = clone $this;
277
		$output->setImageResource($newGD);
278
		return $output;
279
	}
280
281
	/**
282
	 * Rotates image by given angle.
283
	 *
284
	 * @param angle
285
	 *
286
	 * @return GD
287
	*/
288
289
	public function rotate($angle) {
290
		if(!$this->gd) return;
291
292
		if(function_exists("imagerotate")) {
293
			$newGD = imagerotate($this->gd, $angle,0);
294
		} else {
295
			//imagerotate is not included in PHP included in Ubuntu
296
			$newGD = $this->rotatePixelByPixel($angle);
297
		}
298
		$output = clone $this;
299
		$output->setImageResource($newGD);
300
		return $output;
301
	}
302
303
	/**
304
	 * Rotates image by given angle. It's slow because makes it pixel by pixel rather than
305
	 * using built-in function. Used when imagerotate function is not available(i.e. Ubuntu)
306
	 *
307
	 * @param angle
308
	 *
309
	 * @return GD
310
	*/
311
312
	public function rotatePixelByPixel($angle) {
313
		$sourceWidth = imagesx($this->gd);
314
		$sourceHeight = imagesy($this->gd);
315
		if ($angle == 180) {
316
			$destWidth = $sourceWidth;
317
			$destHeight = $sourceHeight;
318
		} else {
319
			$destWidth = $sourceHeight;
320
			$destHeight = $sourceWidth;
321
		}
322
		$rotate=imagecreatetruecolor($destWidth,$destHeight);
323
		imagealphablending($rotate, false);
324
		for ($x = 0; $x < ($sourceWidth); $x++) {
325
			for ($y = 0; $y < ($sourceHeight); $y++) {
326
				$color = imagecolorat($this->gd, $x, $y);
327
				switch ($angle) {
328
					case 90:
329
						imagesetpixel($rotate, $y, $destHeight - $x - 1, $color);
330
					break;
331
					case 180:
332
						imagesetpixel($rotate, $destWidth - $x - 1, $destHeight - $y - 1, $color);
333
					break;
334
					case 270:
335
						imagesetpixel($rotate, $destWidth - $y - 1, $x, $color);
336
					break;
337
					default: $rotate = $this->gd;
338
				};
339
			}
340
		}
341
		return $rotate;
342
	}
343
344
345
	/**
346
	 * Crop's part of image.
347
	 *
348
	 * @param top y position of left upper corner of crop rectangle
349
	 * @param left x position of left upper corner of crop rectangle
350
	 * @param width rectangle width
351
	 * @param height rectangle height
352
	 *
353
	 * @return GD
354
	*/
355
356
	public function crop($top, $left, $width, $height) {
357
		$newGD = imagecreatetruecolor($width, $height);
358
359
		// Preserve alpha channel between images
360
		imagealphablending($newGD, false);
361
		imagesavealpha($newGD, true);
362
363
		imagecopyresampled($newGD, $this->gd, 0, 0, $left, $top, $width, $height, $width, $height);
364
365
		$output = clone $this;
366
		$output->setImageResource($newGD);
367
		return $output;
368
	}
369
370
	/**
371
	 * Method return width of image.
372
	 *
373
	 * @return integer width.
374
	*/
375
	public function getWidth() {
376
		return $this->width;
377
	}
378
379
	/**
380
	 * Method return height of image.
381
	 *
382
	 * @return integer height
383
	*/
384
385
	public function getHeight() {
386
		return $this->height;
387
	}
388
389
	/**
390
	 * Resize an image by width. Preserves aspect ratio.
391
	 */
392
	public function resizeByWidth( $width ) {
393
		$heightScale = $width / $this->width;
394
		return $this->resize( $width, $heightScale * $this->height );
395
	}
396
397
	/**
398
	 * Resize an image by height. Preserves aspect ratio
399
	 */
400
	public function resizeByHeight( $height ) {
401
		$scale = $height / $this->height;
402
		return $this->resize( $scale * $this->width, $height );
403
	}
404
405
	/**
406
	 * Resize the image by preserving aspect ratio. By default, it will keep the image inside the maxWidth
407
	 * and maxHeight. Passing useAsMinimum will make the smaller dimension equal to the maximum corresponding dimension
408
	 */
409
	public function resizeRatio( $maxWidth, $maxHeight, $useAsMinimum = false ) {
410
411
		$widthRatio = $maxWidth / $this->width;
412
		$heightRatio = $maxHeight / $this->height;
413
414 View Code Duplication
		if( $widthRatio < $heightRatio )
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
415
			return $useAsMinimum ? $this->resizeByHeight( $maxHeight ) : $this->resizeByWidth( $maxWidth );
416
		else
417
			return $useAsMinimum ? $this->resizeByWidth( $maxWidth ) : $this->resizeByHeight( $maxHeight );
418
	}
419
420
	public static function color_web2gd($image, $webColor) {
421
		if(substr($webColor,0,1) == "#") $webColor = substr($webColor,1);
422
		$r = hexdec(substr($webColor,0,2));
423
		$g = hexdec(substr($webColor,2,2));
424
		$b = hexdec(substr($webColor,4,2));
425
426
		return imagecolorallocate($image, $r, $g, $b);
427
428
	}
429
430
	/**
431
	 * Resize to fit fully within the given box, without resizing.  Extra space left around
432
	 * the image will be padded with the background color.
433
	 * @param width
434
	 * @param height
435
	 * @param backgroundColour
436
	 */
437
	public function paddedResize($width, $height, $backgroundColor = "FFFFFF") {
438
		if(!$this->gd) return;
439
		$width = round($width);
440
		$height = round($height);
441
442
		// Check that a resize is actually necessary.
443
		if ($width == $this->width && $height == $this->height) {
444
			return $this;
445
		}
446
447
		$newGD = imagecreatetruecolor($width, $height);
448
449
		// Preserves transparency between images
450
		imagealphablending($newGD, false);
451
		imagesavealpha($newGD, true);
452
453
		$bg = GD::color_web2gd($newGD, $backgroundColor);
454
		imagefilledrectangle($newGD, 0, 0, $width, $height, $bg);
455
456
		$destAR = $width / $height;
457
		if ($this->width > 0 && $this->height > 0) {
458
			// We can't divide by zero theres something wrong.
459
460
			$srcAR = $this->width / $this->height;
461
462
			// Destination narrower than the source
463
			if($destAR > $srcAR) {
464
				$destY = 0;
465
				$destHeight = $height;
466
467
				$destWidth = round( $height * $srcAR );
468
				$destX = round( ($width - $destWidth) / 2 );
469
470
			// Destination shorter than the source
471
			} else {
472
				$destX = 0;
473
				$destWidth = $width;
474
475
				$destHeight = round( $width / $srcAR );
476
				$destY = round( ($height - $destHeight) / 2 );
477
			}
478
479
			imagecopyresampled($newGD, $this->gd,
480
				$destX, $destY, 0, 0,
481
				$destWidth, $destHeight, $this->width, $this->height);
482
		}
483
		$output = clone $this;
484
		$output->setImageResource($newGD);
485
		return $output;
486
	}
487
488
	/**
489
	 * Make the image greyscale
490
	 * $rv = red value, defaults to 38
491
	 * $gv = green value, defaults to 36
492
	 * $bv = blue value, defaults to 26
493
	 * Based (more or less entirely, with changes for readability) on code from
494
	 * http://www.teckis.com/scriptix/thumbnails/teck.html
495
	 */
496
	public function greyscale($rv=38, $gv=36, $bv=26) {
497
		$width = $this->width;
498
		$height = $this->height;
499
		$newGD = imagecreatetruecolor($this->width, $this->height);
500
501
		// Preserves transparency between images
502
		imagealphablending($newGD, false);
503
		imagesavealpha($newGD, true);
504
505
		$rt = $rv + $bv + $gv;
506
		$rr = ($rv == 0) ? 0 : 1/($rt/$rv);
507
		$br = ($bv == 0) ? 0 : 1/($rt/$bv);
508
		$gr = ($gv == 0) ? 0 : 1/($rt/$gv);
509
		for($dy = 0; $dy < $height; $dy++) {
510
			for($dx = 0; $dx < $width; $dx++) {
511
				$pxrgb = imagecolorat($this->gd, $dx, $dy);
512
				$heightgb = ImageColorsforIndex($this->gd, $pxrgb);
513
				$newcol = ($rr*$heightgb['red']) + ($br*$heightgb['blue']) + ($gr*$heightgb['green']);
514
				$setcol = ImageColorAllocateAlpha($newGD, $newcol, $newcol, $newcol, $heightgb['alpha']);
515
				imagesetpixel($newGD, $dx, $dy, $setcol);
516
			}
517
		}
518
519
		$output = clone $this;
520
		$output->setImageResource($newGD);
521
		return $output;
522
	}
523
524
	public function makeDir($dirname) {
525
		if(!file_exists(dirname($dirname))) $this->makeDir(dirname($dirname));
526
		if(!file_exists($dirname)) mkdir($dirname, Config::inst()->get('Filesystem', 'folder_create_mask'));
527
	}
528
529
	public function writeTo($filename) {
530
		$this->makeDir(dirname($filename));
531
532
		if($filename) {
533
			if(file_exists($filename)) list($width, $height, $type, $attr) = getimagesize($filename);
0 ignored issues
show
Unused Code introduced by
The assignment to $width is unused. Consider omitting it like so list($first,,$third).

This checks looks for assignemnts to variables using the list(...) function, where not all assigned variables are subsequently used.

Consider the following code example.

<?php

function returnThreeValues() {
    return array('a', 'b', 'c');
}

list($a, $b, $c) = returnThreeValues();

print $a . " - " . $c;

Only the variables $a and $c are used. There was no need to assign $b.

Instead, the list call could have been.

list($a,, $c) = returnThreeValues();
Loading history...
Unused Code introduced by
The assignment to $height is unused. Consider omitting it like so list($first,,$third).

This checks looks for assignemnts to variables using the list(...) function, where not all assigned variables are subsequently used.

Consider the following code example.

<?php

function returnThreeValues() {
    return array('a', 'b', 'c');
}

list($a, $b, $c) = returnThreeValues();

print $a . " - " . $c;

Only the variables $a and $c are used. There was no need to assign $b.

Instead, the list call could have been.

list($a,, $c) = returnThreeValues();
Loading history...
Unused Code introduced by
The assignment to $attr is unused. Consider omitting it like so list($first,,$third).

This checks looks for assignemnts to variables using the list(...) function, where not all assigned variables are subsequently used.

Consider the following code example.

<?php

function returnThreeValues() {
    return array('a', 'b', 'c');
}

list($a, $b, $c) = returnThreeValues();

print $a . " - " . $c;

Only the variables $a and $c are used. There was no need to assign $b.

Instead, the list call could have been.

list($a,, $c) = returnThreeValues();
Loading history...
534
535
			if(file_exists($filename)) unlink($filename);
536
537
			$ext = strtolower(substr($filename, strrpos($filename,'.')+1));
538
			if(!isset($type)) switch($ext) {
539
				case "gif": $type = IMAGETYPE_GIF; break;
540
				case "jpeg": case "jpg": case "jpe": $type = IMAGETYPE_JPEG; break;
541
				default: $type = IMAGETYPE_PNG; break;
542
			}
543
544
			// if $this->interlace != 0, the output image will be interlaced
545
			imageinterlace ($this->gd, $this->interlace);
546
547
			// if the extension does not exist, the file will not be created!
548
549
			switch($type) {
550
				case IMAGETYPE_GIF: imagegif($this->gd, $filename); break;
551
				case IMAGETYPE_JPEG: imagejpeg($this->gd, $filename, $this->quality); break;
552
553
				// case 3, and everything else
554
				default:
555
					// Save them as 8-bit images
556
					// imagetruecolortopalette($this->gd, false, 256);
557
					imagepng($this->gd, $filename); break;
558
			}
559
			if(file_exists($filename)) @chmod($filename,0664);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
560
561
			// Remove image manipulation from cache now that it's complete
562
			$cacheData = unserialize($this->cache->load($this->cacheKey));
563
			if(isset($cacheData[$this->manipulation])) unset($cacheData[$this->manipulation]);
564
			$this->cache->save(serialize($cacheData), $this->cacheKey);
565
		}
566
	}
567
568
	/**
569
	 * @param Image $frontend
570
	 * @return void
571
	 */
572
	public function onBeforeDelete($frontend) {
573
		$file = Director::baseFolder() . "/" . $frontend->Filename;
574
575
		if (file_exists($file)) {
576
			$key = md5(implode('_', array($file, filemtime($file))));
577
			$this->cache->remove($key);
578
		}
579
	}
580
581
}
582
583
/**
584
 * This class is maintained for backwards-compatibility only. Please use the {@link GDBackend} class instead.
585
 *
586
 * @package framework
587
 * @subpackage filesystem
588
 */
589
class GD extends GDBackend {
590
591
	/**
592
	 * @deprecated 4.0 Use the "GDBackend.default_quality" config setting instead
593
	 */
594
	public static function set_default_quality($quality) {
595
		Deprecation::notice('4.0', 'Use the "GDBackend.default_quality" config setting instead');
596
		GDBackend::set_default_quality($quality);
0 ignored issues
show
Deprecated Code introduced by
The method GDBackend::set_default_quality() has been deprecated with message: 4.0 Use the "GDBackend.default_quality" config setting instead

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
597
	}
598
}
599