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 |
|
|
|
|
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) |
|
|
|
|
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')) |
|
|
|
|
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 |
|
|
|
|
234
|
|
|
* @param int $maxHeight |
|
|
|
|
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) |
|
|
|
|
246
|
|
|
{ |
247
|
|
|
$width = ( $height * $this->currentDimensions['width'] ) / $this->currentDimensions['height']; |
248
|
|
|
} |
249
|
|
|
|
250
|
|
View Code Duplication |
if (!is_numeric($height) || $height == 0) |
|
|
|
|
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) |
|
|
|
|
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) |
|
|
|
|
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')) |
|
|
|
|
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 |
|
|
|
|
360
|
|
|
* @param int $maxHeight |
|
|
|
|
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) |
|
|
|
|
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) |
|
|
|
|
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')) |
|
|
|
|
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 |
|
|
|
|
489
|
|
|
* @param int $maxHeight |
|
|
|
|
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) |
|
|
|
|
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) |
|
|
|
|
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')) |
|
|
|
|
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) { |
|
|
|
|
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) { |
|
|
|
|
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')) |
|
|
|
|
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; |
|
|
|
|
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); |
|
|
|
|
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; |
|
|
|
|
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; |
|
|
|
|
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; |
|
|
|
|
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; |
|
|
|
|
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; |
|
|
|
|
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; |
|
|
|
|
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; |
|
|
|
|
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) |
|
|
|
|
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) |
|
|
|
|
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) |
|
|
|
|
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) |
|
|
|
|
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) |
|
|
|
|
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) |
|
|
|
|
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; |
|
|
|
|
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; |
|
|
|
|
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
|
|
|
} |
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.