|
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
|
|
|
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
|
|
|
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
|
|
|
|