xref: /PHP-8.4/ext/gd/gd.c (revision 4124b04e)
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 = &rect;
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