|
1
|
|
|
<?php |
|
|
|
|
|
|
2
|
|
|
|
|
3
|
|
|
/** |
|
4
|
|
|
##DOC-SIGNATURE## |
|
5
|
|
|
|
|
6
|
|
|
This file is part of WideImage. |
|
7
|
|
|
|
|
8
|
|
|
WideImage is free software; you can redistribute it and/or modify |
|
9
|
|
|
it under the terms of the GNU Lesser General Public License as published by |
|
10
|
|
|
the Free Software Foundation; either version 2.1 of the License, or |
|
11
|
|
|
(at your option) any later version. |
|
12
|
|
|
|
|
13
|
|
|
WideImage is distributed in the hope that it will be useful, |
|
14
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
15
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
16
|
|
|
GNU Lesser General Public License for more details. |
|
17
|
|
|
|
|
18
|
|
|
You should have received a copy of the GNU Lesser General Public License |
|
19
|
|
|
along with WideImage; if not, write to the Free Software |
|
20
|
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
|
21
|
|
|
|
|
22
|
|
|
* @package WideImage |
|
23
|
|
|
**/ |
|
24
|
|
|
|
|
25
|
|
|
namespace WideImage; |
|
26
|
|
|
|
|
27
|
|
|
use WideImage\MapperFactory; |
|
28
|
|
|
use WideImage\Exception\Exception; |
|
29
|
|
|
use WideImage\Exception\UnsupportedFormatException; |
|
30
|
|
|
use WideImage\Exception\InvalidImageSourceException; |
|
31
|
|
|
use WideImage\Exception\InvalidImageHandleException; |
|
32
|
|
|
|
|
33
|
|
|
/** |
|
34
|
|
|
* The gateway class for loading images and core library functions |
|
35
|
|
|
* |
|
36
|
|
|
* @package WideImage |
|
37
|
|
|
*/ |
|
38
|
|
|
class WideImage |
|
39
|
|
|
{ |
|
40
|
|
|
const SIDE_TOP_LEFT = 1; |
|
41
|
|
|
const SIDE_TOP = 2; |
|
42
|
|
|
const SIDE_TOP_RIGHT = 4; |
|
43
|
|
|
const SIDE_RIGHT = 8; |
|
44
|
|
|
const SIDE_BOTTOM_RIGHT = 16; |
|
45
|
|
|
const SIDE_BOTTOM = 32; |
|
46
|
|
|
const SIDE_BOTTOM_LEFT = 64; |
|
47
|
|
|
const SIDE_LEFT = 128; |
|
48
|
|
|
const SIDE_ALL = 255; |
|
49
|
|
|
|
|
50
|
|
|
/** |
|
51
|
|
|
* @var string Path to the library base directory |
|
52
|
|
|
*/ |
|
53
|
|
|
protected static $path = null; |
|
54
|
|
|
|
|
55
|
|
|
/** |
|
56
|
|
|
* Returns the library version |
|
57
|
|
|
* @return string The library version |
|
58
|
|
|
*/ |
|
59
|
|
|
public static function version() |
|
60
|
|
|
{ |
|
61
|
|
|
return '##DEV##'; |
|
62
|
|
|
} |
|
63
|
|
|
|
|
64
|
|
|
/** |
|
65
|
|
|
* Returns the path to the library |
|
66
|
|
|
* @return string |
|
67
|
|
|
*/ |
|
68
|
|
|
public static function path() |
|
69
|
|
|
{ |
|
70
|
|
|
if (static::$path === null) { |
|
71
|
|
|
static::$path = __DIR__ . DIRECTORY_SEPARATOR; |
|
72
|
|
|
} |
|
73
|
|
|
|
|
74
|
|
|
return static::$path; |
|
75
|
|
|
} |
|
76
|
|
|
|
|
77
|
|
|
/** |
|
78
|
|
|
* Checks whether the gd library is loaded, and throws an exception otherwise |
|
79
|
|
|
*/ |
|
80
|
|
|
public static function checkGD() |
|
81
|
|
|
{ |
|
82
|
|
|
if (!extension_loaded('gd')) { |
|
83
|
|
|
throw new Exception("WideImage requires the GD extension, but it's apparently not loaded."); |
|
84
|
|
|
} |
|
85
|
|
|
} |
|
86
|
|
|
|
|
87
|
|
|
/** |
|
88
|
|
|
* Registers a custom mapper for image loading and saving |
|
89
|
|
|
* |
|
90
|
|
|
* Example: |
|
91
|
|
|
* <code> |
|
92
|
|
|
* \WideImage\WideImage::registerCustomMapper('\\WideImage\\Mapper\\TGA', 'image/tga', 'tga'); |
|
93
|
|
|
* </code> |
|
94
|
|
|
* |
|
95
|
|
|
* @param string $mapper_class_name |
|
96
|
|
|
* @param string $mime_type |
|
97
|
|
|
* @param string $extension |
|
98
|
|
|
*/ |
|
99
|
|
|
public static function registerCustomMapper($mapper_class_name, $mime_type, $extension) |
|
100
|
|
|
{ |
|
101
|
|
|
MapperFactory::registerMapper($mapper_class_name, $mime_type, strtoupper($extension)); |
|
102
|
|
|
} |
|
103
|
|
|
|
|
104
|
|
|
/** |
|
105
|
|
|
* Loads an image from a file, URL, HTML input file field, binary string, or a valid image handle. |
|
106
|
|
|
* The image format is auto-detected. |
|
107
|
|
|
* |
|
108
|
|
|
* Currently supported formats: PNG, GIF, JPG, BMP, TGA, GD, GD2. |
|
109
|
|
|
* |
|
110
|
|
|
* This function analyzes the input and decides whether to use WideImage::loadFromHandle(), |
|
111
|
|
|
* WideImage::loadFromFile(), WideImage::loadFromUpload() or WideImage::loadFromString(), |
|
112
|
|
|
* all of which you can also call directly to spare WideImage some guessing. |
|
113
|
|
|
* |
|
114
|
|
|
* Arrays are supported for upload fields; it returns an array of loaded images. |
|
115
|
|
|
* To load only a single image from an array field, use WideImage::loadFromUpload('img', $i), |
|
116
|
|
|
* where $i is the index of the image you want to load. |
|
117
|
|
|
* |
|
118
|
|
|
* <code> |
|
119
|
|
|
* $img = WideImage::load('http://url/image.png'); // image URL |
|
120
|
|
|
* $img = WideImage::load('/path/to/image.png'); // local file path |
|
121
|
|
|
* $img = WideImage::load('img'); // upload field name |
|
122
|
|
|
* $img = WideImage::load(imagecreatetruecolor(10, 10)); // a GD resource |
|
123
|
|
|
* $img = WideImage::load($image_data); // binary string containing image data |
|
124
|
|
|
* </code> |
|
125
|
|
|
* |
|
126
|
|
|
* @param mixed $source File name, url, HTML file input field name, binary string, or a GD image resource |
|
127
|
|
|
* @return \WideImage\Image|\WideImage\PaletteImage|\WideImage\TrueColorImage |
|
128
|
|
|
*/ |
|
129
|
|
|
public static function load($source) |
|
130
|
|
|
{ |
|
131
|
|
|
$predictedSourceType = ''; |
|
132
|
|
|
|
|
133
|
|
|
if ($source == '') { |
|
134
|
|
|
$predictedSourceType = 'String'; |
|
135
|
|
|
} |
|
136
|
|
|
|
|
137
|
|
|
// Creating image via a valid resource |
|
138
|
|
|
if (!$predictedSourceType && static::isValidImageHandle($source)) { |
|
139
|
|
|
$predictedSourceType = 'Handle'; |
|
140
|
|
|
} |
|
141
|
|
|
|
|
142
|
|
|
// Check for binary string |
|
143
|
|
|
if (!$predictedSourceType) { |
|
144
|
|
|
// search first $binLength bytes (at a maximum) for ord<32 characters (binary image data) |
|
145
|
|
|
$binLength = 64; |
|
146
|
|
|
$sourceLength = strlen($source); |
|
147
|
|
|
$maxlen = ($sourceLength > $binLength) ? $binLength : $sourceLength; |
|
148
|
|
|
|
|
149
|
|
|
for ($i = 0; $i < $maxlen; $i++) { |
|
150
|
|
|
if (ord($source[$i]) < 32) { |
|
151
|
|
|
$predictedSourceType = 'String'; |
|
152
|
|
|
break; |
|
153
|
|
|
} |
|
154
|
|
|
} |
|
155
|
|
|
} |
|
156
|
|
|
|
|
157
|
|
|
// Uploaded image (array uploads not supported) |
|
158
|
|
|
if (isset($_FILES[$source]) && isset($_FILES[$source]['tmp_name'])) { |
|
159
|
|
|
$predictedSourceType = 'Upload'; |
|
160
|
|
|
} |
|
161
|
|
|
|
|
162
|
|
|
// Otherwise, must be a file or an URL |
|
163
|
|
|
if (!$predictedSourceType) { |
|
164
|
|
|
$predictedSourceType = 'File'; |
|
165
|
|
|
} |
|
166
|
|
|
|
|
167
|
|
|
return call_user_func(array(__CLASS__, 'loadFrom' . $predictedSourceType), $source); |
|
168
|
|
|
} |
|
169
|
|
|
|
|
170
|
|
|
/** |
|
171
|
|
|
* Create and load an image from a file or URL. The image format is auto-detected. |
|
172
|
|
|
* |
|
173
|
|
|
* @param string $uri File or url |
|
174
|
|
|
* @return \WideImage\Image|\WideImage\PaletteImage|\WideImage\TrueColorImage |
|
175
|
|
|
*/ |
|
176
|
|
|
public static function loadFromFile($uri) |
|
177
|
|
|
{ |
|
178
|
|
|
$data = file_get_contents($uri); |
|
179
|
|
|
$handle = @imagecreatefromstring($data); |
|
180
|
|
|
|
|
181
|
|
|
if (!static::isValidImageHandle($handle)) { |
|
182
|
|
|
try { |
|
183
|
|
|
// try to find a mapper first |
|
184
|
|
|
$mapper = MapperFactory::selectMapper($uri); |
|
185
|
|
|
|
|
186
|
|
|
if ($mapper) { |
|
187
|
|
|
$handle = $mapper->load($uri); |
|
188
|
|
|
} |
|
189
|
|
|
} catch (UnsupportedFormatException $e) { |
|
190
|
|
|
// mapper not found |
|
191
|
|
|
} |
|
192
|
|
|
|
|
193
|
|
|
// try all custom mappers |
|
194
|
|
View Code Duplication |
if (!static::isValidImageHandle($handle)) { |
|
195
|
|
|
$custom_mappers = MapperFactory::getCustomMappers(); |
|
196
|
|
|
|
|
197
|
|
|
foreach ($custom_mappers as $mime_type => $mapper_class) { |
|
198
|
|
|
$mapper = MapperFactory::selectMapper(null, $mime_type); |
|
199
|
|
|
$handle = $mapper->loadFromString($data); |
|
200
|
|
|
|
|
201
|
|
|
if (static::isValidImageHandle($handle)) { |
|
202
|
|
|
break; |
|
203
|
|
|
} |
|
204
|
|
|
} |
|
205
|
|
|
} |
|
206
|
|
|
} |
|
207
|
|
|
|
|
208
|
|
|
if (!static::isValidImageHandle($handle)) { |
|
209
|
|
|
throw new InvalidImageSourceException("File '{$uri}' appears to be an invalid image source."); |
|
210
|
|
|
} |
|
211
|
|
|
|
|
212
|
|
|
return static::loadFromHandle($handle); |
|
213
|
|
|
} |
|
214
|
|
|
|
|
215
|
|
|
/** |
|
216
|
|
|
* Create and load an image from a string. Format is auto-detected. |
|
217
|
|
|
* |
|
218
|
|
|
* @param string $string Binary data, i.e. from BLOB field in the database |
|
219
|
|
|
* @return \WideImage\Image|\WideImage\PaletteImage|\WideImage\TrueColorImage |
|
220
|
|
|
*/ |
|
221
|
|
|
public static function loadFromString($string) |
|
222
|
|
|
{ |
|
223
|
|
|
if (strlen($string) < 128) { |
|
224
|
|
|
throw new InvalidImageSourceException("String doesn't contain image data."); |
|
225
|
|
|
} |
|
226
|
|
|
|
|
227
|
|
|
$handle = @imagecreatefromstring($string); |
|
228
|
|
|
|
|
229
|
|
View Code Duplication |
if (!static::isValidImageHandle($handle)) { |
|
230
|
|
|
$custom_mappers = MapperFactory::getCustomMappers(); |
|
231
|
|
|
|
|
232
|
|
|
foreach ($custom_mappers as $mime_type => $mapper_class) { |
|
233
|
|
|
$mapper = MapperFactory::selectMapper(null, $mime_type); |
|
234
|
|
|
$handle = $mapper->loadFromString($string); |
|
235
|
|
|
|
|
236
|
|
|
if (static::isValidImageHandle($handle)) { |
|
237
|
|
|
break; |
|
238
|
|
|
} |
|
239
|
|
|
} |
|
240
|
|
|
} |
|
241
|
|
|
|
|
242
|
|
|
if (!static::isValidImageHandle($handle)) { |
|
243
|
|
|
throw new InvalidImageSourceException("String doesn't contain valid image data."); |
|
244
|
|
|
} |
|
245
|
|
|
|
|
246
|
|
|
return static::loadFromHandle($handle); |
|
247
|
|
|
} |
|
248
|
|
|
|
|
249
|
|
|
/** |
|
250
|
|
|
* Create and load an image from an image handle. |
|
251
|
|
|
* |
|
252
|
|
|
* <b>Note:</b> the resulting image object takes ownership of the passed |
|
253
|
|
|
* handle. When the newly-created image object is destroyed, the handle is |
|
254
|
|
|
* destroyed too, so it's not a valid image handle anymore. In order to |
|
255
|
|
|
* preserve the handle for use after object destruction, you have to call |
|
256
|
|
|
* \WideImage\Image::releaseHandle() on the created image instance prior to its |
|
257
|
|
|
* destruction. |
|
258
|
|
|
* |
|
259
|
|
|
* <code> |
|
260
|
|
|
* $handle = imagecreatefrompng('file.png'); |
|
261
|
|
|
* $image = WideImage::loadFromHandle($handle); |
|
262
|
|
|
* </code> |
|
263
|
|
|
* |
|
264
|
|
|
* @param resource $handle A valid GD image resource |
|
265
|
|
|
* @return \WideImage\Image|\WideImage\PaletteImage|\WideImage\TrueColorImage |
|
266
|
|
|
*/ |
|
267
|
|
|
public static function loadFromHandle($handle) |
|
268
|
|
|
{ |
|
269
|
|
|
if (!static::isValidImageHandle($handle)) { |
|
270
|
|
|
throw new InvalidImageSourceException("Handle is not a valid GD image resource."); |
|
271
|
|
|
} |
|
272
|
|
|
|
|
273
|
|
|
if (imageistruecolor($handle)) { |
|
274
|
|
|
return new TrueColorImage($handle); |
|
275
|
|
|
} |
|
276
|
|
|
|
|
277
|
|
|
return new PaletteImage($handle); |
|
278
|
|
|
} |
|
279
|
|
|
|
|
280
|
|
|
/** |
|
281
|
|
|
* This method loads a file from the $_FILES array. The image format is auto-detected. |
|
282
|
|
|
* |
|
283
|
|
|
* You only have to pass the field name as the parameter. For array fields, this function will |
|
284
|
|
|
* return an array of image objects, unless you specify the $index parameter, which will |
|
285
|
|
|
* load the desired image. |
|
286
|
|
|
* |
|
287
|
|
|
* @param $field_name Name of the key in $_FILES array |
|
288
|
|
|
* @param int $index The index of the file to load (if the input field is an array) |
|
289
|
|
|
* @return \WideImage\Image The loaded image |
|
|
|
|
|
|
290
|
|
|
*/ |
|
291
|
|
|
public static function loadFromUpload($field_name, $index = null) |
|
292
|
|
|
{ |
|
293
|
|
|
if (!array_key_exists($field_name, $_FILES)) { |
|
294
|
|
|
throw new InvalidImageSourceException("Upload field '{$field_name}' doesn't exist."); |
|
295
|
|
|
} |
|
296
|
|
|
|
|
297
|
|
|
if (is_array($_FILES[$field_name]['tmp_name'])) { |
|
298
|
|
|
if (isset($_FILES[$field_name]['tmp_name'][$index])) { |
|
299
|
|
|
$filename = $_FILES[$field_name]['tmp_name'][$index]; |
|
300
|
|
|
} else { |
|
301
|
|
|
$result = array(); |
|
302
|
|
|
|
|
303
|
|
|
foreach ($_FILES[$field_name]['tmp_name'] as $idx => $tmp_name) { |
|
304
|
|
|
$result[$idx] = static::loadFromFile($tmp_name); |
|
305
|
|
|
} |
|
306
|
|
|
|
|
307
|
|
|
return $result; |
|
308
|
|
|
} |
|
309
|
|
|
} else { |
|
310
|
|
|
$filename = $_FILES[$field_name]['tmp_name']; |
|
311
|
|
|
} |
|
312
|
|
|
|
|
313
|
|
|
if (!file_exists($filename)) { |
|
314
|
|
|
throw new InvalidImageSourceException("Uploaded file doesn't exist."); |
|
315
|
|
|
} |
|
316
|
|
|
|
|
317
|
|
|
return static::loadFromFile($filename); |
|
318
|
|
|
} |
|
319
|
|
|
|
|
320
|
|
|
/** |
|
321
|
|
|
* Factory method for creating a palette image |
|
322
|
|
|
* |
|
323
|
|
|
* @param int $width |
|
324
|
|
|
* @param int $height |
|
325
|
|
|
* @return \WideImage\PaletteImage |
|
326
|
|
|
*/ |
|
327
|
|
|
public static function createPaletteImage($width, $height) |
|
328
|
|
|
{ |
|
329
|
|
|
return PaletteImage::create($width, $height); |
|
330
|
|
|
} |
|
331
|
|
|
|
|
332
|
|
|
/** |
|
333
|
|
|
* Factory method for creating a true-color image |
|
334
|
|
|
* |
|
335
|
|
|
* @param int $width |
|
336
|
|
|
* @param int $height |
|
337
|
|
|
* @return \WideImage\TrueColorImage |
|
338
|
|
|
*/ |
|
339
|
|
|
public static function createTrueColorImage($width, $height) |
|
340
|
|
|
{ |
|
341
|
|
|
return TrueColorImage::create($width, $height); |
|
342
|
|
|
} |
|
343
|
|
|
|
|
344
|
|
|
/** |
|
345
|
|
|
* Check whether the given handle is a valid GD resource |
|
346
|
|
|
* |
|
347
|
|
|
* @param mixed $handle The variable to check |
|
348
|
|
|
* @return bool |
|
349
|
|
|
*/ |
|
350
|
|
|
public static function isValidImageHandle($handle) |
|
351
|
|
|
{ |
|
352
|
|
|
return (is_resource($handle) && get_resource_type($handle) == 'gd'); |
|
353
|
|
|
} |
|
354
|
|
|
|
|
355
|
|
|
/** |
|
356
|
|
|
* Throws exception if the handle isn't a valid GD resource |
|
357
|
|
|
* |
|
358
|
|
|
* @param mixed $handle The variable to check |
|
359
|
|
|
*/ |
|
360
|
|
|
public static function assertValidImageHandle($handle) |
|
361
|
|
|
{ |
|
362
|
|
|
if (!static::isValidImageHandle($handle)) { |
|
363
|
|
|
throw new InvalidImageHandleException("{$handle} is not a valid image handle."); |
|
364
|
|
|
} |
|
365
|
|
|
} |
|
366
|
|
|
} |
|
367
|
|
|
|
|
368
|
|
|
WideImage::checkGD(); |
|
369
|
|
|
|
|
370
|
|
|
WideImage::registerCustomMapper('\\WideImage\\Mapper\\BMP', 'image/bmp', 'bmp'); |
|
371
|
|
|
WideImage::registerCustomMapper('\\WideImage\\Mapper\\TGA', 'image/tga', 'tga'); |
|
372
|
|
|
|
The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.
The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.
To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.