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