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