GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

GdThumb   F
last analyzed

Complexity

Total Complexity 180

Size/Duplication

Total Lines 1440
Duplicated Lines 15.42 %

Coupling/Cohesion

Components 1
Dependencies 1

Test Coverage

Coverage 25.52%

Importance

Changes 0
Metric Value
dl 222
loc 1440
rs 0.8
c 0
b 0
f 0
ccs 171
cts 670
cp 0.2552
wmc 180
lcom 1
cbo 1

39 Methods

Rating   Name   Duplication   Size   Complexity  
B __construct() 0 37 6
A __destruct() 0 12 3
B resize() 18 62 7
F adaptiveResize() 36 95 18
F adaptiveResizePercent() 28 102 16
F adaptiveResizeQuadrant() 56 121 20
A resizePercent() 8 41 3
B cropFromCenter() 0 27 7
C crop() 0 81 12
A rotateImage() 0 13 2
A rotateImageNDegrees() 0 22 3
B show() 0 35 10
A getImageAsString() 0 10 1
B save() 0 46 9
A setOptions() 0 36 4
A getCurrentDimensions() 0 4 1
A setCurrentDimensions() 0 4 1
A getMaxHeight() 0 4 1
A setMaxHeight() 0 4 1
A getMaxWidth() 0 4 1
A setMaxWidth() 0 4 1
A getNewDimensions() 0 4 1
A setNewDimensions() 0 4 1
A getOptions() 0 4 1
A getPercent() 0 4 1
A setPercent() 0 4 1
A getOldImage() 0 4 1
A setOldImage() 0 4 1
A getWorkingImage() 0 4 1
A setWorkingImage() 0 4 1
A calcWidth() 0 11 1
A calcHeight() 11 11 1
A calcPercent() 11 11 1
B calcImageSize() 18 30 7
B calcImageSizeStrict() 36 49 11
A calcImageSizePercent() 0 7 2
B determineFormat() 0 43 8
B verifyFormatCompatiblity() 0 31 8
A preserveAlpha() 0 33 5

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 GdThumb 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 GdThumb, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * PhpThumb GD Thumb Class Definition File
4
 * 
5
 * This file contains the definition for the GdThumb object
6
 * 
7
 * PHP Version 5 with GD 2.0+
8
 * PhpThumb : PHP Thumb Library <http://phpthumb.gxdlabs.com>
9
 * Copyright (c) 2009, Ian Selby/Gen X Design
10
 * 
11
 * Author(s): Ian Selby <[email protected]>
12
 * 
13
 * Licensed under the MIT License
14
 * Redistributions of files must retain the above copyright notice.
15
 * 
16
 * @author Ian Selby <[email protected]>
17
 * @copyright Copyright (c) 2009 Gen X Design
18
 * @link http://phpthumb.gxdlabs.com
19
 * @license http://www.opensource.org/licenses/mit-license.php The MIT License
20
 * @version 3.0
21
 * @package PhpThumb
22
 * @filesource
23
 */
24
25
/**
26
 * GdThumb Class Definition
27
 * 
28
 * This is the GD Implementation of the PHP Thumb library.
29
 * 
30
 * @package PhpThumb
31
 * @subpackage Core
32
 */
33
class GdThumb extends ThumbBase
34
{
35
	/**
36
	 * The prior image (before manipulation)
37
	 * 
38
	 * @var resource
39
	 */
40
	protected $oldImage;
41
	/**
42
	 * The working image (used during manipulation)
43
	 * 
44
	 * @var resource
45
	 */
46
	protected $workingImage;
47
	/**
48
	 * The current dimensions of the image
49
	 * 
50
	 * @var array
51
	 */
52
	protected $currentDimensions;
53
	/**
54
	 * The new, calculated dimensions of the image
55
	 * 
56
	 * @var array
57
	 */
58
	protected $newDimensions;
59
	/**
60
	 * The options for this class
61
	 * 
62
	 * This array contains various options that determine the behavior in
63
	 * various functions throughout the class.  Functions note which specific 
64
	 * option key / values are used in their documentation
65
	 * 
66
	 * @var array
67
	 */
68
	protected $options;
69
	/**
70
	 * The maximum width an image can be after resizing (in pixels)
71
	 * 
72
	 * @var int
73
	 */
74
	protected $maxWidth;
75
	/**
76
	 * The maximum height an image can be after resizing (in pixels)
77
	 * 
78
	 * @var int
79
	 */
80
	protected $maxHeight;
81
	/**
82
	 * The percentage to resize the image by
83
	 * 
84
	 * @var int
85
	 */
86
	protected $percent;
87
	
88
	/**
89
	 * Class Constructor
90
	 * 
91
	 * @return GdThumb 
0 ignored issues
show
Comprehensibility Best Practice introduced by
Adding a @return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.

Adding a @return annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.

Please refer to the PHP core documentation on constructors.

Loading history...
92
	 * @param string $fileName
93
	 */
94 1
	public function __construct ($fileName, $options = array(), $isDataStream = false)
95
	{
96 1
		parent::__construct($fileName, $isDataStream);
97
		
98 1
		$this->determineFormat();
99
		
100 1
		if ($this->isDataStream === false)
101 1
		{
102 1
			$this->verifyFormatCompatiblity();
103 1
		}
104
		
105 1
		switch ($this->format)
106
		{
107 1
			case 'GIF':
108
				$this->oldImage = imagecreatefromgif($this->fileName);
109
				break;
110 1
			case 'JPG':
111 1
				$this->oldImage = imagecreatefromjpeg($this->fileName);
112 1
				break;
113
			case 'PNG':
114
				$this->oldImage = imagecreatefrompng($this->fileName);
115
				break;
116
			case 'STRING':
117
				$this->oldImage = imagecreatefromstring($this->fileName);
118
				break;
119 1
		}
120
	
121 1
		$this->currentDimensions = array
122
		(
123 1
			'width' 	=> imagesx($this->oldImage),
124 1
			'height'	=> imagesy($this->oldImage)
125 1
		);
126
		
127 1
		$this->setOptions($options);
128
		
129
		// TODO: Port gatherImageMeta to a separate function that can be called to extract exif data
130 1
	}
131
	
132
	/**
133
	 * Class Destructor
134
	 * 
135
	 */
136 1
	public function __destruct ()
137
	{
138 1
		if (is_resource($this->oldImage))
139 1
		{
140 1
			imagedestroy($this->oldImage);
141 1
		}
142
		
143 1
		if (is_resource($this->workingImage))
144 1
		{
145
			imagedestroy($this->workingImage);
146
		}
147 1
	}
148
	
149
	##############################
150
	# ----- API FUNCTIONS ------ #
151
	##############################
152
	
153
	/**
154
	 * Resizes an image to be no larger than $maxWidth or $maxHeight
155
	 * 
156
	 * If either param is set to zero, then that dimension will not be considered as a part of the resize.
157
	 * Additionally, if $this->options['resizeUp'] is set to true (false by default), then this function will
158
	 * also scale the image up to the maximum dimensions provided.
159
	 * 
160
	 * @param int $maxWidth The maximum width of the image in pixels
161
	 * @param int $maxHeight The maximum height of the image in pixels
162
	 * @return GdThumb
163
	 */
164 1
	public function resize ($maxWidth = 0, $maxHeight = 0)
165
	{
166
		// make sure our arguments are valid
167 1
		if (!is_numeric($maxWidth))
168 1
		{
169
			throw new InvalidArgumentException('$maxWidth must be numeric');
170
		}
171
		
172 1
		if (!is_numeric($maxHeight))
173 1
		{
174
			throw new InvalidArgumentException('$maxHeight must be numeric');
175
		}
176
		
177
		// make sure we're not exceeding our image size if we're not supposed to
178 1 View Code Duplication
		if ($this->options['resizeUp'] === false)
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...
179 1
		{
180 1
			$this->maxHeight	= (intval($maxHeight) > $this->currentDimensions['height']) ? $this->currentDimensions['height'] : $maxHeight;
181 1
			$this->maxWidth		= (intval($maxWidth) > $this->currentDimensions['width']) ? $this->currentDimensions['width'] : $maxWidth;
182 1
		}
183
		else
184
		{
185
			$this->maxHeight	= intval($maxHeight);
186
			$this->maxWidth		= intval($maxWidth);
187
		}
188
		
189
		// get the new dimensions...
190 1
		$this->calcImageSize($this->currentDimensions['width'], $this->currentDimensions['height']);
191
		
192
		// create the working image
193 1 View Code Duplication
		if (function_exists('imagecreatetruecolor'))
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...
194 1
		{
195 1
			$this->workingImage = imagecreatetruecolor($this->newDimensions['newWidth'], $this->newDimensions['newHeight']);
196 1
		}
197
		else
198
		{
199
			$this->workingImage = imagecreate($this->newDimensions['newWidth'], $this->newDimensions['newHeight']);
200
		}
201
		
202 1
		$this->preserveAlpha();		
203
		
204
		// and create the newly sized image
205
		imagecopyresampled
206 1
		(
207 1
			$this->workingImage,
208 1
			$this->oldImage,
209 1
			0,
210 1
			0,
211 1
			0,
212 1
			0,
213 1
			$this->newDimensions['newWidth'],
214 1
			$this->newDimensions['newHeight'],
215 1
			$this->currentDimensions['width'],
216 1
			$this->currentDimensions['height']
217 1
		);
218
219
		// update all the variables and resources to be correct
220 1
		$this->oldImage 					= $this->workingImage;
221 1
		$this->currentDimensions['width'] 	= $this->newDimensions['newWidth'];
222 1
		$this->currentDimensions['height'] 	= $this->newDimensions['newHeight'];
223
		
224 1
		return $this;
225
	}
226
	
227
	/**
228
	 * Adaptively Resizes the Image
229
	 * 
230
	 * This function attempts to get the image to as close to the provided dimensions as possible, and then crops the 
231
	 * remaining overflow (from the center) to get the image to be the size specified
232
	 * 
233
	 * @param int $maxWidth
0 ignored issues
show
Bug introduced by
There is no parameter named $maxWidth. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
234
	 * @param int $maxHeight
0 ignored issues
show
Documentation introduced by
There is no parameter named $maxHeight. Did you maybe mean $height?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
235
	 * @return GdThumb
236
	 */
237
	public function adaptiveResize ($width, $height)
238
	{
239
		// make sure our arguments are valid
240
		if ((!is_numeric($width) || $width  == 0) && (!is_numeric($height) || $height == 0))
241
		{
242
			throw new InvalidArgumentException('$width and $height must be numeric and greater than zero');
243
		}
244
		
245 View Code Duplication
		if (!is_numeric($width) || $width  == 0)
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...
246
		{
247
			$width = ( $height * $this->currentDimensions['width'] ) / $this->currentDimensions['height'];
248
		}
249
		
250 View Code Duplication
		if (!is_numeric($height) || $height  == 0)
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...
251
		{
252
			$height = ( $width * $this->currentDimensions['height'] ) / $this->currentDimensions['width'];
253
		}
254
		
255
		// make sure we're not exceeding our image size if we're not supposed to
256 View Code Duplication
		if ($this->options['resizeUp'] === false)
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...
257
		{
258
			$this->maxHeight	= (intval($height) > $this->currentDimensions['height']) ? $this->currentDimensions['height'] : $height;
259
			$this->maxWidth		= (intval($width) > $this->currentDimensions['width']) ? $this->currentDimensions['width'] : $width;
260
		}
261
		else
262
		{
263
			$this->maxHeight	= intval($height);
264
			$this->maxWidth		= intval($width);
265
		}
266
		
267
		$this->calcImageSizeStrict($this->currentDimensions['width'], $this->currentDimensions['height']);
268
		
269
		// resize the image to be close to our desired dimensions
270
		$this->resize($this->newDimensions['newWidth'], $this->newDimensions['newHeight']);
271
		
272
		// reset the max dimensions...
273 View Code Duplication
		if ($this->options['resizeUp'] === false)
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...
274
		{
275
			$this->maxHeight	= (intval($height) > $this->currentDimensions['height']) ? $this->currentDimensions['height'] : $height;
276
			$this->maxWidth		= (intval($width) > $this->currentDimensions['width']) ? $this->currentDimensions['width'] : $width;
277
		}
278
		else
279
		{
280
			$this->maxHeight	= intval($height);
281
			$this->maxWidth		= intval($width);
282
		}
283
		
284
		// create the working image
285 View Code Duplication
		if (function_exists('imagecreatetruecolor'))
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...
286
		{
287
			$this->workingImage = imagecreatetruecolor($this->maxWidth, $this->maxHeight);
288
		}
289
		else
290
		{
291
			$this->workingImage = imagecreate($this->maxWidth, $this->maxHeight);
292
		}
293
		
294
		$this->preserveAlpha();
295
		
296
		$cropWidth	= $this->maxWidth;
297
		$cropHeight	= $this->maxHeight;
298
		$cropX 		= 0;
299
		$cropY 		= 0;
300
		
301
		// now, figure out how to crop the rest of the image...
302
		if ($this->currentDimensions['width'] > $this->maxWidth)
303
		{
304
			$cropX = intval(($this->currentDimensions['width'] - $this->maxWidth) / 2);
305
		}
306
		elseif ($this->currentDimensions['height'] > $this->maxHeight)
307
		{
308
			$cropY = intval(($this->currentDimensions['height'] - $this->maxHeight) / 2);
309
		}
310
		
311
		imagecopyresampled
312
		(
313
            $this->workingImage,
314
            $this->oldImage,
315
            0,
316
            0,
317
            $cropX,
318
            $cropY,
319
            $cropWidth,
320
            $cropHeight,
321
            $cropWidth,
322
            $cropHeight
323
		);
324
		
325
		// update all the variables and resources to be correct
326
		$this->oldImage 					= $this->workingImage;
327
		$this->currentDimensions['width'] 	= $this->maxWidth;
328
		$this->currentDimensions['height'] 	= $this->maxHeight;
329
		
330
		return $this;
331
	}
332
333
334
	/**
335
	 * Adaptively Resizes the Image and Crops Using a Percentage
336
	 *
337
	 * This function attempts to get the image to as close to the provided dimensions as possible, and then crops the
338
	 * remaining overflow using a provided percentage to get the image to be the size specified.
339
	 *
340
	 * The percentage mean different things depending on the orientation of the original image.
341
	 *
342
	 * For Landscape images:
343
	 * ---------------------
344
	 *
345
	 * A percentage of 1 would crop the image all the way to the left, which would be the same as
346
	 * using adaptiveResizeQuadrant() with $quadrant = 'L'
347
	 *
348
	 * A percentage of 50 would crop the image to the center which would be the same as using
349
	 * adaptiveResizeQuadrant() with $quadrant = 'C', or even the original adaptiveResize()
350
	 *
351
	 * A percentage of 100 would crop the image to the image all the way to the right, etc, etc.
352
	 * Note that you can use any percentage between 1 and 100.
353
	 *
354
	 * For Portrait images:
355
	 * --------------------
356
	 *
357
	 * This works the same as for Landscape images except that a percentage of 1 means top and 100 means bottom
358
	 *
359
	 * @param int $maxWidth
0 ignored issues
show
Bug introduced by
There is no parameter named $maxWidth. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
360
	 * @param int $maxHeight
0 ignored issues
show
Documentation introduced by
There is no parameter named $maxHeight. Did you maybe mean $height?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
361
	 * @param int $percent
362
	 * @return GdThumb
363
	 */
364
	public function adaptiveResizePercent ($width, $height, $percent = 50)
365
	{
366
		// make sure our arguments are valid
367
		if (!is_numeric($width) || $width  == 0)
368
		{
369
			throw new InvalidArgumentException('$width must be numeric and greater than zero');
370
		}
371
372
		if (!is_numeric($height) || $height == 0)
373
		{
374
			throw new InvalidArgumentException('$height must be numeric and greater than zero');
375
		}
376
377
		// make sure we're not exceeding our image size if we're not supposed to
378 View Code Duplication
		if ($this->options['resizeUp'] === false)
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...
379
		{
380
			$this->maxHeight	= (intval($height) > $this->currentDimensions['height']) ? $this->currentDimensions['height'] : $height;
381
			$this->maxWidth		= (intval($width) > $this->currentDimensions['width']) ? $this->currentDimensions['width'] : $width;
382
		}
383
		else
384
		{
385
			$this->maxHeight	= intval($height);
386
			$this->maxWidth		= intval($width);
387
		}
388
389
		$this->calcImageSizeStrict($this->currentDimensions['width'], $this->currentDimensions['height']);
390
391
		// resize the image to be close to our desired dimensions
392
		$this->resize($this->newDimensions['newWidth'], $this->newDimensions['newHeight']);
393
394
		// reset the max dimensions...
395 View Code Duplication
		if ($this->options['resizeUp'] === false)
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...
396
		{
397
			$this->maxHeight	= (intval($height) > $this->currentDimensions['height']) ? $this->currentDimensions['height'] : $height;
398
			$this->maxWidth		= (intval($width) > $this->currentDimensions['width']) ? $this->currentDimensions['width'] : $width;
399
		}
400
		else
401
		{
402
			$this->maxHeight	= intval($height);
403
			$this->maxWidth		= intval($width);
404
		}
405
406
		// create the working image
407 View Code Duplication
		if (function_exists('imagecreatetruecolor'))
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...
408
		{
409
			$this->workingImage = imagecreatetruecolor($this->maxWidth, $this->maxHeight);
410
		}
411
		else
412
		{
413
			$this->workingImage = imagecreate($this->maxWidth, $this->maxHeight);
414
		}
415
416
		$this->preserveAlpha();
417
418
		$cropWidth	= $this->maxWidth;
419
		$cropHeight	= $this->maxHeight;
420
		$cropX 		= 0;
421
		$cropY 		= 0;
422
423
		// Crop the rest of the image using the quadrant
424
425
		if ($percent > 100) {
426
		    $percent = 100;
427
		} elseif ($percent < 1) {
428
		    $percent = 1;
429
		}
430
431
		if ($this->currentDimensions['width'] > $this->maxWidth)
432
		{
433
		    // Image is landscape
434
		    $maxCropX = $this->currentDimensions['width'] - $this->maxWidth;
435
		    $cropX = intval(($percent / 100) * $maxCropX);
436
437
		} elseif ($this->currentDimensions['height'] > $this->maxHeight)
438
		{
439
		    // Image is portrait
440
		    $maxCropY = $this->currentDimensions['height'] - $this->maxHeight;
441
		    $cropY = intval(($percent / 100) * $maxCropY);
442
443
		}
444
445
		imagecopyresampled
446
		(
447
            $this->workingImage,
448
            $this->oldImage,
449
            0,
450
            0,
451
            $cropX,
452
            $cropY,
453
            $cropWidth,
454
            $cropHeight,
455
            $cropWidth,
456
            $cropHeight
457
		);
458
459
		// update all the variables and resources to be correct
460
		$this->oldImage 					= $this->workingImage;
461
		$this->currentDimensions['width'] 	= $this->maxWidth;
462
		$this->currentDimensions['height'] 	= $this->maxHeight;
463
464
		return $this;
465
	}
466
	/**
467
	 * Adaptively Resizes the Image and Crops Using a Quadrant
468
	 *
469
	 * This function attempts to get the image to as close to the provided dimensions as possible, and then crops the
470
	 * remaining overflow using the quadrant to get the image to be the size specified.
471
	 *
472
	 * The quadrants available are Top, Bottom, Center, Left, and Right:
473
	 *
474
	 *
475
	 * +---+---+---+
476
	 * |   | T |   |
477
	 * +---+---+---+
478
	 * | L | C | R |
479
	 * +---+---+---+
480
	 * |   | B |   |
481
	 * +---+---+---+
482
	 *
483
	 * Note that if your image is Landscape and you choose either of the Top or Bottom quadrants (which won't
484
	 * make sence since only the Left and Right would be available, then the Center quadrant will be used
485
	 * to crop. This would have exactly the same result as using adaptiveResize().
486
	 * The same goes if your image is portrait and you choose either the Left or Right quadrants.
487
	 *
488
	 * @param int $maxWidth
0 ignored issues
show
Bug introduced by
There is no parameter named $maxWidth. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
489
	 * @param int $maxHeight
0 ignored issues
show
Documentation introduced by
There is no parameter named $maxHeight. Did you maybe mean $height?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
490
	 * @param string $quadrant T, B, C, L, R
491
	 * @return GdThumb
492
	 */
493
	public function adaptiveResizeQuadrant ($width, $height, $quadrant = 'C')
494
	{
495
		// make sure our arguments are valid
496
		if (!is_numeric($width) || $width  == 0)
497
		{
498
			throw new InvalidArgumentException('$width must be numeric and greater than zero');
499
		}
500
501
		if (!is_numeric($height) || $height == 0)
502
		{
503
			throw new InvalidArgumentException('$height must be numeric and greater than zero');
504
		}
505
506
		// make sure we're not exceeding our image size if we're not supposed to
507 View Code Duplication
		if ($this->options['resizeUp'] === false)
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...
508
		{
509
			$this->maxHeight	= (intval($height) > $this->currentDimensions['height']) ? $this->currentDimensions['height'] : $height;
510
			$this->maxWidth		= (intval($width) > $this->currentDimensions['width']) ? $this->currentDimensions['width'] : $width;
511
		}
512
		else
513
		{
514
			$this->maxHeight	= intval($height);
515
			$this->maxWidth		= intval($width);
516
		}
517
518
		$this->calcImageSizeStrict($this->currentDimensions['width'], $this->currentDimensions['height']);
519
520
		// resize the image to be close to our desired dimensions
521
		$this->resize($this->newDimensions['newWidth'], $this->newDimensions['newHeight']);
522
523
		// reset the max dimensions...
524 View Code Duplication
		if ($this->options['resizeUp'] === false)
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...
525
		{
526
			$this->maxHeight	= (intval($height) > $this->currentDimensions['height']) ? $this->currentDimensions['height'] : $height;
527
			$this->maxWidth		= (intval($width) > $this->currentDimensions['width']) ? $this->currentDimensions['width'] : $width;
528
		}
529
		else
530
		{
531
			$this->maxHeight	= intval($height);
532
			$this->maxWidth		= intval($width);
533
		}
534
535
		// create the working image
536 View Code Duplication
		if (function_exists('imagecreatetruecolor'))
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...
537
		{
538
			$this->workingImage = imagecreatetruecolor($this->maxWidth, $this->maxHeight);
539
		}
540
		else
541
		{
542
			$this->workingImage = imagecreate($this->maxWidth, $this->maxHeight);
543
		}
544
545
		$this->preserveAlpha();
546
547
		$cropWidth	= $this->maxWidth;
548
		$cropHeight	= $this->maxHeight;
549
		$cropX 		= 0;
550
		$cropY 		= 0;
551
552
		// Crop the rest of the image using the quadrant
553
554
		if ($this->currentDimensions['width'] > $this->maxWidth)
555
		{
556
		    // Image is landscape
557 View Code Duplication
		    switch ($quadrant) {
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...
558
		        case 'L':
559
		            $cropX = 0;
560
		            break;
561
562
		        case 'R':
563
		            $cropX = intval(($this->currentDimensions['width'] - $this->maxWidth));
564
		            break;
565
566
		        case 'C':
567
		        default:
568
		            $cropX = intval(($this->currentDimensions['width'] - $this->maxWidth) / 2);
569
		            break;
570
		    }
571
572
573
		} elseif ($this->currentDimensions['height'] > $this->maxHeight)
574
		{
575
		    // Image is portrait
576 View Code Duplication
			switch ($quadrant) {
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...
577
		        case 'T':
578
		            $cropY = 0;
579
		            break;
580
581
		        case 'B':
582
		            $cropY = intval(($this->currentDimensions['height'] - $this->maxHeight));
583
		            break;
584
585
		        case 'C':
586
		        default:
587
		            $cropY = intval(($this->currentDimensions['height'] - $this->maxHeight) / 2);
588
		            break;
589
		    }
590
591
		}
592
593
		imagecopyresampled
594
		(
595
            $this->workingImage,
596
            $this->oldImage,
597
            0,
598
            0,
599
            $cropX,
600
            $cropY,
601
            $cropWidth,
602
            $cropHeight,
603
            $cropWidth,
604
            $cropHeight
605
		);
606
607
		// update all the variables and resources to be correct
608
		$this->oldImage 					= $this->workingImage;
609
		$this->currentDimensions['width'] 	= $this->maxWidth;
610
		$this->currentDimensions['height'] 	= $this->maxHeight;
611
612
		return $this;
613
	}
614
615
	/**
616
	 * Resizes an image by a given percent uniformly
617
	 * 
618
	 * Percentage should be whole number representation (i.e. 1-100)
619
	 * 
620
	 * @param int $percent
621
	 * @return GdThumb
622
	 */
623
	public function resizePercent ($percent = 0)
624
	{
625
		if (!is_numeric($percent))
626
		{
627
			throw new InvalidArgumentException ('$percent must be numeric');
628
		}
629
		
630
		$this->percent = intval($percent);
631
		
632
		$this->calcImageSizePercent($this->currentDimensions['width'], $this->currentDimensions['height']);
633
		
634 View Code Duplication
		if (function_exists('imagecreatetruecolor'))
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...
635
		{
636
			$this->workingImage = imagecreatetruecolor($this->newDimensions['newWidth'], $this->newDimensions['newHeight']);
637
		}
638
		else
639
		{
640
			$this->workingImage = imagecreate($this->newDimensions['newWidth'], $this->newDimensions['newHeight']);
641
		}
642
		
643
		$this->preserveAlpha();
644
		
645
		ImageCopyResampled(
646
			$this->workingImage,
647
			$this->oldImage,
648
			0,
649
			0,
650
			0,
651
			0,
652
			$this->newDimensions['newWidth'],
653
			$this->newDimensions['newHeight'],
654
			$this->currentDimensions['width'],
655
			$this->currentDimensions['height']
656
		);
657
658
		$this->oldImage 					= $this->workingImage;
659
		$this->currentDimensions['width'] 	= $this->newDimensions['newWidth'];
660
		$this->currentDimensions['height'] 	= $this->newDimensions['newHeight'];
661
		
662
		return $this;
663
	}
664
	
665
	/**
666
	 * Crops an image from the center with provided dimensions
667
	 * 
668
	 * If no height is given, the width will be used as a height, thus creating a square crop
669
	 * 
670
	 * @param int $cropWidth
671
	 * @param int $cropHeight
672
	 * @return GdThumb
673
	 */
674
	public function cropFromCenter ($cropWidth, $cropHeight = null)
675
	{
676
		if (!is_numeric($cropWidth))
677
		{
678
			throw new InvalidArgumentException('$cropWidth must be numeric');
679
		}
680
		
681
		if ($cropHeight !== null && !is_numeric($cropHeight))
682
		{
683
			throw new InvalidArgumentException('$cropHeight must be numeric');
684
		}
685
		
686
		if ($cropHeight === null)
687
		{
688
			$cropHeight = $cropWidth;
689
		}
690
		
691
		$cropWidth	= ($this->currentDimensions['width'] < $cropWidth) ? $this->currentDimensions['width'] : $cropWidth;
692
		$cropHeight = ($this->currentDimensions['height'] < $cropHeight) ? $this->currentDimensions['height'] : $cropHeight;
693
		
694
		$cropX = intval(($this->currentDimensions['width'] - $cropWidth) / 2);
695
		$cropY = intval(($this->currentDimensions['height'] - $cropHeight) / 2);
696
		
697
		$this->crop($cropX, $cropY, $cropWidth, $cropHeight);
698
		
699
		return $this;
700
	}
701
	
702
	/**
703
	 * Vanilla Cropping - Crops from x,y with specified width and height
704
	 * 
705
	 * @param int $startX
706
	 * @param int $startY
707
	 * @param int $cropWidth
708
	 * @param int $cropHeight
709
	 * @return GdThumb
710
	 */
711
	public function crop ($startX, $startY, $cropWidth, $cropHeight)
712
	{
713
		// validate input
714
		if (!is_numeric($startX))
715
		{
716
			throw new InvalidArgumentException('$startX must be numeric');
717
		}
718
		
719
		if (!is_numeric($startY))
720
		{
721
			throw new InvalidArgumentException('$startY must be numeric');
722
		}
723
		
724
		if (!is_numeric($cropWidth))
725
		{
726
			throw new InvalidArgumentException('$cropWidth must be numeric');
727
		}
728
		
729
		if (!is_numeric($cropHeight))
730
		{
731
			throw new InvalidArgumentException('$cropHeight must be numeric');
732
		}
733
		
734
		// do some calculations
735
		$cropWidth	= ($this->currentDimensions['width'] < $cropWidth) ? $this->currentDimensions['width'] : $cropWidth;
736
		$cropHeight = ($this->currentDimensions['height'] < $cropHeight) ? $this->currentDimensions['height'] : $cropHeight;
737
		
738
		// ensure everything's in bounds
739
		if (($startX + $cropWidth) > $this->currentDimensions['width'])
740
		{
741
			$startX = ($this->currentDimensions['width'] - $cropWidth);
742
			
743
		}
744
		
745
		if (($startY + $cropHeight) > $this->currentDimensions['height'])
746
		{
747
			$startY = ($this->currentDimensions['height'] - $cropHeight);
748
		}
749
		
750
		if ($startX < 0) 
751
		{
752
			$startX = 0;
753
		}
754
		
755
	    if ($startY < 0) 
756
		{
757
			$startY = 0;
758
		}
759
		
760
		// create the working image
761
		if (function_exists('imagecreatetruecolor'))
762
		{
763
			$this->workingImage = imagecreatetruecolor($cropWidth, $cropHeight);
764
		}
765
		else
766
		{
767
			$this->workingImage = imagecreate($cropWidth, $cropHeight);
768
		}
769
		
770
		$this->preserveAlpha();
771
		
772
		imagecopyresampled
773
		(
774
			$this->workingImage,
775
			$this->oldImage,
776
			0,
777
			0,
778
			$startX,
779
			$startY,
780
			$cropWidth,
781
			$cropHeight,
782
			$cropWidth,
783
			$cropHeight
784
		);
785
		
786
		$this->oldImage 					= $this->workingImage;
787
		$this->currentDimensions['width'] 	= $cropWidth;
788
		$this->currentDimensions['height'] 	= $cropHeight;
789
		
790
		return $this;
791
	}
792
	
793
	/**
794
	 * Rotates image either 90 degrees clockwise or counter-clockwise
795
	 * 
796
	 * @param string $direction
797
	 * @retunrn GdThumb
798
	 */
799
	public function rotateImage ($direction = 'CW') 
800
	{
801
    	if ($direction == 'CW') 
802
		{
803
    		$this->rotateImageNDegrees(90);
804
    	}
805
    	else 
806
		{
807
			$this->rotateImageNDegrees(-90);
808
		}
809
		
810
		return $this;
811
    }
812
	
813
	/**
814
	 * Rotates image specified number of degrees
815
	 * 
816
	 * @param int $degrees
817
	 * @return GdThumb
818
	 */
819
	public function rotateImageNDegrees ($degrees)
820
	{
821
		if (!is_numeric($degrees))
822
		{
823
			throw new InvalidArgumentException('$degrees must be numeric');
824
		}
825
		
826
		if (!function_exists('imagerotate'))
827
		{
828
			throw new RuntimeException('Your version of GD does not support image rotation.');
829
		}
830
		
831
		$this->workingImage = imagerotate($this->oldImage, $degrees, 0);
832
    	
833
		$newWidth 							= $this->currentDimensions['height'];
834
    	$newHeight 							= $this->currentDimensions['width'];
835
		$this->oldImage 					= $this->workingImage;
836
		$this->currentDimensions['width'] 	= $newWidth;
837
		$this->currentDimensions['height'] 	= $newHeight;
838
		
839
		return $this;
840
	}
841
	
842
	/**
843
	 * Shows an image
844
	 * 
845
	 * This function will show the current image by first sending the appropriate header
846
	 * for the format, and then outputting the image data. If headers have already been sent, 
847
	 * a runtime exception will be thrown 
848
	 * 
849
	 * @param bool $rawData Whether or not the raw image stream should be output
850
	 * @return GdThumb
851
	 */
852 1
	public function show ($rawData = false) 
853
	{
854 1
		if (headers_sent() && $rawData === false)
855 1
		{
856
			throw new RuntimeException('Cannot show image, headers have already been sent');
857
		}
858
		
859 1
		switch ($this->format) 
860
		{
861 1
			case 'GIF':
862
				if ($rawData === false) 
863
				{ 
864
					header('Content-type: image/gif'); 
865
				}
866
				imagegif($this->oldImage);
867
				break;
868 1
			case 'JPG':
869 1
				if ($rawData === false) 
870 1
				{ 
871
					header('Content-type: image/jpeg'); 
872
				}
873 1
				imagejpeg($this->oldImage, null, $this->options['jpegQuality']);
874 1
				break;
875
			case 'PNG':
876
			case 'STRING':
877
				if ($rawData === false) 
878
				{ 
879
					header('Content-type: image/png'); 
880
				}
881
				imagepng($this->oldImage);
882
				break;
883 1
		}
884
		
885 1
		return $this;
886
	}
887
	
888
	/**
889
	 * Returns the Working Image as a String
890
	 *
891
	 * This function is useful for getting the raw image data as a string for storage in
892
	 * a database, or other similar things.
893
	 *
894
	 * @return string
895
	 */
896 1
	public function getImageAsString ()
897
	{
898 1
		$data = null;
0 ignored issues
show
Unused Code introduced by
$data is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
899 1
		ob_start();
900 1
		$this->show(true);
901 1
		$data = ob_get_contents();
902 1
		ob_end_clean();
903
		
904 1
		return $data;
905
	}
906
	
907
	/**
908
	 * Saves an image
909
	 * 
910
	 * This function will make sure the target directory is writeable, and then save the image.
911
	 * 
912
	 * If the target directory is not writeable, the function will try to correct the permissions (if allowed, this
913
	 * is set as an option ($this->options['correctPermissions']).  If the target cannot be made writeable, then a
914
	 * RuntimeException is thrown.
915
	 * 
916
	 * TODO: Create additional paramter for color matte when saving images with alpha to non-alpha formats (i.e. PNG => JPG)
917
	 * 
918
	 * @param string $fileName The full path and filename of the image to save
919
	 * @param string $format The format to save the image in (optional, must be one of [GIF,JPG,PNG]
920
	 * @return GdThumb
921
	 */
922 1
	public function save ($fileName, $format = null)
923
	{
924 1
		$validFormats = array('GIF', 'JPG', 'PNG');
925 1
		$format = ($format !== null) ? strtoupper($format) : $this->format;
926
		
927 1
		if (!in_array($format, $validFormats))
928 1
		{
929
			throw new InvalidArgumentException ('Invalid format type specified in save function: ' . $format);
930
		}
931
		
932
		// make sure the directory is writeable
933 1
		if (!is_writeable(dirname($fileName)))
934 1
		{
935
			// try to correct the permissions
936
			if ($this->options['correctPermissions'] === true)
937
			{
938
				@chmod(dirname($fileName), 0777);
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...
939
				
940
				// throw an exception if not writeable
941
				if (!is_writeable(dirname($fileName)))
942
				{
943
					throw new RuntimeException ('File is not writeable, and could not correct permissions: ' . $fileName);
944
				}
945
			}
946
			// throw an exception if not writeable
947
			else
948
			{
949
				throw new RuntimeException ('File not writeable: ' . $fileName);
950
			}
951
		}
952
		
953
		switch ($format) 
954
		{
955 1
			case 'GIF':
956
				imagegif($this->oldImage, $fileName);
957
				break;
958 1
			case 'JPG':
959 1
				imagejpeg($this->oldImage, $fileName, $this->options['jpegQuality']);
960 1
				break;
961
			case 'PNG':
962
				imagepng($this->oldImage, $fileName);
963
				break;
964
		}
965
		
966 1
		return $this;
967
	}
968
	
969
	#################################
970
	# ----- GETTERS / SETTERS ----- #
971
	#################################
972
	
973
	/**
974
	 * Sets $this->options to $options
975
	 * 
976
	 * @param array $options
977
	 */
978 1
	public function setOptions ($options = array())
979
	{
980
		// make sure we've got an array for $this->options (could be null)
981 1
		if (!is_array($this->options))
982 1
		{
983 1
			$this->options = array();
984 1
		}
985
		
986
		// make sure we've gotten a proper argument
987 1
		if (!is_array($options))
988 1
		{
989
			throw new InvalidArgumentException ('setOptions requires an array');
990
		}
991
		
992
		// we've yet to init the default options, so create them here
993 1
		if (sizeof($this->options) == 0)
994 1
		{
995
			$defaultOptions = array 
996
			(
997 1
				'resizeUp'				=> false,
998 1
				'jpegQuality'			=> 100,
999 1
				'correctPermissions'	=> false,
1000 1
				'preserveAlpha'			=> true,
1001 1
				'alphaMaskColor'		=> array (255, 255, 255),
1002 1
				'preserveTransparency'	=> true,
1003 1
				'transparencyMaskColor'	=> array (0, 0, 0)
1004 1
			);
1005 1
		}
1006
		// otherwise, let's use what we've got already
1007
		else
1008
		{
1009
			$defaultOptions = $this->options;
1010
		}
1011
		
1012 1
		$this->options = array_merge($defaultOptions, $options);
1013 1
	}
1014
	
1015
	/**
1016
	 * Returns $currentDimensions.
1017
	 *
1018
	 * @see GdThumb::$currentDimensions
1019
	 */
1020
	public function getCurrentDimensions ()
1021
	{
1022
		return $this->currentDimensions;
1023
	}
1024
	
1025
	/**
1026
	 * Sets $currentDimensions.
1027
	 *
1028
	 * @param object $currentDimensions
1029
	 * @see GdThumb::$currentDimensions
1030
	 */
1031
	public function setCurrentDimensions ($currentDimensions)
1032
	{
1033
		$this->currentDimensions = $currentDimensions;
0 ignored issues
show
Documentation Bug introduced by
It seems like $currentDimensions of type object is incompatible with the declared type array of property $currentDimensions.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
1034
	}
1035
	
1036
	/**
1037
	 * Returns $maxHeight.
1038
	 *
1039
	 * @see GdThumb::$maxHeight
1040
	 */
1041
	public function getMaxHeight ()
1042
	{
1043
		return $this->maxHeight;
1044
	}
1045
	
1046
	/**
1047
	 * Sets $maxHeight.
1048
	 *
1049
	 * @param object $maxHeight
1050
	 * @see GdThumb::$maxHeight
1051
	 */
1052
	public function setMaxHeight ($maxHeight)
1053
	{
1054
		$this->maxHeight = $maxHeight;
0 ignored issues
show
Documentation Bug introduced by
It seems like $maxHeight of type object is incompatible with the declared type integer of property $maxHeight.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
1055
	}
1056
	
1057
	/**
1058
	 * Returns $maxWidth.
1059
	 *
1060
	 * @see GdThumb::$maxWidth
1061
	 */
1062
	public function getMaxWidth ()
1063
	{
1064
		return $this->maxWidth;
1065
	}
1066
	
1067
	/**
1068
	 * Sets $maxWidth.
1069
	 *
1070
	 * @param object $maxWidth
1071
	 * @see GdThumb::$maxWidth
1072
	 */
1073
	public function setMaxWidth ($maxWidth)
1074
	{
1075
		$this->maxWidth = $maxWidth;
0 ignored issues
show
Documentation Bug introduced by
It seems like $maxWidth of type object is incompatible with the declared type integer of property $maxWidth.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
1076
	}
1077
	
1078
	/**
1079
	 * Returns $newDimensions.
1080
	 *
1081
	 * @see GdThumb::$newDimensions
1082
	 */
1083
	public function getNewDimensions ()
1084
	{
1085
		return $this->newDimensions;
1086
	}
1087
	
1088
	/**
1089
	 * Sets $newDimensions.
1090
	 *
1091
	 * @param object $newDimensions
1092
	 * @see GdThumb::$newDimensions
1093
	 */
1094
	public function setNewDimensions ($newDimensions)
1095
	{
1096
		$this->newDimensions = $newDimensions;
0 ignored issues
show
Documentation Bug introduced by
It seems like $newDimensions of type object is incompatible with the declared type array of property $newDimensions.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
1097
	}
1098
	
1099
	/**
1100
	 * Returns $options.
1101
	 *
1102
	 * @see GdThumb::$options
1103
	 */
1104
	public function getOptions ()
1105
	{
1106
		return $this->options;
1107
	}
1108
	
1109
	/**
1110
	 * Returns $percent.
1111
	 *
1112
	 * @see GdThumb::$percent
1113
	 */
1114
	public function getPercent ()
1115
	{
1116
		return $this->percent;
1117
	}
1118
	
1119
	/**
1120
	 * Sets $percent.
1121
	 *
1122
	 * @param object $percent
1123
	 * @see GdThumb::$percent
1124
	 */
1125
	public function setPercent ($percent)
1126
	{
1127
		$this->percent = $percent;
0 ignored issues
show
Documentation Bug introduced by
It seems like $percent of type object is incompatible with the declared type integer of property $percent.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
1128
	} 
1129
	
1130
	/**
1131
	 * Returns $oldImage.
1132
	 *
1133
	 * @see GdThumb::$oldImage
1134
	 */
1135
	public function getOldImage ()
1136
	{
1137
		return $this->oldImage;
1138
	}
1139
	
1140
	/**
1141
	 * Sets $oldImage.
1142
	 *
1143
	 * @param object $oldImage
1144
	 * @see GdThumb::$oldImage
1145
	 */
1146
	public function setOldImage ($oldImage)
1147
	{
1148
		$this->oldImage = $oldImage;
0 ignored issues
show
Documentation Bug introduced by
It seems like $oldImage of type object is incompatible with the declared type resource of property $oldImage.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
1149
	}
1150
	
1151
	/**
1152
	 * Returns $workingImage.
1153
	 *
1154
	 * @see GdThumb::$workingImage
1155
	 */
1156
	public function getWorkingImage ()
1157
	{
1158
		return $this->workingImage;
1159
	}
1160
	
1161
	/**
1162
	 * Sets $workingImage.
1163
	 *
1164
	 * @param object $workingImage
1165
	 * @see GdThumb::$workingImage
1166
	 */
1167
	public function setWorkingImage ($workingImage)
1168
	{
1169
		$this->workingImage = $workingImage;
0 ignored issues
show
Documentation Bug introduced by
It seems like $workingImage of type object is incompatible with the declared type resource of property $workingImage.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
1170
	} 
1171
	
1172
	
1173
	#################################
1174
	# ----- UTILITY FUNCTIONS ----- #
1175
	#################################
1176
	
1177
	/**
1178
	 * Calculates a new width and height for the image based on $this->maxWidth and the provided dimensions
1179
	 * 
1180
	 * @return array 
1181
	 * @param int $width
1182
	 * @param int $height
1183
	 */
1184 1
	protected function calcWidth ($width, $height)
1185
	{
1186 1
		$newWidthPercentage	= (100 * $this->maxWidth) / $width;
1187 1
		$newHeight			= ($height * $newWidthPercentage) / 100;
1188
		
1189
		return array
1190
		(
1191 1
			'newWidth'	=> intval($this->maxWidth),
1192 1
			'newHeight'	=> intval($newHeight)
1193 1
		);
1194
	}
1195
	
1196
	/**
1197
	 * Calculates a new width and height for the image based on $this->maxWidth and the provided dimensions
1198
	 * 
1199
	 * @return array 
1200
	 * @param int $width
1201
	 * @param int $height
1202
	 */
1203 1 View Code Duplication
	protected function calcHeight ($width, $height)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
1204
	{
1205 1
		$newHeightPercentage	= (100 * $this->maxHeight) / $height;
1206 1
		$newWidth 				= ($width * $newHeightPercentage) / 100;
1207
		
1208
		return array
1209
		(
1210 1
			'newWidth'	=> ceil($newWidth),
1211 1
			'newHeight'	=> ceil($this->maxHeight)
1212 1
		);
1213
	}
1214
	
1215
	/**
1216
	 * Calculates a new width and height for the image based on $this->percent and the provided dimensions
1217
	 * 
1218
	 * @return array 
1219
	 * @param int $width
1220
	 * @param int $height
1221
	 */
1222 View Code Duplication
	protected function calcPercent ($width, $height)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
1223
	{
1224
		$newWidth	= ($width * $this->percent) / 100;
1225
		$newHeight	= ($height * $this->percent) / 100;
1226
		
1227
		return array 
1228
		(
1229
			'newWidth'	=> ceil($newWidth),
1230
			'newHeight'	=> ceil($newHeight)
1231
		);
1232
	}
1233
	
1234
	/**
1235
	 * Calculates the new image dimensions
1236
	 * 
1237
	 * These calculations are based on both the provided dimensions and $this->maxWidth and $this->maxHeight
1238
	 * 
1239
	 * @param int $width
1240
	 * @param int $height
1241
	 */
1242 1
	protected function calcImageSize ($width, $height)
1243
	{
1244
		$newSize = array
1245
		(
1246 1
			'newWidth'	=> $width,
1247
			'newHeight'	=> $height
1248 1
		);
1249
		
1250 1 View Code Duplication
		if ($this->maxWidth > 0)
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...
1251 1
		{
1252 1
			$newSize = $this->calcWidth($width, $height);
1253
			
1254 1
			if ($this->maxHeight > 0 && $newSize['newHeight'] > $this->maxHeight)
1255 1
			{
1256
				$newSize = $this->calcHeight($newSize['newWidth'], $newSize['newHeight']);
1257
			}
1258 1
		}
1259
		
1260 1 View Code Duplication
		if ($this->maxHeight > 0)
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...
1261 1
		{
1262 1
			$newSize = $this->calcHeight($width, $height);
1263
			
1264 1
			if ($this->maxWidth > 0 && $newSize['newWidth'] > $this->maxWidth)
1265 1
			{
1266 1
				$newSize = $this->calcWidth($newSize['newWidth'], $newSize['newHeight']);
1267 1
			}
1268 1
		}
1269
		
1270 1
		$this->newDimensions = $newSize;
1271 1
	}
1272
	
1273
	/**
1274
	 * Calculates new image dimensions, not allowing the width and height to be less than either the max width or height 
1275
	 * 
1276
	 * @param int $width
1277
	 * @param int $height
1278
	 */
1279
	protected function calcImageSizeStrict ($width, $height)
1280
	{
1281
		// first, we need to determine what the longest resize dimension is..
1282
		if ($this->maxWidth >= $this->maxHeight)
1283
		{
1284
			// and determine the longest original dimension
1285 View Code Duplication
			if ($width > $height)
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...
1286
			{
1287
				$newDimensions = $this->calcHeight($width, $height);
1288
				
1289
				if ($newDimensions['newWidth'] < $this->maxWidth)
1290
				{
1291
					$newDimensions = $this->calcWidth($width, $height);
1292
				}
1293
			}
1294
			elseif ($height >= $width)
1295
			{
1296
				$newDimensions = $this->calcWidth($width, $height);
1297
				
1298
				if ($newDimensions['newHeight'] < $this->maxHeight)
1299
				{
1300
					$newDimensions = $this->calcHeight($width, $height);
1301
				}
1302
			}
1303
		}
1304
		elseif ($this->maxHeight > $this->maxWidth)
1305
		{
1306 View Code Duplication
			if ($width >= $height)
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...
1307
			{
1308
				$newDimensions = $this->calcWidth($width, $height);
1309
				
1310
				if ($newDimensions['newHeight'] < $this->maxHeight)
1311
				{
1312
					$newDimensions = $this->calcHeight($width, $height);
1313
				}
1314
			}
1315
			elseif ($height > $width)
1316
			{
1317
				$newDimensions = $this->calcHeight($width, $height);
1318
				
1319
				if ($newDimensions['newWidth'] < $this->maxWidth)
1320
				{
1321
					$newDimensions = $this->calcWidth($width, $height);
1322
				}
1323
			}
1324
		}
1325
		
1326
		$this->newDimensions = $newDimensions;
0 ignored issues
show
Bug introduced by
The variable $newDimensions does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1327
	}
1328
	
1329
	/**
1330
	 * Calculates new dimensions based on $this->percent and the provided dimensions
1331
	 * 
1332
	 * @param int $width
1333
	 * @param int $height
1334
	 */
1335
	protected function calcImageSizePercent ($width, $height)
1336
	{
1337
		if ($this->percent > 0)
1338
		{
1339
			$this->newDimensions = $this->calcPercent($width, $height);
1340
		}
1341
	}
1342
	
1343
	/**
1344
	 * Determines the file format by mime-type
1345
	 * 
1346
	 * This function will throw exceptions for invalid images / mime-types
1347
	 * 
1348
	 */
1349 1
	protected function determineFormat ()
1350
	{
1351 1
		if ($this->isDataStream === true)
1352 1
		{
1353
			$this->format = 'STRING';
1354
			return;
1355
		}
1356
		
1357 1
		$formatInfo = getimagesize($this->fileName);
1358
		
1359
		// non-image files will return false
1360 1
		if ($formatInfo === false)
1361 1
		{
1362
			if ($this->remoteImage)
1363
			{
1364
				$this->triggerError('Could not determine format of remote image: ' . $this->fileName);
1365
			}
1366
			else
1367
			{
1368
				$this->triggerError('File is not a valid image: ' . $this->fileName);
1369
			}
1370
			
1371
			// make sure we really stop execution
1372
			return;
1373
		}
1374
		
1375 1
		$mimeType = isset($formatInfo['mime']) ? $formatInfo['mime'] : null;
1376
		
1377
		switch ($mimeType)
1378
		{
1379 1
			case 'image/gif':
1380
				$this->format = 'GIF';
1381
				break;
1382 1
			case 'image/jpeg':
1383 1
				$this->format = 'JPG';
1384 1
				break;
1385
			case 'image/png':
1386
				$this->format = 'PNG';
1387
				break;
1388
			default:
1389
				$this->triggerError('Image format not supported: ' . $mimeType);
1390
		}
1391 1
	}
1392
	
1393
	/**
1394
	 * Makes sure the correct GD implementation exists for the file type
1395
	 * 
1396
	 */
1397 1
	protected function verifyFormatCompatiblity ()
1398
	{
1399 1
		$isCompatible 	= true;
0 ignored issues
show
Unused Code introduced by
$isCompatible is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1400 1
		$gdInfo			= gd_info();
1401
		
1402 1
		switch ($this->format)
1403
		{
1404 1
			case 'GIF':
1405
				$isCompatible = $gdInfo['GIF Create Support'];
1406
				break;
1407 1
			case 'JPG':
1408 1
				$isCompatible = (isset($gdInfo['JPG Support']) || isset($gdInfo['JPEG Support'])) ? true : false;
1409 1
				break;
1410
			case 'PNG':
1411
				$isCompatible = $gdInfo[$this->format . ' Support'];
1412
				break;
1413
			default:
1414
				$isCompatible = false;
1415 1
		}
1416
		
1417 1
		if (!$isCompatible)
1418 1
		{
1419
			// one last check for "JPEG" instead
1420
			$isCompatible = $gdInfo['JPEG Support'];
1421
			
1422
			if (!$isCompatible)
1423
			{
1424
				$this->triggerError('Your GD installation does not support ' . $this->format . ' image types');
1425
			}
1426
		}
1427 1
	}
1428
	
1429
	/**
1430
	 * Preserves the alpha or transparency for PNG and GIF files
1431
	 * 
1432
	 * Alpha / transparency will not be preserved if the appropriate options are set to false.
1433
	 * Also, the GIF transparency is pretty skunky (the results aren't awesome), but it works like a 
1434
	 * champ... that's the nature of GIFs tho, so no huge surprise.
1435
	 * 
1436
	 * This functionality was originally suggested by commenter Aimi (no links / site provided) - Thanks! :)
1437
	 *   
1438
	 */
1439 1
	protected function preserveAlpha ()
1440
	{
1441 1
		if ($this->format == 'PNG' && $this->options['preserveAlpha'] === true)
1442 1
		{
1443
			imagealphablending($this->workingImage, false);
1444
			
1445
			$colorTransparent = imagecolorallocatealpha
1446
			(
1447
				$this->workingImage, 
1448
				$this->options['alphaMaskColor'][0], 
1449
				$this->options['alphaMaskColor'][1], 
1450
				$this->options['alphaMaskColor'][2], 
1451
				0
1452
			);
1453
			
1454
			imagefill($this->workingImage, 0, 0, $colorTransparent);
1455
			imagesavealpha($this->workingImage, true);
1456
		}
1457
		// preserve transparency in GIFs... this is usually pretty rough tho
1458 1
		if ($this->format == 'GIF' && $this->options['preserveTransparency'] === true)
1459 1
		{
1460
			$colorTransparent = imagecolorallocate
1461
			(
1462
				$this->workingImage, 
1463
				$this->options['transparencyMaskColor'][0], 
1464
				$this->options['transparencyMaskColor'][1], 
1465
				$this->options['transparencyMaskColor'][2] 
1466
			);
1467
			
1468
			imagecolortransparent($this->workingImage, $colorTransparent);
1469
			imagetruecolortopalette($this->workingImage, true, 256);
1470
		}
1471
	}
1472
}