1 /*
2 +----------------------------------------------------------------------+
3 | Copyright (c) The PHP Group |
4 +----------------------------------------------------------------------+
5 | This source file is subject to version 3.01 of the PHP license, |
6 | that is bundled with this package in the file LICENSE, and is |
7 | available through the world-wide-web at the following url: |
8 | http://www.php.net/license/3_01.txt |
9 | If you did not receive a copy of the PHP license and are unable to |
10 | obtain it through the world-wide-web, please send a note to |
11 | license@php.net so we can mail you a copy immediately. |
12 +----------------------------------------------------------------------+
13 | Authors: Rasmus Lerdorf <rasmus@php.net> |
14 | Stig Bakken <ssb@php.net> |
15 | Jim Winstead <jimw@php.net> |
16 +----------------------------------------------------------------------+
17 */
18
19 /* gd 1.2 is copyright 1994, 1995, Quest Protein Database Center,
20 Cold Spring Harbor Labs. */
21
22 /* Note that there is no code from the gd package in this file */
23
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27
28 #include "php.h"
29 #include "php_ini.h"
30 #include "ext/standard/head.h"
31 #include <math.h>
32 #include "SAPI.h"
33 #include "php_gd.h"
34 #include "ext/standard/info.h"
35 #include "php_open_temporary_file.h"
36 #include "zend_object_handlers.h"
37 #include "zend_interfaces.h"
38
39 #ifdef HAVE_SYS_WAIT_H
40 # include <sys/wait.h>
41 #endif
42 #ifdef HAVE_UNISTD_H
43 # include <unistd.h>
44 #endif
45 #ifdef PHP_WIN32
46 # include <io.h>
47 # include <fcntl.h>
48 # include <windows.h>
49 # include <Winuser.h>
50 # include <Wingdi.h>
51 #endif
52
53 #if defined(HAVE_GD_XPM) && defined(HAVE_GD_BUNDLED)
54 # include <X11/xpm.h>
55 #endif
56
57
58 #include "gd_compat.h"
59
60 static int le_gd_font;
61
62 #ifdef HAVE_GD_BUNDLED
63 # include "libgd/gd.h"
64 # include "libgd/gd_errors.h"
65 # include "libgd/gdfontt.h" /* 1 Tiny font */
66 # include "libgd/gdfonts.h" /* 2 Small font */
67 # include "libgd/gdfontmb.h" /* 3 Medium bold font */
68 # include "libgd/gdfontl.h" /* 4 Large font */
69 # include "libgd/gdfontg.h" /* 5 Giant font */
70 #else
71 # include <gd.h>
72 # include <gd_errors.h>
73 # include <gdfontt.h> /* 1 Tiny font */
74 # include <gdfonts.h> /* 2 Small font */
75 # include <gdfontmb.h> /* 3 Medium bold font */
76 # include <gdfontl.h> /* 4 Large font */
77 # include <gdfontg.h> /* 5 Giant font */
78 #endif
79
80 #if defined(HAVE_GD_FREETYPE) && defined(HAVE_GD_BUNDLED)
81 # include <ft2build.h>
82 # include FT_FREETYPE_H
83 #endif
84
85 #if defined(HAVE_GD_XPM) && defined(HAVE_GD_BUNDLED)
86 # include "X11/xpm.h"
87 #endif
88
89 #ifndef M_PI
90 #define M_PI 3.14159265358979323846
91 #endif
92
93 /* workaround typo in system libgd 2.3.0 */
94 #if defined(GD_FLIP_HORINZONTAL) && !defined(GD_FLIP_HORIZONTAL)
95 #define GD_FLIP_HORIZONTAL GD_FLIP_HORINZONTAL
96 #endif
97
98 #ifdef HAVE_GD_FREETYPE
99 static void php_imagettftext_common(INTERNAL_FUNCTION_PARAMETERS, int);
100 #endif
101
102 #include "gd_arginfo.h"
103
104 /* as it is not really public, duplicate declaration here to avoid
105 pointless warnings */
106 int overflow2(int a, int b);
107
108 /* Section Filters Declarations */
109 /* IMPORTANT NOTE FOR NEW FILTER
110 * Do not forget to update:
111 * IMAGE_FILTER_MAX: define the last filter index
112 * IMAGE_FILTER_MAX_ARGS: define the biggest amount of arguments
113 * image_filter array in PHP_FUNCTION(imagefilter)
114 * */
115 #define IMAGE_FILTER_NEGATE 0
116 #define IMAGE_FILTER_GRAYSCALE 1
117 #define IMAGE_FILTER_BRIGHTNESS 2
118 #define IMAGE_FILTER_CONTRAST 3
119 #define IMAGE_FILTER_COLORIZE 4
120 #define IMAGE_FILTER_EDGEDETECT 5
121 #define IMAGE_FILTER_EMBOSS 6
122 #define IMAGE_FILTER_GAUSSIAN_BLUR 7
123 #define IMAGE_FILTER_SELECTIVE_BLUR 8
124 #define IMAGE_FILTER_MEAN_REMOVAL 9
125 #define IMAGE_FILTER_SMOOTH 10
126 #define IMAGE_FILTER_PIXELATE 11
127 #define IMAGE_FILTER_SCATTER 12
128 #define IMAGE_FILTER_MAX 12
129 #define IMAGE_FILTER_MAX_ARGS 6
130 static void php_image_filter_negate(INTERNAL_FUNCTION_PARAMETERS);
131 static void php_image_filter_grayscale(INTERNAL_FUNCTION_PARAMETERS);
132 static void php_image_filter_brightness(INTERNAL_FUNCTION_PARAMETERS);
133 static void php_image_filter_contrast(INTERNAL_FUNCTION_PARAMETERS);
134 static void php_image_filter_colorize(INTERNAL_FUNCTION_PARAMETERS);
135 static void php_image_filter_edgedetect(INTERNAL_FUNCTION_PARAMETERS);
136 static void php_image_filter_emboss(INTERNAL_FUNCTION_PARAMETERS);
137 static void php_image_filter_gaussian_blur(INTERNAL_FUNCTION_PARAMETERS);
138 static void php_image_filter_selective_blur(INTERNAL_FUNCTION_PARAMETERS);
139 static void php_image_filter_mean_removal(INTERNAL_FUNCTION_PARAMETERS);
140 static void php_image_filter_smooth(INTERNAL_FUNCTION_PARAMETERS);
141 static void php_image_filter_pixelate(INTERNAL_FUNCTION_PARAMETERS);
142 static void php_image_filter_scatter(INTERNAL_FUNCTION_PARAMETERS);
143
144 /* End Section filters declarations */
145 static gdImagePtr _php_image_create_from_string(zend_string *Data, char *tn, gdImagePtr (*ioctx_func_p)());
146 static void _php_image_create_from(INTERNAL_FUNCTION_PARAMETERS, int image_type, char *tn, gdImagePtr (*func_p)(), gdImagePtr (*ioctx_func_p)());
147 static void _php_image_output(INTERNAL_FUNCTION_PARAMETERS, int image_type, char *tn, void (*func_p)());
148 static gdIOCtx *create_stream_context_from_zval(zval *to_zval);
149 static gdIOCtx *create_stream_context(php_stream *stream, int close_stream);
150 static gdIOCtx *create_output_context();
151 static int _php_image_type(char data[12]);
152
153 /* output streaming (formerly gd_ctx.c) */
154 static void _php_image_output_ctx(INTERNAL_FUNCTION_PARAMETERS, int image_type, char *tn, void (*func_p)());
155
156 /*********************************************************
157 *
158 * GD Object Representation
159 *
160 ********************************************************/
161
162 zend_class_entry *gd_image_ce;
163
164 typedef struct _gd_ext_image_object {
165 gdImagePtr image;
166 zend_object std;
167 } php_gd_image_object;
168
169 static zend_object_handlers php_gd_image_object_handlers;
170
php_gd_image_object_get_constructor(zend_object * object)171 static zend_function *php_gd_image_object_get_constructor(zend_object *object)
172 {
173 zend_throw_error(NULL, "You cannot initialize a GdImage object except through helper functions");
174 return NULL;
175 }
176
177 /**
178 * Returns the underlying php_gd_image_object from a zend_object
179 */
180
php_gd_exgdimage_from_zobj_p(zend_object * obj)181 static zend_always_inline php_gd_image_object* php_gd_exgdimage_from_zobj_p(zend_object* obj)
182 {
183 return (php_gd_image_object *) ((char *) (obj) - XtOffsetOf(php_gd_image_object, std));
184 }
185
186 /**
187 * Converts an extension GdImage instance contained within a zval into the gdImagePtr
188 * for use with library APIs
189 */
php_gd_libgdimageptr_from_zval_p(zval * zp)190 PHP_GD_API gdImagePtr php_gd_libgdimageptr_from_zval_p(zval* zp)
191 {
192 return php_gd_exgdimage_from_zobj_p(Z_OBJ_P(zp))->image;
193 }
194
195
php_gd_image_object_create(zend_class_entry * class_type)196 zend_object *php_gd_image_object_create(zend_class_entry *class_type)
197 {
198 size_t block_len = sizeof(php_gd_image_object) + zend_object_properties_size(class_type);
199 php_gd_image_object *intern = emalloc(block_len);
200 memset(intern, 0, block_len);
201
202 zend_object_std_init(&intern->std, class_type);
203 object_properties_init(&intern->std, class_type);
204 intern->std.handlers = &php_gd_image_object_handlers;
205
206 return &intern->std;
207 }
208
php_gd_image_object_free(zend_object * intern)209 static void php_gd_image_object_free(zend_object *intern)
210 {
211 php_gd_image_object *img_obj_ptr = php_gd_exgdimage_from_zobj_p(intern);
212 if (img_obj_ptr->image) {
213 gdImageDestroy(img_obj_ptr->image);
214 }
215 zend_object_std_dtor(intern);
216 }
217
218 /**
219 * Creates a new GdImage object wrapping the gdImagePtr and attaches it
220 * to the zval (usually return_value).
221 *
222 * This function must only be called once per valid gdImagePtr
223 */
php_gd_assign_libgdimageptr_as_extgdimage(zval * val,gdImagePtr image)224 void php_gd_assign_libgdimageptr_as_extgdimage(zval *val, gdImagePtr image)
225 {
226 object_init_ex(val, gd_image_ce);
227 php_gd_exgdimage_from_zobj_p(Z_OBJ_P(val))->image = image;
228 }
229
php_gd_object_minit_helper()230 static void php_gd_object_minit_helper()
231 {
232 zend_class_entry ce;
233 INIT_CLASS_ENTRY(ce, "GdImage", class_GdImage_methods);
234 gd_image_ce = zend_register_internal_class(&ce);
235 gd_image_ce->ce_flags |= ZEND_ACC_FINAL | ZEND_ACC_NO_DYNAMIC_PROPERTIES;
236 gd_image_ce->create_object = php_gd_image_object_create;
237 gd_image_ce->serialize = zend_class_serialize_deny;
238 gd_image_ce->unserialize = zend_class_unserialize_deny;
239
240 /* setting up the object handlers for the GdImage class */
241 memcpy(&php_gd_image_object_handlers, &std_object_handlers, sizeof(zend_object_handlers));
242 php_gd_image_object_handlers.clone_obj = NULL;
243 php_gd_image_object_handlers.free_obj = php_gd_image_object_free;
244 php_gd_image_object_handlers.get_constructor = php_gd_image_object_get_constructor;
245 php_gd_image_object_handlers.compare = zend_objects_not_comparable;
246 php_gd_image_object_handlers.offset = XtOffsetOf(php_gd_image_object, std);
247 }
248
249
250 /*********************************************************
251 *
252 * Extension Implementation
253 *
254 ********************************************************/
255
256 zend_module_entry gd_module_entry = {
257 STANDARD_MODULE_HEADER,
258 "gd",
259 ext_functions,
260 PHP_MINIT(gd),
261 PHP_MSHUTDOWN(gd),
262 NULL,
263 PHP_RSHUTDOWN(gd),
264 PHP_MINFO(gd),
265 PHP_GD_VERSION,
266 STANDARD_MODULE_PROPERTIES
267 };
268
269 #ifdef COMPILE_DL_GD
270 ZEND_GET_MODULE(gd)
271 #endif
272
273 /* {{{ PHP_INI_BEGIN */
PHP_INI_BEGIN()274 PHP_INI_BEGIN()
275 PHP_INI_ENTRY("gd.jpeg_ignore_warning", "1", PHP_INI_ALL, NULL)
276 PHP_INI_END()
277 /* }}} */
278
279 /* {{{ php_free_gd_font */
280 static void php_free_gd_font(zend_resource *rsrc)
281 {
282 gdFontPtr fp = (gdFontPtr) rsrc->ptr;
283
284 if (fp->data) {
285 efree(fp->data);
286 }
287
288 efree(fp);
289 }
290 /* }}} */
291
292 /* {{{ php_gd_error_method */
php_gd_error_method(int type,const char * format,va_list args)293 void php_gd_error_method(int type, const char *format, va_list args)
294 {
295 switch (type) {
296 #ifndef PHP_WIN32
297 case GD_DEBUG:
298 case GD_INFO:
299 #endif
300 case GD_NOTICE:
301 type = E_NOTICE;
302 break;
303 case GD_WARNING:
304 type = E_WARNING;
305 break;
306 default:
307 type = E_ERROR;
308 }
309 php_verror(NULL, "", type, format, args);
310 }
311 /* }}} */
312
313 /* {{{ PHP_MINIT_FUNCTION */
PHP_MINIT_FUNCTION(gd)314 PHP_MINIT_FUNCTION(gd)
315 {
316 le_gd_font = zend_register_list_destructors_ex(php_free_gd_font, NULL, "gd font", module_number);
317 php_gd_object_minit_helper();
318
319 #if defined(HAVE_GD_FREETYPE) && defined(HAVE_GD_BUNDLED)
320 gdFontCacheMutexSetup();
321 #endif
322 gdSetErrorMethod(php_gd_error_method);
323
324 REGISTER_INI_ENTRIES();
325
326 REGISTER_LONG_CONSTANT("IMG_GIF", PHP_IMG_GIF, CONST_CS | CONST_PERSISTENT);
327 REGISTER_LONG_CONSTANT("IMG_JPG", PHP_IMG_JPG, CONST_CS | CONST_PERSISTENT);
328 REGISTER_LONG_CONSTANT("IMG_JPEG", PHP_IMG_JPEG, CONST_CS | CONST_PERSISTENT);
329 REGISTER_LONG_CONSTANT("IMG_PNG", PHP_IMG_PNG, CONST_CS | CONST_PERSISTENT);
330 REGISTER_LONG_CONSTANT("IMG_WBMP", PHP_IMG_WBMP, CONST_CS | CONST_PERSISTENT);
331 REGISTER_LONG_CONSTANT("IMG_XPM", PHP_IMG_XPM, CONST_CS | CONST_PERSISTENT);
332 REGISTER_LONG_CONSTANT("IMG_WEBP", PHP_IMG_WEBP, CONST_CS | CONST_PERSISTENT);
333 REGISTER_LONG_CONSTANT("IMG_BMP", PHP_IMG_BMP, CONST_CS | CONST_PERSISTENT);
334 REGISTER_LONG_CONSTANT("IMG_TGA", PHP_IMG_TGA, CONST_CS | CONST_PERSISTENT);
335
336 /* special colours for gd */
337 REGISTER_LONG_CONSTANT("IMG_COLOR_TILED", gdTiled, CONST_CS | CONST_PERSISTENT);
338 REGISTER_LONG_CONSTANT("IMG_COLOR_STYLED", gdStyled, CONST_CS | CONST_PERSISTENT);
339 REGISTER_LONG_CONSTANT("IMG_COLOR_BRUSHED", gdBrushed, CONST_CS | CONST_PERSISTENT);
340 REGISTER_LONG_CONSTANT("IMG_COLOR_STYLEDBRUSHED", gdStyledBrushed, CONST_CS | CONST_PERSISTENT);
341 REGISTER_LONG_CONSTANT("IMG_COLOR_TRANSPARENT", gdTransparent, CONST_CS | CONST_PERSISTENT);
342
343 /* for imagefilledarc */
344 REGISTER_LONG_CONSTANT("IMG_ARC_ROUNDED", gdArc, CONST_CS | CONST_PERSISTENT);
345 REGISTER_LONG_CONSTANT("IMG_ARC_PIE", gdPie, CONST_CS | CONST_PERSISTENT);
346 REGISTER_LONG_CONSTANT("IMG_ARC_CHORD", gdChord, CONST_CS | CONST_PERSISTENT);
347 REGISTER_LONG_CONSTANT("IMG_ARC_NOFILL", gdNoFill, CONST_CS | CONST_PERSISTENT);
348 REGISTER_LONG_CONSTANT("IMG_ARC_EDGED", gdEdged, CONST_CS | CONST_PERSISTENT);
349
350 /* GD2 image format types */
351 REGISTER_LONG_CONSTANT("IMG_GD2_RAW", GD2_FMT_RAW, CONST_CS | CONST_PERSISTENT);
352 REGISTER_LONG_CONSTANT("IMG_GD2_COMPRESSED", GD2_FMT_COMPRESSED, CONST_CS | CONST_PERSISTENT);
353 REGISTER_LONG_CONSTANT("IMG_FLIP_HORIZONTAL", GD_FLIP_HORIZONTAL, CONST_CS | CONST_PERSISTENT);
354 REGISTER_LONG_CONSTANT("IMG_FLIP_VERTICAL", GD_FLIP_VERTICAL, CONST_CS | CONST_PERSISTENT);
355 REGISTER_LONG_CONSTANT("IMG_FLIP_BOTH", GD_FLIP_BOTH, CONST_CS | CONST_PERSISTENT);
356 REGISTER_LONG_CONSTANT("IMG_EFFECT_REPLACE", gdEffectReplace, CONST_CS | CONST_PERSISTENT);
357 REGISTER_LONG_CONSTANT("IMG_EFFECT_ALPHABLEND", gdEffectAlphaBlend, CONST_CS | CONST_PERSISTENT);
358 REGISTER_LONG_CONSTANT("IMG_EFFECT_NORMAL", gdEffectNormal, CONST_CS | CONST_PERSISTENT);
359 REGISTER_LONG_CONSTANT("IMG_EFFECT_OVERLAY", gdEffectOverlay, CONST_CS | CONST_PERSISTENT);
360 #ifdef gdEffectMultiply
361 REGISTER_LONG_CONSTANT("IMG_EFFECT_MULTIPLY", gdEffectMultiply, CONST_CS | CONST_PERSISTENT);
362 #endif
363
364 REGISTER_LONG_CONSTANT("IMG_CROP_DEFAULT", GD_CROP_DEFAULT, CONST_CS | CONST_PERSISTENT);
365 REGISTER_LONG_CONSTANT("IMG_CROP_TRANSPARENT", GD_CROP_TRANSPARENT, CONST_CS | CONST_PERSISTENT);
366 REGISTER_LONG_CONSTANT("IMG_CROP_BLACK", GD_CROP_BLACK, CONST_CS | CONST_PERSISTENT);
367 REGISTER_LONG_CONSTANT("IMG_CROP_WHITE", GD_CROP_WHITE, CONST_CS | CONST_PERSISTENT);
368 REGISTER_LONG_CONSTANT("IMG_CROP_SIDES", GD_CROP_SIDES, CONST_CS | CONST_PERSISTENT);
369 REGISTER_LONG_CONSTANT("IMG_CROP_THRESHOLD", GD_CROP_THRESHOLD, CONST_CS | CONST_PERSISTENT);
370
371
372 REGISTER_LONG_CONSTANT("IMG_BELL", GD_BELL, CONST_CS | CONST_PERSISTENT);
373 REGISTER_LONG_CONSTANT("IMG_BESSEL", GD_BESSEL, CONST_CS | CONST_PERSISTENT);
374 REGISTER_LONG_CONSTANT("IMG_BILINEAR_FIXED", GD_BILINEAR_FIXED, CONST_CS | CONST_PERSISTENT);
375 REGISTER_LONG_CONSTANT("IMG_BICUBIC", GD_BICUBIC, CONST_CS | CONST_PERSISTENT);
376 REGISTER_LONG_CONSTANT("IMG_BICUBIC_FIXED", GD_BICUBIC_FIXED, CONST_CS | CONST_PERSISTENT);
377 REGISTER_LONG_CONSTANT("IMG_BLACKMAN", GD_BLACKMAN, CONST_CS | CONST_PERSISTENT);
378 REGISTER_LONG_CONSTANT("IMG_BOX", GD_BOX, CONST_CS | CONST_PERSISTENT);
379 REGISTER_LONG_CONSTANT("IMG_BSPLINE", GD_BSPLINE, CONST_CS | CONST_PERSISTENT);
380 REGISTER_LONG_CONSTANT("IMG_CATMULLROM", GD_CATMULLROM, CONST_CS | CONST_PERSISTENT);
381 REGISTER_LONG_CONSTANT("IMG_GAUSSIAN", GD_GAUSSIAN, CONST_CS | CONST_PERSISTENT);
382 REGISTER_LONG_CONSTANT("IMG_GENERALIZED_CUBIC", GD_GENERALIZED_CUBIC, CONST_CS | CONST_PERSISTENT);
383 REGISTER_LONG_CONSTANT("IMG_HERMITE", GD_HERMITE, CONST_CS | CONST_PERSISTENT);
384 REGISTER_LONG_CONSTANT("IMG_HAMMING", GD_HAMMING, CONST_CS | CONST_PERSISTENT);
385 REGISTER_LONG_CONSTANT("IMG_HANNING", GD_HANNING, CONST_CS | CONST_PERSISTENT);
386 REGISTER_LONG_CONSTANT("IMG_MITCHELL", GD_MITCHELL, CONST_CS | CONST_PERSISTENT);
387 REGISTER_LONG_CONSTANT("IMG_POWER", GD_POWER, CONST_CS | CONST_PERSISTENT);
388 REGISTER_LONG_CONSTANT("IMG_QUADRATIC", GD_QUADRATIC, CONST_CS | CONST_PERSISTENT);
389 REGISTER_LONG_CONSTANT("IMG_SINC", GD_SINC, CONST_CS | CONST_PERSISTENT);
390 REGISTER_LONG_CONSTANT("IMG_NEAREST_NEIGHBOUR", GD_NEAREST_NEIGHBOUR, CONST_CS | CONST_PERSISTENT);
391 REGISTER_LONG_CONSTANT("IMG_WEIGHTED4", GD_WEIGHTED4, CONST_CS | CONST_PERSISTENT);
392 REGISTER_LONG_CONSTANT("IMG_TRIANGLE", GD_TRIANGLE, CONST_CS | CONST_PERSISTENT);
393
394 REGISTER_LONG_CONSTANT("IMG_AFFINE_TRANSLATE", GD_AFFINE_TRANSLATE, CONST_CS | CONST_PERSISTENT);
395 REGISTER_LONG_CONSTANT("IMG_AFFINE_SCALE", GD_AFFINE_SCALE, CONST_CS | CONST_PERSISTENT);
396 REGISTER_LONG_CONSTANT("IMG_AFFINE_ROTATE", GD_AFFINE_ROTATE, CONST_CS | CONST_PERSISTENT);
397 REGISTER_LONG_CONSTANT("IMG_AFFINE_SHEAR_HORIZONTAL", GD_AFFINE_SHEAR_HORIZONTAL, CONST_CS | CONST_PERSISTENT);
398 REGISTER_LONG_CONSTANT("IMG_AFFINE_SHEAR_VERTICAL", GD_AFFINE_SHEAR_VERTICAL, CONST_CS | CONST_PERSISTENT);
399
400 #ifdef HAVE_GD_BUNDLED
401 REGISTER_LONG_CONSTANT("GD_BUNDLED", 1, CONST_CS | CONST_PERSISTENT);
402 #else
403 REGISTER_LONG_CONSTANT("GD_BUNDLED", 0, CONST_CS | CONST_PERSISTENT);
404 #endif
405
406 /* Section Filters */
407 REGISTER_LONG_CONSTANT("IMG_FILTER_NEGATE", IMAGE_FILTER_NEGATE, CONST_CS | CONST_PERSISTENT);
408 REGISTER_LONG_CONSTANT("IMG_FILTER_GRAYSCALE", IMAGE_FILTER_GRAYSCALE, CONST_CS | CONST_PERSISTENT);
409 REGISTER_LONG_CONSTANT("IMG_FILTER_BRIGHTNESS", IMAGE_FILTER_BRIGHTNESS, CONST_CS | CONST_PERSISTENT);
410 REGISTER_LONG_CONSTANT("IMG_FILTER_CONTRAST", IMAGE_FILTER_CONTRAST, CONST_CS | CONST_PERSISTENT);
411 REGISTER_LONG_CONSTANT("IMG_FILTER_COLORIZE", IMAGE_FILTER_COLORIZE, CONST_CS | CONST_PERSISTENT);
412 REGISTER_LONG_CONSTANT("IMG_FILTER_EDGEDETECT", IMAGE_FILTER_EDGEDETECT, CONST_CS | CONST_PERSISTENT);
413 REGISTER_LONG_CONSTANT("IMG_FILTER_GAUSSIAN_BLUR", IMAGE_FILTER_GAUSSIAN_BLUR, CONST_CS | CONST_PERSISTENT);
414 REGISTER_LONG_CONSTANT("IMG_FILTER_SELECTIVE_BLUR", IMAGE_FILTER_SELECTIVE_BLUR, CONST_CS | CONST_PERSISTENT);
415 REGISTER_LONG_CONSTANT("IMG_FILTER_EMBOSS", IMAGE_FILTER_EMBOSS, CONST_CS | CONST_PERSISTENT);
416 REGISTER_LONG_CONSTANT("IMG_FILTER_MEAN_REMOVAL", IMAGE_FILTER_MEAN_REMOVAL, CONST_CS | CONST_PERSISTENT);
417 REGISTER_LONG_CONSTANT("IMG_FILTER_SMOOTH", IMAGE_FILTER_SMOOTH, CONST_CS | CONST_PERSISTENT);
418 REGISTER_LONG_CONSTANT("IMG_FILTER_PIXELATE", IMAGE_FILTER_PIXELATE, CONST_CS | CONST_PERSISTENT);
419 REGISTER_LONG_CONSTANT("IMG_FILTER_SCATTER", IMAGE_FILTER_SCATTER, CONST_CS | CONST_PERSISTENT);
420 /* End Section Filters */
421
422 #ifdef GD_VERSION_STRING
423 REGISTER_STRING_CONSTANT("GD_VERSION", GD_VERSION_STRING, CONST_CS | CONST_PERSISTENT);
424 #endif
425
426 #if defined(GD_MAJOR_VERSION) && defined(GD_MINOR_VERSION) && defined(GD_RELEASE_VERSION) && defined(GD_EXTRA_VERSION)
427 REGISTER_LONG_CONSTANT("GD_MAJOR_VERSION", GD_MAJOR_VERSION, CONST_CS | CONST_PERSISTENT);
428 REGISTER_LONG_CONSTANT("GD_MINOR_VERSION", GD_MINOR_VERSION, CONST_CS | CONST_PERSISTENT);
429 REGISTER_LONG_CONSTANT("GD_RELEASE_VERSION", GD_RELEASE_VERSION, CONST_CS | CONST_PERSISTENT);
430 REGISTER_STRING_CONSTANT("GD_EXTRA_VERSION", GD_EXTRA_VERSION, CONST_CS | CONST_PERSISTENT);
431 #endif
432
433
434 #ifdef HAVE_GD_PNG
435
436 /*
437 * cannot include #include "png.h"
438 * /usr/include/pngconf.h:310:2: error: #error png.h already includes setjmp.h with some additional fixup.
439 * as error, use the values for now...
440 */
441 REGISTER_LONG_CONSTANT("PNG_NO_FILTER", 0x00, CONST_CS | CONST_PERSISTENT);
442 REGISTER_LONG_CONSTANT("PNG_FILTER_NONE", 0x08, CONST_CS | CONST_PERSISTENT);
443 REGISTER_LONG_CONSTANT("PNG_FILTER_SUB", 0x10, CONST_CS | CONST_PERSISTENT);
444 REGISTER_LONG_CONSTANT("PNG_FILTER_UP", 0x20, CONST_CS | CONST_PERSISTENT);
445 REGISTER_LONG_CONSTANT("PNG_FILTER_AVG", 0x40, CONST_CS | CONST_PERSISTENT);
446 REGISTER_LONG_CONSTANT("PNG_FILTER_PAETH", 0x80, CONST_CS | CONST_PERSISTENT);
447 REGISTER_LONG_CONSTANT("PNG_ALL_FILTERS", 0x08 | 0x10 | 0x20 | 0x40 | 0x80, CONST_CS | CONST_PERSISTENT);
448 #endif
449
450 return SUCCESS;
451 }
452 /* }}} */
453
454 /* {{{ PHP_MSHUTDOWN_FUNCTION */
PHP_MSHUTDOWN_FUNCTION(gd)455 PHP_MSHUTDOWN_FUNCTION(gd)
456 {
457 #if defined(HAVE_GD_FREETYPE) && defined(HAVE_GD_BUNDLED)
458 gdFontCacheMutexShutdown();
459 #endif
460 UNREGISTER_INI_ENTRIES();
461 return SUCCESS;
462 }
463 /* }}} */
464
465 /* {{{ PHP_RSHUTDOWN_FUNCTION */
PHP_RSHUTDOWN_FUNCTION(gd)466 PHP_RSHUTDOWN_FUNCTION(gd)
467 {
468 #ifdef HAVE_GD_FREETYPE
469 gdFontCacheShutdown();
470 #endif
471 return SUCCESS;
472 }
473 /* }}} */
474
475 #ifdef HAVE_GD_BUNDLED
476 #define PHP_GD_VERSION_STRING "bundled (2.1.0 compatible)"
477 #else
478 # define PHP_GD_VERSION_STRING GD_VERSION_STRING
479 #endif
480
481 /* {{{ PHP_MINFO_FUNCTION */
PHP_MINFO_FUNCTION(gd)482 PHP_MINFO_FUNCTION(gd)
483 {
484 php_info_print_table_start();
485 php_info_print_table_row(2, "GD Support", "enabled");
486
487 /* need to use a PHPAPI function here because it is external module in windows */
488
489 #ifdef HAVE_GD_BUNDLED
490 php_info_print_table_row(2, "GD Version", PHP_GD_VERSION_STRING);
491 #else
492 php_info_print_table_row(2, "GD headers Version", PHP_GD_VERSION_STRING);
493 #ifdef HAVE_GD_LIBVERSION
494 php_info_print_table_row(2, "GD library Version", gdVersionString());
495 #endif
496 #endif
497
498 #ifdef HAVE_GD_FREETYPE
499 php_info_print_table_row(2, "FreeType Support", "enabled");
500 php_info_print_table_row(2, "FreeType Linkage", "with freetype");
501 #ifdef HAVE_GD_BUNDLED
502 {
503 char tmp[256];
504
505 #ifdef FREETYPE_PATCH
506 snprintf(tmp, sizeof(tmp), "%d.%d.%d", FREETYPE_MAJOR, FREETYPE_MINOR, FREETYPE_PATCH);
507 #elif defined(FREETYPE_MAJOR)
508 snprintf(tmp, sizeof(tmp), "%d.%d", FREETYPE_MAJOR, FREETYPE_MINOR);
509 #else
510 snprintf(tmp, sizeof(tmp), "1.x");
511 #endif
512 php_info_print_table_row(2, "FreeType Version", tmp);
513 }
514 #endif
515 #endif
516
517 php_info_print_table_row(2, "GIF Read Support", "enabled");
518 php_info_print_table_row(2, "GIF Create Support", "enabled");
519
520 #ifdef HAVE_GD_JPG
521 {
522 php_info_print_table_row(2, "JPEG Support", "enabled");
523 #ifdef HAVE_GD_BUNDLED
524 php_info_print_table_row(2, "libJPEG Version", gdJpegGetVersionString());
525 #endif
526 }
527 #endif
528
529 #ifdef HAVE_GD_PNG
530 php_info_print_table_row(2, "PNG Support", "enabled");
531 #ifdef HAVE_GD_BUNDLED
532 php_info_print_table_row(2, "libPNG Version", gdPngGetVersionString());
533 #endif
534 #endif
535 php_info_print_table_row(2, "WBMP Support", "enabled");
536 #ifdef HAVE_GD_XPM
537 php_info_print_table_row(2, "XPM Support", "enabled");
538 #ifdef HAVE_GD_BUNDLED
539 {
540 char tmp[12];
541 snprintf(tmp, sizeof(tmp), "%d", XpmLibraryVersion());
542 php_info_print_table_row(2, "libXpm Version", tmp);
543 }
544 #endif
545 #endif
546 php_info_print_table_row(2, "XBM Support", "enabled");
547 #ifdef USE_GD_JISX0208
548 php_info_print_table_row(2, "JIS-mapped Japanese Font Support", "enabled");
549 #endif
550 #ifdef HAVE_GD_WEBP
551 php_info_print_table_row(2, "WebP Support", "enabled");
552 #endif
553 #ifdef HAVE_GD_BMP
554 php_info_print_table_row(2, "BMP Support", "enabled");
555 #endif
556 #ifdef HAVE_GD_TGA
557 php_info_print_table_row(2, "TGA Read Support", "enabled");
558 #endif
559 php_info_print_table_end();
560 DISPLAY_INI_ENTRIES();
561 }
562 /* }}} */
563
564 /* {{{ */
PHP_FUNCTION(gd_info)565 PHP_FUNCTION(gd_info)
566 {
567 if (zend_parse_parameters_none() == FAILURE) {
568 RETURN_THROWS();
569 }
570
571 array_init(return_value);
572
573 add_assoc_string(return_value, "GD Version", PHP_GD_VERSION_STRING);
574
575 #ifdef HAVE_GD_FREETYPE
576 add_assoc_bool(return_value, "FreeType Support", 1);
577 add_assoc_string(return_value, "FreeType Linkage", "with freetype");
578 #else
579 add_assoc_bool(return_value, "FreeType Support", 0);
580 #endif
581 add_assoc_bool(return_value, "GIF Read Support", 1);
582 add_assoc_bool(return_value, "GIF Create Support", 1);
583 #ifdef HAVE_GD_JPG
584 add_assoc_bool(return_value, "JPEG Support", 1);
585 #else
586 add_assoc_bool(return_value, "JPEG Support", 0);
587 #endif
588 #ifdef HAVE_GD_PNG
589 add_assoc_bool(return_value, "PNG Support", 1);
590 #else
591 add_assoc_bool(return_value, "PNG Support", 0);
592 #endif
593 add_assoc_bool(return_value, "WBMP Support", 1);
594 #ifdef HAVE_GD_XPM
595 add_assoc_bool(return_value, "XPM Support", 1);
596 #else
597 add_assoc_bool(return_value, "XPM Support", 0);
598 #endif
599 add_assoc_bool(return_value, "XBM Support", 1);
600 #ifdef HAVE_GD_WEBP
601 add_assoc_bool(return_value, "WebP Support", 1);
602 #else
603 add_assoc_bool(return_value, "WebP Support", 0);
604 #endif
605 #ifdef HAVE_GD_BMP
606 add_assoc_bool(return_value, "BMP Support", 1);
607 #else
608 add_assoc_bool(return_value, "BMP Support", 0);
609 #endif
610 #ifdef HAVE_GD_TGA
611 add_assoc_bool(return_value, "TGA Read Support", 1);
612 #else
613 add_assoc_bool(return_value, "TGA Read Support", 0);
614 #endif
615 #ifdef USE_GD_JISX0208
616 add_assoc_bool(return_value, "JIS-mapped Japanese Font Support", 1);
617 #else
618 add_assoc_bool(return_value, "JIS-mapped Japanese Font Support", 0);
619 #endif
620 }
621 /* }}} */
622
623 #define FLIPWORD(a) (((a & 0xff000000) >> 24) | ((a & 0x00ff0000) >> 8) | ((a & 0x0000ff00) << 8) | ((a & 0x000000ff) << 24))
624
625 /* {{{ Load a new font */
PHP_FUNCTION(imageloadfont)626 PHP_FUNCTION(imageloadfont)
627 {
628 zval *ind;
629 zend_string *file;
630 int hdr_size = sizeof(gdFont) - sizeof(char *);
631 int body_size, n = 0, b, i, body_size_check;
632 gdFontPtr font;
633 php_stream *stream;
634
635 if (zend_parse_parameters(ZEND_NUM_ARGS(), "P", &file) == FAILURE) {
636 RETURN_THROWS();
637 }
638
639 stream = php_stream_open_wrapper(ZSTR_VAL(file), "rb", IGNORE_PATH | IGNORE_URL_WIN | REPORT_ERRORS, NULL);
640 if (stream == NULL) {
641 RETURN_FALSE;
642 }
643
644 /* Only supports a architecture-dependent binary dump format
645 * at the moment.
646 * The file format is like this on machines with 32-byte integers:
647 *
648 * byte 0-3: (int) number of characters in the font
649 * byte 4-7: (int) value of first character in the font (often 32, space)
650 * byte 8-11: (int) pixel width of each character
651 * byte 12-15: (int) pixel height of each character
652 * bytes 16-: (char) array with character data, one byte per pixel
653 * in each character, for a total of
654 * (nchars*width*height) bytes.
655 */
656 font = (gdFontPtr) emalloc(sizeof(gdFont));
657 b = 0;
658 while (b < hdr_size && (n = php_stream_read(stream, (char*)&font[b], hdr_size - b)) > 0) {
659 b += n;
660 }
661
662 if (n <= 0) {
663 efree(font);
664 if (php_stream_eof(stream)) {
665 php_error_docref(NULL, E_WARNING, "End of file while reading header");
666 } else {
667 php_error_docref(NULL, E_WARNING, "Error while reading header");
668 }
669 php_stream_close(stream);
670 RETURN_FALSE;
671 }
672 i = php_stream_tell(stream);
673 php_stream_seek(stream, 0, SEEK_END);
674 body_size_check = php_stream_tell(stream) - hdr_size;
675 php_stream_seek(stream, i, SEEK_SET);
676
677 if (overflow2(font->nchars, font->h) || overflow2(font->nchars * font->h, font->w )) {
678 php_error_docref(NULL, E_WARNING, "Error reading font, invalid font header");
679 efree(font);
680 php_stream_close(stream);
681 RETURN_FALSE;
682 }
683
684 body_size = font->w * font->h * font->nchars;
685 if (body_size != body_size_check) {
686 font->w = FLIPWORD(font->w);
687 font->h = FLIPWORD(font->h);
688 font->nchars = FLIPWORD(font->nchars);
689 if (overflow2(font->nchars, font->h) || overflow2(font->nchars * font->h, font->w )) {
690 php_error_docref(NULL, E_WARNING, "Error reading font, invalid font header");
691 efree(font);
692 php_stream_close(stream);
693 RETURN_FALSE;
694 }
695 body_size = font->w * font->h * font->nchars;
696 }
697
698 if (body_size != body_size_check) {
699 php_error_docref(NULL, E_WARNING, "Error reading font");
700 efree(font);
701 php_stream_close(stream);
702 RETURN_FALSE;
703 }
704
705 ZEND_ASSERT(body_size > 0);
706 font->data = emalloc(body_size);
707 b = 0;
708 while (b < body_size && (n = php_stream_read(stream, &font->data[b], body_size - b)) > 0) {
709 b += n;
710 }
711
712 if (n <= 0) {
713 efree(font->data);
714 efree(font);
715 if (php_stream_eof(stream)) {
716 php_error_docref(NULL, E_WARNING, "End of file while reading body");
717 } else {
718 php_error_docref(NULL, E_WARNING, "Error while reading body");
719 }
720 php_stream_close(stream);
721 RETURN_FALSE;
722 }
723 php_stream_close(stream);
724
725 ind = zend_list_insert(font, le_gd_font);
726
727 /* Adding 5 to the font index so we will never have font indices
728 * that overlap with the old fonts (with indices 1-5). The first
729 * list index given out is always 1.
730 */
731 RETURN_LONG(Z_RES_HANDLE_P(ind) + 5);
732 }
733 /* }}} */
734
735 /* {{{ Set the line drawing styles for use with imageline and IMG_COLOR_STYLED. */
PHP_FUNCTION(imagesetstyle)736 PHP_FUNCTION(imagesetstyle)
737 {
738 zval *IM, *styles, *item;
739 gdImagePtr im;
740 int *stylearr;
741 int index = 0;
742 uint32_t num_styles;
743
744 if (zend_parse_parameters(ZEND_NUM_ARGS(), "Oa", &IM, gd_image_ce, &styles) == FAILURE) {
745 RETURN_THROWS();
746 }
747
748 im = php_gd_libgdimageptr_from_zval_p(IM);
749
750 num_styles = zend_hash_num_elements(Z_ARRVAL_P(styles));
751 if (num_styles == 0) {
752 zend_argument_value_error(2, "cannot be empty");
753 RETURN_THROWS();
754 }
755
756 /* copy the style values in the stylearr */
757 stylearr = safe_emalloc(sizeof(int), num_styles, 0);
758
759 ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(styles), item) {
760 stylearr[index++] = zval_get_long(item);
761 } ZEND_HASH_FOREACH_END();
762
763 gdImageSetStyle(im, stylearr, index);
764
765 efree(stylearr);
766
767 RETURN_TRUE;
768 }
769 /* }}} */
770
771 /* {{{ Create a new true color image */
PHP_FUNCTION(imagecreatetruecolor)772 PHP_FUNCTION(imagecreatetruecolor)
773 {
774 zend_long x_size, y_size;
775 gdImagePtr im;
776
777 if (zend_parse_parameters(ZEND_NUM_ARGS(), "ll", &x_size, &y_size) == FAILURE) {
778 RETURN_THROWS();
779 }
780
781 if (x_size <= 0 || x_size >= INT_MAX) {
782 zend_argument_value_error(1, "must be greater than 0");
783 RETURN_THROWS();
784 }
785
786 if (y_size <= 0 || y_size >= INT_MAX) {
787 zend_argument_value_error(2, "must be greater than 0");
788 RETURN_THROWS();
789 }
790
791 im = gdImageCreateTrueColor(x_size, y_size);
792
793 if (!im) {
794 RETURN_FALSE;
795 }
796
797 php_gd_assign_libgdimageptr_as_extgdimage(return_value, im);
798 }
799 /* }}} */
800
801 /* {{{ return true if the image uses truecolor */
PHP_FUNCTION(imageistruecolor)802 PHP_FUNCTION(imageistruecolor)
803 {
804 zval *IM;
805 gdImagePtr im;
806
807 if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &IM, gd_image_ce) == FAILURE) {
808 RETURN_THROWS();
809 }
810
811 im = php_gd_libgdimageptr_from_zval_p(IM);
812
813 RETURN_BOOL(im->trueColor);
814 }
815 /* }}} */
816
817 /* {{{ Convert a true color image to a palette based image with a number of colors, optionally using dithering. */
PHP_FUNCTION(imagetruecolortopalette)818 PHP_FUNCTION(imagetruecolortopalette)
819 {
820 zval *IM;
821 zend_bool dither;
822 zend_long ncolors;
823 gdImagePtr im;
824
825 if (zend_parse_parameters(ZEND_NUM_ARGS(), "Obl", &IM, gd_image_ce, &dither, &ncolors) == FAILURE) {
826 RETURN_THROWS();
827 }
828
829 im = php_gd_libgdimageptr_from_zval_p(IM);
830
831 if (ncolors <= 0 || ZEND_LONG_INT_OVFL(ncolors)) {
832 zend_argument_value_error(3, "must be greater than 0 and less than %d", INT_MAX);
833 RETURN_THROWS();
834 }
835
836 if (gdImageTrueColorToPalette(im, dither, (int)ncolors)) {
837 RETURN_TRUE;
838 } else {
839 php_error_docref(NULL, E_WARNING, "Couldn't convert to palette");
840 RETURN_FALSE;
841 }
842 }
843 /* }}} */
844
845 /* {{{ Convert a palette based image to a true color image. */
PHP_FUNCTION(imagepalettetotruecolor)846 PHP_FUNCTION(imagepalettetotruecolor)
847 {
848 zval *IM;
849 gdImagePtr im;
850
851 if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &IM, gd_image_ce) == FAILURE) {
852 RETURN_THROWS();
853 }
854
855 im = php_gd_libgdimageptr_from_zval_p(IM);
856
857 if (gdImagePaletteToTrueColor(im) == 0) {
858 RETURN_FALSE;
859 }
860
861 RETURN_TRUE;
862 }
863 /* }}} */
864
865 /* {{{ Makes the colors of the palette version of an image more closely match the true color version */
PHP_FUNCTION(imagecolormatch)866 PHP_FUNCTION(imagecolormatch)
867 {
868 zval *IM1, *IM2;
869 gdImagePtr im1, im2;
870 int result;
871
872 if (zend_parse_parameters(ZEND_NUM_ARGS(), "OO", &IM1, gd_image_ce, &IM2, gd_image_ce) == FAILURE) {
873 RETURN_THROWS();
874 }
875
876 im1 = php_gd_libgdimageptr_from_zval_p(IM1);
877 im2 = php_gd_libgdimageptr_from_zval_p(IM2);
878
879 result = gdImageColorMatch(im1, im2);
880 switch (result) {
881 case -1:
882 zend_argument_value_error(1, "must be TrueColor");
883 RETURN_THROWS();
884 break;
885 case -2:
886 zend_argument_value_error(2, "must be Palette");
887 RETURN_THROWS();
888 break;
889 case -3:
890 zend_argument_value_error(2, "must be the same size as argument #1 ($im1)");
891 RETURN_THROWS();
892 break;
893 case -4:
894 zend_argument_value_error(2, "must have at least one color");
895 RETURN_THROWS();
896 break;
897 }
898
899 RETURN_TRUE;
900 }
901 /* }}} */
902
903 /* {{{ Set line thickness for drawing lines, ellipses, rectangles, polygons etc. */
PHP_FUNCTION(imagesetthickness)904 PHP_FUNCTION(imagesetthickness)
905 {
906 zval *IM;
907 zend_long thick;
908 gdImagePtr im;
909
910 if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ol", &IM, gd_image_ce, &thick) == FAILURE) {
911 RETURN_THROWS();
912 }
913
914 im = php_gd_libgdimageptr_from_zval_p(IM);
915
916 gdImageSetThickness(im, thick);
917
918 RETURN_TRUE;
919 }
920 /* }}} */
921
922 /* {{{ Draw an ellipse */
PHP_FUNCTION(imagefilledellipse)923 PHP_FUNCTION(imagefilledellipse)
924 {
925 zval *IM;
926 zend_long cx, cy, w, h, color;
927 gdImagePtr im;
928
929 if (zend_parse_parameters(ZEND_NUM_ARGS(), "Olllll", &IM, gd_image_ce, &cx, &cy, &w, &h, &color) == FAILURE) {
930 RETURN_THROWS();
931 }
932
933 im = php_gd_libgdimageptr_from_zval_p(IM);
934
935 gdImageFilledEllipse(im, cx, cy, w, h, color);
936 RETURN_TRUE;
937 }
938 /* }}} */
939
940 /* {{{ Draw a filled partial ellipse */
PHP_FUNCTION(imagefilledarc)941 PHP_FUNCTION(imagefilledarc)
942 {
943 zval *IM;
944 zend_long cx, cy, w, h, ST, E, col, style;
945 gdImagePtr im;
946 int e, st;
947
948 if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ollllllll", &IM, gd_image_ce, &cx, &cy, &w, &h, &ST, &E, &col, &style) == FAILURE) {
949 RETURN_THROWS();
950 }
951
952 im = php_gd_libgdimageptr_from_zval_p(IM);
953
954 e = E;
955 if (e < 0) {
956 e %= 360;
957 }
958
959 st = ST;
960 if (st < 0) {
961 st %= 360;
962 }
963
964 gdImageFilledArc(im, cx, cy, w, h, st, e, col, style);
965
966 RETURN_TRUE;
967 }
968 /* }}} */
969
970 /* {{{ Turn alpha blending mode on or off for the given image */
PHP_FUNCTION(imagealphablending)971 PHP_FUNCTION(imagealphablending)
972 {
973 zval *IM;
974 zend_bool blend;
975 gdImagePtr im;
976
977 if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ob", &IM, gd_image_ce, &blend) == FAILURE) {
978 RETURN_THROWS();
979 }
980
981 im = php_gd_libgdimageptr_from_zval_p(IM);
982
983 gdImageAlphaBlending(im, blend);
984
985 RETURN_TRUE;
986 }
987 /* }}} */
988
989 /* {{{ Include alpha channel to a saved image */
PHP_FUNCTION(imagesavealpha)990 PHP_FUNCTION(imagesavealpha)
991 {
992 zval *IM;
993 zend_bool save;
994 gdImagePtr im;
995
996 if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ob", &IM, gd_image_ce, &save) == FAILURE) {
997 RETURN_THROWS();
998 }
999
1000 im = php_gd_libgdimageptr_from_zval_p(IM);
1001
1002 gdImageSaveAlpha(im, save);
1003
1004 RETURN_TRUE;
1005 }
1006 /* }}} */
1007
1008 /* {{{ Set the alpha blending flag to use the bundled libgd layering effects */
PHP_FUNCTION(imagelayereffect)1009 PHP_FUNCTION(imagelayereffect)
1010 {
1011 zval *IM;
1012 zend_long effect;
1013 gdImagePtr im;
1014
1015 if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ol", &IM, gd_image_ce, &effect) == FAILURE) {
1016 RETURN_THROWS();
1017 }
1018
1019 im = php_gd_libgdimageptr_from_zval_p(IM);
1020
1021 gdImageAlphaBlending(im, effect);
1022
1023 RETURN_TRUE;
1024 }
1025 /* }}} */
1026
1027 #define CHECK_RGBA_RANGE(component, name, argument_number) \
1028 if (component < 0 || component > gd##name##Max) { \
1029 zend_argument_value_error(argument_number, "must be between 0 and %d (inclusive)", gd##name##Max); \
1030 RETURN_THROWS(); \
1031 }
1032
1033 /* {{{ Allocate a color with an alpha level. Works for true color and palette based images */
PHP_FUNCTION(imagecolorallocatealpha)1034 PHP_FUNCTION(imagecolorallocatealpha)
1035 {
1036 zval *IM;
1037 zend_long red, green, blue, alpha;
1038 gdImagePtr im;
1039 int ct = (-1);
1040
1041 if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ollll", &IM, gd_image_ce, &red, &green, &blue, &alpha) == FAILURE) {
1042 RETURN_THROWS();
1043 }
1044
1045 im = php_gd_libgdimageptr_from_zval_p(IM);
1046
1047 CHECK_RGBA_RANGE(red, Red, 2);
1048 CHECK_RGBA_RANGE(green, Green, 3);
1049 CHECK_RGBA_RANGE(blue, Blue, 4);
1050 CHECK_RGBA_RANGE(alpha, Alpha, 5);
1051
1052 ct = gdImageColorAllocateAlpha(im, red, green, blue, alpha);
1053 if (ct < 0) {
1054 RETURN_FALSE;
1055 }
1056 RETURN_LONG((zend_long)ct);
1057 }
1058 /* }}} */
1059
1060 /* {{{ Resolve/Allocate a colour with an alpha level. Works for true colour and palette based images */
PHP_FUNCTION(imagecolorresolvealpha)1061 PHP_FUNCTION(imagecolorresolvealpha)
1062 {
1063 zval *IM;
1064 zend_long red, green, blue, alpha;
1065 gdImagePtr im;
1066
1067 if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ollll", &IM, gd_image_ce, &red, &green, &blue, &alpha) == FAILURE) {
1068 RETURN_THROWS();
1069 }
1070
1071 im = php_gd_libgdimageptr_from_zval_p(IM);
1072
1073 CHECK_RGBA_RANGE(red, Red, 2);
1074 CHECK_RGBA_RANGE(green, Green, 3);
1075 CHECK_RGBA_RANGE(blue, Blue, 4);
1076 CHECK_RGBA_RANGE(alpha, Alpha, 5);
1077
1078 RETURN_LONG(gdImageColorResolveAlpha(im, red, green, blue, alpha));
1079 }
1080 /* }}} */
1081
1082 /* {{{ Find the closest matching colour with alpha transparency */
PHP_FUNCTION(imagecolorclosestalpha)1083 PHP_FUNCTION(imagecolorclosestalpha)
1084 {
1085 zval *IM;
1086 zend_long red, green, blue, alpha;
1087 gdImagePtr im;
1088
1089 if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ollll", &IM, gd_image_ce, &red, &green, &blue, &alpha) == FAILURE) {
1090 RETURN_THROWS();
1091 }
1092
1093 im = php_gd_libgdimageptr_from_zval_p(IM);
1094
1095 CHECK_RGBA_RANGE(red, Red, 2);
1096 CHECK_RGBA_RANGE(green, Green, 3);
1097 CHECK_RGBA_RANGE(blue, Blue, 4);
1098 CHECK_RGBA_RANGE(alpha, Alpha, 5);
1099
1100 RETURN_LONG(gdImageColorClosestAlpha(im, red, green, blue, alpha));
1101 }
1102 /* }}} */
1103
1104 /* {{{ Find exact match for colour with transparency */
PHP_FUNCTION(imagecolorexactalpha)1105 PHP_FUNCTION(imagecolorexactalpha)
1106 {
1107 zval *IM;
1108 zend_long red, green, blue, alpha;
1109 gdImagePtr im;
1110
1111 if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ollll", &IM, gd_image_ce, &red, &green, &blue, &alpha) == FAILURE) {
1112 RETURN_THROWS();
1113 }
1114
1115 im = php_gd_libgdimageptr_from_zval_p(IM);
1116
1117 CHECK_RGBA_RANGE(red, Red, 2);
1118 CHECK_RGBA_RANGE(green, Green, 3);
1119 CHECK_RGBA_RANGE(blue, Blue, 4);
1120 CHECK_RGBA_RANGE(alpha, Alpha, 5);
1121
1122 RETURN_LONG(gdImageColorExactAlpha(im, red, green, blue, alpha));
1123 }
1124 /* }}} */
1125
1126 /* {{{ Copy and resize part of an image using resampling to help ensure clarity */
PHP_FUNCTION(imagecopyresampled)1127 PHP_FUNCTION(imagecopyresampled)
1128 {
1129 zval *SIM, *DIM;
1130 zend_long SX, SY, SW, SH, DX, DY, DW, DH;
1131 gdImagePtr im_dst, im_src;
1132 int srcH, srcW, dstH, dstW, srcY, srcX, dstY, dstX;
1133
1134 if (zend_parse_parameters(ZEND_NUM_ARGS(), "OOllllllll", &DIM, gd_image_ce, &SIM, gd_image_ce, &DX, &DY, &SX, &SY, &DW, &DH, &SW, &SH) == FAILURE) {
1135 RETURN_THROWS();
1136 }
1137
1138 im_src = php_gd_libgdimageptr_from_zval_p(SIM);
1139 im_dst = php_gd_libgdimageptr_from_zval_p(DIM);
1140
1141 srcX = SX;
1142 srcY = SY;
1143 srcH = SH;
1144 srcW = SW;
1145 dstX = DX;
1146 dstY = DY;
1147 dstH = DH;
1148 dstW = DW;
1149
1150 gdImageCopyResampled(im_dst, im_src, dstX, dstY, srcX, srcY, dstW, dstH, srcW, srcH);
1151
1152 RETURN_TRUE;
1153 }
1154 /* }}} */
1155
1156 #ifdef PHP_WIN32
1157 /* {{{ Grab a window or its client area using a windows handle (HWND property in COM instance) */
PHP_FUNCTION(imagegrabwindow)1158 PHP_FUNCTION(imagegrabwindow)
1159 {
1160 HWND window;
1161 zend_bool client_area = 0;
1162 RECT rc = {0};
1163 int Width, Height;
1164 HDC hdc;
1165 HDC memDC;
1166 HBITMAP memBM;
1167 HBITMAP hOld;
1168 zend_long lwindow_handle;
1169 gdImagePtr im = NULL;
1170
1171 if (zend_parse_parameters(ZEND_NUM_ARGS(), "l|b", &lwindow_handle, &client_area) == FAILURE) {
1172 RETURN_THROWS();
1173 }
1174
1175 window = (HWND) lwindow_handle;
1176
1177 if (!IsWindow(window)) {
1178 php_error_docref(NULL, E_NOTICE, "Invalid window handle");
1179 RETURN_FALSE;
1180 }
1181
1182 hdc = GetDC(0);
1183
1184 if (client_area) {
1185 GetClientRect(window, &rc);
1186 Width = rc.right;
1187 Height = rc.bottom;
1188 } else {
1189 GetWindowRect(window, &rc);
1190 Width = rc.right - rc.left;
1191 Height = rc.bottom - rc.top;
1192 }
1193
1194 Width = (Width/4)*4;
1195
1196 memDC = CreateCompatibleDC(hdc);
1197 memBM = CreateCompatibleBitmap(hdc, Width, Height);
1198 hOld = (HBITMAP) SelectObject (memDC, memBM);
1199
1200 PrintWindow(window, memDC, (UINT) client_area);
1201
1202 im = gdImageCreateTrueColor(Width, Height);
1203 if (im) {
1204 int x,y;
1205 for (y=0; y <= Height; y++) {
1206 for (x=0; x <= Width; x++) {
1207 int c = GetPixel(memDC, x,y);
1208 gdImageSetPixel(im, x, y, gdTrueColor(GetRValue(c), GetGValue(c), GetBValue(c)));
1209 }
1210 }
1211 }
1212
1213 SelectObject(memDC,hOld);
1214 DeleteObject(memBM);
1215 DeleteDC(memDC);
1216 ReleaseDC( 0, hdc );
1217
1218 if (!im) {
1219 RETURN_FALSE;
1220 }
1221
1222 php_gd_assign_libgdimageptr_as_extgdimage(return_value, im);
1223 }
1224 /* }}} */
1225
1226 /* {{{ Grab a screenshot */
PHP_FUNCTION(imagegrabscreen)1227 PHP_FUNCTION(imagegrabscreen)
1228 {
1229 HWND window = GetDesktopWindow();
1230 RECT rc = {0};
1231 int Width, Height;
1232 HDC hdc;
1233 HDC memDC;
1234 HBITMAP memBM;
1235 HBITMAP hOld;
1236 gdImagePtr im;
1237 hdc = GetDC(0);
1238
1239 if (zend_parse_parameters_none() == FAILURE) {
1240 RETURN_THROWS();
1241 }
1242
1243 if (!hdc) {
1244 RETURN_FALSE;
1245 }
1246
1247 GetWindowRect(window, &rc);
1248 Width = rc.right - rc.left;
1249 Height = rc.bottom - rc.top;
1250
1251 Width = (Width/4)*4;
1252
1253 memDC = CreateCompatibleDC(hdc);
1254 memBM = CreateCompatibleBitmap(hdc, Width, Height);
1255 hOld = (HBITMAP) SelectObject (memDC, memBM);
1256 BitBlt( memDC, 0, 0, Width, Height , hdc, rc.left, rc.top , SRCCOPY );
1257
1258 im = gdImageCreateTrueColor(Width, Height);
1259 if (im) {
1260 int x,y;
1261 for (y=0; y <= Height; y++) {
1262 for (x=0; x <= Width; x++) {
1263 int c = GetPixel(memDC, x,y);
1264 gdImageSetPixel(im, x, y, gdTrueColor(GetRValue(c), GetGValue(c), GetBValue(c)));
1265 }
1266 }
1267 }
1268
1269 SelectObject(memDC,hOld);
1270 DeleteObject(memBM);
1271 DeleteDC(memDC);
1272 ReleaseDC( 0, hdc );
1273
1274 if (!im) {
1275 RETURN_FALSE;
1276 }
1277
1278 php_gd_assign_libgdimageptr_as_extgdimage(return_value, im);
1279 }
1280 /* }}} */
1281 #endif /* PHP_WIN32 */
1282
1283 /* {{{ Rotate an image using a custom angle */
PHP_FUNCTION(imagerotate)1284 PHP_FUNCTION(imagerotate)
1285 {
1286 zval *SIM;
1287 gdImagePtr im_dst, im_src;
1288 double degrees;
1289 zend_long color;
1290 zend_bool ignoretransparent = 0;
1291
1292 if (zend_parse_parameters(ZEND_NUM_ARGS(), "Odl|b", &SIM, gd_image_ce, °rees, &color, &ignoretransparent) == FAILURE) {
1293 RETURN_THROWS();
1294 }
1295
1296 im_src = php_gd_libgdimageptr_from_zval_p(SIM);
1297 im_dst = gdImageRotateInterpolated(im_src, (const float)degrees, color);
1298
1299 if (im_dst == NULL) {
1300 RETURN_FALSE;
1301 }
1302
1303 php_gd_assign_libgdimageptr_as_extgdimage(return_value, im_dst);
1304 }
1305 /* }}} */
1306
1307 /* {{{ Set the tile image to $tile when filling $image with the "IMG_COLOR_TILED" color */
PHP_FUNCTION(imagesettile)1308 PHP_FUNCTION(imagesettile)
1309 {
1310 zval *IM, *TILE;
1311 gdImagePtr im, tile;
1312
1313 if (zend_parse_parameters(ZEND_NUM_ARGS(), "OO", &IM, gd_image_ce, &TILE, gd_image_ce) == FAILURE) {
1314 RETURN_THROWS();
1315 }
1316
1317 im = php_gd_libgdimageptr_from_zval_p(IM);
1318 tile = php_gd_libgdimageptr_from_zval_p(TILE);
1319
1320 gdImageSetTile(im, tile);
1321
1322 RETURN_TRUE;
1323 }
1324 /* }}} */
1325
1326 /* {{{ Set the brush image to $brush when filling $image with the "IMG_COLOR_BRUSHED" color */
PHP_FUNCTION(imagesetbrush)1327 PHP_FUNCTION(imagesetbrush)
1328 {
1329 zval *IM, *TILE;
1330 gdImagePtr im, tile;
1331
1332 if (zend_parse_parameters(ZEND_NUM_ARGS(), "OO", &IM, gd_image_ce, &TILE, gd_image_ce) == FAILURE) {
1333 RETURN_THROWS();
1334 }
1335
1336 im = php_gd_libgdimageptr_from_zval_p(IM);
1337 tile = php_gd_libgdimageptr_from_zval_p(TILE);
1338
1339 gdImageSetBrush(im, tile);
1340
1341 RETURN_TRUE;
1342 }
1343 /* }}} */
1344
1345 /* {{{ Create a new image */
PHP_FUNCTION(imagecreate)1346 PHP_FUNCTION(imagecreate)
1347 {
1348 zend_long x_size, y_size;
1349 gdImagePtr im;
1350
1351 if (zend_parse_parameters(ZEND_NUM_ARGS(), "ll", &x_size, &y_size) == FAILURE) {
1352 RETURN_THROWS();
1353 }
1354
1355 if (x_size <= 0 || x_size >= INT_MAX) {
1356 zend_argument_value_error(1, "must be greater than 0");
1357 RETURN_THROWS();
1358 }
1359
1360 if (y_size <= 0 || y_size >= INT_MAX) {
1361 zend_argument_value_error(2, "must be greater than 0");
1362 RETURN_THROWS();
1363 }
1364
1365 im = gdImageCreate(x_size, y_size);
1366
1367 if (!im) {
1368 RETURN_FALSE;
1369 }
1370
1371 php_gd_assign_libgdimageptr_as_extgdimage(return_value, im);
1372 }
1373 /* }}} */
1374
1375 /* {{{ Return the types of images supported in a bitfield - 1=GIF, 2=JPEG, 4=PNG, 8=WBMP, 16=XPM */
PHP_FUNCTION(imagetypes)1376 PHP_FUNCTION(imagetypes)
1377 {
1378 int ret = 0;
1379 ret = PHP_IMG_GIF;
1380 #ifdef HAVE_GD_JPG
1381 ret |= PHP_IMG_JPG;
1382 #endif
1383 #ifdef HAVE_GD_PNG
1384 ret |= PHP_IMG_PNG;
1385 #endif
1386 ret |= PHP_IMG_WBMP;
1387 #ifdef HAVE_GD_XPM
1388 ret |= PHP_IMG_XPM;
1389 #endif
1390 #ifdef HAVE_GD_WEBP
1391 ret |= PHP_IMG_WEBP;
1392 #endif
1393 #ifdef HAVE_GD_BMP
1394 ret |= PHP_IMG_BMP;
1395 #endif
1396 #ifdef HAVE_GD_TGA
1397 ret |= PHP_IMG_TGA;
1398 #endif
1399
1400 if (zend_parse_parameters_none() == FAILURE) {
1401 RETURN_THROWS();
1402 }
1403
1404 RETURN_LONG(ret);
1405 }
1406 /* }}} */
1407
1408 /* {{{ _php_ctx_getmbi */
1409
_php_ctx_getmbi(gdIOCtx * ctx)1410 static int _php_ctx_getmbi(gdIOCtx *ctx)
1411 {
1412 int i, mbi = 0;
1413
1414 do {
1415 i = (ctx->getC)(ctx);
1416 if (i < 0) {
1417 return -1;
1418 }
1419 mbi = (mbi << 7) | (i & 0x7f);
1420 } while (i & 0x80);
1421
1422 return mbi;
1423 }
1424 /* }}} */
1425
1426 /* {{{ _php_image_type */
1427 static const char php_sig_gd2[3] = {'g', 'd', '2'};
1428
_php_image_type(char data[12])1429 static int _php_image_type (char data[12])
1430 {
1431 /* Based on ext/standard/image.c */
1432
1433 if (data == NULL) {
1434 return -1;
1435 }
1436
1437 if (!memcmp(data, php_sig_gd2, sizeof(php_sig_gd2))) {
1438 return PHP_GDIMG_TYPE_GD2;
1439 } else if (!memcmp(data, php_sig_jpg, sizeof(php_sig_jpg))) {
1440 return PHP_GDIMG_TYPE_JPG;
1441 } else if (!memcmp(data, php_sig_png, sizeof(php_sig_png))) {
1442 return PHP_GDIMG_TYPE_PNG;
1443 } else if (!memcmp(data, php_sig_gif, sizeof(php_sig_gif))) {
1444 return PHP_GDIMG_TYPE_GIF;
1445 } else if (!memcmp(data, php_sig_bmp, sizeof(php_sig_bmp))) {
1446 return PHP_GDIMG_TYPE_BMP;
1447 } else if(!memcmp(data, php_sig_riff, sizeof(php_sig_riff)) && !memcmp(data + sizeof(php_sig_riff) + sizeof(uint32_t), php_sig_webp, sizeof(php_sig_webp))) {
1448 return PHP_GDIMG_TYPE_WEBP;
1449 }
1450 else {
1451 gdIOCtx *io_ctx;
1452 io_ctx = gdNewDynamicCtxEx(8, data, 0);
1453 if (io_ctx) {
1454 if (_php_ctx_getmbi(io_ctx) == 0 && _php_ctx_getmbi(io_ctx) >= 0) {
1455 io_ctx->gd_free(io_ctx);
1456 return PHP_GDIMG_TYPE_WBM;
1457 } else {
1458 io_ctx->gd_free(io_ctx);
1459 }
1460 }
1461 }
1462 return -1;
1463 }
1464 /* }}} */
1465
1466 /* {{{ _php_image_create_from_string */
_php_image_create_from_string(zend_string * data,char * tn,gdImagePtr (* ioctx_func_p)())1467 gdImagePtr _php_image_create_from_string(zend_string *data, char *tn, gdImagePtr (*ioctx_func_p)())
1468 {
1469 gdImagePtr im;
1470 gdIOCtx *io_ctx;
1471
1472 io_ctx = gdNewDynamicCtxEx(ZSTR_LEN(data), ZSTR_VAL(data), 0);
1473
1474 if (!io_ctx) {
1475 return NULL;
1476 }
1477
1478 im = (*ioctx_func_p)(io_ctx);
1479 if (!im) {
1480 php_error_docref(NULL, E_WARNING, "Passed data is not in \"%s\" format", tn);
1481 io_ctx->gd_free(io_ctx);
1482 return NULL;
1483 }
1484
1485 io_ctx->gd_free(io_ctx);
1486
1487 return im;
1488 }
1489 /* }}} */
1490
1491 /* {{{ Create a new image from the image stream in the string */
PHP_FUNCTION(imagecreatefromstring)1492 PHP_FUNCTION(imagecreatefromstring)
1493 {
1494 zend_string *data;
1495 gdImagePtr im;
1496 int imtype;
1497 char sig[12];
1498
1499 if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &data) == FAILURE) {
1500 RETURN_THROWS();
1501 }
1502
1503 if (ZSTR_LEN(data) < sizeof(sig)) {
1504 /* Handle this the same way as an unknown image type. */
1505 php_error_docref(NULL, E_WARNING, "Data is not in a recognized format");
1506 RETURN_FALSE;
1507 }
1508
1509 memcpy(sig, ZSTR_VAL(data), sizeof(sig));
1510
1511 imtype = _php_image_type(sig);
1512
1513 switch (imtype) {
1514 case PHP_GDIMG_TYPE_JPG:
1515 #ifdef HAVE_GD_JPG
1516 im = _php_image_create_from_string(data, "JPEG", gdImageCreateFromJpegCtx);
1517 #else
1518 php_error_docref(NULL, E_WARNING, "No JPEG support in this PHP build");
1519 RETURN_FALSE;
1520 #endif
1521 break;
1522
1523 case PHP_GDIMG_TYPE_PNG:
1524 #ifdef HAVE_GD_PNG
1525 im = _php_image_create_from_string(data, "PNG", gdImageCreateFromPngCtx);
1526 #else
1527 php_error_docref(NULL, E_WARNING, "No PNG support in this PHP build");
1528 RETURN_FALSE;
1529 #endif
1530 break;
1531
1532 case PHP_GDIMG_TYPE_GIF:
1533 im = _php_image_create_from_string(data, "GIF", gdImageCreateFromGifCtx);
1534 break;
1535
1536 case PHP_GDIMG_TYPE_WBM:
1537 im = _php_image_create_from_string(data, "WBMP", gdImageCreateFromWBMPCtx);
1538 break;
1539
1540 case PHP_GDIMG_TYPE_GD2:
1541 im = _php_image_create_from_string(data, "GD2", gdImageCreateFromGd2Ctx);
1542 break;
1543
1544 case PHP_GDIMG_TYPE_BMP:
1545 im = _php_image_create_from_string(data, "BMP", gdImageCreateFromBmpCtx);
1546 break;
1547
1548 case PHP_GDIMG_TYPE_WEBP:
1549 #ifdef HAVE_GD_WEBP
1550 im = _php_image_create_from_string(data, "WEBP", gdImageCreateFromWebpCtx);
1551 break;
1552 #else
1553 php_error_docref(NULL, E_WARNING, "No WEBP support in this PHP build");
1554 RETURN_FALSE;
1555 #endif
1556
1557 default:
1558 php_error_docref(NULL, E_WARNING, "Data is not in a recognized format");
1559 RETURN_FALSE;
1560 }
1561
1562 if (!im) {
1563 php_error_docref(NULL, E_WARNING, "Couldn't create GD Image Stream out of Data");
1564 RETURN_FALSE;
1565 }
1566
1567 php_gd_assign_libgdimageptr_as_extgdimage(return_value, im);
1568 }
1569 /* }}} */
1570
1571 /* {{{ _php_image_create_from */
_php_image_create_from(INTERNAL_FUNCTION_PARAMETERS,int image_type,char * tn,gdImagePtr (* func_p)(),gdImagePtr (* ioctx_func_p)())1572 static void _php_image_create_from(INTERNAL_FUNCTION_PARAMETERS, int image_type, char *tn, gdImagePtr (*func_p)(), gdImagePtr (*ioctx_func_p)())
1573 {
1574 char *file;
1575 size_t file_len;
1576 zend_long srcx, srcy, width, height;
1577 gdImagePtr im = NULL;
1578 php_stream *stream;
1579 FILE * fp = NULL;
1580 #ifdef HAVE_GD_JPG
1581 long ignore_warning;
1582 #endif
1583
1584 if (image_type == PHP_GDIMG_TYPE_GD2PART) {
1585 if (zend_parse_parameters(ZEND_NUM_ARGS(), "pllll", &file, &file_len, &srcx, &srcy, &width, &height) == FAILURE) {
1586 RETURN_THROWS();
1587 }
1588
1589 if (width < 1) {
1590 zend_argument_value_error(4, "must be greater than or equal to 1");
1591 RETURN_THROWS();
1592 }
1593
1594 if (height < 1) {
1595 zend_argument_value_error(5, "must be greater than or equal to 1");
1596 RETURN_THROWS();
1597 }
1598
1599 } else {
1600 if (zend_parse_parameters(ZEND_NUM_ARGS(), "p", &file, &file_len) == FAILURE) {
1601 RETURN_THROWS();
1602 }
1603 }
1604
1605
1606 stream = php_stream_open_wrapper(file, "rb", REPORT_ERRORS|IGNORE_PATH|IGNORE_URL_WIN, NULL);
1607 if (stream == NULL) {
1608 RETURN_FALSE;
1609 }
1610
1611 /* try and avoid allocating a FILE* if the stream is not naturally a FILE* */
1612 if (php_stream_is(stream, PHP_STREAM_IS_STDIO)) {
1613 if (FAILURE == php_stream_cast(stream, PHP_STREAM_AS_STDIO, (void**)&fp, REPORT_ERRORS)) {
1614 goto out_err;
1615 }
1616 } else if (ioctx_func_p) {
1617 /* we can create an io context */
1618 gdIOCtx* io_ctx;
1619 zend_string *buff;
1620 char *pstr;
1621
1622 buff = php_stream_copy_to_mem(stream, PHP_STREAM_COPY_ALL, 0);
1623
1624 if (!buff) {
1625 php_error_docref(NULL, E_WARNING,"Cannot read image data");
1626 goto out_err;
1627 }
1628
1629 /* needs to be malloc (persistent) - GD will free() it later */
1630 pstr = pestrndup(ZSTR_VAL(buff), ZSTR_LEN(buff), 1);
1631 io_ctx = gdNewDynamicCtxEx(ZSTR_LEN(buff), pstr, 0);
1632 if (!io_ctx) {
1633 pefree(pstr, 1);
1634 zend_string_release_ex(buff, 0);
1635 php_error_docref(NULL, E_WARNING,"Cannot allocate GD IO context");
1636 goto out_err;
1637 }
1638
1639 if (image_type == PHP_GDIMG_TYPE_GD2PART) {
1640 im = (*ioctx_func_p)(io_ctx, srcx, srcy, width, height);
1641 } else {
1642 im = (*ioctx_func_p)(io_ctx);
1643 }
1644 io_ctx->gd_free(io_ctx);
1645 pefree(pstr, 1);
1646 zend_string_release_ex(buff, 0);
1647 }
1648 else if (php_stream_can_cast(stream, PHP_STREAM_AS_STDIO)) {
1649 /* try and force the stream to be FILE* */
1650 if (FAILURE == php_stream_cast(stream, PHP_STREAM_AS_STDIO | PHP_STREAM_CAST_TRY_HARD, (void **) &fp, REPORT_ERRORS)) {
1651 goto out_err;
1652 }
1653 }
1654
1655 if (!im && fp) {
1656 switch (image_type) {
1657 case PHP_GDIMG_TYPE_GD2PART:
1658 im = (*func_p)(fp, srcx, srcy, width, height);
1659 break;
1660 #ifdef HAVE_GD_XPM
1661 case PHP_GDIMG_TYPE_XPM:
1662 im = gdImageCreateFromXpm(file);
1663 break;
1664 #endif
1665
1666 #ifdef HAVE_GD_JPG
1667 case PHP_GDIMG_TYPE_JPG:
1668 ignore_warning = INI_INT("gd.jpeg_ignore_warning");
1669 im = gdImageCreateFromJpegEx(fp, ignore_warning);
1670 break;
1671 #endif
1672
1673 default:
1674 im = (*func_p)(fp);
1675 break;
1676 }
1677
1678 fflush(fp);
1679 }
1680
1681 /* register_im: */
1682 if (im) {
1683 php_stream_close(stream);
1684 php_gd_assign_libgdimageptr_as_extgdimage(return_value, im);
1685 return;
1686 }
1687
1688 php_error_docref(NULL, E_WARNING, "\"%s\" is not a valid %s file", file, tn);
1689 out_err:
1690 php_stream_close(stream);
1691 RETURN_FALSE;
1692
1693 }
1694 /* }}} */
1695
1696 /* {{{ Create a new image from GIF file or URL */
PHP_FUNCTION(imagecreatefromgif)1697 PHP_FUNCTION(imagecreatefromgif)
1698 {
1699 _php_image_create_from(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_GIF, "GIF", gdImageCreateFromGif, gdImageCreateFromGifCtx);
1700 }
1701 /* }}} */
1702
1703 #ifdef HAVE_GD_JPG
1704 /* {{{ Create a new image from JPEG file or URL */
PHP_FUNCTION(imagecreatefromjpeg)1705 PHP_FUNCTION(imagecreatefromjpeg)
1706 {
1707 _php_image_create_from(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_JPG, "JPEG", gdImageCreateFromJpeg, gdImageCreateFromJpegCtx);
1708 }
1709 /* }}} */
1710 #endif /* HAVE_GD_JPG */
1711
1712 #ifdef HAVE_GD_PNG
1713 /* {{{ Create a new image from PNG file or URL */
PHP_FUNCTION(imagecreatefrompng)1714 PHP_FUNCTION(imagecreatefrompng)
1715 {
1716 _php_image_create_from(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_PNG, "PNG", gdImageCreateFromPng, gdImageCreateFromPngCtx);
1717 }
1718 /* }}} */
1719 #endif /* HAVE_GD_PNG */
1720
1721 #ifdef HAVE_GD_WEBP
1722 /* {{{ Create a new image from WEBP file or URL */
PHP_FUNCTION(imagecreatefromwebp)1723 PHP_FUNCTION(imagecreatefromwebp)
1724 {
1725 _php_image_create_from(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_WEBP, "WEBP", gdImageCreateFromWebp, gdImageCreateFromWebpCtx);
1726 }
1727 /* }}} */
1728 #endif /* HAVE_GD_WEBP */
1729
1730 /* {{{ Create a new image from XBM file or URL */
PHP_FUNCTION(imagecreatefromxbm)1731 PHP_FUNCTION(imagecreatefromxbm)
1732 {
1733 _php_image_create_from(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_XBM, "XBM", gdImageCreateFromXbm, NULL);
1734 }
1735 /* }}} */
1736
1737 #ifdef HAVE_GD_XPM
1738 /* {{{ Create a new image from XPM file or URL */
PHP_FUNCTION(imagecreatefromxpm)1739 PHP_FUNCTION(imagecreatefromxpm)
1740 {
1741 _php_image_create_from(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_XPM, "XPM", gdImageCreateFromXpm, NULL);
1742 }
1743 /* }}} */
1744 #endif
1745
1746 /* {{{ Create a new image from WBMP file or URL */
PHP_FUNCTION(imagecreatefromwbmp)1747 PHP_FUNCTION(imagecreatefromwbmp)
1748 {
1749 _php_image_create_from(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_WBM, "WBMP", gdImageCreateFromWBMP, gdImageCreateFromWBMPCtx);
1750 }
1751 /* }}} */
1752
1753 /* {{{ Create a new image from GD file or URL */
PHP_FUNCTION(imagecreatefromgd)1754 PHP_FUNCTION(imagecreatefromgd)
1755 {
1756 _php_image_create_from(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_GD, "GD", gdImageCreateFromGd, gdImageCreateFromGdCtx);
1757 }
1758 /* }}} */
1759
1760 /* {{{ Create a new image from GD2 file or URL */
PHP_FUNCTION(imagecreatefromgd2)1761 PHP_FUNCTION(imagecreatefromgd2)
1762 {
1763 _php_image_create_from(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_GD2, "GD2", gdImageCreateFromGd2, gdImageCreateFromGd2Ctx);
1764 }
1765 /* }}} */
1766
1767 /* {{{ Create a new image from a given part of GD2 file or URL */
PHP_FUNCTION(imagecreatefromgd2part)1768 PHP_FUNCTION(imagecreatefromgd2part)
1769 {
1770 _php_image_create_from(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_GD2PART, "GD2", gdImageCreateFromGd2Part, gdImageCreateFromGd2PartCtx);
1771 }
1772 /* }}} */
1773
1774 #ifdef HAVE_GD_BMP
1775 /* {{{ Create a new image from BMP file or URL */
PHP_FUNCTION(imagecreatefrombmp)1776 PHP_FUNCTION(imagecreatefrombmp)
1777 {
1778 _php_image_create_from(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_BMP, "BMP", gdImageCreateFromBmp, gdImageCreateFromBmpCtx);
1779 }
1780 /* }}} */
1781 #endif
1782
1783 #ifdef HAVE_GD_TGA
1784 /* {{{ Create a new image from TGA file or URL */
PHP_FUNCTION(imagecreatefromtga)1785 PHP_FUNCTION(imagecreatefromtga)
1786 {
1787 _php_image_create_from(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_TGA, "TGA", gdImageCreateFromTga, gdImageCreateFromTgaCtx);
1788 }
1789 /* }}} */
1790 #endif
1791
1792 /* {{{ _php_image_output */
_php_image_output(INTERNAL_FUNCTION_PARAMETERS,int image_type,char * tn,void (* func_p)())1793 static void _php_image_output(INTERNAL_FUNCTION_PARAMETERS, int image_type, char *tn, void (*func_p)())
1794 {
1795 zval *imgind;
1796 char *file = NULL;
1797 zend_long quality = 0, type = 0;
1798 gdImagePtr im;
1799 FILE *fp;
1800 size_t file_len = 0;
1801 int argc = ZEND_NUM_ARGS();
1802 int q = -1, t = 1;
1803
1804 /* The quality parameter for gd2 stands for chunk size */
1805
1806 switch (image_type) {
1807 case PHP_GDIMG_TYPE_GD:
1808 if (zend_parse_parameters(argc, "O|p!", &imgind, gd_image_ce, &file, &file_len) == FAILURE) {
1809 RETURN_THROWS();
1810 }
1811 break;
1812 case PHP_GDIMG_TYPE_GD2:
1813 if (zend_parse_parameters(argc, "O|p!ll", &imgind, gd_image_ce, &file, &file_len, &quality, &type) == FAILURE) {
1814 RETURN_THROWS();
1815 }
1816 break;
1817 EMPTY_SWITCH_DEFAULT_CASE()
1818 }
1819
1820 im = php_gd_libgdimageptr_from_zval_p(imgind);
1821
1822 if (argc >= 3) {
1823 q = quality;
1824 if (argc == 4) {
1825 t = type;
1826 }
1827 }
1828
1829 if (file_len) {
1830 PHP_GD_CHECK_OPEN_BASEDIR(file, "Invalid filename");
1831
1832 fp = VCWD_FOPEN(file, "wb");
1833 if (!fp) {
1834 php_error_docref(NULL, E_WARNING, "Unable to open \"%s\" for writing", file);
1835 RETURN_FALSE;
1836 }
1837
1838 switch (image_type) {
1839 case PHP_GDIMG_TYPE_GD:
1840 (*func_p)(im, fp);
1841 break;
1842 case PHP_GDIMG_TYPE_GD2:
1843 if (q == -1) {
1844 q = 128;
1845 }
1846 (*func_p)(im, fp, q, t);
1847 break;
1848 EMPTY_SWITCH_DEFAULT_CASE()
1849 }
1850 fflush(fp);
1851 fclose(fp);
1852 } else {
1853 int b;
1854 FILE *tmp;
1855 char buf[4096];
1856 zend_string *path;
1857
1858 tmp = php_open_temporary_file(NULL, NULL, &path);
1859 if (tmp == NULL) {
1860 php_error_docref(NULL, E_WARNING, "Unable to open temporary file");
1861 RETURN_FALSE;
1862 }
1863
1864 switch (image_type) {
1865 case PHP_GDIMG_TYPE_GD:
1866 (*func_p)(im, tmp);
1867 break;
1868 case PHP_GDIMG_TYPE_GD2:
1869 if (q == -1) {
1870 q = 128;
1871 }
1872 (*func_p)(im, tmp, q, t);
1873 break;
1874 EMPTY_SWITCH_DEFAULT_CASE()
1875 }
1876
1877 fseek(tmp, 0, SEEK_SET);
1878
1879 while ((b = fread(buf, 1, sizeof(buf), tmp)) > 0) {
1880 php_write(buf, b);
1881 }
1882
1883 fclose(tmp);
1884 VCWD_UNLINK((const char *)ZSTR_VAL(path)); /* make sure that the temporary file is removed */
1885 zend_string_release_ex(path, 0);
1886 }
1887 RETURN_TRUE;
1888 }
1889 /* }}} */
1890
1891 /* {{{ Output XBM image to browser or file */
PHP_FUNCTION(imagexbm)1892 PHP_FUNCTION(imagexbm)
1893 {
1894 zval *imgind;
1895 char *file = NULL;
1896 size_t file_len = 0;
1897 zend_long foreground_color;
1898 zend_bool foreground_color_is_null = 1;
1899 gdImagePtr im;
1900 int i;
1901 gdIOCtx *ctx = NULL;
1902 php_stream *stream;
1903
1904 if (zend_parse_parameters(ZEND_NUM_ARGS(), "Op!|l!", &imgind, gd_image_ce, &file, &file_len, &foreground_color, &foreground_color_is_null) == FAILURE) {
1905 RETURN_THROWS();
1906 }
1907
1908 im = php_gd_libgdimageptr_from_zval_p(imgind);
1909
1910 if (file != NULL) {
1911 stream = php_stream_open_wrapper(file, "wb", REPORT_ERRORS|IGNORE_PATH|IGNORE_URL_WIN, NULL);
1912 if (stream == NULL) {
1913 RETURN_FALSE;
1914 }
1915
1916 ctx = create_stream_context(stream, 1);
1917 } else {
1918 ctx = create_output_context();
1919 }
1920
1921 if (foreground_color_is_null) {
1922 for (i=0; i < gdImageColorsTotal(im); i++) {
1923 if (!gdImageRed(im, i) && !gdImageGreen(im, i) && !gdImageBlue(im, i)) {
1924 break;
1925 }
1926 }
1927
1928 foreground_color = i;
1929 }
1930
1931 gdImageXbmCtx(im, file ? file : "", (int) foreground_color, ctx);
1932
1933 ctx->gd_free(ctx);
1934
1935 RETURN_TRUE;
1936 }
1937 /* }}} */
1938
1939 /* {{{ Output GIF image to browser or file */
PHP_FUNCTION(imagegif)1940 PHP_FUNCTION(imagegif)
1941 {
1942 _php_image_output_ctx(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_GIF, "GIF", gdImageGifCtx);
1943 }
1944 /* }}} */
1945
1946 #ifdef HAVE_GD_PNG
1947 /* {{{ Output PNG image to browser or file */
PHP_FUNCTION(imagepng)1948 PHP_FUNCTION(imagepng)
1949 {
1950 _php_image_output_ctx(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_PNG, "PNG", gdImagePngCtxEx);
1951 }
1952 /* }}} */
1953 #endif /* HAVE_GD_PNG */
1954
1955 #ifdef HAVE_GD_WEBP
1956 /* {{{ Output WEBP image to browser or file */
PHP_FUNCTION(imagewebp)1957 PHP_FUNCTION(imagewebp)
1958 {
1959 _php_image_output_ctx(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_WEBP, "WEBP", gdImageWebpCtx);
1960 }
1961 /* }}} */
1962 #endif /* HAVE_GD_WEBP */
1963
1964 #ifdef HAVE_GD_JPG
1965 /* {{{ Output JPEG image to browser or file */
PHP_FUNCTION(imagejpeg)1966 PHP_FUNCTION(imagejpeg)
1967 {
1968 _php_image_output_ctx(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_JPG, "JPEG", gdImageJpegCtx);
1969 }
1970 /* }}} */
1971 #endif /* HAVE_GD_JPG */
1972
1973 /* {{{ Output WBMP image to browser or file */
PHP_FUNCTION(imagewbmp)1974 PHP_FUNCTION(imagewbmp)
1975 {
1976 zval *imgind;
1977 zend_long foreground_color;
1978 zend_long foreground_color_is_null = 1;
1979 gdImagePtr im;
1980 int i;
1981 gdIOCtx *ctx = NULL;
1982 zval *to_zval = NULL;
1983
1984 if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|z!l!", &imgind, gd_image_ce, &to_zval, &foreground_color, &foreground_color_is_null) == FAILURE) {
1985 RETURN_THROWS();
1986 }
1987
1988 im = php_gd_libgdimageptr_from_zval_p(imgind);
1989
1990 if (to_zval != NULL) {
1991 ctx = create_stream_context_from_zval(to_zval);
1992 if (!ctx) {
1993 RETURN_FALSE;
1994 }
1995 } else {
1996 ctx = create_output_context();
1997 }
1998
1999 if (foreground_color_is_null) {
2000 for (i=0; i < gdImageColorsTotal(im); i++) {
2001 if (!gdImageRed(im, i) && !gdImageGreen(im, i) && !gdImageBlue(im, i)) {
2002 break;
2003 }
2004 }
2005
2006 foreground_color = i;
2007 }
2008
2009 gdImageWBMPCtx(im, foreground_color, ctx);
2010
2011 ctx->gd_free(ctx);
2012
2013 RETURN_TRUE;
2014 }
2015 /* }}} */
2016
2017 /* {{{ Output GD image to browser or file */
PHP_FUNCTION(imagegd)2018 PHP_FUNCTION(imagegd)
2019 {
2020 _php_image_output(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_GD, "GD", gdImageGd);
2021 }
2022 /* }}} */
2023
2024 /* {{{ Output GD2 image to browser or file */
PHP_FUNCTION(imagegd2)2025 PHP_FUNCTION(imagegd2)
2026 {
2027 _php_image_output(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_GD2, "GD2", gdImageGd2);
2028 }
2029 /* }}} */
2030
2031 #ifdef HAVE_GD_BMP
2032 /* {{{ Output BMP image to browser or file */
PHP_FUNCTION(imagebmp)2033 PHP_FUNCTION(imagebmp)
2034 {
2035 zval *imgind;
2036 zend_bool compressed = 1;
2037 gdImagePtr im;
2038 gdIOCtx *ctx = NULL;
2039 zval *to_zval = NULL;
2040
2041 if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|z!b", &imgind, gd_image_ce, &to_zval, &compressed) == FAILURE) {
2042 RETURN_THROWS();
2043 }
2044
2045 im = php_gd_libgdimageptr_from_zval_p(imgind);
2046
2047 if (to_zval != NULL) {
2048 ctx = create_stream_context_from_zval(to_zval);
2049 if (!ctx) {
2050 RETURN_FALSE;
2051 }
2052 } else {
2053 ctx = create_output_context();
2054 }
2055
2056 gdImageBmpCtx(im, ctx, (int) compressed);
2057
2058 ctx->gd_free(ctx);
2059
2060 RETURN_TRUE;
2061 }
2062 /* }}} */
2063 #endif
2064
2065 /* {{{ Destroy an image - No effect as of PHP 8.0 */
PHP_FUNCTION(imagedestroy)2066 PHP_FUNCTION(imagedestroy)
2067 {
2068 /* This function used to free the resource, as resources are no longer used, it does nothing */
2069 zval *IM;
2070
2071 if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &IM, gd_image_ce) == FAILURE) {
2072 RETURN_THROWS();
2073 }
2074
2075 RETURN_TRUE;
2076 }
2077 /* }}} */
2078
2079 /* {{{ Allocate a color for an image */
PHP_FUNCTION(imagecolorallocate)2080 PHP_FUNCTION(imagecolorallocate)
2081 {
2082 zval *IM;
2083 zend_long red, green, blue;
2084 gdImagePtr im;
2085 int ct = (-1);
2086
2087 if (zend_parse_parameters(ZEND_NUM_ARGS(), "Olll", &IM, gd_image_ce, &red, &green, &blue) == FAILURE) {
2088 RETURN_THROWS();
2089 }
2090
2091 im = php_gd_libgdimageptr_from_zval_p(IM);
2092
2093 CHECK_RGBA_RANGE(red, Red, 2);
2094 CHECK_RGBA_RANGE(green, Green, 3);
2095 CHECK_RGBA_RANGE(blue, Blue, 4);
2096
2097 ct = gdImageColorAllocate(im, red, green, blue);
2098 if (ct < 0) {
2099 RETURN_FALSE;
2100 }
2101 RETURN_LONG(ct);
2102 }
2103 /* }}} */
2104
2105 /* {{{ Copy the palette from the src image onto the dst image */
PHP_FUNCTION(imagepalettecopy)2106 PHP_FUNCTION(imagepalettecopy)
2107 {
2108 zval *dstim, *srcim;
2109 gdImagePtr dst, src;
2110
2111 if (zend_parse_parameters(ZEND_NUM_ARGS(), "OO", &dstim, gd_image_ce, &srcim, gd_image_ce) == FAILURE) {
2112 RETURN_THROWS();
2113 }
2114
2115 src = php_gd_libgdimageptr_from_zval_p(srcim);
2116 dst = php_gd_libgdimageptr_from_zval_p(dstim);
2117
2118 gdImagePaletteCopy(dst, src);
2119 }
2120 /* }}} */
2121
2122 /* {{{ Get the index of the color of a pixel */
PHP_FUNCTION(imagecolorat)2123 PHP_FUNCTION(imagecolorat)
2124 {
2125 zval *IM;
2126 zend_long x, y;
2127 gdImagePtr im;
2128
2129 ZEND_PARSE_PARAMETERS_START(3, 3)
2130 Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
2131 Z_PARAM_LONG(x)
2132 Z_PARAM_LONG(y)
2133 ZEND_PARSE_PARAMETERS_END();
2134
2135 im = php_gd_libgdimageptr_from_zval_p(IM);
2136
2137 if (gdImageTrueColor(im)) {
2138 if (im->tpixels && gdImageBoundsSafe(im, x, y)) {
2139 RETURN_LONG(gdImageTrueColorPixel(im, x, y));
2140 } else {
2141 php_error_docref(NULL, E_NOTICE, "" ZEND_LONG_FMT "," ZEND_LONG_FMT " is out of bounds", x, y);
2142 RETURN_FALSE;
2143 }
2144 } else {
2145 if (im->pixels && gdImageBoundsSafe(im, x, y)) {
2146 RETURN_LONG(im->pixels[y][x]);
2147 } else {
2148 php_error_docref(NULL, E_NOTICE, "" ZEND_LONG_FMT "," ZEND_LONG_FMT " is out of bounds", x, y);
2149 RETURN_FALSE;
2150 }
2151 }
2152 }
2153 /* }}} */
2154
2155 /* {{{ Get the index of the closest color to the specified color */
PHP_FUNCTION(imagecolorclosest)2156 PHP_FUNCTION(imagecolorclosest)
2157 {
2158 zval *IM;
2159 zend_long red, green, blue;
2160 gdImagePtr im;
2161
2162 if (zend_parse_parameters(ZEND_NUM_ARGS(), "Olll", &IM, gd_image_ce, &red, &green, &blue) == FAILURE) {
2163 RETURN_THROWS();
2164 }
2165
2166 im = php_gd_libgdimageptr_from_zval_p(IM);
2167
2168 CHECK_RGBA_RANGE(red, Red, 2);
2169 CHECK_RGBA_RANGE(green, Green, 3);
2170 CHECK_RGBA_RANGE(blue, Blue, 4);
2171
2172 RETURN_LONG(gdImageColorClosest(im, red, green, blue));
2173 }
2174 /* }}} */
2175
2176 /* {{{ Get the index of the color which has the hue, white and blackness nearest to the given color */
PHP_FUNCTION(imagecolorclosesthwb)2177 PHP_FUNCTION(imagecolorclosesthwb)
2178 {
2179 zval *IM;
2180 zend_long red, green, blue;
2181 gdImagePtr im;
2182
2183 if (zend_parse_parameters(ZEND_NUM_ARGS(), "Olll", &IM, gd_image_ce, &red, &green, &blue) == FAILURE) {
2184 RETURN_THROWS();
2185 }
2186
2187 im = php_gd_libgdimageptr_from_zval_p(IM);
2188
2189 CHECK_RGBA_RANGE(red, Red, 2);
2190 CHECK_RGBA_RANGE(green, Green, 3);
2191 CHECK_RGBA_RANGE(blue, Blue, 4);
2192
2193 RETURN_LONG(gdImageColorClosestHWB(im, red, green, blue));
2194 }
2195 /* }}} */
2196
2197 /* {{{ De-allocate a color for an image */
PHP_FUNCTION(imagecolordeallocate)2198 PHP_FUNCTION(imagecolordeallocate)
2199 {
2200 zval *IM;
2201 zend_long index;
2202 int col;
2203 gdImagePtr im;
2204
2205 if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ol", &IM, gd_image_ce, &index) == FAILURE) {
2206 RETURN_THROWS();
2207 }
2208
2209 im = php_gd_libgdimageptr_from_zval_p(IM);
2210
2211 /* We can return right away for a truecolor image as deallocating colours is meaningless here */
2212 if (gdImageTrueColor(im)) {
2213 RETURN_TRUE;
2214 }
2215
2216 col = index;
2217
2218 if (col >= 0 && col < gdImageColorsTotal(im)) {
2219 gdImageColorDeallocate(im, col);
2220 RETURN_TRUE;
2221 } else {
2222 zend_argument_value_error(2, "must be between 0 and %d", gdImageColorsTotal(im));
2223 RETURN_THROWS();
2224 }
2225 }
2226 /* }}} */
2227
2228 /* {{{ Get the index of the specified color or its closest possible alternative */
PHP_FUNCTION(imagecolorresolve)2229 PHP_FUNCTION(imagecolorresolve)
2230 {
2231 zval *IM;
2232 zend_long red, green, blue;
2233 gdImagePtr im;
2234
2235 if (zend_parse_parameters(ZEND_NUM_ARGS(), "Olll", &IM, gd_image_ce, &red, &green, &blue) == FAILURE) {
2236 RETURN_THROWS();
2237 }
2238
2239 im = php_gd_libgdimageptr_from_zval_p(IM);
2240
2241 CHECK_RGBA_RANGE(red, Red, 2);
2242 CHECK_RGBA_RANGE(green, Green, 3);
2243 CHECK_RGBA_RANGE(blue, Blue, 4);
2244
2245 RETURN_LONG(gdImageColorResolve(im, red, green, blue));
2246 }
2247 /* }}} */
2248
2249 /* {{{ Get the index of the specified color */
PHP_FUNCTION(imagecolorexact)2250 PHP_FUNCTION(imagecolorexact)
2251 {
2252 zval *IM;
2253 zend_long red, green, blue;
2254 gdImagePtr im;
2255
2256 if (zend_parse_parameters(ZEND_NUM_ARGS(), "Olll", &IM, gd_image_ce, &red, &green, &blue) == FAILURE) {
2257 RETURN_THROWS();
2258 }
2259
2260 im = php_gd_libgdimageptr_from_zval_p(IM);
2261
2262 CHECK_RGBA_RANGE(red, Red, 2);
2263 CHECK_RGBA_RANGE(green, Green, 3);
2264 CHECK_RGBA_RANGE(blue, Blue, 4);
2265
2266 RETURN_LONG(gdImageColorExact(im, red, green, blue));
2267 }
2268 /* }}} */
2269
2270 /* {{{ Set the color for the specified palette index */
PHP_FUNCTION(imagecolorset)2271 PHP_FUNCTION(imagecolorset)
2272 {
2273 zval *IM;
2274 zend_long color, red, green, blue, alpha = 0;
2275 int col;
2276 gdImagePtr im;
2277
2278 if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ollll|l", &IM, gd_image_ce, &color, &red, &green, &blue, &alpha) == FAILURE) {
2279 RETURN_THROWS();
2280 }
2281
2282 im = php_gd_libgdimageptr_from_zval_p(IM);
2283
2284 CHECK_RGBA_RANGE(red, Red, 2);
2285 CHECK_RGBA_RANGE(green, Green, 3);
2286 CHECK_RGBA_RANGE(blue, Blue, 4);
2287
2288 col = color;
2289
2290 if (col >= 0 && col < gdImageColorsTotal(im)) {
2291 im->red[col] = red;
2292 im->green[col] = green;
2293 im->blue[col] = blue;
2294 im->alpha[col] = alpha;
2295 } else {
2296 RETURN_FALSE;
2297 }
2298 }
2299 /* }}} */
2300
2301 /* {{{ Get the colors for an index */
PHP_FUNCTION(imagecolorsforindex)2302 PHP_FUNCTION(imagecolorsforindex)
2303 {
2304 zval *IM;
2305 zend_long index;
2306 int col;
2307 gdImagePtr im;
2308
2309 if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ol", &IM, gd_image_ce, &index) == FAILURE) {
2310 RETURN_THROWS();
2311 }
2312
2313 im = php_gd_libgdimageptr_from_zval_p(IM);
2314
2315 col = index;
2316
2317 if ((col >= 0 && gdImageTrueColor(im)) || (!gdImageTrueColor(im) && col >= 0 && col < gdImageColorsTotal(im))) {
2318 array_init(return_value);
2319
2320 add_assoc_long(return_value,"red", gdImageRed(im,col));
2321 add_assoc_long(return_value,"green", gdImageGreen(im,col));
2322 add_assoc_long(return_value,"blue", gdImageBlue(im,col));
2323 add_assoc_long(return_value,"alpha", gdImageAlpha(im,col));
2324 } else {
2325 zend_argument_value_error(2, "is out of range");
2326 RETURN_THROWS();
2327 }
2328 }
2329 /* }}} */
2330
2331 /* {{{ Apply a gamma correction to a GD image */
PHP_FUNCTION(imagegammacorrect)2332 PHP_FUNCTION(imagegammacorrect)
2333 {
2334 zval *IM;
2335 gdImagePtr im;
2336 int i;
2337 double input, output, gamma;
2338
2339 if (zend_parse_parameters(ZEND_NUM_ARGS(), "Odd", &IM, gd_image_ce, &input, &output) == FAILURE) {
2340 RETURN_THROWS();
2341 }
2342
2343 if (input <= 0.0) {
2344 zend_argument_value_error(2, "must be greater than 0");
2345 RETURN_THROWS();
2346 }
2347
2348 if (output <= 0.0) {
2349 zend_argument_value_error(3, "must be greater than 0");
2350 RETURN_THROWS();
2351 }
2352
2353 gamma = input / output;
2354
2355 im = php_gd_libgdimageptr_from_zval_p(IM);
2356
2357 if (gdImageTrueColor(im)) {
2358 int x, y, c;
2359
2360 for (y = 0; y < gdImageSY(im); y++) {
2361 for (x = 0; x < gdImageSX(im); x++) {
2362 c = gdImageGetPixel(im, x, y);
2363 gdImageSetPixel(im, x, y,
2364 gdTrueColorAlpha(
2365 (int) ((pow((gdTrueColorGetRed(c) / 255.0), gamma) * 255) + .5),
2366 (int) ((pow((gdTrueColorGetGreen(c) / 255.0), gamma) * 255) + .5),
2367 (int) ((pow((gdTrueColorGetBlue(c) / 255.0), gamma) * 255) + .5),
2368 gdTrueColorGetAlpha(c)
2369 )
2370 );
2371 }
2372 }
2373 RETURN_TRUE;
2374 }
2375
2376 for (i = 0; i < gdImageColorsTotal(im); i++) {
2377 im->red[i] = (int)((pow((im->red[i] / 255.0), gamma) * 255) + .5);
2378 im->green[i] = (int)((pow((im->green[i] / 255.0), gamma) * 255) + .5);
2379 im->blue[i] = (int)((pow((im->blue[i] / 255.0), gamma) * 255) + .5);
2380 }
2381
2382 RETURN_TRUE;
2383 }
2384 /* }}} */
2385
2386 /* {{{ Set a single pixel */
PHP_FUNCTION(imagesetpixel)2387 PHP_FUNCTION(imagesetpixel)
2388 {
2389 zval *IM;
2390 zend_long x, y, col;
2391 gdImagePtr im;
2392
2393 ZEND_PARSE_PARAMETERS_START(4, 4)
2394 Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
2395 Z_PARAM_LONG(x)
2396 Z_PARAM_LONG(y)
2397 Z_PARAM_LONG(col)
2398 ZEND_PARSE_PARAMETERS_END();
2399
2400 im = php_gd_libgdimageptr_from_zval_p(IM);
2401
2402 gdImageSetPixel(im, x, y, col);
2403 RETURN_TRUE;
2404 }
2405 /* }}} */
2406
2407 /* {{{ Draw a line */
PHP_FUNCTION(imageline)2408 PHP_FUNCTION(imageline)
2409 {
2410 zval *IM;
2411 zend_long x1, y1, x2, y2, col;
2412 gdImagePtr im;
2413
2414 if (zend_parse_parameters(ZEND_NUM_ARGS(), "Olllll", &IM, gd_image_ce, &x1, &y1, &x2, &y2, &col) == FAILURE) {
2415 RETURN_THROWS();
2416 }
2417
2418 im = php_gd_libgdimageptr_from_zval_p(IM);
2419
2420 if (im->AA) {
2421 gdImageSetAntiAliased(im, col);
2422 col = gdAntiAliased;
2423 }
2424 gdImageLine(im, x1, y1, x2, y2, col);
2425 RETURN_TRUE;
2426 }
2427 /* }}} */
2428
2429 /* {{{ Draw a dashed line */
PHP_FUNCTION(imagedashedline)2430 PHP_FUNCTION(imagedashedline)
2431 {
2432 zval *IM;
2433 zend_long x1, y1, x2, y2, col;
2434 gdImagePtr im;
2435
2436 if (zend_parse_parameters(ZEND_NUM_ARGS(), "Olllll", &IM, gd_image_ce, &x1, &y1, &x2, &y2, &col) == FAILURE) {
2437 RETURN_THROWS();
2438 }
2439
2440 im = php_gd_libgdimageptr_from_zval_p(IM);
2441
2442 gdImageDashedLine(im, x1, y1, x2, y2, col);
2443 RETURN_TRUE;
2444 }
2445 /* }}} */
2446
2447 /* {{{ Draw a rectangle */
PHP_FUNCTION(imagerectangle)2448 PHP_FUNCTION(imagerectangle)
2449 {
2450 zval *IM;
2451 zend_long x1, y1, x2, y2, col;
2452 gdImagePtr im;
2453
2454 if (zend_parse_parameters(ZEND_NUM_ARGS(), "Olllll", &IM, gd_image_ce, &x1, &y1, &x2, &y2, &col) == FAILURE) {
2455 RETURN_THROWS();
2456 }
2457
2458 im = php_gd_libgdimageptr_from_zval_p(IM);
2459
2460 gdImageRectangle(im, x1, y1, x2, y2, col);
2461 RETURN_TRUE;
2462 }
2463 /* }}} */
2464
2465 /* {{{ Draw a filled rectangle */
PHP_FUNCTION(imagefilledrectangle)2466 PHP_FUNCTION(imagefilledrectangle)
2467 {
2468 zval *IM;
2469 zend_long x1, y1, x2, y2, col;
2470 gdImagePtr im;
2471
2472 if (zend_parse_parameters(ZEND_NUM_ARGS(), "Olllll", &IM, gd_image_ce, &x1, &y1, &x2, &y2, &col) == FAILURE) {
2473 RETURN_THROWS();
2474 }
2475
2476 im = php_gd_libgdimageptr_from_zval_p(IM);
2477 gdImageFilledRectangle(im, x1, y1, x2, y2, col);
2478 RETURN_TRUE;
2479 }
2480 /* }}} */
2481
2482 /* {{{ Draw a partial ellipse */
PHP_FUNCTION(imagearc)2483 PHP_FUNCTION(imagearc)
2484 {
2485 zval *IM;
2486 zend_long cx, cy, w, h, ST, E, col;
2487 gdImagePtr im;
2488 int e, st;
2489
2490 if (zend_parse_parameters(ZEND_NUM_ARGS(), "Olllllll", &IM, gd_image_ce, &cx, &cy, &w, &h, &ST, &E, &col) == FAILURE) {
2491 RETURN_THROWS();
2492 }
2493
2494 im = php_gd_libgdimageptr_from_zval_p(IM);
2495
2496 e = E;
2497 if (e < 0) {
2498 e %= 360;
2499 }
2500
2501 st = ST;
2502 if (st < 0) {
2503 st %= 360;
2504 }
2505
2506 gdImageArc(im, cx, cy, w, h, st, e, col);
2507 RETURN_TRUE;
2508 }
2509 /* }}} */
2510
2511 /* {{{ Draw an ellipse */
PHP_FUNCTION(imageellipse)2512 PHP_FUNCTION(imageellipse)
2513 {
2514 zval *IM;
2515 zend_long cx, cy, w, h, color;
2516 gdImagePtr im;
2517
2518 if (zend_parse_parameters(ZEND_NUM_ARGS(), "Olllll", &IM, gd_image_ce, &cx, &cy, &w, &h, &color) == FAILURE) {
2519 RETURN_THROWS();
2520 }
2521
2522 im = php_gd_libgdimageptr_from_zval_p(IM);
2523
2524 gdImageEllipse(im, cx, cy, w, h, color);
2525 RETURN_TRUE;
2526 }
2527 /* }}} */
2528
2529 /* {{{ Flood fill to specific color */
PHP_FUNCTION(imagefilltoborder)2530 PHP_FUNCTION(imagefilltoborder)
2531 {
2532 zval *IM;
2533 zend_long x, y, border, col;
2534 gdImagePtr im;
2535
2536 if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ollll", &IM, gd_image_ce, &x, &y, &border, &col) == FAILURE) {
2537 RETURN_THROWS();
2538 }
2539
2540 im = php_gd_libgdimageptr_from_zval_p(IM);
2541
2542 gdImageFillToBorder(im, x, y, border, col);
2543 RETURN_TRUE;
2544 }
2545 /* }}} */
2546
2547 /* {{{ Flood fill */
PHP_FUNCTION(imagefill)2548 PHP_FUNCTION(imagefill)
2549 {
2550 zval *IM;
2551 zend_long x, y, col;
2552 gdImagePtr im;
2553
2554 if (zend_parse_parameters(ZEND_NUM_ARGS(), "Olll", &IM, gd_image_ce, &x, &y, &col) == FAILURE) {
2555 RETURN_THROWS();
2556 }
2557
2558 im = php_gd_libgdimageptr_from_zval_p(IM);
2559
2560 gdImageFill(im, x, y, col);
2561 RETURN_TRUE;
2562 }
2563 /* }}} */
2564
2565 /* {{{ Find out the number of colors in an image's palette */
PHP_FUNCTION(imagecolorstotal)2566 PHP_FUNCTION(imagecolorstotal)
2567 {
2568 zval *IM;
2569 gdImagePtr im;
2570
2571 if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &IM, gd_image_ce) == FAILURE) {
2572 RETURN_THROWS();
2573 }
2574
2575 im = php_gd_libgdimageptr_from_zval_p(IM);
2576
2577 RETURN_LONG(gdImageColorsTotal(im));
2578 }
2579 /* }}} */
2580
2581 /* {{{ Define a color as transparent */
PHP_FUNCTION(imagecolortransparent)2582 PHP_FUNCTION(imagecolortransparent)
2583 {
2584 zval *IM;
2585 zend_long COL = 0;
2586 zend_bool COL_IS_NULL = 1;
2587 gdImagePtr im;
2588
2589 if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|l!", &IM, gd_image_ce, &COL, &COL_IS_NULL) == FAILURE) {
2590 RETURN_THROWS();
2591 }
2592
2593 im = php_gd_libgdimageptr_from_zval_p(IM);
2594
2595 if (!COL_IS_NULL) {
2596 gdImageColorTransparent(im, COL);
2597 }
2598
2599 RETURN_LONG(gdImageGetTransparent(im));
2600 }
2601 /* }}} */
2602
2603 /* {{{ Enable or disable interlace */
PHP_FUNCTION(imageinterlace)2604 PHP_FUNCTION(imageinterlace)
2605 {
2606 zval *IM;
2607 zend_bool INT = 0;
2608 zend_bool INT_IS_NULL = 1;
2609 gdImagePtr im;
2610
2611 if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|b!", &IM, gd_image_ce, &INT, &INT_IS_NULL) == FAILURE) {
2612 RETURN_THROWS();
2613 }
2614
2615 im = php_gd_libgdimageptr_from_zval_p(IM);
2616
2617 if (!INT_IS_NULL) {
2618 gdImageInterlace(im, INT);
2619 }
2620
2621 RETURN_BOOL(gdImageGetInterlaced(im));
2622 }
2623 /* }}} */
2624
2625 /* {{{ php_imagepolygon
2626 arg = -1 open polygon
2627 arg = 0 normal polygon
2628 arg = 1 filled polygon */
2629 /* im, points, num_points, col */
php_imagepolygon(INTERNAL_FUNCTION_PARAMETERS,int filled)2630 static void php_imagepolygon(INTERNAL_FUNCTION_PARAMETERS, int filled)
2631 {
2632 zval *IM, *POINTS;
2633 zend_long NPOINTS, COL;
2634 zend_bool COL_IS_NULL = 1;
2635 zval *var = NULL;
2636 gdImagePtr im;
2637 gdPointPtr points;
2638 int npoints, col, nelem, i;
2639
2640 if (zend_parse_parameters(ZEND_NUM_ARGS(), "Oal|l!", &IM, gd_image_ce, &POINTS, &NPOINTS, &COL, &COL_IS_NULL) == FAILURE) {
2641 RETURN_THROWS();
2642 }
2643 if (COL_IS_NULL) {
2644 COL = NPOINTS;
2645 NPOINTS = zend_hash_num_elements(Z_ARRVAL_P(POINTS));
2646 if (NPOINTS % 2 != 0) {
2647 zend_argument_value_error(2, "must have an even number of elements");
2648 RETURN_THROWS();
2649 }
2650 NPOINTS /= 2;
2651 }
2652
2653 im = php_gd_libgdimageptr_from_zval_p(IM);
2654
2655 npoints = NPOINTS;
2656 col = COL;
2657
2658 nelem = zend_hash_num_elements(Z_ARRVAL_P(POINTS));
2659 if (npoints < 3) {
2660 zend_argument_value_error(3, "must be greater than or equal to 3");
2661 RETURN_THROWS();
2662 }
2663
2664 if (nelem < npoints * 2) {
2665 zend_value_error("Trying to use %d points in array with only %d points", npoints, nelem/2);
2666 RETURN_THROWS();
2667 }
2668
2669 points = (gdPointPtr) safe_emalloc(npoints, sizeof(gdPoint), 0);
2670
2671 for (i = 0; i < npoints; i++) {
2672 if ((var = zend_hash_index_find(Z_ARRVAL_P(POINTS), (i * 2))) != NULL) {
2673 points[i].x = zval_get_long(var);
2674 }
2675 if ((var = zend_hash_index_find(Z_ARRVAL_P(POINTS), (i * 2) + 1)) != NULL) {
2676 points[i].y = zval_get_long(var);
2677 }
2678 }
2679
2680 if (im->AA) {
2681 gdImageSetAntiAliased(im, col);
2682 col = gdAntiAliased;
2683 }
2684 switch (filled) {
2685 case -1:
2686 gdImageOpenPolygon(im, points, npoints, col);
2687 break;
2688 case 0:
2689 gdImagePolygon(im, points, npoints, col);
2690 break;
2691 case 1:
2692 gdImageFilledPolygon(im, points, npoints, col);
2693 break;
2694 }
2695
2696 efree(points);
2697 RETURN_TRUE;
2698 }
2699 /* }}} */
2700
2701 /* {{{ Draw a polygon */
PHP_FUNCTION(imagepolygon)2702 PHP_FUNCTION(imagepolygon)
2703 {
2704 php_imagepolygon(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
2705 }
2706 /* }}} */
2707
2708 /* {{{ Draw a polygon */
PHP_FUNCTION(imageopenpolygon)2709 PHP_FUNCTION(imageopenpolygon)
2710 {
2711 php_imagepolygon(INTERNAL_FUNCTION_PARAM_PASSTHRU, -1);
2712 }
2713 /* }}} */
2714
2715 /* {{{ Draw a filled polygon */
PHP_FUNCTION(imagefilledpolygon)2716 PHP_FUNCTION(imagefilledpolygon)
2717 {
2718 php_imagepolygon(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
2719 }
2720 /* }}} */
2721
2722 /* {{{ php_find_gd_font */
php_find_gd_font(int size)2723 static gdFontPtr php_find_gd_font(int size)
2724 {
2725 gdFontPtr font;
2726
2727 switch (size) {
2728 case 1:
2729 font = gdFontTiny;
2730 break;
2731 case 2:
2732 font = gdFontSmall;
2733 break;
2734 case 3:
2735 font = gdFontMediumBold;
2736 break;
2737 case 4:
2738 font = gdFontLarge;
2739 break;
2740 case 5:
2741 font = gdFontGiant;
2742 break;
2743 default: {
2744 zval *zv = zend_hash_index_find(&EG(regular_list), size - 5);
2745 if (!zv || (Z_RES_P(zv))->type != le_gd_font) {
2746 if (size < 1) {
2747 font = gdFontTiny;
2748 } else {
2749 font = gdFontGiant;
2750 }
2751 } else {
2752 font = (gdFontPtr)Z_RES_P(zv)->ptr;
2753 }
2754 }
2755 break;
2756 }
2757
2758 return font;
2759 }
2760 /* }}} */
2761
2762 /* {{{ php_imagefontsize
2763 * arg = 0 ImageFontWidth
2764 * arg = 1 ImageFontHeight
2765 */
php_imagefontsize(INTERNAL_FUNCTION_PARAMETERS,int arg)2766 static void php_imagefontsize(INTERNAL_FUNCTION_PARAMETERS, int arg)
2767 {
2768 zend_long SIZE;
2769 gdFontPtr font;
2770
2771 if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &SIZE) == FAILURE) {
2772 RETURN_THROWS();
2773 }
2774
2775 font = php_find_gd_font(SIZE);
2776 RETURN_LONG(arg ? font->h : font->w);
2777 }
2778 /* }}} */
2779
2780 /* {{{ Get font width */
PHP_FUNCTION(imagefontwidth)2781 PHP_FUNCTION(imagefontwidth)
2782 {
2783 php_imagefontsize(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
2784 }
2785 /* }}} */
2786
2787 /* {{{ Get font height */
PHP_FUNCTION(imagefontheight)2788 PHP_FUNCTION(imagefontheight)
2789 {
2790 php_imagefontsize(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
2791 }
2792 /* }}} */
2793
2794 /* {{{ php_gdimagecharup
2795 * workaround for a bug in gd 1.2 */
php_gdimagecharup(gdImagePtr im,gdFontPtr f,int x,int y,int c,int color)2796 static void php_gdimagecharup(gdImagePtr im, gdFontPtr f, int x, int y, int c, int color)
2797 {
2798 int cx, cy, px, py, fline;
2799 cx = 0;
2800 cy = 0;
2801
2802 if ((c < f->offset) || (c >= (f->offset + f->nchars))) {
2803 return;
2804 }
2805
2806 fline = (c - f->offset) * f->h * f->w;
2807 for (py = y; (py > (y - f->w)); py--) {
2808 for (px = x; (px < (x + f->h)); px++) {
2809 if (f->data[fline + cy * f->w + cx]) {
2810 gdImageSetPixel(im, px, py, color);
2811 }
2812 cy++;
2813 }
2814 cy = 0;
2815 cx++;
2816 }
2817 }
2818 /* }}} */
2819
2820 /* {{{ php_imagechar
2821 * arg = 0 ImageChar
2822 * arg = 1 ImageCharUp
2823 * arg = 2 ImageString
2824 * arg = 3 ImageStringUp
2825 */
php_imagechar(INTERNAL_FUNCTION_PARAMETERS,int mode)2826 static void php_imagechar(INTERNAL_FUNCTION_PARAMETERS, int mode)
2827 {
2828 zval *IM;
2829 zend_long SIZE, X, Y, COL;
2830 char *C;
2831 size_t C_len;
2832 gdImagePtr im;
2833 int ch = 0, col, x, y, size, i, l = 0;
2834 unsigned char *str = NULL;
2835 gdFontPtr font;
2836
2837 if (zend_parse_parameters(ZEND_NUM_ARGS(), "Olllsl", &IM, gd_image_ce, &SIZE, &X, &Y, &C, &C_len, &COL) == FAILURE) {
2838 RETURN_THROWS();
2839 }
2840
2841 im = php_gd_libgdimageptr_from_zval_p(IM);
2842
2843 col = COL;
2844
2845 if (mode < 2) {
2846 ch = (int)((unsigned char)*C);
2847 } else {
2848 str = (unsigned char *) estrndup(C, C_len);
2849 l = strlen((char *)str);
2850 }
2851
2852 y = Y;
2853 x = X;
2854 size = SIZE;
2855
2856 font = php_find_gd_font(size);
2857
2858 switch (mode) {
2859 case 0:
2860 gdImageChar(im, font, x, y, ch, col);
2861 break;
2862 case 1:
2863 php_gdimagecharup(im, font, x, y, ch, col);
2864 break;
2865 case 2:
2866 for (i = 0; (i < l); i++) {
2867 gdImageChar(im, font, x, y, (int) ((unsigned char) str[i]), col);
2868 x += font->w;
2869 }
2870 break;
2871 case 3: {
2872 for (i = 0; (i < l); i++) {
2873 /* php_gdimagecharup(im, font, x, y, (int) str[i], col); */
2874 gdImageCharUp(im, font, x, y, (int) str[i], col);
2875 y -= font->w;
2876 }
2877 break;
2878 }
2879 }
2880 if (str) {
2881 efree(str);
2882 }
2883 RETURN_TRUE;
2884 }
2885 /* }}} */
2886
2887 /* {{{ Draw a character */
PHP_FUNCTION(imagechar)2888 PHP_FUNCTION(imagechar)
2889 {
2890 php_imagechar(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
2891 }
2892 /* }}} */
2893
2894 /* {{{ Draw a character rotated 90 degrees counter-clockwise */
PHP_FUNCTION(imagecharup)2895 PHP_FUNCTION(imagecharup)
2896 {
2897 php_imagechar(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
2898 }
2899 /* }}} */
2900
2901 /* {{{ Draw a string horizontally */
PHP_FUNCTION(imagestring)2902 PHP_FUNCTION(imagestring)
2903 {
2904 php_imagechar(INTERNAL_FUNCTION_PARAM_PASSTHRU, 2);
2905 }
2906 /* }}} */
2907
2908 /* {{{ Draw a string vertically - rotated 90 degrees counter-clockwise */
PHP_FUNCTION(imagestringup)2909 PHP_FUNCTION(imagestringup)
2910 {
2911 php_imagechar(INTERNAL_FUNCTION_PARAM_PASSTHRU, 3);
2912 }
2913 /* }}} */
2914
2915 /* {{{ Copy part of an image */
PHP_FUNCTION(imagecopy)2916 PHP_FUNCTION(imagecopy)
2917 {
2918 zval *SIM, *DIM;
2919 zend_long SX, SY, SW, SH, DX, DY;
2920 gdImagePtr im_dst, im_src;
2921 int srcH, srcW, srcY, srcX, dstY, dstX;
2922
2923 if (zend_parse_parameters(ZEND_NUM_ARGS(), "OOllllll", &DIM, gd_image_ce, &SIM, gd_image_ce, &DX, &DY, &SX, &SY, &SW, &SH) == FAILURE) {
2924 RETURN_THROWS();
2925 }
2926
2927 im_dst = php_gd_libgdimageptr_from_zval_p(DIM);
2928 im_src = php_gd_libgdimageptr_from_zval_p(SIM);
2929
2930 srcX = SX;
2931 srcY = SY;
2932 srcH = SH;
2933 srcW = SW;
2934 dstX = DX;
2935 dstY = DY;
2936
2937 gdImageCopy(im_dst, im_src, dstX, dstY, srcX, srcY, srcW, srcH);
2938 RETURN_TRUE;
2939 }
2940 /* }}} */
2941
2942 /* {{{ Merge one part of an image with another */
PHP_FUNCTION(imagecopymerge)2943 PHP_FUNCTION(imagecopymerge)
2944 {
2945 zval *SIM, *DIM;
2946 zend_long SX, SY, SW, SH, DX, DY, PCT;
2947 gdImagePtr im_dst, im_src;
2948 int srcH, srcW, srcY, srcX, dstY, dstX, pct;
2949
2950 if (zend_parse_parameters(ZEND_NUM_ARGS(), "OOlllllll", &DIM, gd_image_ce, &SIM, gd_image_ce, &DX, &DY, &SX, &SY, &SW, &SH, &PCT) == FAILURE) {
2951 RETURN_THROWS();
2952 }
2953
2954 im_src = php_gd_libgdimageptr_from_zval_p(SIM);
2955 im_dst = php_gd_libgdimageptr_from_zval_p(DIM);
2956
2957 srcX = SX;
2958 srcY = SY;
2959 srcH = SH;
2960 srcW = SW;
2961 dstX = DX;
2962 dstY = DY;
2963 pct = PCT;
2964
2965 gdImageCopyMerge(im_dst, im_src, dstX, dstY, srcX, srcY, srcW, srcH, pct);
2966 RETURN_TRUE;
2967 }
2968 /* }}} */
2969
2970 /* {{{ Merge one part of an image with another */
PHP_FUNCTION(imagecopymergegray)2971 PHP_FUNCTION(imagecopymergegray)
2972 {
2973 zval *SIM, *DIM;
2974 zend_long SX, SY, SW, SH, DX, DY, PCT;
2975 gdImagePtr im_dst, im_src;
2976 int srcH, srcW, srcY, srcX, dstY, dstX, pct;
2977
2978 if (zend_parse_parameters(ZEND_NUM_ARGS(), "OOlllllll", &DIM, gd_image_ce, &SIM, gd_image_ce, &DX, &DY, &SX, &SY, &SW, &SH, &PCT) == FAILURE) {
2979 RETURN_THROWS();
2980 }
2981
2982 im_src = php_gd_libgdimageptr_from_zval_p(SIM);
2983 im_dst = php_gd_libgdimageptr_from_zval_p(DIM);
2984
2985 srcX = SX;
2986 srcY = SY;
2987 srcH = SH;
2988 srcW = SW;
2989 dstX = DX;
2990 dstY = DY;
2991 pct = PCT;
2992
2993 gdImageCopyMergeGray(im_dst, im_src, dstX, dstY, srcX, srcY, srcW, srcH, pct);
2994 RETURN_TRUE;
2995 }
2996 /* }}} */
2997
2998 /* {{{ Copy and resize part of an image */
PHP_FUNCTION(imagecopyresized)2999 PHP_FUNCTION(imagecopyresized)
3000 {
3001 zval *SIM, *DIM;
3002 zend_long SX, SY, SW, SH, DX, DY, DW, DH;
3003 gdImagePtr im_dst, im_src;
3004 int srcH, srcW, dstH, dstW, srcY, srcX, dstY, dstX;
3005
3006 if (zend_parse_parameters(ZEND_NUM_ARGS(), "OOllllllll", &DIM, gd_image_ce, &SIM, gd_image_ce, &DX, &DY, &SX, &SY, &DW, &DH, &SW, &SH) == FAILURE) {
3007 RETURN_THROWS();
3008 }
3009
3010 im_src = php_gd_libgdimageptr_from_zval_p(SIM);
3011 im_dst = php_gd_libgdimageptr_from_zval_p(DIM);
3012
3013 srcX = SX;
3014 srcY = SY;
3015 srcH = SH;
3016 srcW = SW;
3017 dstX = DX;
3018 dstY = DY;
3019 dstH = DH;
3020 dstW = DW;
3021
3022 if (dstW <= 0) {
3023 zend_argument_value_error(7, "must be greater than 0");
3024 RETURN_THROWS();
3025 }
3026
3027 if (dstH <= 0) {
3028 zend_argument_value_error(8, "must be greater than 0");
3029 RETURN_THROWS();
3030 }
3031
3032 if (srcW <= 0) {
3033 zend_argument_value_error(9, "must be greater than 0");
3034 RETURN_THROWS();
3035 }
3036
3037 if (srcH <= 0) {
3038 zend_argument_value_error(10, "must be greater than 0");
3039 RETURN_THROWS();
3040 }
3041
3042 gdImageCopyResized(im_dst, im_src, dstX, dstY, srcX, srcY, dstW, dstH, srcW, srcH);
3043 RETURN_TRUE;
3044 }
3045 /* }}} */
3046
3047 /* {{{ Get image width */
PHP_FUNCTION(imagesx)3048 PHP_FUNCTION(imagesx)
3049 {
3050 zval *IM;
3051 gdImagePtr im;
3052
3053 if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &IM, gd_image_ce) == FAILURE) {
3054 RETURN_THROWS();
3055 }
3056
3057 im = php_gd_libgdimageptr_from_zval_p(IM);
3058
3059 RETURN_LONG(gdImageSX(im));
3060 }
3061 /* }}} */
3062
3063 /* {{{ Get image height */
PHP_FUNCTION(imagesy)3064 PHP_FUNCTION(imagesy)
3065 {
3066 zval *IM;
3067 gdImagePtr im;
3068
3069 if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &IM, gd_image_ce) == FAILURE) {
3070 RETURN_THROWS();
3071 }
3072
3073 im = php_gd_libgdimageptr_from_zval_p(IM);
3074
3075 RETURN_LONG(gdImageSY(im));
3076 }
3077 /* }}} */
3078
3079 /* {{{ Set the clipping rectangle. */
PHP_FUNCTION(imagesetclip)3080 PHP_FUNCTION(imagesetclip)
3081 {
3082 zval *im_zval;
3083 gdImagePtr im;
3084 zend_long x1, y1, x2, y2;
3085
3086 if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ollll", &im_zval, gd_image_ce, &x1, &y1, &x2, &y2) == FAILURE) {
3087 RETURN_THROWS();
3088 }
3089
3090 im = php_gd_libgdimageptr_from_zval_p(im_zval);
3091
3092 gdImageSetClip(im, x1, y1, x2, y2);
3093 RETURN_TRUE;
3094 }
3095 /* }}} */
3096
3097 /* {{{ Get the clipping rectangle. */
PHP_FUNCTION(imagegetclip)3098 PHP_FUNCTION(imagegetclip)
3099 {
3100 zval *im_zval;
3101 gdImagePtr im;
3102 int x1, y1, x2, y2;
3103
3104 if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &im_zval, gd_image_ce) == FAILURE) {
3105 RETURN_THROWS();
3106 }
3107
3108 im = php_gd_libgdimageptr_from_zval_p(im_zval);
3109
3110 gdImageGetClip(im, &x1, &y1, &x2, &y2);
3111
3112 array_init(return_value);
3113 add_next_index_long(return_value, x1);
3114 add_next_index_long(return_value, y1);
3115 add_next_index_long(return_value, x2);
3116 add_next_index_long(return_value, y2);
3117 }
3118 /* }}} */
3119
3120 #define TTFTEXT_DRAW 0
3121 #define TTFTEXT_BBOX 1
3122
3123 #ifdef HAVE_GD_FREETYPE
3124 /* {{{ Give the bounding box of a text using fonts via freetype2 */
PHP_FUNCTION(imageftbbox)3125 PHP_FUNCTION(imageftbbox)
3126 {
3127 php_imagettftext_common(INTERNAL_FUNCTION_PARAM_PASSTHRU, TTFTEXT_BBOX);
3128 }
3129 /* }}} */
3130
3131 /* {{{ Write text to the image using fonts via freetype2 */
PHP_FUNCTION(imagefttext)3132 PHP_FUNCTION(imagefttext)
3133 {
3134 php_imagettftext_common(INTERNAL_FUNCTION_PARAM_PASSTHRU, TTFTEXT_DRAW);
3135 }
3136 /* }}} */
3137
3138 /* {{{ php_imagettftext_common */
php_imagettftext_common(INTERNAL_FUNCTION_PARAMETERS,int mode)3139 static void php_imagettftext_common(INTERNAL_FUNCTION_PARAMETERS, int mode)
3140 {
3141 zval *IM, *EXT = NULL;
3142 gdImagePtr im=NULL;
3143 zend_long col = -1, x = 0, y = 0;
3144 size_t str_len, fontname_len;
3145 int i, brect[8];
3146 double ptsize, angle;
3147 char *str = NULL, *fontname = NULL;
3148 char *error = NULL;
3149 gdFTStringExtra strex = {0};
3150
3151 if (mode == TTFTEXT_BBOX) {
3152 if (zend_parse_parameters(ZEND_NUM_ARGS(), "ddss|a", &ptsize, &angle, &fontname, &fontname_len, &str, &str_len, &EXT) == FAILURE) {
3153 RETURN_THROWS();
3154 }
3155 } else {
3156 if (zend_parse_parameters(ZEND_NUM_ARGS(), "Oddlllss|a", &IM, gd_image_ce, &ptsize, &angle, &x, &y, &col, &fontname, &fontname_len, &str, &str_len, &EXT) == FAILURE) {
3157 RETURN_THROWS();
3158 }
3159 im = php_gd_libgdimageptr_from_zval_p(IM);
3160 }
3161
3162 /* convert angle to radians */
3163 angle = angle * (M_PI/180);
3164
3165 if (EXT) { /* parse extended info */
3166 zval *item;
3167 zend_string *key;
3168
3169 /* walk the assoc array */
3170 ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(EXT), key, item) {
3171 if (key == NULL) {
3172 continue;
3173 }
3174 if (strcmp("linespacing", ZSTR_VAL(key)) == 0) {
3175 strex.flags |= gdFTEX_LINESPACE;
3176 strex.linespacing = zval_get_double(item);
3177 }
3178 } ZEND_HASH_FOREACH_END();
3179 }
3180
3181 #ifdef VIRTUAL_DIR
3182 {
3183 char tmp_font_path[MAXPATHLEN];
3184
3185 if (!VCWD_REALPATH(fontname, tmp_font_path)) {
3186 fontname = NULL;
3187 }
3188 }
3189 #endif /* VIRTUAL_DIR */
3190
3191 PHP_GD_CHECK_OPEN_BASEDIR(fontname, "Invalid font filename");
3192
3193 if (EXT) {
3194 error = gdImageStringFTEx(im, brect, col, fontname, ptsize, angle, x, y, str, &strex);
3195 } else {
3196 error = gdImageStringFT(im, brect, col, fontname, ptsize, angle, x, y, str);
3197 }
3198
3199 if (error) {
3200 php_error_docref(NULL, E_WARNING, "%s", error);
3201 RETURN_FALSE;
3202 }
3203
3204 array_init(return_value);
3205
3206 /* return array with the text's bounding box */
3207 for (i = 0; i < 8; i++) {
3208 add_next_index_long(return_value, brect[i]);
3209 }
3210 }
3211 /* }}} */
3212 #endif /* HAVE_GD_FREETYPE */
3213
3214 /* Section Filters */
3215 #define PHP_GD_SINGLE_RES \
3216 zval *SIM; \
3217 gdImagePtr im_src; \
3218 if (zend_parse_parameters(1, "O", &SIM, gd_image_ce) == FAILURE) { \
3219 RETURN_THROWS(); \
3220 } \
3221 im_src = php_gd_libgdimageptr_from_zval_p(SIM);
3222
php_image_filter_negate(INTERNAL_FUNCTION_PARAMETERS)3223 static void php_image_filter_negate(INTERNAL_FUNCTION_PARAMETERS)
3224 {
3225 PHP_GD_SINGLE_RES
3226
3227 if (gdImageNegate(im_src) == 1) {
3228 RETURN_TRUE;
3229 }
3230
3231 RETURN_FALSE;
3232 }
3233
php_image_filter_grayscale(INTERNAL_FUNCTION_PARAMETERS)3234 static void php_image_filter_grayscale(INTERNAL_FUNCTION_PARAMETERS)
3235 {
3236 PHP_GD_SINGLE_RES
3237
3238 if (gdImageGrayScale(im_src) == 1) {
3239 RETURN_TRUE;
3240 }
3241
3242 RETURN_FALSE;
3243 }
3244
php_image_filter_brightness(INTERNAL_FUNCTION_PARAMETERS)3245 static void php_image_filter_brightness(INTERNAL_FUNCTION_PARAMETERS)
3246 {
3247 zval *SIM;
3248 gdImagePtr im_src;
3249 zend_long brightness, tmp;
3250
3251 if (zend_parse_parameters(ZEND_NUM_ARGS(), "Oll", &SIM, gd_image_ce, &tmp, &brightness) == FAILURE) {
3252 RETURN_THROWS();
3253 }
3254
3255 im_src = php_gd_libgdimageptr_from_zval_p(SIM);
3256
3257 if (gdImageBrightness(im_src, (int)brightness) == 1) {
3258 RETURN_TRUE;
3259 }
3260
3261 RETURN_FALSE;
3262 }
3263
php_image_filter_contrast(INTERNAL_FUNCTION_PARAMETERS)3264 static void php_image_filter_contrast(INTERNAL_FUNCTION_PARAMETERS)
3265 {
3266 zval *SIM;
3267 gdImagePtr im_src;
3268 zend_long contrast, tmp;
3269
3270 if (zend_parse_parameters(ZEND_NUM_ARGS(), "Oll", &SIM, gd_image_ce, &tmp, &contrast) == FAILURE) {
3271 RETURN_THROWS();
3272 }
3273
3274 im_src = php_gd_libgdimageptr_from_zval_p(SIM);
3275
3276 if (gdImageContrast(im_src, (int)contrast) == 1) {
3277 RETURN_TRUE;
3278 }
3279
3280 RETURN_FALSE;
3281 }
3282
php_image_filter_colorize(INTERNAL_FUNCTION_PARAMETERS)3283 static void php_image_filter_colorize(INTERNAL_FUNCTION_PARAMETERS)
3284 {
3285 zval *SIM;
3286 gdImagePtr im_src;
3287 zend_long r,g,b,tmp;
3288 zend_long a = 0;
3289
3290 if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ollll|l", &SIM, gd_image_ce, &tmp, &r, &g, &b, &a) == FAILURE) {
3291 RETURN_THROWS();
3292 }
3293
3294 im_src = php_gd_libgdimageptr_from_zval_p(SIM);
3295
3296 if (gdImageColor(im_src, (int) r, (int) g, (int) b, (int) a) == 1) {
3297 RETURN_TRUE;
3298 }
3299
3300 RETURN_FALSE;
3301 }
3302
php_image_filter_edgedetect(INTERNAL_FUNCTION_PARAMETERS)3303 static void php_image_filter_edgedetect(INTERNAL_FUNCTION_PARAMETERS)
3304 {
3305 PHP_GD_SINGLE_RES
3306
3307 if (gdImageEdgeDetectQuick(im_src) == 1) {
3308 RETURN_TRUE;
3309 }
3310
3311 RETURN_FALSE;
3312 }
3313
php_image_filter_emboss(INTERNAL_FUNCTION_PARAMETERS)3314 static void php_image_filter_emboss(INTERNAL_FUNCTION_PARAMETERS)
3315 {
3316 PHP_GD_SINGLE_RES
3317
3318 if (gdImageEmboss(im_src) == 1) {
3319 RETURN_TRUE;
3320 }
3321
3322 RETURN_FALSE;
3323 }
3324
php_image_filter_gaussian_blur(INTERNAL_FUNCTION_PARAMETERS)3325 static void php_image_filter_gaussian_blur(INTERNAL_FUNCTION_PARAMETERS)
3326 {
3327 PHP_GD_SINGLE_RES
3328
3329 if (gdImageGaussianBlur(im_src) == 1) {
3330 RETURN_TRUE;
3331 }
3332
3333 RETURN_FALSE;
3334 }
3335
php_image_filter_selective_blur(INTERNAL_FUNCTION_PARAMETERS)3336 static void php_image_filter_selective_blur(INTERNAL_FUNCTION_PARAMETERS)
3337 {
3338 PHP_GD_SINGLE_RES
3339
3340 if (gdImageSelectiveBlur(im_src) == 1) {
3341 RETURN_TRUE;
3342 }
3343
3344 RETURN_FALSE;
3345 }
3346
php_image_filter_mean_removal(INTERNAL_FUNCTION_PARAMETERS)3347 static void php_image_filter_mean_removal(INTERNAL_FUNCTION_PARAMETERS)
3348 {
3349 PHP_GD_SINGLE_RES
3350
3351 if (gdImageMeanRemoval(im_src) == 1) {
3352 RETURN_TRUE;
3353 }
3354
3355 RETURN_FALSE;
3356 }
3357
php_image_filter_smooth(INTERNAL_FUNCTION_PARAMETERS)3358 static void php_image_filter_smooth(INTERNAL_FUNCTION_PARAMETERS)
3359 {
3360 zval *SIM;
3361 zend_long tmp;
3362 gdImagePtr im_src;
3363 double weight;
3364
3365 if (zend_parse_parameters(ZEND_NUM_ARGS(), "Old", &SIM, gd_image_ce, &tmp, &weight) == FAILURE) {
3366 RETURN_THROWS();
3367 }
3368
3369 im_src = php_gd_libgdimageptr_from_zval_p(SIM);
3370
3371 if (gdImageSmooth(im_src, (float)weight)==1) {
3372 RETURN_TRUE;
3373 }
3374
3375 RETURN_FALSE;
3376 }
3377
php_image_filter_pixelate(INTERNAL_FUNCTION_PARAMETERS)3378 static void php_image_filter_pixelate(INTERNAL_FUNCTION_PARAMETERS)
3379 {
3380 zval *IM;
3381 gdImagePtr im;
3382 zend_long tmp, blocksize;
3383 zend_bool mode = 0;
3384
3385 if (zend_parse_parameters(ZEND_NUM_ARGS(), "Oll|b", &IM, gd_image_ce, &tmp, &blocksize, &mode) == FAILURE) {
3386 RETURN_THROWS();
3387 }
3388
3389 im = php_gd_libgdimageptr_from_zval_p(IM);
3390
3391 if (gdImagePixelate(im, (int) blocksize, (const unsigned int) mode)) {
3392 RETURN_TRUE;
3393 }
3394
3395 RETURN_FALSE;
3396 }
3397
php_image_filter_scatter(INTERNAL_FUNCTION_PARAMETERS)3398 static void php_image_filter_scatter(INTERNAL_FUNCTION_PARAMETERS)
3399 {
3400 zval *IM;
3401 zval *hash_colors = NULL;
3402 gdImagePtr im;
3403 zend_long tmp;
3404 zend_long scatter_sub, scatter_plus;
3405
3406 if (zend_parse_parameters(ZEND_NUM_ARGS(), "Olll|a", &IM, gd_image_ce, &tmp, &scatter_sub, &scatter_plus, &hash_colors) == FAILURE) {
3407 RETURN_THROWS();
3408 }
3409
3410 im = php_gd_libgdimageptr_from_zval_p(IM);
3411
3412 if (hash_colors) {
3413 uint32_t i = 0;
3414 uint32_t num_colors = zend_hash_num_elements(Z_ARRVAL_P(hash_colors));
3415 zval *color;
3416 int *colors;
3417
3418 if (num_colors == 0) {
3419 RETURN_BOOL(gdImageScatter(im, (int)scatter_sub, (int)scatter_plus));
3420 }
3421
3422 colors = emalloc(num_colors * sizeof(int));
3423
3424 ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(hash_colors), color) {
3425 *(colors + i++) = (int) zval_get_long(color);
3426 } ZEND_HASH_FOREACH_END();
3427
3428 RETVAL_BOOL(gdImageScatterColor(im, (int)scatter_sub, (int)scatter_plus, colors, num_colors));
3429
3430 efree(colors);
3431 } else {
3432 RETURN_BOOL(gdImageScatter(im, (int) scatter_sub, (int) scatter_plus));
3433 }
3434 }
3435
3436 /* {{{ Applies Filter an image using a custom angle */
PHP_FUNCTION(imagefilter)3437 PHP_FUNCTION(imagefilter)
3438 {
3439 zval *tmp;
3440
3441 typedef void (*image_filter)(INTERNAL_FUNCTION_PARAMETERS);
3442 zend_long filtertype;
3443 image_filter filters[] =
3444 {
3445 php_image_filter_negate ,
3446 php_image_filter_grayscale,
3447 php_image_filter_brightness,
3448 php_image_filter_contrast,
3449 php_image_filter_colorize,
3450 php_image_filter_edgedetect,
3451 php_image_filter_emboss,
3452 php_image_filter_gaussian_blur,
3453 php_image_filter_selective_blur,
3454 php_image_filter_mean_removal,
3455 php_image_filter_smooth,
3456 php_image_filter_pixelate,
3457 php_image_filter_scatter
3458 };
3459
3460 if (ZEND_NUM_ARGS() < 2 || ZEND_NUM_ARGS() > IMAGE_FILTER_MAX_ARGS) {
3461 WRONG_PARAM_COUNT;
3462 } else if (zend_parse_parameters(2, "Ol", &tmp, gd_image_ce, &filtertype) == FAILURE) {
3463 RETURN_THROWS();
3464 }
3465
3466 if (filtertype >= 0 && filtertype <= IMAGE_FILTER_MAX) {
3467 filters[filtertype](INTERNAL_FUNCTION_PARAM_PASSTHRU);
3468 }
3469 }
3470 /* }}} */
3471
3472 /* {{{ Apply a 3x3 convolution matrix, using coefficient div and offset */
PHP_FUNCTION(imageconvolution)3473 PHP_FUNCTION(imageconvolution)
3474 {
3475 zval *SIM, *hash_matrix;
3476 zval *var = NULL, *var2 = NULL;
3477 gdImagePtr im_src = NULL;
3478 double div, offset;
3479 int nelem, i, j, res;
3480 float matrix[3][3] = {{0,0,0}, {0,0,0}, {0,0,0}};
3481
3482 if (zend_parse_parameters(ZEND_NUM_ARGS(), "Oadd", &SIM, gd_image_ce, &hash_matrix, &div, &offset) == FAILURE) {
3483 RETURN_THROWS();
3484 }
3485
3486 im_src = php_gd_libgdimageptr_from_zval_p(SIM);
3487
3488 nelem = zend_hash_num_elements(Z_ARRVAL_P(hash_matrix));
3489 if (nelem != 3) {
3490 zend_argument_value_error(2, "must be a 3x3 array");
3491 RETURN_THROWS();
3492 }
3493
3494 for (i=0; i<3; i++) {
3495 if ((var = zend_hash_index_find(Z_ARRVAL_P(hash_matrix), (i))) != NULL && Z_TYPE_P(var) == IS_ARRAY) {
3496 if (zend_hash_num_elements(Z_ARRVAL_P(var)) != 3 ) {
3497 zend_argument_value_error(2, "must be a 3x3 array, matrix[%d] only has %d elements", i, zend_hash_num_elements(Z_ARRVAL_P(var)));
3498 RETURN_THROWS();
3499 }
3500
3501 for (j=0; j<3; j++) {
3502 if ((var2 = zend_hash_index_find(Z_ARRVAL_P(var), j)) != NULL) {
3503 matrix[i][j] = (float) zval_get_double(var2);
3504 } else {
3505 zend_argument_value_error(2, "must be a 3x3 array, matrix[%d][%d] cannot be found (missing integer key)", i, j);
3506 RETURN_THROWS();
3507 }
3508 }
3509 }
3510 }
3511 res = gdImageConvolution(im_src, matrix, (float)div, (float)offset);
3512
3513 if (res) {
3514 RETURN_TRUE;
3515 } else {
3516 RETURN_FALSE;
3517 }
3518 }
3519 /* }}} */
3520 /* End section: Filters */
3521
3522 /* {{{ Flip an image (in place) horizontally, vertically or both directions. */
PHP_FUNCTION(imageflip)3523 PHP_FUNCTION(imageflip)
3524 {
3525 zval *IM;
3526 zend_long mode;
3527 gdImagePtr im;
3528
3529 if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ol", &IM, gd_image_ce, &mode) == FAILURE) {
3530 RETURN_THROWS();
3531 }
3532
3533 im = php_gd_libgdimageptr_from_zval_p(IM);
3534
3535 switch (mode) {
3536 case GD_FLIP_VERTICAL:
3537 gdImageFlipVertical(im);
3538 break;
3539
3540 case GD_FLIP_HORIZONTAL:
3541 gdImageFlipHorizontal(im);
3542 break;
3543
3544 case GD_FLIP_BOTH:
3545 gdImageFlipBoth(im);
3546 break;
3547
3548 default:
3549 zend_argument_value_error(2, "must be one of IMG_FLIP_VERTICAL, IMG_FLIP_HORIZONTAL, or IMG_FLIP_BOTH");
3550 RETURN_THROWS();
3551 }
3552
3553 RETURN_TRUE;
3554 }
3555 /* }}} */
3556
3557 /* {{{ Should antialiased functions used or not*/
PHP_FUNCTION(imageantialias)3558 PHP_FUNCTION(imageantialias)
3559 {
3560 zval *IM;
3561 zend_bool alias;
3562 gdImagePtr im;
3563
3564 if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ob", &IM, gd_image_ce, &alias) == FAILURE) {
3565 RETURN_THROWS();
3566 }
3567
3568 im = php_gd_libgdimageptr_from_zval_p(IM);
3569 if (im->trueColor) {
3570 im->AA = alias;
3571 }
3572
3573 RETURN_TRUE;
3574 }
3575 /* }}} */
3576
3577 /* {{{ Crop an image using the given coordinates and size, x, y, width and height. */
PHP_FUNCTION(imagecrop)3578 PHP_FUNCTION(imagecrop)
3579 {
3580 zval *IM;
3581 gdImagePtr im;
3582 gdImagePtr im_crop;
3583 gdRect rect;
3584 zval *z_rect;
3585 zval *tmp;
3586
3587 if (zend_parse_parameters(ZEND_NUM_ARGS(), "Oa", &IM, gd_image_ce, &z_rect) == FAILURE) {
3588 RETURN_THROWS();
3589 }
3590
3591 im = php_gd_libgdimageptr_from_zval_p(IM);
3592
3593 if ((tmp = zend_hash_str_find(Z_ARRVAL_P(z_rect), "x", sizeof("x") -1)) != NULL) {
3594 rect.x = zval_get_long(tmp);
3595 } else {
3596 zend_argument_value_error(2, "must have an \"x\" key");
3597 RETURN_THROWS();
3598 }
3599
3600 if ((tmp = zend_hash_str_find(Z_ARRVAL_P(z_rect), "y", sizeof("y") - 1)) != NULL) {
3601 rect.y = zval_get_long(tmp);
3602 } else {
3603 zend_argument_value_error(2, "must have a \"y\" key");
3604 RETURN_THROWS();
3605 }
3606
3607 if ((tmp = zend_hash_str_find(Z_ARRVAL_P(z_rect), "width", sizeof("width") - 1)) != NULL) {
3608 rect.width = zval_get_long(tmp);
3609 } else {
3610 zend_argument_value_error(2, "must have a \"width\" key");
3611 RETURN_THROWS();
3612 }
3613
3614 if ((tmp = zend_hash_str_find(Z_ARRVAL_P(z_rect), "height", sizeof("height") - 1)) != NULL) {
3615 rect.height = zval_get_long(tmp);
3616 } else {
3617 zend_argument_value_error(2, "must have a \"height\" key");
3618 RETURN_THROWS();
3619 }
3620
3621 im_crop = gdImageCrop(im, &rect);
3622
3623 if (im_crop == NULL) {
3624 RETURN_FALSE;
3625 }
3626
3627 php_gd_assign_libgdimageptr_as_extgdimage(return_value, im_crop);
3628 }
3629 /* }}} */
3630
3631 /* {{{ Crop an image automatically using one of the available modes. */
PHP_FUNCTION(imagecropauto)3632 PHP_FUNCTION(imagecropauto)
3633 {
3634 zval *IM;
3635 zend_long mode = GD_CROP_DEFAULT;
3636 zend_long color = -1;
3637 double threshold = 0.5f;
3638 gdImagePtr im;
3639 gdImagePtr im_crop;
3640
3641 if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|ldl", &IM, gd_image_ce, &mode, &threshold, &color) == FAILURE) {
3642 RETURN_THROWS();
3643 }
3644
3645 im = php_gd_libgdimageptr_from_zval_p(IM);
3646
3647 switch (mode) {
3648 case GD_CROP_DEFAULT:
3649 case GD_CROP_TRANSPARENT:
3650 case GD_CROP_BLACK:
3651 case GD_CROP_WHITE:
3652 case GD_CROP_SIDES:
3653 im_crop = gdImageCropAuto(im, mode);
3654 break;
3655
3656 case GD_CROP_THRESHOLD:
3657 if (color < 0 || (!gdImageTrueColor(im) && color >= gdImageColorsTotal(im))) {
3658 zend_argument_value_error(4, "must be greater than or equal to 0 when using the threshold mode");
3659 RETURN_THROWS();
3660 }
3661 im_crop = gdImageCropThreshold(im, color, (float) threshold);
3662 break;
3663
3664 default:
3665 zend_argument_value_error(2, "must be a valid mode");
3666 RETURN_THROWS();
3667 }
3668
3669 if (im_crop == NULL) {
3670 RETURN_FALSE;
3671 }
3672
3673 php_gd_assign_libgdimageptr_as_extgdimage(return_value, im_crop);
3674 }
3675 /* }}} */
3676
3677 /* {{{ Scale an image using the given new width and height. */
PHP_FUNCTION(imagescale)3678 PHP_FUNCTION(imagescale)
3679 {
3680 zval *IM;
3681 gdImagePtr im;
3682 gdImagePtr im_scaled = NULL;
3683 int new_width, new_height;
3684 zend_long tmp_w, tmp_h=-1, tmp_m = GD_BILINEAR_FIXED;
3685 gdInterpolationMethod method, old_method;
3686
3687 if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ol|ll", &IM, gd_image_ce, &tmp_w, &tmp_h, &tmp_m) == FAILURE) {
3688 RETURN_THROWS();
3689 }
3690 method = tmp_m;
3691
3692 im = php_gd_libgdimageptr_from_zval_p(IM);
3693
3694 if (tmp_h < 0 || tmp_w < 0) {
3695 /* preserve ratio */
3696 long src_x, src_y;
3697
3698 src_x = gdImageSX(im);
3699 src_y = gdImageSY(im);
3700
3701 if (src_x && tmp_h < 0) {
3702 tmp_h = tmp_w * src_y / src_x;
3703 }
3704 if (src_y && tmp_w < 0) {
3705 tmp_w = tmp_h * src_x / src_y;
3706 }
3707 }
3708
3709 if (tmp_h <= 0 || tmp_h > INT_MAX || tmp_w <= 0 || tmp_w > INT_MAX) {
3710 RETURN_FALSE;
3711 }
3712
3713 new_width = tmp_w;
3714 new_height = tmp_h;
3715
3716 /* gdImageGetInterpolationMethod() is only available as of GD 2.1.1 */
3717 old_method = im->interpolation_id;
3718 if (gdImageSetInterpolationMethod(im, method)) {
3719 im_scaled = gdImageScale(im, new_width, new_height);
3720 }
3721 gdImageSetInterpolationMethod(im, old_method);
3722
3723 if (im_scaled == NULL) {
3724 RETURN_FALSE;
3725 }
3726
3727 php_gd_assign_libgdimageptr_as_extgdimage(return_value, im_scaled);
3728 }
3729 /* }}} */
3730
3731 /* {{{ Return an image containing the affine tramsformed src image, using an optional clipping area */
PHP_FUNCTION(imageaffine)3732 PHP_FUNCTION(imageaffine)
3733 {
3734 zval *IM;
3735 gdImagePtr src;
3736 gdImagePtr dst;
3737 gdRect rect;
3738 gdRectPtr pRect = NULL;
3739 zval *z_rect = NULL;
3740 zval *z_affine;
3741 zval *tmp;
3742 double affine[6];
3743 int i, nelems;
3744 zval *zval_affine_elem = NULL;
3745
3746 if (zend_parse_parameters(ZEND_NUM_ARGS(), "Oa|a!", &IM, gd_image_ce, &z_affine, &z_rect) == FAILURE) {
3747 RETURN_THROWS();
3748 }
3749
3750 src = php_gd_libgdimageptr_from_zval_p(IM);
3751
3752 if ((nelems = zend_hash_num_elements(Z_ARRVAL_P(z_affine))) != 6) {
3753 zend_argument_value_error(2, "must have 6 elements");
3754 RETURN_THROWS();
3755 }
3756
3757 for (i = 0; i < nelems; i++) {
3758 if ((zval_affine_elem = zend_hash_index_find(Z_ARRVAL_P(z_affine), i)) != NULL) {
3759 switch (Z_TYPE_P(zval_affine_elem)) {
3760 case IS_LONG:
3761 affine[i] = Z_LVAL_P(zval_affine_elem);
3762 break;
3763 case IS_DOUBLE:
3764 affine[i] = Z_DVAL_P(zval_affine_elem);
3765 break;
3766 case IS_STRING:
3767 affine[i] = zval_get_double(zval_affine_elem);
3768 break;
3769 default:
3770 zend_argument_type_error(3, "contains invalid type for element %i", i);
3771 RETURN_THROWS();
3772 }
3773 }
3774 }
3775
3776 if (z_rect != NULL) {
3777 if ((tmp = zend_hash_str_find(Z_ARRVAL_P(z_rect), "x", sizeof("x") - 1)) != NULL) {
3778 rect.x = zval_get_long(tmp);
3779 } else {
3780 zend_argument_value_error(3, "must have an \"x\" key");
3781 RETURN_THROWS();
3782 }
3783
3784 if ((tmp = zend_hash_str_find(Z_ARRVAL_P(z_rect), "y", sizeof("y") - 1)) != NULL) {
3785 rect.y = zval_get_long(tmp);
3786 } else {
3787 zend_argument_value_error(3, "must have a \"y\" key");
3788 RETURN_THROWS();
3789 }
3790
3791 if ((tmp = zend_hash_str_find(Z_ARRVAL_P(z_rect), "width", sizeof("width") - 1)) != NULL) {
3792 rect.width = zval_get_long(tmp);
3793 } else {
3794 zend_argument_value_error(3, "must have a \"width\" key");
3795 RETURN_THROWS();
3796 }
3797
3798 if ((tmp = zend_hash_str_find(Z_ARRVAL_P(z_rect), "height", sizeof("height") - 1)) != NULL) {
3799 rect.height = zval_get_long(tmp);
3800 } else {
3801 zend_argument_value_error(3, "must have a \"height\" key");
3802 RETURN_THROWS();
3803 }
3804 pRect = ▭
3805 }
3806
3807 if (gdTransformAffineGetImage(&dst, src, pRect, affine) != GD_TRUE) {
3808 RETURN_FALSE;
3809 }
3810
3811 if (dst == NULL) {
3812 RETURN_FALSE;
3813 }
3814
3815 php_gd_assign_libgdimageptr_as_extgdimage(return_value, dst);
3816 }
3817 /* }}} */
3818
3819 /* {{{ Return an image containing the affine tramsformed src image, using an optional clipping area */
PHP_FUNCTION(imageaffinematrixget)3820 PHP_FUNCTION(imageaffinematrixget)
3821 {
3822 double affine[6];
3823 zend_long type;
3824 zval *options = NULL;
3825 zval *tmp;
3826 int res = GD_FALSE, i;
3827
3828 if (zend_parse_parameters(ZEND_NUM_ARGS(), "lz", &type, &options) == FAILURE) {
3829 RETURN_THROWS();
3830 }
3831
3832 switch((gdAffineStandardMatrix)type) {
3833 case GD_AFFINE_TRANSLATE:
3834 case GD_AFFINE_SCALE: {
3835 double x, y;
3836 if (Z_TYPE_P(options) != IS_ARRAY) {
3837 zend_argument_type_error(1, "must be of type array when using translate or scale");
3838 RETURN_THROWS();
3839 }
3840
3841 if ((tmp = zend_hash_str_find(Z_ARRVAL_P(options), "x", sizeof("x") - 1)) != NULL) {
3842 x = zval_get_double(tmp);
3843 } else {
3844 zend_argument_value_error(2, "must have an \"x\" key");
3845 RETURN_THROWS();
3846 }
3847
3848 if ((tmp = zend_hash_str_find(Z_ARRVAL_P(options), "y", sizeof("y") - 1)) != NULL) {
3849 y = zval_get_double(tmp);
3850 } else {
3851 zend_argument_value_error(2, "must have a \"y\" key");
3852 RETURN_THROWS();
3853 }
3854
3855 if (type == GD_AFFINE_TRANSLATE) {
3856 res = gdAffineTranslate(affine, x, y);
3857 } else {
3858 res = gdAffineScale(affine, x, y);
3859 }
3860 break;
3861 }
3862
3863 case GD_AFFINE_ROTATE:
3864 case GD_AFFINE_SHEAR_HORIZONTAL:
3865 case GD_AFFINE_SHEAR_VERTICAL: {
3866 double angle;
3867
3868 angle = zval_get_double(options);
3869
3870 if (type == GD_AFFINE_SHEAR_HORIZONTAL) {
3871 res = gdAffineShearHorizontal(affine, angle);
3872 } else if (type == GD_AFFINE_SHEAR_VERTICAL) {
3873 res = gdAffineShearVertical(affine, angle);
3874 } else {
3875 res = gdAffineRotate(affine, angle);
3876 }
3877 break;
3878 }
3879
3880 default:
3881 zend_argument_value_error(1, "must be a valid element type");
3882 RETURN_THROWS();
3883 }
3884
3885 if (res == GD_FALSE) {
3886 RETURN_FALSE;
3887 } else {
3888 array_init(return_value);
3889 for (i = 0; i < 6; i++) {
3890 add_index_double(return_value, i, affine[i]);
3891 }
3892 }
3893 } /* }}} */
3894
3895 /* {{{ Concat two matrices (as in doing many ops in one go) */
PHP_FUNCTION(imageaffinematrixconcat)3896 PHP_FUNCTION(imageaffinematrixconcat)
3897 {
3898 double m1[6];
3899 double m2[6];
3900 double mr[6];
3901
3902 zval *tmp;
3903 zval *z_m1;
3904 zval *z_m2;
3905 int i;
3906
3907 if (zend_parse_parameters(ZEND_NUM_ARGS(), "aa", &z_m1, &z_m2) == FAILURE) {
3908 RETURN_THROWS();
3909 }
3910
3911 if (zend_hash_num_elements(Z_ARRVAL_P(z_m1)) != 6) {
3912 zend_argument_value_error(1, "must have 6 elements");
3913 RETURN_THROWS();
3914 }
3915
3916 if (zend_hash_num_elements(Z_ARRVAL_P(z_m2)) != 6) {
3917 zend_argument_value_error(1, "must have 6 elements");
3918 RETURN_THROWS();
3919 }
3920
3921 for (i = 0; i < 6; i++) {
3922 if ((tmp = zend_hash_index_find(Z_ARRVAL_P(z_m1), i)) != NULL) {
3923 switch (Z_TYPE_P(tmp)) {
3924 case IS_LONG:
3925 m1[i] = Z_LVAL_P(tmp);
3926 break;
3927 case IS_DOUBLE:
3928 m1[i] = Z_DVAL_P(tmp);
3929 break;
3930 case IS_STRING:
3931 m1[i] = zval_get_double(tmp);
3932 break;
3933 default:
3934 zend_argument_type_error(1, "contains invalid type for element %i", i);
3935 RETURN_THROWS();
3936 }
3937 }
3938
3939 if ((tmp = zend_hash_index_find(Z_ARRVAL_P(z_m2), i)) != NULL) {
3940 switch (Z_TYPE_P(tmp)) {
3941 case IS_LONG:
3942 m2[i] = Z_LVAL_P(tmp);
3943 break;
3944 case IS_DOUBLE:
3945 m2[i] = Z_DVAL_P(tmp);
3946 break;
3947 case IS_STRING:
3948 m2[i] = zval_get_double(tmp);
3949 break;
3950 default:
3951 zend_argument_type_error(2, "contains invalid type for element %i", i);
3952 RETURN_THROWS();
3953 }
3954 }
3955 }
3956
3957 if (gdAffineConcat (mr, m1, m2) != GD_TRUE) {
3958 RETURN_FALSE;
3959 }
3960
3961 array_init(return_value);
3962 for (i = 0; i < 6; i++) {
3963 add_index_double(return_value, i, mr[i]);
3964 }
3965 } /* }}} */
3966
3967 /* {{{ Get the default interpolation method. */
PHP_FUNCTION(imagegetinterpolation)3968 PHP_FUNCTION(imagegetinterpolation)
3969 {
3970 zval *IM;
3971 gdImagePtr im;
3972
3973 if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &IM, gd_image_ce) == FAILURE) {
3974 RETURN_THROWS();
3975 }
3976 im = php_gd_libgdimageptr_from_zval_p(IM);
3977
3978 #ifdef HAVE_GD_GET_INTERPOLATION
3979 RETURN_LONG(gdImageGetInterpolationMethod(im));
3980 #else
3981 RETURN_LONG(im->interpolation_id);
3982 #endif
3983 }
3984 /* }}} */
3985
3986 /* {{{ Set the default interpolation method, passing -1 or 0 sets it to the libgd default (bilinear). */
PHP_FUNCTION(imagesetinterpolation)3987 PHP_FUNCTION(imagesetinterpolation)
3988 {
3989 zval *IM;
3990 gdImagePtr im;
3991 zend_long method = GD_BILINEAR_FIXED;
3992
3993 if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|l", &IM, gd_image_ce, &method) == FAILURE) {
3994 RETURN_THROWS();
3995 }
3996
3997 im = php_gd_libgdimageptr_from_zval_p(IM);
3998
3999 if (method == -1) {
4000 method = GD_BILINEAR_FIXED;
4001 }
4002 RETURN_BOOL(gdImageSetInterpolationMethod(im, (gdInterpolationMethod) method));
4003 }
4004 /* }}} */
4005
4006 /* {{{ Get or set the resolution of the image in DPI. */
PHP_FUNCTION(imageresolution)4007 PHP_FUNCTION(imageresolution)
4008 {
4009 zval *IM;
4010 gdImagePtr im;
4011 zend_long res_x, res_y;
4012 zend_bool res_x_is_null = 1, res_y_is_null = 1;
4013
4014 if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|l!l!", &IM, gd_image_ce, &res_x, &res_x_is_null, &res_y, &res_y_is_null) == FAILURE) {
4015 RETURN_THROWS();
4016 }
4017
4018 im = php_gd_libgdimageptr_from_zval_p(IM);
4019
4020 if (!res_x_is_null && !res_y_is_null) {
4021 gdImageSetResolution(im, res_x, res_y);
4022 RETURN_TRUE;
4023 } else if (!res_x_is_null && res_y_is_null) {
4024 gdImageSetResolution(im, res_x, res_x);
4025 RETURN_TRUE;
4026 } else if (res_x_is_null && !res_y_is_null) {
4027 gdImageSetResolution(im, res_y, res_y);
4028 RETURN_TRUE;
4029 }
4030
4031 array_init(return_value);
4032 add_next_index_long(return_value, gdImageResolutionX(im));
4033 add_next_index_long(return_value, gdImageResolutionY(im));
4034 }
4035 /* }}} */
4036
4037
4038 /*********************************************************
4039 *
4040 * Stream Handling
4041 * Formerly contained within ext/gd/gd_ctx.c and included
4042 * at the the top of this file
4043 *
4044 ********************************************************/
4045
4046 #define CTX_PUTC(c,ctx) ctx->putC(ctx, c)
4047
_php_image_output_putc(struct gdIOCtx * ctx,int c)4048 static void _php_image_output_putc(struct gdIOCtx *ctx, int c) /* {{{ */
4049 {
4050 /* without the following downcast, the write will fail
4051 * (i.e., will write a zero byte) for all
4052 * big endian architectures:
4053 */
4054 unsigned char ch = (unsigned char) c;
4055 php_write(&ch, 1);
4056 } /* }}} */
4057
_php_image_output_putbuf(struct gdIOCtx * ctx,const void * buf,int l)4058 static int _php_image_output_putbuf(struct gdIOCtx *ctx, const void* buf, int l) /* {{{ */
4059 {
4060 return php_write((void *)buf, l);
4061 } /* }}} */
4062
_php_image_output_ctxfree(struct gdIOCtx * ctx)4063 static void _php_image_output_ctxfree(struct gdIOCtx *ctx) /* {{{ */
4064 {
4065 if(ctx) {
4066 efree(ctx);
4067 }
4068 } /* }}} */
4069
_php_image_stream_putc(struct gdIOCtx * ctx,int c)4070 static void _php_image_stream_putc(struct gdIOCtx *ctx, int c) /* {{{ */ {
4071 char ch = (char) c;
4072 php_stream * stream = (php_stream *)ctx->data;
4073 php_stream_write(stream, &ch, 1);
4074 } /* }}} */
4075
_php_image_stream_putbuf(struct gdIOCtx * ctx,const void * buf,int l)4076 static int _php_image_stream_putbuf(struct gdIOCtx *ctx, const void* buf, int l) /* {{{ */
4077 {
4078 php_stream * stream = (php_stream *)ctx->data;
4079 return php_stream_write(stream, (void *)buf, l);
4080 } /* }}} */
4081
_php_image_stream_ctxfree(struct gdIOCtx * ctx)4082 static void _php_image_stream_ctxfree(struct gdIOCtx *ctx) /* {{{ */
4083 {
4084 if(ctx->data) {
4085 ctx->data = NULL;
4086 }
4087 if(ctx) {
4088 efree(ctx);
4089 }
4090 } /* }}} */
4091
_php_image_stream_ctxfreeandclose(struct gdIOCtx * ctx)4092 static void _php_image_stream_ctxfreeandclose(struct gdIOCtx *ctx) /* {{{ */
4093 {
4094
4095 if(ctx->data) {
4096 php_stream_close((php_stream *) ctx->data);
4097 ctx->data = NULL;
4098 }
4099 if(ctx) {
4100 efree(ctx);
4101 }
4102 } /* }}} */
4103
create_stream_context_from_zval(zval * to_zval)4104 static gdIOCtx *create_stream_context_from_zval(zval *to_zval) {
4105 php_stream *stream;
4106 int close_stream = 1;
4107
4108 if (Z_TYPE_P(to_zval) == IS_RESOURCE) {
4109 php_stream_from_zval_no_verify(stream, to_zval);
4110 if (stream == NULL) {
4111 return NULL;
4112 }
4113 close_stream = 0;
4114 } else if (Z_TYPE_P(to_zval) == IS_STRING) {
4115 if (CHECK_ZVAL_NULL_PATH(to_zval)) {
4116 zend_argument_type_error(2, "must not contain null bytes");
4117 return NULL;
4118 }
4119
4120 stream = php_stream_open_wrapper(Z_STRVAL_P(to_zval), "wb", REPORT_ERRORS|IGNORE_PATH|IGNORE_URL_WIN, NULL);
4121 if (stream == NULL) {
4122 return NULL;
4123 }
4124 } else {
4125 zend_argument_type_error(2, "must be a file name or a stream resource, %s given", zend_zval_type_name(to_zval));
4126 return NULL;
4127 }
4128
4129 return create_stream_context(stream, close_stream);
4130 }
4131
create_stream_context(php_stream * stream,int close_stream)4132 static gdIOCtx *create_stream_context(php_stream *stream, int close_stream) {
4133 gdIOCtx *ctx = ecalloc(1, sizeof(gdIOCtx));
4134
4135 ctx->putC = _php_image_stream_putc;
4136 ctx->putBuf = _php_image_stream_putbuf;
4137 if (close_stream) {
4138 ctx->gd_free = _php_image_stream_ctxfreeandclose;
4139 } else {
4140 ctx->gd_free = _php_image_stream_ctxfree;
4141 }
4142 ctx->data = (void *)stream;
4143
4144 return ctx;
4145 }
4146
create_output_context()4147 static gdIOCtx *create_output_context() {
4148 gdIOCtx *ctx = ecalloc(1, sizeof(gdIOCtx));
4149
4150 ctx->putC = _php_image_output_putc;
4151 ctx->putBuf = _php_image_output_putbuf;
4152 ctx->gd_free = _php_image_output_ctxfree;
4153
4154 return ctx;
4155 }
4156
_php_image_output_ctx(INTERNAL_FUNCTION_PARAMETERS,int image_type,char * tn,void (* func_p)())4157 static void _php_image_output_ctx(INTERNAL_FUNCTION_PARAMETERS, int image_type, char *tn, void (*func_p)())
4158 {
4159 zval *imgind;
4160 zend_long quality = -1, basefilter = -1;
4161 gdImagePtr im;
4162 gdIOCtx *ctx = NULL;
4163 zval *to_zval = NULL;
4164
4165 if (image_type == PHP_GDIMG_TYPE_GIF) {
4166 if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|z!", &imgind, gd_image_ce, &to_zval) == FAILURE) {
4167 RETURN_THROWS();
4168 }
4169 } else if (image_type == PHP_GDIMG_TYPE_PNG) {
4170 if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|z!ll", &imgind, gd_image_ce, &to_zval, &quality, &basefilter) == FAILURE) {
4171 RETURN_THROWS();
4172 }
4173 } else {
4174 if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|z!l", &imgind, gd_image_ce, &to_zval, &quality) == FAILURE) {
4175 RETURN_THROWS();
4176 }
4177 }
4178
4179 im = php_gd_libgdimageptr_from_zval_p(imgind);
4180
4181 if (to_zval != NULL) {
4182 ctx = create_stream_context_from_zval(to_zval);
4183 if (!ctx) {
4184 RETURN_FALSE;
4185 }
4186 } else {
4187 ctx = create_output_context();
4188 }
4189
4190 switch (image_type) {
4191 case PHP_GDIMG_TYPE_JPG:
4192 (*func_p)(im, ctx, (int) quality);
4193 break;
4194 case PHP_GDIMG_TYPE_WEBP:
4195 if (quality == -1) {
4196 quality = 80;
4197 }
4198 (*func_p)(im, ctx, (int) quality);
4199 break;
4200 #ifdef HAVE_GD_PNG
4201 case PHP_GDIMG_TYPE_PNG:
4202 #ifdef HAVE_GD_BUNDLED
4203 gdImagePngCtxEx(im, ctx, (int) quality, (int) basefilter);
4204 #else
4205 gdImagePngCtxEx(im, ctx, (int) quality);
4206 #endif
4207 break;
4208 #endif
4209 case PHP_GDIMG_TYPE_GIF:
4210 (*func_p)(im, ctx);
4211 break;
4212 EMPTY_SWITCH_DEFAULT_CASE()
4213 }
4214
4215 ctx->gd_free(ctx);
4216
4217 RETURN_TRUE;
4218 }
4219
4220 /* }}} */
4221