xref: /php-src/ext/gd/gd.c (revision 2d1c3825)
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_image_type
1362  * Based on ext/standard/image.c
1363  */
1364 static const char php_sig_gd2[3] = {'g', 'd', '2'};
1365 
_php_image_type(zend_string * data)1366 static int _php_image_type(zend_string *data)
1367 {
1368 	if (ZSTR_LEN(data) < 12) {
1369 		/* Handle this the same way as an unknown image type. */
1370 		return -1;
1371 	}
1372 
1373 	if (!memcmp(ZSTR_VAL(data), php_sig_gd2, sizeof(php_sig_gd2))) {
1374 		return PHP_GDIMG_TYPE_GD2;
1375 	} else if (!memcmp(ZSTR_VAL(data), php_sig_jpg, sizeof(php_sig_jpg))) {
1376 		return PHP_GDIMG_TYPE_JPG;
1377 	} else if (!memcmp(ZSTR_VAL(data), php_sig_png, sizeof(php_sig_png))) {
1378 		return PHP_GDIMG_TYPE_PNG;
1379 	} else if (!memcmp(ZSTR_VAL(data), php_sig_gif, sizeof(php_sig_gif))) {
1380 		return PHP_GDIMG_TYPE_GIF;
1381 	} else if (!memcmp(ZSTR_VAL(data), php_sig_bmp, sizeof(php_sig_bmp))) {
1382 		return PHP_GDIMG_TYPE_BMP;
1383 	} 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))) {
1384 		return PHP_GDIMG_TYPE_WEBP;
1385 	}
1386 
1387 	php_stream *image_stream = php_stream_memory_open(TEMP_STREAM_READONLY, data);
1388 
1389 	if (image_stream != NULL) {
1390 		bool is_avif = php_is_image_avif(image_stream);
1391 		php_stream_close(image_stream);
1392 
1393 		if (is_avif) {
1394 			return PHP_GDIMG_TYPE_AVIF;
1395 		}
1396 	}
1397 
1398 	if (ZSTR_VAL(data)[0] == 0) {
1399 		return PHP_GDIMG_TYPE_WBM;
1400 	}
1401 
1402 	return -1;
1403 }
1404 /* }}} */
1405 
1406 /* {{{ _php_image_create_from_string */
_php_image_create_from_string(zend_string * data,const char * tn,gdImagePtr (* ioctx_func_p)(gdIOCtxPtr))1407 gdImagePtr _php_image_create_from_string(zend_string *data, const char *tn, gdImagePtr (*ioctx_func_p)(gdIOCtxPtr))
1408 {
1409 	gdImagePtr im;
1410 	gdIOCtx *io_ctx;
1411 
1412 	io_ctx = gdNewDynamicCtxEx(ZSTR_LEN(data), ZSTR_VAL(data), 0);
1413 
1414 	if (!io_ctx) {
1415 		return NULL;
1416 	}
1417 
1418 	im = (*ioctx_func_p)(io_ctx);
1419 	if (!im) {
1420 		php_error_docref(NULL, E_WARNING, "Passed data is not in \"%s\" format", tn);
1421 		io_ctx->gd_free(io_ctx);
1422 		return NULL;
1423 	}
1424 
1425 	io_ctx->gd_free(io_ctx);
1426 
1427 	return im;
1428 }
1429 /* }}} */
1430 
1431 /* {{{ Create a new image from the image stream in the string */
PHP_FUNCTION(imagecreatefromstring)1432 PHP_FUNCTION(imagecreatefromstring)
1433 {
1434 	zend_string *data;
1435 	gdImagePtr im;
1436 	int imtype;
1437 
1438 	ZEND_PARSE_PARAMETERS_START(1, 1)
1439 		Z_PARAM_STR(data)
1440 	ZEND_PARSE_PARAMETERS_END();
1441 
1442 	imtype = _php_image_type(data);
1443 
1444 	switch (imtype) {
1445 		case PHP_GDIMG_TYPE_JPG:
1446 #ifdef HAVE_GD_JPG
1447 			im = _php_image_create_from_string(data, "JPEG", gdImageCreateFromJpegCtx);
1448 #else
1449 			php_error_docref(NULL, E_WARNING, "No JPEG support in this PHP build");
1450 			RETURN_FALSE;
1451 #endif
1452 			break;
1453 
1454 		case PHP_GDIMG_TYPE_PNG:
1455 #ifdef HAVE_GD_PNG
1456 			im = _php_image_create_from_string(data, "PNG", gdImageCreateFromPngCtx);
1457 #else
1458 			php_error_docref(NULL, E_WARNING, "No PNG support in this PHP build");
1459 			RETURN_FALSE;
1460 #endif
1461 			break;
1462 
1463 		case PHP_GDIMG_TYPE_GIF:
1464 			im = _php_image_create_from_string(data, "GIF", gdImageCreateFromGifCtx);
1465 			break;
1466 
1467 		case PHP_GDIMG_TYPE_WBM:
1468 			im = _php_image_create_from_string(data, "WBMP", gdImageCreateFromWBMPCtx);
1469 			break;
1470 
1471 		case PHP_GDIMG_TYPE_GD2:
1472 			im = _php_image_create_from_string(data, "GD2", gdImageCreateFromGd2Ctx);
1473 			break;
1474 
1475 		case PHP_GDIMG_TYPE_BMP:
1476 			im = _php_image_create_from_string(data, "BMP", gdImageCreateFromBmpCtx);
1477 			break;
1478 
1479 		case PHP_GDIMG_TYPE_WEBP:
1480 #ifdef HAVE_GD_WEBP
1481 			im = _php_image_create_from_string(data, "WEBP", gdImageCreateFromWebpCtx);
1482 			break;
1483 #else
1484 			php_error_docref(NULL, E_WARNING, "No WEBP support in this PHP build");
1485 			RETURN_FALSE;
1486 #endif
1487 
1488 		case PHP_GDIMG_TYPE_AVIF:
1489 #ifdef HAVE_GD_AVIF
1490 			im = _php_image_create_from_string(data, "AVIF", gdImageCreateFromAvifCtx);
1491 			break;
1492 #else
1493 			php_error_docref(NULL, E_WARNING, "No AVIF support in this PHP build");
1494 			RETURN_FALSE;
1495 #endif
1496 
1497 		default:
1498 			php_error_docref(NULL, E_WARNING, "Data is not in a recognized format");
1499 			RETURN_FALSE;
1500 	}
1501 
1502 	if (!im) {
1503 		php_error_docref(NULL, E_WARNING, "Couldn't create GD Image Stream out of Data");
1504 		RETURN_FALSE;
1505 	}
1506 
1507 	php_gd_assign_libgdimageptr_as_extgdimage(return_value, im);
1508 }
1509 /* }}} */
1510 
1511 /* {{{ _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))1512 static void _php_image_create_from(INTERNAL_FUNCTION_PARAMETERS, int image_type, const char *tn, gdImagePtr (*func_p)(FILE *), gdImagePtr (*ioctx_func_p)(gdIOCtxPtr))
1513 {
1514 	char *file;
1515 	size_t file_len;
1516 	zend_long srcx, srcy, width, height;
1517 	gdImagePtr im = NULL;
1518 	php_stream *stream;
1519 	FILE * fp = NULL;
1520 #ifdef HAVE_GD_JPG
1521 	long ignore_warning;
1522 #endif
1523 
1524 	if (image_type == PHP_GDIMG_TYPE_GD2PART) {
1525 		if (zend_parse_parameters(ZEND_NUM_ARGS(), "pllll", &file, &file_len, &srcx, &srcy, &width, &height) == FAILURE) {
1526 			RETURN_THROWS();
1527 		}
1528 
1529 		if (width < 1) {
1530 			zend_argument_value_error(4, "must be greater than or equal to 1");
1531 			RETURN_THROWS();
1532 		}
1533 
1534 		if (height < 1) {
1535 			zend_argument_value_error(5, "must be greater than or equal to 1");
1536 			RETURN_THROWS();
1537 		}
1538 
1539 	} else {
1540 		if (zend_parse_parameters(ZEND_NUM_ARGS(), "p", &file, &file_len) == FAILURE) {
1541 			RETURN_THROWS();
1542 		}
1543 	}
1544 
1545 
1546 	stream = php_stream_open_wrapper(file, "rb", REPORT_ERRORS|IGNORE_PATH, NULL);
1547 	if (stream == NULL)	{
1548 		RETURN_FALSE;
1549 	}
1550 
1551 	/* try and avoid allocating a FILE* if the stream is not naturally a FILE* */
1552 	if (php_stream_is(stream, PHP_STREAM_IS_STDIO))	{
1553 		if (FAILURE == php_stream_cast(stream, PHP_STREAM_AS_STDIO, (void**)&fp, REPORT_ERRORS)) {
1554 			goto out_err;
1555 		}
1556 	} else if (ioctx_func_p || image_type == PHP_GDIMG_TYPE_GD2PART) {
1557 		/* we can create an io context */
1558 		gdIOCtx* io_ctx;
1559 		zend_string *buff;
1560 		char *pstr;
1561 
1562 		buff = php_stream_copy_to_mem(stream, PHP_STREAM_COPY_ALL, 0);
1563 
1564 		if (!buff) {
1565 			php_error_docref(NULL, E_WARNING,"Cannot read image data");
1566 			goto out_err;
1567 		}
1568 
1569 		/* needs to be malloc (persistent) - GD will free() it later */
1570 		pstr = pestrndup(ZSTR_VAL(buff), ZSTR_LEN(buff), 1);
1571 		io_ctx = gdNewDynamicCtxEx(ZSTR_LEN(buff), pstr, 0);
1572 		if (!io_ctx) {
1573 			pefree(pstr, 1);
1574 			zend_string_release_ex(buff, 0);
1575 			php_error_docref(NULL, E_WARNING,"Cannot allocate GD IO context");
1576 			goto out_err;
1577 		}
1578 
1579 		if (image_type == PHP_GDIMG_TYPE_GD2PART) {
1580 			im = gdImageCreateFromGd2PartCtx(io_ctx, srcx, srcy, width, height);
1581 		} else {
1582 			im = (*ioctx_func_p)(io_ctx);
1583 		}
1584 		io_ctx->gd_free(io_ctx);
1585 		pefree(pstr, 1);
1586 		zend_string_release_ex(buff, 0);
1587 	}
1588 	else if (php_stream_can_cast(stream, PHP_STREAM_AS_STDIO)) {
1589 		/* try and force the stream to be FILE* */
1590 		if (FAILURE == php_stream_cast(stream, PHP_STREAM_AS_STDIO | PHP_STREAM_CAST_TRY_HARD, (void **) &fp, REPORT_ERRORS)) {
1591 			goto out_err;
1592 		}
1593 	}
1594 
1595 	if (!im && fp) {
1596 		switch (image_type) {
1597 			case PHP_GDIMG_TYPE_GD2PART:
1598 				im = gdImageCreateFromGd2Part(fp, srcx, srcy, width, height);
1599 				break;
1600 #ifdef HAVE_GD_XPM
1601 			case PHP_GDIMG_TYPE_XPM:
1602 				im = gdImageCreateFromXpm(file);
1603 				break;
1604 #endif
1605 
1606 #ifdef HAVE_GD_JPG
1607 			case PHP_GDIMG_TYPE_JPG:
1608 				ignore_warning = INI_INT("gd.jpeg_ignore_warning");
1609 				im = gdImageCreateFromJpegEx(fp, ignore_warning);
1610 			break;
1611 #endif
1612 
1613 			default:
1614 				im = (*func_p)(fp);
1615 				break;
1616 		}
1617 
1618 		fflush(fp);
1619 	}
1620 
1621 /* register_im: */
1622 	if (im) {
1623 		php_stream_close(stream);
1624 		php_gd_assign_libgdimageptr_as_extgdimage(return_value, im);
1625 		return;
1626 	}
1627 
1628 	php_error_docref(NULL, E_WARNING, "\"%s\" is not a valid %s file", file, tn);
1629 out_err:
1630 	php_stream_close(stream);
1631 	RETURN_FALSE;
1632 
1633 }
1634 /* }}} */
1635 
1636 /* {{{ Create a new image from GIF file or URL */
PHP_FUNCTION(imagecreatefromgif)1637 PHP_FUNCTION(imagecreatefromgif)
1638 {
1639 	_php_image_create_from(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_GIF, "GIF", gdImageCreateFromGif, gdImageCreateFromGifCtx);
1640 }
1641 /* }}} */
1642 
1643 #ifdef HAVE_GD_JPG
1644 /* {{{ Create a new image from JPEG file or URL */
PHP_FUNCTION(imagecreatefromjpeg)1645 PHP_FUNCTION(imagecreatefromjpeg)
1646 {
1647 	_php_image_create_from(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_JPG, "JPEG", gdImageCreateFromJpeg, gdImageCreateFromJpegCtx);
1648 }
1649 /* }}} */
1650 #endif /* HAVE_GD_JPG */
1651 
1652 #ifdef HAVE_GD_PNG
1653 /* {{{ Create a new image from PNG file or URL */
PHP_FUNCTION(imagecreatefrompng)1654 PHP_FUNCTION(imagecreatefrompng)
1655 {
1656 	_php_image_create_from(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_PNG, "PNG", gdImageCreateFromPng, gdImageCreateFromPngCtx);
1657 }
1658 /* }}} */
1659 #endif /* HAVE_GD_PNG */
1660 
1661 #ifdef HAVE_GD_WEBP
1662 /* {{{ Create a new image from WEBP file or URL */
PHP_FUNCTION(imagecreatefromwebp)1663 PHP_FUNCTION(imagecreatefromwebp)
1664 {
1665 	_php_image_create_from(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_WEBP, "WEBP", gdImageCreateFromWebp, gdImageCreateFromWebpCtx);
1666 }
1667 /* }}} */
1668 #endif /* HAVE_GD_WEBP */
1669 
1670 /* {{{ Create a new image from XBM file or URL */
PHP_FUNCTION(imagecreatefromxbm)1671 PHP_FUNCTION(imagecreatefromxbm)
1672 {
1673 	_php_image_create_from(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_XBM, "XBM", gdImageCreateFromXbm, NULL);
1674 }
1675 /* }}} */
1676 
1677 #ifdef HAVE_GD_AVIF
1678 /* {{{ Create a new image from AVIF file or URL */
PHP_FUNCTION(imagecreatefromavif)1679 PHP_FUNCTION(imagecreatefromavif)
1680 {
1681 	_php_image_create_from(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_AVIF, "AVIF", gdImageCreateFromAvif, gdImageCreateFromAvifCtx);
1682 }
1683 /* }}} */
1684 #endif /* HAVE_GD_AVIF */
1685 
1686 #ifdef HAVE_GD_XPM
1687 /* {{{ Create a new image from XPM file or URL */
PHP_FUNCTION(imagecreatefromxpm)1688 PHP_FUNCTION(imagecreatefromxpm)
1689 {
1690 	_php_image_create_from(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_XPM, "XPM", NULL, NULL);
1691 }
1692 /* }}} */
1693 #endif
1694 
1695 /* {{{ Create a new image from WBMP file or URL */
PHP_FUNCTION(imagecreatefromwbmp)1696 PHP_FUNCTION(imagecreatefromwbmp)
1697 {
1698 	_php_image_create_from(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_WBM, "WBMP", gdImageCreateFromWBMP, gdImageCreateFromWBMPCtx);
1699 }
1700 /* }}} */
1701 
1702 /* {{{ Create a new image from GD file or URL */
PHP_FUNCTION(imagecreatefromgd)1703 PHP_FUNCTION(imagecreatefromgd)
1704 {
1705 	_php_image_create_from(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_GD, "GD", gdImageCreateFromGd, gdImageCreateFromGdCtx);
1706 }
1707 /* }}} */
1708 
1709 /* {{{ Create a new image from GD2 file or URL */
PHP_FUNCTION(imagecreatefromgd2)1710 PHP_FUNCTION(imagecreatefromgd2)
1711 {
1712 	_php_image_create_from(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_GD2, "GD2", gdImageCreateFromGd2, gdImageCreateFromGd2Ctx);
1713 }
1714 /* }}} */
1715 
1716 /* {{{ Create a new image from a given part of GD2 file or URL */
PHP_FUNCTION(imagecreatefromgd2part)1717 PHP_FUNCTION(imagecreatefromgd2part)
1718 {
1719 	_php_image_create_from(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_GD2PART, "GD2", NULL, NULL);
1720 }
1721 /* }}} */
1722 
1723 #ifdef HAVE_GD_BMP
1724 /* {{{ Create a new image from BMP file or URL */
PHP_FUNCTION(imagecreatefrombmp)1725 PHP_FUNCTION(imagecreatefrombmp)
1726 {
1727 	_php_image_create_from(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_BMP, "BMP", gdImageCreateFromBmp, gdImageCreateFromBmpCtx);
1728 }
1729 /* }}} */
1730 #endif
1731 
1732 #ifdef HAVE_GD_TGA
1733 /* {{{ Create a new image from TGA file or URL */
PHP_FUNCTION(imagecreatefromtga)1734 PHP_FUNCTION(imagecreatefromtga)
1735 {
1736 	_php_image_create_from(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_TGA, "TGA", gdImageCreateFromTga, gdImageCreateFromTgaCtx);
1737 }
1738 /* }}} */
1739 #endif
1740 
1741 /* {{{ _php_image_output */
_php_image_output(INTERNAL_FUNCTION_PARAMETERS,int image_type,const char * tn)1742 static void _php_image_output(INTERNAL_FUNCTION_PARAMETERS, int image_type, const char *tn)
1743 {
1744 	zval *imgind;
1745 	char *file = NULL;
1746 	zend_long quality = 128, type = 1;
1747 	gdImagePtr im;
1748 	FILE *fp;
1749 	size_t file_len = 0;
1750 
1751 	/* The quality parameter for gd2 stands for chunk size */
1752 
1753 	switch (image_type) {
1754 		case PHP_GDIMG_TYPE_GD:
1755 			if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|p!", &imgind, gd_image_ce, &file, &file_len) == FAILURE) {
1756 				RETURN_THROWS();
1757 			}
1758 			break;
1759 		case PHP_GDIMG_TYPE_GD2:
1760 			if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|p!ll", &imgind, gd_image_ce, &file, &file_len, &quality, &type) == FAILURE) {
1761 				RETURN_THROWS();
1762 			}
1763 			break;
1764 		EMPTY_SWITCH_DEFAULT_CASE()
1765 	}
1766 
1767 	/* quality must fit in an int */
1768 	if (quality < INT_MIN || quality > INT_MAX) {
1769 		php_error_docref(NULL, E_WARNING, "Argument #3 ($chunk_size) must be between %d and %d", INT_MIN, INT_MAX);
1770 		RETURN_FALSE;
1771 	}
1772 
1773 	im = php_gd_libgdimageptr_from_zval_p(imgind);
1774 
1775 	if (file_len) {
1776 		PHP_GD_CHECK_OPEN_BASEDIR(file, "Invalid filename");
1777 
1778 		fp = VCWD_FOPEN(file, "wb");
1779 		if (!fp) {
1780 			php_error_docref(NULL, E_WARNING, "Unable to open \"%s\" for writing", file);
1781 			RETURN_FALSE;
1782 		}
1783 
1784 		switch (image_type) {
1785 			case PHP_GDIMG_TYPE_GD:
1786 				gdImageGd(im, fp);
1787 				break;
1788 			case PHP_GDIMG_TYPE_GD2:
1789 				if (quality == -1) {
1790 					quality = 128;
1791 				}
1792 				gdImageGd2(im, fp, quality, type);
1793 				break;
1794 			EMPTY_SWITCH_DEFAULT_CASE()
1795 		}
1796 		fflush(fp);
1797 		fclose(fp);
1798 	} else {
1799 		int   b;
1800 		FILE *tmp;
1801 		char  buf[4096];
1802 		zend_string *path;
1803 
1804 		tmp = php_open_temporary_file(NULL, NULL, &path);
1805 		if (tmp == NULL) {
1806 			php_error_docref(NULL, E_WARNING, "Unable to open temporary file");
1807 			RETURN_FALSE;
1808 		}
1809 
1810 		switch (image_type) {
1811 			case PHP_GDIMG_TYPE_GD:
1812 				gdImageGd(im, tmp);
1813 				break;
1814 			case PHP_GDIMG_TYPE_GD2:
1815 				if (quality == -1) {
1816 					quality = 128;
1817 				}
1818 				gdImageGd2(im, tmp, quality, type);
1819 				break;
1820 			EMPTY_SWITCH_DEFAULT_CASE()
1821 		}
1822 
1823 		fseek(tmp, 0, SEEK_SET);
1824 
1825 		while ((b = fread(buf, 1, sizeof(buf), tmp)) > 0) {
1826 			php_write(buf, b);
1827 		}
1828 
1829 		fclose(tmp);
1830 		VCWD_UNLINK((const char *)ZSTR_VAL(path)); /* make sure that the temporary file is removed */
1831 		zend_string_release_ex(path, 0);
1832 	}
1833 	RETURN_TRUE;
1834 }
1835 /* }}} */
1836 
1837 /* {{{ Output XBM image to browser or file */
PHP_FUNCTION(imagexbm)1838 PHP_FUNCTION(imagexbm)
1839 {
1840 	zval *imgind;
1841 	char *file = NULL;
1842 	size_t file_len = 0;
1843 	zend_long foreground_color;
1844 	bool foreground_color_is_null = true;
1845 	gdImagePtr im;
1846 	int i;
1847 	gdIOCtx *ctx = NULL;
1848 	php_stream *stream;
1849 
1850 	ZEND_PARSE_PARAMETERS_START(2, 3)
1851 		Z_PARAM_OBJECT_OF_CLASS(imgind, gd_image_ce)
1852 		Z_PARAM_PATH_OR_NULL(file, file_len)
1853 		Z_PARAM_OPTIONAL
1854 		Z_PARAM_LONG_OR_NULL(foreground_color, foreground_color_is_null)
1855 	ZEND_PARSE_PARAMETERS_END();
1856 
1857 	im = php_gd_libgdimageptr_from_zval_p(imgind);
1858 
1859 	if (file != NULL) {
1860 		stream = php_stream_open_wrapper(file, "wb", REPORT_ERRORS|IGNORE_PATH, NULL);
1861 		if (stream == NULL) {
1862 			RETURN_FALSE;
1863 		}
1864 
1865 		ctx = create_stream_context(stream, 1);
1866 	} else {
1867 		ctx = create_output_context(NULL, 0);
1868 	}
1869 
1870 	if (foreground_color_is_null) {
1871 		for (i = 0; i < gdImageColorsTotal(im); i++) {
1872 			if (!gdImageRed(im, i) && !gdImageGreen(im, i) && !gdImageBlue(im, i)) {
1873 				break;
1874 			}
1875 		}
1876 
1877 		foreground_color = i;
1878 	}
1879 
1880 	gdImageXbmCtx(im, file ? file : "", (int) foreground_color, ctx);
1881 
1882 	ctx->gd_free(ctx);
1883 
1884 	RETURN_TRUE;
1885 }
1886 /* }}} */
1887 
1888 /* {{{ Output GIF image to browser or file */
PHP_FUNCTION(imagegif)1889 PHP_FUNCTION(imagegif)
1890 {
1891 	zval *imgind;
1892 	gdImagePtr im;
1893 	gdIOCtx *ctx;
1894 	zval *to_zval = NULL;
1895 
1896 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|z!", &imgind, gd_image_ce, &to_zval) == FAILURE) {
1897 		RETURN_THROWS();
1898 	}
1899 
1900 	im = php_gd_libgdimageptr_from_zval_p(imgind);
1901 
1902 	ctx = create_output_context(to_zval, 2);
1903 	if (!ctx) {
1904 		RETURN_FALSE;
1905 	}
1906 
1907 	gdImageGifCtx(im, ctx);
1908 
1909 	ctx->gd_free(ctx);
1910 
1911 	RETURN_TRUE;
1912 }
1913 /* }}} */
1914 
1915 #ifdef HAVE_GD_PNG
1916 /* {{{ Output PNG image to browser or file */
PHP_FUNCTION(imagepng)1917 PHP_FUNCTION(imagepng)
1918 {
1919 	zval *imgind;
1920 	zend_long quality = -1, basefilter = -1;
1921 	gdImagePtr im;
1922 	gdIOCtx *ctx;
1923 	zval *to_zval = NULL;
1924 
1925 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|z!ll", &imgind, gd_image_ce, &to_zval, &quality, &basefilter) == FAILURE) {
1926 		RETURN_THROWS();
1927 	}
1928 
1929 	im = php_gd_libgdimageptr_from_zval_p(imgind);
1930 
1931 	ctx = create_output_context(to_zval, 2);
1932 	if (!ctx) {
1933 		RETURN_FALSE;
1934 	}
1935 
1936 	if (quality < -1 || quality > 9) {
1937 		zend_argument_value_error(3, "must be between -1 and 9");
1938 		ctx->gd_free(ctx);
1939 		RETURN_THROWS();
1940 	}
1941 
1942 #ifdef HAVE_GD_BUNDLED
1943 	gdImagePngCtxEx(im, ctx, (int) quality, (int) basefilter);
1944 #else
1945 	gdImagePngCtxEx(im, ctx, (int) quality);
1946 #endif
1947 
1948 	ctx->gd_free(ctx);
1949 
1950 	RETURN_TRUE;
1951 }
1952 /* }}} */
1953 #endif /* HAVE_GD_PNG */
1954 
1955 #ifdef HAVE_GD_WEBP
1956 /* {{{ Output WEBP image to browser or file */
PHP_FUNCTION(imagewebp)1957 PHP_FUNCTION(imagewebp)
1958 {
1959 	zval *imgind;
1960 	zend_long quality = -1;
1961 	gdImagePtr im;
1962 	gdIOCtx *ctx;
1963 	zval *to_zval = NULL;
1964 
1965 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|z!l", &imgind, gd_image_ce, &to_zval, &quality) == FAILURE) {
1966 		RETURN_THROWS();
1967 	}
1968 
1969 	im = php_gd_libgdimageptr_from_zval_p(imgind);
1970 
1971 	ctx = create_output_context(to_zval, 2);
1972 	if (!ctx) {
1973 		RETURN_FALSE;
1974 	}
1975 
1976 	if (quality < -1) {
1977 		zend_argument_value_error(3, "must be greater than or equal to -1");
1978 		ctx->gd_free(ctx);
1979 		RETURN_THROWS();
1980 	}
1981 
1982 	gdImageWebpCtx(im, ctx, (int) quality);
1983 
1984 	ctx->gd_free(ctx);
1985 
1986 	RETURN_TRUE;
1987 }
1988 /* }}} */
1989 #endif /* HAVE_GD_WEBP */
1990 
1991 #ifdef HAVE_GD_AVIF
1992 /* {{{ Output AVIF image to browser or file */
PHP_FUNCTION(imageavif)1993 PHP_FUNCTION(imageavif)
1994 {
1995 	zval *imgind;
1996 	zend_long quality = -1, speed = -1;
1997 	gdImagePtr im;
1998 	gdIOCtx *ctx;
1999 	zval *to_zval = NULL;
2000 
2001 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|z!ll", &imgind, gd_image_ce, &to_zval, &quality, &speed) == FAILURE) {
2002 		RETURN_THROWS();
2003 	}
2004 
2005 	im = php_gd_libgdimageptr_from_zval_p(imgind);
2006 
2007 	ctx = create_output_context(to_zval, 2);
2008 	if (!ctx) {
2009 		RETURN_FALSE;
2010 	}
2011 
2012 	if (quality < -1 || quality > 100) {
2013 		zend_argument_value_error(3, "must be between -1 and 100");
2014 		ctx->gd_free(ctx);
2015 		RETURN_THROWS();
2016 	}
2017 
2018 	if (speed < -1 || speed > 10) {
2019 		zend_argument_value_error(4, "must be between -1 and 10");
2020 		ctx->gd_free(ctx);
2021 		RETURN_THROWS();
2022 	} else if (speed == -1) {
2023 		speed = 6;
2024 	}
2025 
2026 	gdImageAvifCtx(im, ctx, (int) quality, (int) speed);
2027 
2028 	ctx->gd_free(ctx);
2029 
2030 	RETURN_TRUE;
2031 }
2032 /* }}} */
2033 #endif /* HAVE_GD_AVIF */
2034 
2035 #ifdef HAVE_GD_JPG
2036 /* {{{ Output JPEG image to browser or file */
PHP_FUNCTION(imagejpeg)2037 PHP_FUNCTION(imagejpeg)
2038 {
2039 	zval *imgind;
2040 	zend_long quality = -1;
2041 	gdImagePtr im;
2042 	gdIOCtx *ctx;
2043 	zval *to_zval = NULL;
2044 
2045 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|z!l", &imgind, gd_image_ce, &to_zval, &quality) == FAILURE) {
2046 		RETURN_THROWS();
2047 	}
2048 
2049 	im = php_gd_libgdimageptr_from_zval_p(imgind);
2050 
2051 	ctx = create_output_context(to_zval, 2);
2052 	if (!ctx) {
2053 		RETURN_FALSE;
2054 	}
2055 
2056 	if (quality < -1 || quality > 100) {
2057 		zend_argument_value_error(3, "must be at between -1 and 100");
2058 		ctx->gd_free(ctx);
2059 		RETURN_THROWS();
2060 	}
2061 
2062 	gdImageJpegCtx(im, ctx, (int) quality);
2063 
2064 	ctx->gd_free(ctx);
2065 
2066 	RETURN_TRUE;
2067 }
2068 /* }}} */
2069 #endif /* HAVE_GD_JPG */
2070 
2071 /* {{{ Output WBMP image to browser or file */
PHP_FUNCTION(imagewbmp)2072 PHP_FUNCTION(imagewbmp)
2073 {
2074 	zval *imgind;
2075 	zend_long foreground_color;
2076 	bool foreground_color_is_null = true;
2077 	gdImagePtr im;
2078 	int i;
2079 	gdIOCtx *ctx;
2080 	zval *to_zval = NULL;
2081 
2082 	ZEND_PARSE_PARAMETERS_START(1, 3)
2083 		Z_PARAM_OBJECT_OF_CLASS(imgind, gd_image_ce)
2084 		Z_PARAM_OPTIONAL
2085 		Z_PARAM_ZVAL_OR_NULL(to_zval)
2086 		Z_PARAM_LONG_OR_NULL(foreground_color, foreground_color_is_null)
2087 	ZEND_PARSE_PARAMETERS_END();
2088 
2089 	im = php_gd_libgdimageptr_from_zval_p(imgind);
2090 
2091 	ctx = create_output_context(to_zval, 2);
2092 	if (!ctx) {
2093 		RETURN_FALSE;
2094 	}
2095 
2096 	if (foreground_color_is_null) {
2097 		for (i = 0; i < gdImageColorsTotal(im); i++) {
2098 			if (!gdImageRed(im, i) && !gdImageGreen(im, i) && !gdImageBlue(im, i)) {
2099 				break;
2100 			}
2101 		}
2102 
2103 		foreground_color = i;
2104 	}
2105 
2106 	gdImageWBMPCtx(im, foreground_color, ctx);
2107 
2108 	ctx->gd_free(ctx);
2109 
2110 	RETURN_TRUE;
2111 }
2112 /* }}} */
2113 
2114 /* {{{ Output GD image to browser or file */
PHP_FUNCTION(imagegd)2115 PHP_FUNCTION(imagegd)
2116 {
2117 	_php_image_output(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_GD, "GD");
2118 }
2119 /* }}} */
2120 
2121 /* {{{ Output GD2 image to browser or file */
PHP_FUNCTION(imagegd2)2122 PHP_FUNCTION(imagegd2)
2123 {
2124 	_php_image_output(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_GD2, "GD2");
2125 }
2126 /* }}} */
2127 
2128 #ifdef HAVE_GD_BMP
2129 /* {{{ Output BMP image to browser or file */
PHP_FUNCTION(imagebmp)2130 PHP_FUNCTION(imagebmp)
2131 {
2132 	zval *imgind;
2133 	bool compressed = true;
2134 	gdImagePtr im;
2135 	gdIOCtx *ctx;
2136 	zval *to_zval = NULL;
2137 
2138 	ZEND_PARSE_PARAMETERS_START(1, 3)
2139 		Z_PARAM_OBJECT_OF_CLASS(imgind, gd_image_ce)
2140 		Z_PARAM_OPTIONAL
2141 		Z_PARAM_ZVAL_OR_NULL(to_zval)
2142 		Z_PARAM_BOOL(compressed)
2143 	ZEND_PARSE_PARAMETERS_END();
2144 
2145 	im = php_gd_libgdimageptr_from_zval_p(imgind);
2146 
2147 	ctx = create_output_context(to_zval, 2);
2148 	if (!ctx) {
2149 		RETURN_FALSE;
2150 	}
2151 
2152 	gdImageBmpCtx(im, ctx, (int) compressed);
2153 
2154 	ctx->gd_free(ctx);
2155 
2156 	RETURN_TRUE;
2157 }
2158 /* }}} */
2159 #endif
2160 
2161 /* {{{ Destroy an image - No effect as of PHP 8.0 */
PHP_FUNCTION(imagedestroy)2162 PHP_FUNCTION(imagedestroy)
2163 {
2164 	/* This function used to free the resource, as resources are no longer used, it does nothing */
2165 	zval *IM;
2166 
2167 	ZEND_PARSE_PARAMETERS_START(1, 1)
2168 		Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
2169 	ZEND_PARSE_PARAMETERS_END();
2170 
2171 	RETURN_TRUE;
2172 }
2173 /* }}} */
2174 
2175 /* {{{ Allocate a color for an image */
PHP_FUNCTION(imagecolorallocate)2176 PHP_FUNCTION(imagecolorallocate)
2177 {
2178 	zval *IM;
2179 	zend_long red, green, blue;
2180 	gdImagePtr im;
2181 	int ct = -1;
2182 
2183 	ZEND_PARSE_PARAMETERS_START(4, 4)
2184 		Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
2185 		Z_PARAM_LONG(red)
2186 		Z_PARAM_LONG(green)
2187 		Z_PARAM_LONG(blue)
2188 	ZEND_PARSE_PARAMETERS_END();
2189 
2190 	im = php_gd_libgdimageptr_from_zval_p(IM);
2191 
2192 	CHECK_RGBA_RANGE(red, Red, 2);
2193 	CHECK_RGBA_RANGE(green, Green, 3);
2194 	CHECK_RGBA_RANGE(blue, Blue, 4);
2195 
2196 	ct = gdImageColorAllocate(im, red, green, blue);
2197 	if (ct < 0) {
2198 		RETURN_FALSE;
2199 	}
2200 	RETURN_LONG(ct);
2201 }
2202 /* }}} */
2203 
2204 /* {{{ Copy the palette from the src image onto the dst image */
PHP_FUNCTION(imagepalettecopy)2205 PHP_FUNCTION(imagepalettecopy)
2206 {
2207 	zval *dstim, *srcim;
2208 	gdImagePtr dst, src;
2209 
2210 	ZEND_PARSE_PARAMETERS_START(2, 2)
2211 		Z_PARAM_OBJECT_OF_CLASS(dstim, gd_image_ce)
2212 		Z_PARAM_OBJECT_OF_CLASS(srcim, gd_image_ce)
2213 	ZEND_PARSE_PARAMETERS_END();
2214 
2215 	src = php_gd_libgdimageptr_from_zval_p(srcim);
2216 	dst = php_gd_libgdimageptr_from_zval_p(dstim);
2217 
2218 	gdImagePaletteCopy(dst, src);
2219 }
2220 /* }}} */
2221 
2222 /* {{{ Get the index of the color of a pixel */
PHP_FUNCTION(imagecolorat)2223 PHP_FUNCTION(imagecolorat)
2224 {
2225 	zval *IM;
2226 	zend_long x, y;
2227 	gdImagePtr im;
2228 
2229 	ZEND_PARSE_PARAMETERS_START(3, 3)
2230 		Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
2231 		Z_PARAM_LONG(x)
2232 		Z_PARAM_LONG(y)
2233 	ZEND_PARSE_PARAMETERS_END();
2234 
2235 	im = php_gd_libgdimageptr_from_zval_p(IM);
2236 
2237 	if (gdImageTrueColor(im)) {
2238 		if (im->tpixels && gdImageBoundsSafe(im, x, y)) {
2239 			RETURN_LONG(gdImageTrueColorPixel(im, x, y));
2240 		} else {
2241 			php_error_docref(NULL, E_NOTICE, "" ZEND_LONG_FMT "," ZEND_LONG_FMT " is out of bounds", x, y);
2242 			RETURN_FALSE;
2243 		}
2244 	} else {
2245 		if (im->pixels && gdImageBoundsSafe(im, x, y)) {
2246 			RETURN_LONG(im->pixels[y][x]);
2247 		} else {
2248 			php_error_docref(NULL, E_NOTICE, "" ZEND_LONG_FMT "," ZEND_LONG_FMT " is out of bounds", x, y);
2249 			RETURN_FALSE;
2250 		}
2251 	}
2252 }
2253 /* }}} */
2254 
2255 /* {{{ Get the index of the closest color to the specified color */
PHP_FUNCTION(imagecolorclosest)2256 PHP_FUNCTION(imagecolorclosest)
2257 {
2258 	zval *IM;
2259 	zend_long red, green, blue;
2260 	gdImagePtr im;
2261 
2262 	ZEND_PARSE_PARAMETERS_START(4, 4)
2263 		Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
2264 		Z_PARAM_LONG(red)
2265 		Z_PARAM_LONG(green)
2266 		Z_PARAM_LONG(blue)
2267 	ZEND_PARSE_PARAMETERS_END();
2268 
2269 	im = php_gd_libgdimageptr_from_zval_p(IM);
2270 
2271 	CHECK_RGBA_RANGE(red, Red, 2);
2272 	CHECK_RGBA_RANGE(green, Green, 3);
2273 	CHECK_RGBA_RANGE(blue, Blue, 4);
2274 
2275 	RETURN_LONG(gdImageColorClosest(im, red, green, blue));
2276 }
2277 /* }}} */
2278 
2279 /* {{{ Get the index of the color which has the hue, white and blackness nearest to the given color */
PHP_FUNCTION(imagecolorclosesthwb)2280 PHP_FUNCTION(imagecolorclosesthwb)
2281 {
2282 	zval *IM;
2283 	zend_long red, green, blue;
2284 	gdImagePtr im;
2285 
2286 	ZEND_PARSE_PARAMETERS_START(4, 4)
2287 		Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
2288 		Z_PARAM_LONG(red)
2289 		Z_PARAM_LONG(green)
2290 		Z_PARAM_LONG(blue)
2291 	ZEND_PARSE_PARAMETERS_END();
2292 
2293 	im = php_gd_libgdimageptr_from_zval_p(IM);
2294 
2295 	CHECK_RGBA_RANGE(red, Red, 2);
2296 	CHECK_RGBA_RANGE(green, Green, 3);
2297 	CHECK_RGBA_RANGE(blue, Blue, 4);
2298 
2299 	RETURN_LONG(gdImageColorClosestHWB(im, red, green, blue));
2300 }
2301 /* }}} */
2302 
2303 /* {{{ De-allocate a color for an image */
PHP_FUNCTION(imagecolordeallocate)2304 PHP_FUNCTION(imagecolordeallocate)
2305 {
2306 	zval *IM;
2307 	zend_long index;
2308 	int col;
2309 	gdImagePtr im;
2310 
2311 	ZEND_PARSE_PARAMETERS_START(2, 2)
2312 		Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
2313 		Z_PARAM_LONG(index)
2314 	ZEND_PARSE_PARAMETERS_END();
2315 
2316 	im = php_gd_libgdimageptr_from_zval_p(IM);
2317 
2318 	/* We can return right away for a truecolor image as deallocating colours is meaningless here */
2319 	if (gdImageTrueColor(im)) {
2320 		RETURN_TRUE;
2321 	}
2322 
2323 	col = index;
2324 
2325 	if (col >= 0 && col < gdImageColorsTotal(im)) {
2326 		gdImageColorDeallocate(im, col);
2327 		RETURN_TRUE;
2328 	} else {
2329 		zend_argument_value_error(2, "must be between 0 and %d", gdImageColorsTotal(im));
2330 		RETURN_THROWS();
2331 	}
2332 }
2333 /* }}} */
2334 
2335 /* {{{ Get the index of the specified color or its closest possible alternative */
PHP_FUNCTION(imagecolorresolve)2336 PHP_FUNCTION(imagecolorresolve)
2337 {
2338 	zval *IM;
2339 	zend_long red, green, blue;
2340 	gdImagePtr im;
2341 
2342 	ZEND_PARSE_PARAMETERS_START(4, 4)
2343 		Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
2344 		Z_PARAM_LONG(red)
2345 		Z_PARAM_LONG(green)
2346 		Z_PARAM_LONG(blue)
2347 	ZEND_PARSE_PARAMETERS_END();
2348 
2349 	im = php_gd_libgdimageptr_from_zval_p(IM);
2350 
2351 	CHECK_RGBA_RANGE(red, Red, 2);
2352 	CHECK_RGBA_RANGE(green, Green, 3);
2353 	CHECK_RGBA_RANGE(blue, Blue, 4);
2354 
2355 	RETURN_LONG(gdImageColorResolve(im, red, green, blue));
2356 }
2357 /* }}} */
2358 
2359 /* {{{ Get the index of the specified color */
PHP_FUNCTION(imagecolorexact)2360 PHP_FUNCTION(imagecolorexact)
2361 {
2362 	zval *IM;
2363 	zend_long red, green, blue;
2364 	gdImagePtr im;
2365 
2366 	ZEND_PARSE_PARAMETERS_START(4, 4)
2367 		Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
2368 		Z_PARAM_LONG(red)
2369 		Z_PARAM_LONG(green)
2370 		Z_PARAM_LONG(blue)
2371 	ZEND_PARSE_PARAMETERS_END();
2372 
2373 	im = php_gd_libgdimageptr_from_zval_p(IM);
2374 
2375 	CHECK_RGBA_RANGE(red, Red, 2);
2376 	CHECK_RGBA_RANGE(green, Green, 3);
2377 	CHECK_RGBA_RANGE(blue, Blue, 4);
2378 
2379 	RETURN_LONG(gdImageColorExact(im, red, green, blue));
2380 }
2381 /* }}} */
2382 
2383 /* {{{ Set the color for the specified palette index */
PHP_FUNCTION(imagecolorset)2384 PHP_FUNCTION(imagecolorset)
2385 {
2386 	zval *IM;
2387 	zend_long color, red, green, blue, alpha = 0;
2388 	int col;
2389 	gdImagePtr im;
2390 
2391 	ZEND_PARSE_PARAMETERS_START(5, 6)
2392 		Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
2393 		Z_PARAM_LONG(color)
2394 		Z_PARAM_LONG(red)
2395 		Z_PARAM_LONG(green)
2396 		Z_PARAM_LONG(blue)
2397 		Z_PARAM_OPTIONAL
2398 		Z_PARAM_LONG(alpha)
2399 	ZEND_PARSE_PARAMETERS_END();
2400 
2401 	im = php_gd_libgdimageptr_from_zval_p(IM);
2402 
2403 	CHECK_RGBA_RANGE(red, Red, 3);
2404 	CHECK_RGBA_RANGE(green, Green, 4);
2405 	CHECK_RGBA_RANGE(blue, Blue, 5);
2406 	CHECK_RGBA_RANGE(alpha, Alpha, 6);
2407 
2408 	col = color;
2409 
2410 	if (col >= 0 && col < gdImageColorsTotal(im)) {
2411 		im->red[col]   = red;
2412 		im->green[col] = green;
2413 		im->blue[col]  = blue;
2414 		im->alpha[col]  = alpha;
2415 	} else {
2416 		RETURN_FALSE;
2417 	}
2418 }
2419 /* }}} */
2420 
2421 /* {{{ Get the colors for an index */
PHP_FUNCTION(imagecolorsforindex)2422 PHP_FUNCTION(imagecolorsforindex)
2423 {
2424 	zval *IM;
2425 	zend_long index;
2426 	int col;
2427 	gdImagePtr im;
2428 
2429 	ZEND_PARSE_PARAMETERS_START(2, 2)
2430 		Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
2431 		Z_PARAM_LONG(index)
2432 	ZEND_PARSE_PARAMETERS_END();
2433 
2434 	im = php_gd_libgdimageptr_from_zval_p(IM);
2435 
2436 	col = index;
2437 
2438 	if ((col >= 0 && gdImageTrueColor(im)) || (!gdImageTrueColor(im) && col >= 0 && col < gdImageColorsTotal(im))) {
2439 		array_init(return_value);
2440 
2441 		add_assoc_long(return_value,"red",  gdImageRed(im,col));
2442 		add_assoc_long(return_value,"green", gdImageGreen(im,col));
2443 		add_assoc_long(return_value,"blue", gdImageBlue(im,col));
2444 		add_assoc_long(return_value,"alpha", gdImageAlpha(im,col));
2445 	} else {
2446 		zend_argument_value_error(2, "is out of range");
2447 		RETURN_THROWS();
2448 	}
2449 }
2450 /* }}} */
2451 
2452 /* {{{ Apply a gamma correction to a GD image */
PHP_FUNCTION(imagegammacorrect)2453 PHP_FUNCTION(imagegammacorrect)
2454 {
2455 	zval *IM;
2456 	gdImagePtr im;
2457 	int i;
2458 	double input, output, gamma;
2459 
2460 	ZEND_PARSE_PARAMETERS_START(3, 3)
2461 		Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
2462 		Z_PARAM_DOUBLE(input)
2463 		Z_PARAM_DOUBLE(output)
2464 	ZEND_PARSE_PARAMETERS_END();
2465 
2466 	if (input <= 0.0) {
2467 		zend_argument_value_error(2, "must be greater than 0");
2468 		RETURN_THROWS();
2469 	}
2470 
2471 	if (output <= 0.0) {
2472 		zend_argument_value_error(3, "must be greater than 0");
2473 		RETURN_THROWS();
2474 	}
2475 
2476 	gamma = input / output;
2477 
2478 	im = php_gd_libgdimageptr_from_zval_p(IM);
2479 
2480 	if (gdImageTrueColor(im))	{
2481 		int x, y, c;
2482 
2483 		for (y = 0; y < gdImageSY(im); y++)	{
2484 			for (x = 0; x < gdImageSX(im); x++)	{
2485 				c = gdImageGetPixel(im, x, y);
2486 				gdImageSetPixel(im, x, y,
2487 					gdTrueColorAlpha(
2488 						(int) ((pow((gdTrueColorGetRed(c)   / 255.0), gamma) * 255) + .5),
2489 						(int) ((pow((gdTrueColorGetGreen(c) / 255.0), gamma) * 255) + .5),
2490 						(int) ((pow((gdTrueColorGetBlue(c)  / 255.0), gamma) * 255) + .5),
2491 						gdTrueColorGetAlpha(c)
2492 					)
2493 				);
2494 			}
2495 		}
2496 		RETURN_TRUE;
2497 	}
2498 
2499 	for (i = 0; i < gdImageColorsTotal(im); i++) {
2500 		im->red[i]   = (int)((pow((im->red[i]   / 255.0), gamma) * 255) + .5);
2501 		im->green[i] = (int)((pow((im->green[i] / 255.0), gamma) * 255) + .5);
2502 		im->blue[i]  = (int)((pow((im->blue[i]  / 255.0), gamma) * 255) + .5);
2503 	}
2504 
2505 	RETURN_TRUE;
2506 }
2507 /* }}} */
2508 
2509 /* {{{ Set a single pixel */
PHP_FUNCTION(imagesetpixel)2510 PHP_FUNCTION(imagesetpixel)
2511 {
2512 	zval *IM;
2513 	zend_long x, y, col;
2514 	gdImagePtr im;
2515 
2516 	ZEND_PARSE_PARAMETERS_START(4, 4)
2517 		Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
2518 		Z_PARAM_LONG(x)
2519 		Z_PARAM_LONG(y)
2520 		Z_PARAM_LONG(col)
2521 	ZEND_PARSE_PARAMETERS_END();
2522 
2523 	im = php_gd_libgdimageptr_from_zval_p(IM);
2524 
2525 	gdImageSetPixel(im, x, y, col);
2526 	RETURN_TRUE;
2527 }
2528 /* }}} */
2529 
2530 /* {{{ Draw a line */
PHP_FUNCTION(imageline)2531 PHP_FUNCTION(imageline)
2532 {
2533 	zval *IM;
2534 	zend_long x1, y1, x2, y2, col;
2535 	gdImagePtr im;
2536 
2537 	ZEND_PARSE_PARAMETERS_START(6, 6)
2538 		Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
2539 		Z_PARAM_LONG(x1)
2540 		Z_PARAM_LONG(y1)
2541 		Z_PARAM_LONG(x2)
2542 		Z_PARAM_LONG(y2)
2543 		Z_PARAM_LONG(col)
2544 	ZEND_PARSE_PARAMETERS_END();
2545 
2546 
2547 	im = php_gd_libgdimageptr_from_zval_p(IM);
2548 
2549 	if (im->AA) {
2550 		gdImageSetAntiAliased(im, col);
2551 		col = gdAntiAliased;
2552 	}
2553 	gdImageLine(im, x1, y1, x2, y2, col);
2554 	RETURN_TRUE;
2555 }
2556 /* }}} */
2557 
2558 /* {{{ Draw a dashed line */
PHP_FUNCTION(imagedashedline)2559 PHP_FUNCTION(imagedashedline)
2560 {
2561 	zval *IM;
2562 	zend_long x1, y1, x2, y2, col;
2563 	gdImagePtr im;
2564 
2565 	ZEND_PARSE_PARAMETERS_START(6, 6)
2566 		Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
2567 		Z_PARAM_LONG(x1)
2568 		Z_PARAM_LONG(y1)
2569 		Z_PARAM_LONG(x2)
2570 		Z_PARAM_LONG(y2)
2571 		Z_PARAM_LONG(col)
2572 	ZEND_PARSE_PARAMETERS_END();
2573 
2574 	im = php_gd_libgdimageptr_from_zval_p(IM);
2575 
2576 	gdImageDashedLine(im, x1, y1, x2, y2, col);
2577 	RETURN_TRUE;
2578 }
2579 /* }}} */
2580 
2581 /* {{{ Draw a rectangle */
PHP_FUNCTION(imagerectangle)2582 PHP_FUNCTION(imagerectangle)
2583 {
2584 	zval *IM;
2585 	zend_long x1, y1, x2, y2, col;
2586 	gdImagePtr im;
2587 
2588 	ZEND_PARSE_PARAMETERS_START(6, 6)
2589 		Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
2590 		Z_PARAM_LONG(x1)
2591 		Z_PARAM_LONG(y1)
2592 		Z_PARAM_LONG(x2)
2593 		Z_PARAM_LONG(y2)
2594 		Z_PARAM_LONG(col)
2595 	ZEND_PARSE_PARAMETERS_END();
2596 
2597 	im = php_gd_libgdimageptr_from_zval_p(IM);
2598 
2599 	gdImageRectangle(im, x1, y1, x2, y2, col);
2600 	RETURN_TRUE;
2601 }
2602 /* }}} */
2603 
2604 /* {{{ Draw a filled rectangle */
PHP_FUNCTION(imagefilledrectangle)2605 PHP_FUNCTION(imagefilledrectangle)
2606 {
2607 	zval *IM;
2608 	zend_long x1, y1, x2, y2, col;
2609 	gdImagePtr im;
2610 
2611 	ZEND_PARSE_PARAMETERS_START(6, 6)
2612 		Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
2613 		Z_PARAM_LONG(x1)
2614 		Z_PARAM_LONG(y1)
2615 		Z_PARAM_LONG(x2)
2616 		Z_PARAM_LONG(y2)
2617 		Z_PARAM_LONG(col)
2618 	ZEND_PARSE_PARAMETERS_END();
2619 
2620 	im = php_gd_libgdimageptr_from_zval_p(IM);
2621 	gdImageFilledRectangle(im, x1, y1, x2, y2, col);
2622 	RETURN_TRUE;
2623 }
2624 /* }}} */
2625 
2626 /* {{{ Draw a partial ellipse */
PHP_FUNCTION(imagearc)2627 PHP_FUNCTION(imagearc)
2628 {
2629 	zval *IM;
2630 	zend_long cx, cy, w, h, ST, E, col;
2631 	gdImagePtr im;
2632 	int e, st;
2633 
2634 	ZEND_PARSE_PARAMETERS_START(8, 8)
2635 		Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
2636 		Z_PARAM_LONG(cx)
2637 		Z_PARAM_LONG(cy)
2638 		Z_PARAM_LONG(w)
2639 		Z_PARAM_LONG(h)
2640 		Z_PARAM_LONG(ST)
2641 		Z_PARAM_LONG(E)
2642 		Z_PARAM_LONG(col)
2643 	ZEND_PARSE_PARAMETERS_END();
2644 
2645 	im = php_gd_libgdimageptr_from_zval_p(IM);
2646 
2647 	e = E;
2648 	if (e < 0) {
2649 		e %= 360;
2650 	}
2651 
2652 	st = ST;
2653 	if (st < 0) {
2654 		st %= 360;
2655 	}
2656 
2657 	gdImageArc(im, cx, cy, w, h, st, e, col);
2658 	RETURN_TRUE;
2659 }
2660 /* }}} */
2661 
2662 /* {{{ Draw an ellipse */
PHP_FUNCTION(imageellipse)2663 PHP_FUNCTION(imageellipse)
2664 {
2665 	zval *IM;
2666 	zend_long cx, cy, w, h, color;
2667 	gdImagePtr im;
2668 
2669 	ZEND_PARSE_PARAMETERS_START(6, 6)
2670 		Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
2671 		Z_PARAM_LONG(cx)
2672 		Z_PARAM_LONG(cy)
2673 		Z_PARAM_LONG(w)
2674 		Z_PARAM_LONG(h)
2675 		Z_PARAM_LONG(color)
2676 	ZEND_PARSE_PARAMETERS_END();
2677 
2678 	im = php_gd_libgdimageptr_from_zval_p(IM);
2679 
2680 	gdImageEllipse(im, cx, cy, w, h, color);
2681 	RETURN_TRUE;
2682 }
2683 /* }}} */
2684 
2685 /* {{{ Flood fill to specific color */
PHP_FUNCTION(imagefilltoborder)2686 PHP_FUNCTION(imagefilltoborder)
2687 {
2688 	zval *IM;
2689 	zend_long x, y, border, col;
2690 	gdImagePtr im;
2691 
2692 	ZEND_PARSE_PARAMETERS_START(5, 5)
2693 		Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
2694 		Z_PARAM_LONG(x)
2695 		Z_PARAM_LONG(y)
2696 		Z_PARAM_LONG(border)
2697 		Z_PARAM_LONG(col)
2698 	ZEND_PARSE_PARAMETERS_END();
2699 
2700 	im = php_gd_libgdimageptr_from_zval_p(IM);
2701 
2702 	gdImageFillToBorder(im, x, y, border, col);
2703 	RETURN_TRUE;
2704 }
2705 /* }}} */
2706 
2707 /* {{{ Flood fill */
PHP_FUNCTION(imagefill)2708 PHP_FUNCTION(imagefill)
2709 {
2710 	zval *IM;
2711 	zend_long x, y, col;
2712 	gdImagePtr im;
2713 
2714 	ZEND_PARSE_PARAMETERS_START(4, 4)
2715 		Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
2716 		Z_PARAM_LONG(x)
2717 		Z_PARAM_LONG(y)
2718 		Z_PARAM_LONG(col)
2719 	ZEND_PARSE_PARAMETERS_END();
2720 
2721 	im = php_gd_libgdimageptr_from_zval_p(IM);
2722 
2723 	gdImageFill(im, x, y, col);
2724 	RETURN_TRUE;
2725 }
2726 /* }}} */
2727 
2728 /* {{{ Find out the number of colors in an image's palette */
PHP_FUNCTION(imagecolorstotal)2729 PHP_FUNCTION(imagecolorstotal)
2730 {
2731 	zval *IM;
2732 	gdImagePtr im;
2733 
2734 	ZEND_PARSE_PARAMETERS_START(1, 1)
2735 		Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
2736 	ZEND_PARSE_PARAMETERS_END();
2737 
2738 	im = php_gd_libgdimageptr_from_zval_p(IM);
2739 
2740 	RETURN_LONG(gdImageColorsTotal(im));
2741 }
2742 /* }}} */
2743 
2744 /* {{{ Define a color as transparent */
PHP_FUNCTION(imagecolortransparent)2745 PHP_FUNCTION(imagecolortransparent)
2746 {
2747 	zval *IM;
2748 	zend_long COL = 0;
2749 	bool COL_IS_NULL = true;
2750 	gdImagePtr im;
2751 
2752 	ZEND_PARSE_PARAMETERS_START(1, 2)
2753 		Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
2754 		Z_PARAM_OPTIONAL
2755 		Z_PARAM_LONG_OR_NULL(COL, COL_IS_NULL)
2756 	ZEND_PARSE_PARAMETERS_END();
2757 
2758 	im = php_gd_libgdimageptr_from_zval_p(IM);
2759 
2760 	if (!COL_IS_NULL) {
2761 		gdImageColorTransparent(im, COL);
2762 	}
2763 
2764 	RETURN_LONG(gdImageGetTransparent(im));
2765 }
2766 /* }}} */
2767 
2768 /* {{{ Enable or disable interlace */
PHP_FUNCTION(imageinterlace)2769 PHP_FUNCTION(imageinterlace)
2770 {
2771 	zval *IM;
2772 	bool INT = false;
2773 	bool INT_IS_NULL = true;
2774 	gdImagePtr im;
2775 
2776 	ZEND_PARSE_PARAMETERS_START(1, 2)
2777 		Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
2778 		Z_PARAM_OPTIONAL
2779 		Z_PARAM_BOOL_OR_NULL(INT, INT_IS_NULL)
2780 	ZEND_PARSE_PARAMETERS_END();
2781 
2782 	im = php_gd_libgdimageptr_from_zval_p(IM);
2783 
2784 	if (!INT_IS_NULL) {
2785 		gdImageInterlace(im, INT);
2786 	}
2787 
2788 	RETURN_BOOL(gdImageGetInterlaced(im));
2789 }
2790 /* }}} */
2791 
2792 /* {{{ php_imagepolygon
2793    arg = -1 open polygon
2794    arg = 0  normal polygon
2795    arg = 1  filled polygon */
2796 /* im, points, num_points, col */
php_imagepolygon(INTERNAL_FUNCTION_PARAMETERS,int filled)2797 static void php_imagepolygon(INTERNAL_FUNCTION_PARAMETERS, int filled)
2798 {
2799 	zval *IM, *POINTS;
2800 	zend_long NPOINTS, COL;
2801 	bool COL_IS_NULL = true;
2802 	zval *var = NULL;
2803 	gdImagePtr im;
2804 	gdPointPtr points;
2805 	int npoints, col, nelem, i;
2806 
2807 	ZEND_PARSE_PARAMETERS_START(3, 4)
2808 		Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
2809 		Z_PARAM_ARRAY(POINTS)
2810 		Z_PARAM_LONG(NPOINTS)
2811 		Z_PARAM_OPTIONAL
2812 		Z_PARAM_LONG_OR_NULL(COL, COL_IS_NULL)
2813 	ZEND_PARSE_PARAMETERS_END();
2814 
2815 	if (COL_IS_NULL) {
2816 		COL = NPOINTS;
2817 		NPOINTS = zend_hash_num_elements(Z_ARRVAL_P(POINTS));
2818 		if (NPOINTS % 2 != 0) {
2819 			zend_argument_value_error(2, "must have an even number of elements");
2820 			RETURN_THROWS();
2821 		}
2822 		NPOINTS /= 2;
2823 	} else {
2824 		php_error_docref(NULL, E_DEPRECATED, "Using the $num_points parameter is deprecated");
2825 	}
2826 
2827 	im = php_gd_libgdimageptr_from_zval_p(IM);
2828 
2829 	npoints = NPOINTS;
2830 	col = COL;
2831 
2832 	nelem = zend_hash_num_elements(Z_ARRVAL_P(POINTS));
2833 	if (npoints < 3) {
2834 		zend_argument_value_error(3, "must be greater than or equal to 3");
2835 		RETURN_THROWS();
2836 	}
2837 
2838 	if (nelem < npoints * 2) {
2839 		zend_value_error("Trying to use %d points in array with only %d points", npoints, nelem/2);
2840 		RETURN_THROWS();
2841 	}
2842 
2843 	points = (gdPointPtr) safe_emalloc(npoints, sizeof(gdPoint), 0);
2844 
2845 	for (i = 0; i < npoints; i++) {
2846 		if ((var = zend_hash_index_find(Z_ARRVAL_P(POINTS), (i * 2))) != NULL) {
2847 			points[i].x = zval_get_long(var);
2848 		}
2849 		if ((var = zend_hash_index_find(Z_ARRVAL_P(POINTS), (i * 2) + 1)) != NULL) {
2850 			points[i].y = zval_get_long(var);
2851 		}
2852 	}
2853 
2854 	if (im->AA) {
2855 		gdImageSetAntiAliased(im, col);
2856 		col = gdAntiAliased;
2857 	}
2858 	switch (filled) {
2859 		case -1:
2860 			gdImageOpenPolygon(im, points, npoints, col);
2861 			break;
2862 		case 0:
2863 			gdImagePolygon(im, points, npoints, col);
2864 			break;
2865 		case 1:
2866 			gdImageFilledPolygon(im, points, npoints, col);
2867 			break;
2868 	}
2869 
2870 	efree(points);
2871 	RETURN_TRUE;
2872 }
2873 /* }}} */
2874 
2875 /* {{{ Draw a polygon */
PHP_FUNCTION(imagepolygon)2876 PHP_FUNCTION(imagepolygon)
2877 {
2878 	php_imagepolygon(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
2879 }
2880 /* }}} */
2881 
2882 /* {{{ Draw a polygon */
PHP_FUNCTION(imageopenpolygon)2883 PHP_FUNCTION(imageopenpolygon)
2884 {
2885 	php_imagepolygon(INTERNAL_FUNCTION_PARAM_PASSTHRU, -1);
2886 }
2887 /* }}} */
2888 
2889 /* {{{ Draw a filled polygon */
PHP_FUNCTION(imagefilledpolygon)2890 PHP_FUNCTION(imagefilledpolygon)
2891 {
2892 	php_imagepolygon(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
2893 }
2894 /* }}} */
2895 
2896 /* {{{ php_find_gd_font */
php_find_gd_font(zend_object * font_obj,zend_long font_int)2897 static gdFontPtr php_find_gd_font(zend_object *font_obj, zend_long font_int)
2898 {
2899 	if (font_obj) {
2900 		return php_gd_font_object_from_zend_object(font_obj)->font;
2901 	}
2902 
2903 	switch (font_int) {
2904 		case 1: return gdFontTiny;
2905 		case 2: return gdFontSmall;
2906 		case 3: return gdFontMediumBold;
2907 		case 4: return gdFontLarge;
2908 		case 5: return gdFontGiant;
2909 	}
2910 
2911 	return font_int < 1 ? gdFontTiny : gdFontGiant;
2912 }
2913 /* }}} */
2914 
2915 /* {{{ php_imagefontsize
2916  * arg = 0  ImageFontWidth
2917  * arg = 1  ImageFontHeight
2918  */
php_imagefontsize(INTERNAL_FUNCTION_PARAMETERS,int arg)2919 static void php_imagefontsize(INTERNAL_FUNCTION_PARAMETERS, int arg)
2920 {
2921 	zend_object *font_obj = NULL;
2922 	zend_long font_int = 0;
2923 	gdFontPtr font;
2924 
2925 	ZEND_PARSE_PARAMETERS_START(1, 1)
2926 		Z_PARAM_OBJ_OF_CLASS_OR_LONG(font_obj, gd_font_ce, font_int)
2927 	ZEND_PARSE_PARAMETERS_END();
2928 
2929 	font = php_find_gd_font(font_obj, font_int);
2930 	RETURN_LONG(arg ? font->h : font->w);
2931 }
2932 /* }}} */
2933 
2934 /* {{{ Get font width */
PHP_FUNCTION(imagefontwidth)2935 PHP_FUNCTION(imagefontwidth)
2936 {
2937 	php_imagefontsize(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
2938 }
2939 /* }}} */
2940 
2941 /* {{{ Get font height */
PHP_FUNCTION(imagefontheight)2942 PHP_FUNCTION(imagefontheight)
2943 {
2944 	php_imagefontsize(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
2945 }
2946 /* }}} */
2947 
2948 /* {{{ php_gdimagecharup
2949  * workaround for a bug in gd 1.2 */
php_gdimagecharup(gdImagePtr im,gdFontPtr f,int x,int y,int c,int color)2950 static void php_gdimagecharup(gdImagePtr im, gdFontPtr f, int x, int y, int c, int color)
2951 {
2952 	int cx, cy, px, py, fline;
2953 	cx = 0;
2954 	cy = 0;
2955 
2956 	if ((c < f->offset) || (c >= (f->offset + f->nchars))) {
2957 		return;
2958 	}
2959 
2960 	fline = (c - f->offset) * f->h * f->w;
2961 	for (py = y; (py > (y - f->w)); py--) {
2962 		for (px = x; (px < (x + f->h)); px++) {
2963 			if (f->data[fline + cy * f->w + cx]) {
2964 				gdImageSetPixel(im, px, py, color);
2965 			}
2966 			cy++;
2967 		}
2968 		cy = 0;
2969 		cx++;
2970 	}
2971 }
2972 /* }}} */
2973 
2974 /* {{{ php_imagechar
2975  * arg = 0  ImageChar
2976  * arg = 1  ImageCharUp
2977  * arg = 2  ImageString
2978  * arg = 3  ImageStringUp
2979  */
php_imagechar(INTERNAL_FUNCTION_PARAMETERS,int mode)2980 static void php_imagechar(INTERNAL_FUNCTION_PARAMETERS, int mode)
2981 {
2982 	zval *IM;
2983 	zend_long X, Y, COL;
2984 	zend_string *C;
2985 	gdImagePtr im;
2986 	int ch = 0, col, x, y, i, l = 0;
2987 	unsigned char *str = NULL;
2988 	zend_object *font_obj = NULL;
2989 	zend_long font_int = 0;
2990 
2991 	ZEND_PARSE_PARAMETERS_START(6, 6)
2992 		Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
2993 		Z_PARAM_OBJ_OF_CLASS_OR_LONG(font_obj, gd_font_ce, font_int)
2994 		Z_PARAM_LONG(X)
2995 		Z_PARAM_LONG(Y)
2996 		Z_PARAM_STR(C)
2997 		Z_PARAM_LONG(COL)
2998 	ZEND_PARSE_PARAMETERS_END();
2999 
3000 	im = php_gd_libgdimageptr_from_zval_p(IM);
3001 
3002 	col = COL;
3003 
3004 	if (mode < 2) {
3005 		ch = (int)((unsigned char)*ZSTR_VAL(C));
3006 	} else {
3007 		str = (unsigned char *) estrndup(ZSTR_VAL(C), ZSTR_LEN(C));
3008 		l = strlen((char *)str);
3009 	}
3010 
3011 	y = Y;
3012 	x = X;
3013 
3014 	gdFontPtr font = php_find_gd_font(font_obj, font_int);
3015 
3016 	switch (mode) {
3017 		case 0:
3018 			gdImageChar(im, font, x, y, ch, col);
3019 			break;
3020 		case 1:
3021 			php_gdimagecharup(im, font, x, y, ch, col);
3022 			break;
3023 		case 2:
3024 			for (i = 0; (i < l); i++) {
3025 				gdImageChar(im, font, x, y, (int) ((unsigned char) str[i]), col);
3026 				x += font->w;
3027 			}
3028 			break;
3029 		case 3: {
3030 			for (i = 0; (i < l); i++) {
3031 				/* php_gdimagecharup(im, font, x, y, (int) str[i], col); */
3032 				gdImageCharUp(im, font, x, y, (int) str[i], col);
3033 				y -= font->w;
3034 			}
3035 			break;
3036 		}
3037 	}
3038 	if (str) {
3039 		efree(str);
3040 	}
3041 	RETURN_TRUE;
3042 }
3043 /* }}} */
3044 
3045 /* {{{ Draw a character */
PHP_FUNCTION(imagechar)3046 PHP_FUNCTION(imagechar)
3047 {
3048 	php_imagechar(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
3049 }
3050 /* }}} */
3051 
3052 /* {{{ Draw a character rotated 90 degrees counter-clockwise */
PHP_FUNCTION(imagecharup)3053 PHP_FUNCTION(imagecharup)
3054 {
3055 	php_imagechar(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
3056 }
3057 /* }}} */
3058 
3059 /* {{{ Draw a string horizontally */
PHP_FUNCTION(imagestring)3060 PHP_FUNCTION(imagestring)
3061 {
3062 	php_imagechar(INTERNAL_FUNCTION_PARAM_PASSTHRU, 2);
3063 }
3064 /* }}} */
3065 
3066 /* {{{ Draw a string vertically - rotated 90 degrees counter-clockwise */
PHP_FUNCTION(imagestringup)3067 PHP_FUNCTION(imagestringup)
3068 {
3069 	php_imagechar(INTERNAL_FUNCTION_PARAM_PASSTHRU, 3);
3070 }
3071 /* }}} */
3072 
3073 /* {{{ Copy part of an image */
PHP_FUNCTION(imagecopy)3074 PHP_FUNCTION(imagecopy)
3075 {
3076 	zval *SIM, *DIM;
3077 	zend_long SX, SY, SW, SH, DX, DY;
3078 	gdImagePtr im_dst, im_src;
3079 	int srcH, srcW, srcY, srcX, dstY, dstX;
3080 
3081 	ZEND_PARSE_PARAMETERS_START(8, 8)
3082 		Z_PARAM_OBJECT_OF_CLASS(DIM, gd_image_ce)
3083 		Z_PARAM_OBJECT_OF_CLASS(SIM, gd_image_ce)
3084 		Z_PARAM_LONG(DX)
3085 		Z_PARAM_LONG(DY)
3086 		Z_PARAM_LONG(SX)
3087 		Z_PARAM_LONG(SY)
3088 		Z_PARAM_LONG(SW)
3089 		Z_PARAM_LONG(SH)
3090 	ZEND_PARSE_PARAMETERS_END();
3091 
3092 	im_dst = php_gd_libgdimageptr_from_zval_p(DIM);
3093 	im_src = php_gd_libgdimageptr_from_zval_p(SIM);
3094 
3095 	srcX = SX;
3096 	srcY = SY;
3097 	srcH = SH;
3098 	srcW = SW;
3099 	dstX = DX;
3100 	dstY = DY;
3101 
3102 	gdImageCopy(im_dst, im_src, dstX, dstY, srcX, srcY, srcW, srcH);
3103 	RETURN_TRUE;
3104 }
3105 /* }}} */
3106 
3107 /* {{{ Merge one part of an image with another */
PHP_FUNCTION(imagecopymerge)3108 PHP_FUNCTION(imagecopymerge)
3109 {
3110 	zval *SIM, *DIM;
3111 	zend_long SX, SY, SW, SH, DX, DY, PCT;
3112 	gdImagePtr im_dst, im_src;
3113 	int srcH, srcW, srcY, srcX, dstY, dstX, pct;
3114 
3115 	ZEND_PARSE_PARAMETERS_START(9, 9)
3116 		Z_PARAM_OBJECT_OF_CLASS(DIM, gd_image_ce)
3117 		Z_PARAM_OBJECT_OF_CLASS(SIM, gd_image_ce)
3118 		Z_PARAM_LONG(DX)
3119 		Z_PARAM_LONG(DY)
3120 		Z_PARAM_LONG(SX)
3121 		Z_PARAM_LONG(SY)
3122 		Z_PARAM_LONG(SW)
3123 		Z_PARAM_LONG(SH)
3124 		Z_PARAM_LONG(PCT)
3125 	ZEND_PARSE_PARAMETERS_END();
3126 
3127 	im_src = php_gd_libgdimageptr_from_zval_p(SIM);
3128 	im_dst = php_gd_libgdimageptr_from_zval_p(DIM);
3129 
3130 	srcX = SX;
3131 	srcY = SY;
3132 	srcH = SH;
3133 	srcW = SW;
3134 	dstX = DX;
3135 	dstY = DY;
3136 	pct  = PCT;
3137 
3138 	gdImageCopyMerge(im_dst, im_src, dstX, dstY, srcX, srcY, srcW, srcH, pct);
3139 	RETURN_TRUE;
3140 }
3141 /* }}} */
3142 
3143 /* {{{ Merge one part of an image with another */
PHP_FUNCTION(imagecopymergegray)3144 PHP_FUNCTION(imagecopymergegray)
3145 {
3146 	zval *SIM, *DIM;
3147 	zend_long SX, SY, SW, SH, DX, DY, PCT;
3148 	gdImagePtr im_dst, im_src;
3149 	int srcH, srcW, srcY, srcX, dstY, dstX, pct;
3150 
3151 	ZEND_PARSE_PARAMETERS_START(9, 9)
3152 		Z_PARAM_OBJECT_OF_CLASS(DIM, gd_image_ce)
3153 		Z_PARAM_OBJECT_OF_CLASS(SIM, gd_image_ce)
3154 		Z_PARAM_LONG(DX)
3155 		Z_PARAM_LONG(DY)
3156 		Z_PARAM_LONG(SX)
3157 		Z_PARAM_LONG(SY)
3158 		Z_PARAM_LONG(SW)
3159 		Z_PARAM_LONG(SH)
3160 		Z_PARAM_LONG(PCT)
3161 	ZEND_PARSE_PARAMETERS_END();
3162 
3163 	im_src = php_gd_libgdimageptr_from_zval_p(SIM);
3164 	im_dst = php_gd_libgdimageptr_from_zval_p(DIM);
3165 
3166 	srcX = SX;
3167 	srcY = SY;
3168 	srcH = SH;
3169 	srcW = SW;
3170 	dstX = DX;
3171 	dstY = DY;
3172 	pct  = PCT;
3173 
3174 	gdImageCopyMergeGray(im_dst, im_src, dstX, dstY, srcX, srcY, srcW, srcH, pct);
3175 	RETURN_TRUE;
3176 }
3177 /* }}} */
3178 
3179 /* {{{ Copy and resize part of an image */
PHP_FUNCTION(imagecopyresized)3180 PHP_FUNCTION(imagecopyresized)
3181 {
3182 	zval *SIM, *DIM;
3183 	zend_long SX, SY, SW, SH, DX, DY, DW, DH;
3184 	gdImagePtr im_dst, im_src;
3185 	int srcH, srcW, dstH, dstW, srcY, srcX, dstY, dstX;
3186 
3187 	ZEND_PARSE_PARAMETERS_START(10, 10)
3188 		Z_PARAM_OBJECT_OF_CLASS(DIM, gd_image_ce)
3189 		Z_PARAM_OBJECT_OF_CLASS(SIM, gd_image_ce)
3190 		Z_PARAM_LONG(DX)
3191 		Z_PARAM_LONG(DY)
3192 		Z_PARAM_LONG(SX)
3193 		Z_PARAM_LONG(SY)
3194 		Z_PARAM_LONG(DW)
3195 		Z_PARAM_LONG(DH)
3196 		Z_PARAM_LONG(SW)
3197 		Z_PARAM_LONG(SH)
3198 	ZEND_PARSE_PARAMETERS_END();
3199 
3200 	im_src = php_gd_libgdimageptr_from_zval_p(SIM);
3201 	im_dst = php_gd_libgdimageptr_from_zval_p(DIM);
3202 
3203 	srcX = SX;
3204 	srcY = SY;
3205 	srcH = SH;
3206 	srcW = SW;
3207 	dstX = DX;
3208 	dstY = DY;
3209 	dstH = DH;
3210 	dstW = DW;
3211 
3212 	if (dstW <= 0) {
3213 		zend_argument_value_error(7, "must be greater than 0");
3214 		RETURN_THROWS();
3215 	}
3216 
3217 	if (dstH <= 0) {
3218 		zend_argument_value_error(8, "must be greater than 0");
3219 		RETURN_THROWS();
3220 	}
3221 
3222 	if (srcW <= 0) {
3223 		zend_argument_value_error(9, "must be greater than 0");
3224 		RETURN_THROWS();
3225 	}
3226 
3227 	if (srcH <= 0) {
3228 		zend_argument_value_error(10, "must be greater than 0");
3229 		RETURN_THROWS();
3230 	}
3231 
3232 	gdImageCopyResized(im_dst, im_src, dstX, dstY, srcX, srcY, dstW, dstH, srcW, srcH);
3233 	RETURN_TRUE;
3234 }
3235 /* }}} */
3236 
3237 /* {{{ Get image width */
PHP_FUNCTION(imagesx)3238 PHP_FUNCTION(imagesx)
3239 {
3240 	zval *IM;
3241 	gdImagePtr im;
3242 
3243 	ZEND_PARSE_PARAMETERS_START(1, 1)
3244 		Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
3245 	ZEND_PARSE_PARAMETERS_END();
3246 
3247 	im = php_gd_libgdimageptr_from_zval_p(IM);
3248 
3249 	RETURN_LONG(gdImageSX(im));
3250 }
3251 /* }}} */
3252 
3253 /* {{{ Get image height */
PHP_FUNCTION(imagesy)3254 PHP_FUNCTION(imagesy)
3255 {
3256 	zval *IM;
3257 	gdImagePtr im;
3258 
3259 	ZEND_PARSE_PARAMETERS_START(1, 1)
3260 		Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
3261 	ZEND_PARSE_PARAMETERS_END();
3262 
3263 	im = php_gd_libgdimageptr_from_zval_p(IM);
3264 
3265 	RETURN_LONG(gdImageSY(im));
3266 }
3267 /* }}} */
3268 
3269 /* {{{ Set the clipping rectangle. */
PHP_FUNCTION(imagesetclip)3270 PHP_FUNCTION(imagesetclip)
3271 {
3272 	zval *im_zval;
3273 	gdImagePtr im;
3274 	zend_long x1, y1, x2, y2;
3275 
3276 	ZEND_PARSE_PARAMETERS_START(5, 5)
3277 		Z_PARAM_OBJECT_OF_CLASS(im_zval, gd_image_ce)
3278 		Z_PARAM_LONG(x1)
3279 		Z_PARAM_LONG(y1)
3280 		Z_PARAM_LONG(x2)
3281 		Z_PARAM_LONG(y2)
3282 	ZEND_PARSE_PARAMETERS_END();
3283 
3284 	im = php_gd_libgdimageptr_from_zval_p(im_zval);
3285 
3286 	gdImageSetClip(im, x1, y1, x2, y2);
3287 	RETURN_TRUE;
3288 }
3289 /* }}} */
3290 
3291 /* {{{ Get the clipping rectangle. */
PHP_FUNCTION(imagegetclip)3292 PHP_FUNCTION(imagegetclip)
3293 {
3294 	zval *im_zval;
3295 	gdImagePtr im;
3296 	int x1, y1, x2, y2;
3297 
3298 	ZEND_PARSE_PARAMETERS_START(1, 1)
3299 		Z_PARAM_OBJECT_OF_CLASS(im_zval, gd_image_ce)
3300 	ZEND_PARSE_PARAMETERS_END();
3301 
3302 	im = php_gd_libgdimageptr_from_zval_p(im_zval);
3303 
3304 	gdImageGetClip(im, &x1, &y1, &x2, &y2);
3305 
3306 	array_init(return_value);
3307 	add_next_index_long(return_value, x1);
3308 	add_next_index_long(return_value, y1);
3309 	add_next_index_long(return_value, x2);
3310 	add_next_index_long(return_value, y2);
3311 }
3312 /* }}} */
3313 
3314 #define TTFTEXT_DRAW 0
3315 #define TTFTEXT_BBOX 1
3316 
3317 #ifdef HAVE_GD_FREETYPE
3318 /* {{{ Give the bounding box of a text using fonts via freetype2 */
PHP_FUNCTION(imageftbbox)3319 PHP_FUNCTION(imageftbbox)
3320 {
3321 	php_imagettftext_common(INTERNAL_FUNCTION_PARAM_PASSTHRU, TTFTEXT_BBOX);
3322 }
3323 /* }}} */
3324 
3325 /* {{{ Write text to the image using fonts via freetype2 */
PHP_FUNCTION(imagefttext)3326 PHP_FUNCTION(imagefttext)
3327 {
3328 	php_imagettftext_common(INTERNAL_FUNCTION_PARAM_PASSTHRU, TTFTEXT_DRAW);
3329 }
3330 /* }}} */
3331 
3332 /* {{{ php_imagettftext_common */
php_imagettftext_common(INTERNAL_FUNCTION_PARAMETERS,int mode)3333 static void php_imagettftext_common(INTERNAL_FUNCTION_PARAMETERS, int mode)
3334 {
3335 	zval *IM, *EXT = NULL;
3336 	gdImagePtr im=NULL;
3337 	zend_long col = -1, x = 0, y = 0;
3338 	size_t str_len, fontname_len;
3339 	int i, brect[8];
3340 	double ptsize, angle;
3341 	char *str = NULL, *fontname = NULL;
3342 	char *error = NULL;
3343 	gdFTStringExtra strex = {0};
3344 
3345 	if (mode == TTFTEXT_BBOX) {
3346 		if (zend_parse_parameters(ZEND_NUM_ARGS(), "ddss|a", &ptsize, &angle, &fontname, &fontname_len, &str, &str_len, &EXT) == FAILURE) {
3347 			RETURN_THROWS();
3348 		}
3349 	} else {
3350 		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) {
3351 			RETURN_THROWS();
3352 		}
3353 		im = php_gd_libgdimageptr_from_zval_p(IM);
3354 	}
3355 
3356 	/* convert angle to radians */
3357 	angle = angle * (M_PI/180);
3358 
3359 	if (EXT) {	/* parse extended info */
3360 		zval *item;
3361 		zend_string *key;
3362 
3363 		/* walk the assoc array */
3364 		if (!HT_IS_PACKED(Z_ARRVAL_P(EXT))) {
3365 			ZEND_HASH_MAP_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(EXT), key, item) {
3366 				if (key == NULL) {
3367 					continue;
3368 				}
3369 				if (zend_string_equals_literal(key, "linespacing")) {
3370 					strex.flags |= gdFTEX_LINESPACE;
3371 					strex.linespacing = zval_get_double(item);
3372 				}
3373 			} ZEND_HASH_FOREACH_END();
3374 		}
3375 	}
3376 
3377 #ifdef VIRTUAL_DIR
3378 	{
3379 		char tmp_font_path[MAXPATHLEN];
3380 
3381 		if (!VCWD_REALPATH(fontname, tmp_font_path)) {
3382 			fontname = NULL;
3383 		}
3384 	}
3385 #endif /* VIRTUAL_DIR */
3386 
3387 	PHP_GD_CHECK_OPEN_BASEDIR(fontname, "Invalid font filename");
3388 
3389 	// libgd note: Those should return const char * ideally, but backward compatibility ..
3390 	if (EXT) {
3391 		error = gdImageStringFTEx(im, brect, col, fontname, ptsize, angle, x, y, str, &strex);
3392 	} else {
3393 		error = gdImageStringFT(im, brect, col, fontname, ptsize, angle, x, y, str);
3394 	}
3395 
3396 	if (error) {
3397 		php_error_docref(NULL, E_WARNING, "%s", error);
3398 		RETURN_FALSE;
3399 	}
3400 
3401 	array_init(return_value);
3402 
3403 	/* return array with the text's bounding box */
3404 	for (i = 0; i < 8; i++) {
3405 		add_next_index_long(return_value, brect[i]);
3406 	}
3407 }
3408 /* }}} */
3409 #endif /* HAVE_GD_FREETYPE */
3410 
3411 /* Section Filters */
3412 #define PHP_GD_SINGLE_RES	\
3413 	zval *SIM;	\
3414 	gdImagePtr im_src;	\
3415 	if (zend_parse_parameters(1, "O", &SIM, gd_image_ce) == FAILURE) {	\
3416 		RETURN_THROWS();	\
3417 	}	\
3418 	im_src = php_gd_libgdimageptr_from_zval_p(SIM);
3419 
php_image_filter_negate(INTERNAL_FUNCTION_PARAMETERS)3420 static void php_image_filter_negate(INTERNAL_FUNCTION_PARAMETERS)
3421 {
3422 	PHP_GD_SINGLE_RES
3423 
3424 	if (gdImageNegate(im_src) == 1) {
3425 		RETURN_TRUE;
3426 	}
3427 
3428 	RETURN_FALSE;
3429 }
3430 
php_image_filter_grayscale(INTERNAL_FUNCTION_PARAMETERS)3431 static void php_image_filter_grayscale(INTERNAL_FUNCTION_PARAMETERS)
3432 {
3433 	PHP_GD_SINGLE_RES
3434 
3435 	if (gdImageGrayScale(im_src) == 1) {
3436 		RETURN_TRUE;
3437 	}
3438 
3439 	RETURN_FALSE;
3440 }
3441 
php_image_filter_brightness(INTERNAL_FUNCTION_PARAMETERS)3442 static void php_image_filter_brightness(INTERNAL_FUNCTION_PARAMETERS)
3443 {
3444 	zval *SIM;
3445 	gdImagePtr im_src;
3446 	zend_long brightness, tmp;
3447 
3448 	ZEND_PARSE_PARAMETERS_START(3, 3)
3449 		Z_PARAM_OBJECT_OF_CLASS(SIM, gd_image_ce)
3450 		Z_PARAM_LONG(tmp)
3451 		Z_PARAM_LONG(brightness)
3452 	ZEND_PARSE_PARAMETERS_END();
3453 
3454 	im_src = php_gd_libgdimageptr_from_zval_p(SIM);
3455 
3456 	if (gdImageBrightness(im_src, (int)brightness) == 1) {
3457 		RETURN_TRUE;
3458 	}
3459 
3460 	RETURN_FALSE;
3461 }
3462 
php_image_filter_contrast(INTERNAL_FUNCTION_PARAMETERS)3463 static void php_image_filter_contrast(INTERNAL_FUNCTION_PARAMETERS)
3464 {
3465 	zval *SIM;
3466 	gdImagePtr im_src;
3467 	zend_long contrast, tmp;
3468 
3469 	ZEND_PARSE_PARAMETERS_START(3, 3)
3470 		Z_PARAM_OBJECT_OF_CLASS(SIM, gd_image_ce)
3471 		Z_PARAM_LONG(tmp)
3472 		Z_PARAM_LONG(contrast)
3473 	ZEND_PARSE_PARAMETERS_END();
3474 
3475 	im_src = php_gd_libgdimageptr_from_zval_p(SIM);
3476 
3477 	if (gdImageContrast(im_src, (int)contrast) == 1) {
3478 		RETURN_TRUE;
3479 	}
3480 
3481 	RETURN_FALSE;
3482 }
3483 
php_image_filter_colorize(INTERNAL_FUNCTION_PARAMETERS)3484 static void php_image_filter_colorize(INTERNAL_FUNCTION_PARAMETERS)
3485 {
3486 	zval *SIM;
3487 	gdImagePtr im_src;
3488 	zend_long r,g,b,tmp;
3489 	zend_long a = 0;
3490 
3491 	ZEND_PARSE_PARAMETERS_START(5, 6)
3492 		Z_PARAM_OBJECT_OF_CLASS(SIM, gd_image_ce)
3493 		Z_PARAM_LONG(tmp)
3494 		Z_PARAM_LONG(r)
3495 		Z_PARAM_LONG(g)
3496 		Z_PARAM_LONG(b)
3497 		Z_PARAM_OPTIONAL
3498 		Z_PARAM_LONG(a)
3499 	ZEND_PARSE_PARAMETERS_END();
3500 
3501 	im_src = php_gd_libgdimageptr_from_zval_p(SIM);
3502 
3503 	if (gdImageColor(im_src, (int) r, (int) g, (int) b, (int) a) == 1) {
3504 		RETURN_TRUE;
3505 	}
3506 
3507 	RETURN_FALSE;
3508 }
3509 
php_image_filter_edgedetect(INTERNAL_FUNCTION_PARAMETERS)3510 static void php_image_filter_edgedetect(INTERNAL_FUNCTION_PARAMETERS)
3511 {
3512 	PHP_GD_SINGLE_RES
3513 
3514 	if (gdImageEdgeDetectQuick(im_src) == 1) {
3515 		RETURN_TRUE;
3516 	}
3517 
3518 	RETURN_FALSE;
3519 }
3520 
php_image_filter_emboss(INTERNAL_FUNCTION_PARAMETERS)3521 static void php_image_filter_emboss(INTERNAL_FUNCTION_PARAMETERS)
3522 {
3523 	PHP_GD_SINGLE_RES
3524 
3525 	if (gdImageEmboss(im_src) == 1) {
3526 		RETURN_TRUE;
3527 	}
3528 
3529 	RETURN_FALSE;
3530 }
3531 
php_image_filter_gaussian_blur(INTERNAL_FUNCTION_PARAMETERS)3532 static void php_image_filter_gaussian_blur(INTERNAL_FUNCTION_PARAMETERS)
3533 {
3534 	PHP_GD_SINGLE_RES
3535 
3536 	if (gdImageGaussianBlur(im_src) == 1) {
3537 		RETURN_TRUE;
3538 	}
3539 
3540 	RETURN_FALSE;
3541 }
3542 
php_image_filter_selective_blur(INTERNAL_FUNCTION_PARAMETERS)3543 static void php_image_filter_selective_blur(INTERNAL_FUNCTION_PARAMETERS)
3544 {
3545 	PHP_GD_SINGLE_RES
3546 
3547 	if (gdImageSelectiveBlur(im_src) == 1) {
3548 		RETURN_TRUE;
3549 	}
3550 
3551 	RETURN_FALSE;
3552 }
3553 
php_image_filter_mean_removal(INTERNAL_FUNCTION_PARAMETERS)3554 static void php_image_filter_mean_removal(INTERNAL_FUNCTION_PARAMETERS)
3555 {
3556 	PHP_GD_SINGLE_RES
3557 
3558 	if (gdImageMeanRemoval(im_src) == 1) {
3559 		RETURN_TRUE;
3560 	}
3561 
3562 	RETURN_FALSE;
3563 }
3564 
php_image_filter_smooth(INTERNAL_FUNCTION_PARAMETERS)3565 static void php_image_filter_smooth(INTERNAL_FUNCTION_PARAMETERS)
3566 {
3567 	zval *SIM;
3568 	zend_long tmp;
3569 	gdImagePtr im_src;
3570 	double weight;
3571 
3572 	ZEND_PARSE_PARAMETERS_START(3, 3)
3573 		Z_PARAM_OBJECT_OF_CLASS(SIM, gd_image_ce)
3574 		Z_PARAM_LONG(tmp)
3575 		Z_PARAM_DOUBLE(weight)
3576 	ZEND_PARSE_PARAMETERS_END();
3577 
3578 	im_src = php_gd_libgdimageptr_from_zval_p(SIM);
3579 
3580 	if (gdImageSmooth(im_src, (float)weight)==1) {
3581 		RETURN_TRUE;
3582 	}
3583 
3584 	RETURN_FALSE;
3585 }
3586 
php_image_filter_pixelate(INTERNAL_FUNCTION_PARAMETERS)3587 static void php_image_filter_pixelate(INTERNAL_FUNCTION_PARAMETERS)
3588 {
3589 	zval *IM;
3590 	gdImagePtr im;
3591 	zend_long tmp, blocksize;
3592 	bool mode = false;
3593 
3594 	ZEND_PARSE_PARAMETERS_START(3, 4)
3595 		Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
3596 		Z_PARAM_LONG(tmp)
3597 		Z_PARAM_LONG(blocksize)
3598 		Z_PARAM_OPTIONAL
3599 		Z_PARAM_BOOL(mode)
3600 	ZEND_PARSE_PARAMETERS_END();
3601 
3602 	im = php_gd_libgdimageptr_from_zval_p(IM);
3603 
3604 	if (gdImagePixelate(im, (int) blocksize, (const unsigned int) mode)) {
3605 		RETURN_TRUE;
3606 	}
3607 
3608 	RETURN_FALSE;
3609 }
3610 
php_image_filter_scatter(INTERNAL_FUNCTION_PARAMETERS)3611 static void php_image_filter_scatter(INTERNAL_FUNCTION_PARAMETERS)
3612 {
3613 	zval *IM;
3614 	zval *hash_colors = NULL;
3615 	gdImagePtr im;
3616 	zend_long tmp;
3617 	zend_long scatter_sub, scatter_plus;
3618 
3619 	ZEND_PARSE_PARAMETERS_START(4, 5)
3620 		Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
3621 		Z_PARAM_LONG(tmp)
3622 		Z_PARAM_LONG(scatter_sub)
3623 		Z_PARAM_LONG(scatter_plus)
3624 		Z_PARAM_OPTIONAL
3625 		Z_PARAM_ARRAY(hash_colors)
3626 	ZEND_PARSE_PARAMETERS_END();
3627 
3628 	if (scatter_sub < 0 || ZEND_SIZE_T_INT_OVFL(scatter_sub)) {
3629 		zend_argument_value_error(3, "must be between 0 and %d", INT_MAX);
3630 		RETURN_THROWS();
3631 	}
3632 
3633 	if (scatter_plus < 0 || ZEND_SIZE_T_INT_OVFL(scatter_plus)) {
3634 		zend_argument_value_error(4, "must be between 0 and %d", INT_MAX);
3635 		RETURN_THROWS();
3636 	}
3637 
3638 	im = php_gd_libgdimageptr_from_zval_p(IM);
3639 
3640 	if (hash_colors) {
3641 		uint32_t i = 0;
3642 		uint32_t num_colors = zend_hash_num_elements(Z_ARRVAL_P(hash_colors));
3643 		zval *color;
3644 		int *colors;
3645 
3646 		if (num_colors == 0) {
3647 			RETURN_BOOL(gdImageScatter(im, (int)scatter_sub, (int)scatter_plus));
3648 		}
3649 
3650 		colors = emalloc(num_colors * sizeof(int));
3651 
3652 		ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(hash_colors), color) {
3653 			*(colors + i++) = (int) zval_get_long(color);
3654 		} ZEND_HASH_FOREACH_END();
3655 
3656 		RETVAL_BOOL(gdImageScatterColor(im, (int)scatter_sub, (int)scatter_plus, colors, num_colors));
3657 
3658 		efree(colors);
3659 	} else {
3660 		RETURN_BOOL(gdImageScatter(im, (int) scatter_sub, (int) scatter_plus));
3661 	}
3662 }
3663 
3664 /* {{{ Applies Filter an image using a custom angle */
PHP_FUNCTION(imagefilter)3665 PHP_FUNCTION(imagefilter)
3666 {
3667 	zval *tmp;
3668 
3669 	typedef void (*image_filter)(INTERNAL_FUNCTION_PARAMETERS);
3670 	zend_long filtertype;
3671 	image_filter filters[] =
3672 	{
3673 		php_image_filter_negate ,
3674 		php_image_filter_grayscale,
3675 		php_image_filter_brightness,
3676 		php_image_filter_contrast,
3677 		php_image_filter_colorize,
3678 		php_image_filter_edgedetect,
3679 		php_image_filter_emboss,
3680 		php_image_filter_gaussian_blur,
3681 		php_image_filter_selective_blur,
3682 		php_image_filter_mean_removal,
3683 		php_image_filter_smooth,
3684 		php_image_filter_pixelate,
3685 		php_image_filter_scatter
3686 	};
3687 
3688 	if (ZEND_NUM_ARGS() < 2 || ZEND_NUM_ARGS() > IMAGE_FILTER_MAX_ARGS) {
3689 		WRONG_PARAM_COUNT;
3690 	} else if (zend_parse_parameters(2, "Ol", &tmp, gd_image_ce, &filtertype) == FAILURE) {
3691 		RETURN_THROWS();
3692 	}
3693 
3694 	if (filtertype >= 0 && filtertype <= IMAGE_FILTER_MAX) {
3695 		filters[filtertype](INTERNAL_FUNCTION_PARAM_PASSTHRU);
3696 	}
3697 }
3698 /* }}} */
3699 
3700 /* {{{ Apply a 3x3 convolution matrix, using coefficient div and offset */
PHP_FUNCTION(imageconvolution)3701 PHP_FUNCTION(imageconvolution)
3702 {
3703 	zval *SIM, *hash_matrix;
3704 	zval *var = NULL, *var2 = NULL;
3705 	gdImagePtr im_src = NULL;
3706 	double div, offset;
3707 	int nelem, i, j, res;
3708 	float matrix[3][3] = {{0,0,0}, {0,0,0}, {0,0,0}};
3709 
3710 	ZEND_PARSE_PARAMETERS_START(4, 4)
3711 		Z_PARAM_OBJECT_OF_CLASS(SIM, gd_image_ce)
3712 		Z_PARAM_ARRAY(hash_matrix)
3713 		Z_PARAM_DOUBLE(div)
3714 		Z_PARAM_DOUBLE(offset)
3715 	ZEND_PARSE_PARAMETERS_END();
3716 
3717 	im_src = php_gd_libgdimageptr_from_zval_p(SIM);
3718 
3719 	nelem = zend_hash_num_elements(Z_ARRVAL_P(hash_matrix));
3720 	if (nelem != 3) {
3721 		zend_argument_value_error(2, "must be a 3x3 array");
3722 		RETURN_THROWS();
3723 	}
3724 
3725 	for (i=0; i<3; i++) {
3726 		if ((var = zend_hash_index_find(Z_ARRVAL_P(hash_matrix), (i))) != NULL && Z_TYPE_P(var) == IS_ARRAY) {
3727 			if (zend_hash_num_elements(Z_ARRVAL_P(var)) != 3 ) {
3728 				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)));
3729 				RETURN_THROWS();
3730 			}
3731 
3732 			for (j=0; j<3; j++) {
3733 				if ((var2 = zend_hash_index_find(Z_ARRVAL_P(var), j)) != NULL) {
3734 					matrix[i][j] = (float) zval_get_double(var2);
3735 				} else {
3736 					zend_argument_value_error(2, "must be a 3x3 array, matrix[%d][%d] cannot be found (missing integer key)", i, j);
3737 					RETURN_THROWS();
3738 				}
3739 			}
3740 		}
3741 	}
3742 	res = gdImageConvolution(im_src, matrix, (float)div, (float)offset);
3743 
3744 	if (res) {
3745 		RETURN_TRUE;
3746 	} else {
3747 		RETURN_FALSE;
3748 	}
3749 }
3750 /* }}} */
3751 /* End section: Filters */
3752 
3753 /* {{{ Flip an image (in place) horizontally, vertically or both directions. */
PHP_FUNCTION(imageflip)3754 PHP_FUNCTION(imageflip)
3755 {
3756 	zval *IM;
3757 	zend_long mode;
3758 	gdImagePtr im;
3759 
3760 	ZEND_PARSE_PARAMETERS_START(2, 2)
3761 		Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
3762 		Z_PARAM_LONG(mode)
3763 	ZEND_PARSE_PARAMETERS_END();
3764 
3765 	im = php_gd_libgdimageptr_from_zval_p(IM);
3766 
3767 	switch (mode) {
3768 		case PHP_GD_FLIP_VERTICAL:
3769 			gdImageFlipVertical(im);
3770 			break;
3771 
3772 		case PHP_GD_FLIP_HORIZONTAL:
3773 			gdImageFlipHorizontal(im);
3774 			break;
3775 
3776 		case PHP_GD_FLIP_BOTH:
3777 			gdImageFlipBoth(im);
3778 			break;
3779 
3780 		default:
3781 			zend_argument_value_error(2, "must be one of IMG_FLIP_VERTICAL, IMG_FLIP_HORIZONTAL, or IMG_FLIP_BOTH");
3782 			RETURN_THROWS();
3783 	}
3784 
3785 	RETURN_TRUE;
3786 }
3787 /* }}} */
3788 
3789 /* {{{ Should antialiased functions used or not*/
PHP_FUNCTION(imageantialias)3790 PHP_FUNCTION(imageantialias)
3791 {
3792 	zval *IM;
3793 	bool alias;
3794 	gdImagePtr im;
3795 
3796 	ZEND_PARSE_PARAMETERS_START(2, 2)
3797 		Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
3798 		Z_PARAM_BOOL(alias)
3799 	ZEND_PARSE_PARAMETERS_END();
3800 
3801 	im = php_gd_libgdimageptr_from_zval_p(IM);
3802 	if (im->trueColor) {
3803 		im->AA = alias;
3804 	}
3805 
3806 	RETURN_TRUE;
3807 }
3808 /* }}} */
3809 
3810 /* {{{ Crop an image using the given coordinates and size, x, y, width and height. */
PHP_FUNCTION(imagecrop)3811 PHP_FUNCTION(imagecrop)
3812 {
3813 	zval *IM;
3814 	gdImagePtr im;
3815 	gdImagePtr im_crop;
3816 	gdRect rect;
3817 	zval *z_rect;
3818 	zval *tmp;
3819 
3820 	ZEND_PARSE_PARAMETERS_START(2, 2)
3821 		Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
3822 		Z_PARAM_ARRAY(z_rect)
3823 	ZEND_PARSE_PARAMETERS_END();
3824 
3825 	im = php_gd_libgdimageptr_from_zval_p(IM);
3826 
3827 	if ((tmp = zend_hash_str_find(Z_ARRVAL_P(z_rect), "x", sizeof("x") -1)) != NULL) {
3828 		rect.x = zval_get_long(tmp);
3829 	} else {
3830 		zend_argument_value_error(2, "must have an \"x\" key");
3831 		RETURN_THROWS();
3832 	}
3833 
3834 	if ((tmp = zend_hash_str_find(Z_ARRVAL_P(z_rect), "y", sizeof("y") - 1)) != NULL) {
3835 		rect.y = zval_get_long(tmp);
3836 	} else {
3837 		zend_argument_value_error(2, "must have a \"y\" key");
3838 		RETURN_THROWS();
3839 	}
3840 
3841 	if ((tmp = zend_hash_str_find(Z_ARRVAL_P(z_rect), "width", sizeof("width") - 1)) != NULL) {
3842 		rect.width = zval_get_long(tmp);
3843 	} else {
3844 		zend_argument_value_error(2, "must have a \"width\" key");
3845 		RETURN_THROWS();
3846 	}
3847 
3848 	if ((tmp = zend_hash_str_find(Z_ARRVAL_P(z_rect), "height", sizeof("height") - 1)) != NULL) {
3849 		rect.height = zval_get_long(tmp);
3850 	} else {
3851 		zend_argument_value_error(2, "must have a \"height\" key");
3852 		RETURN_THROWS();
3853 	}
3854 
3855 	im_crop = gdImageCrop(im, &rect);
3856 
3857 	if (im_crop == NULL) {
3858 		RETURN_FALSE;
3859 	}
3860 
3861 	php_gd_assign_libgdimageptr_as_extgdimage(return_value, im_crop);
3862 }
3863 /* }}} */
3864 
3865 /* {{{ Crop an image automatically using one of the available modes. */
PHP_FUNCTION(imagecropauto)3866 PHP_FUNCTION(imagecropauto)
3867 {
3868 	zval *IM;
3869 	zend_long mode = GD_CROP_DEFAULT;
3870 	zend_long color = -1;
3871 	double threshold = 0.5f;
3872 	gdImagePtr im;
3873 	gdImagePtr im_crop;
3874 
3875 	ZEND_PARSE_PARAMETERS_START(1, 4)
3876 		Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
3877 		Z_PARAM_OPTIONAL
3878 		Z_PARAM_LONG(mode)
3879 		Z_PARAM_DOUBLE(threshold)
3880 		Z_PARAM_LONG(color)
3881 	ZEND_PARSE_PARAMETERS_END();
3882 
3883 	im = php_gd_libgdimageptr_from_zval_p(IM);
3884 
3885 	switch (mode) {
3886 		case GD_CROP_DEFAULT:
3887 		case GD_CROP_TRANSPARENT:
3888 		case GD_CROP_BLACK:
3889 		case GD_CROP_WHITE:
3890 		case GD_CROP_SIDES:
3891 			im_crop = gdImageCropAuto(im, mode);
3892 			break;
3893 
3894 		case GD_CROP_THRESHOLD:
3895 			if (color < 0 || (!gdImageTrueColor(im) && color >= gdImageColorsTotal(im))) {
3896 				zend_argument_value_error(4, "must be greater than or equal to 0 when using the threshold mode");
3897 				RETURN_THROWS();
3898 			}
3899 			im_crop = gdImageCropThreshold(im, color, (float) threshold);
3900 			break;
3901 
3902 		default:
3903 			zend_argument_value_error(2, "must be a valid mode");
3904 			RETURN_THROWS();
3905 	}
3906 
3907 	if (im_crop == NULL) {
3908 		RETURN_FALSE;
3909 	}
3910 
3911 	php_gd_assign_libgdimageptr_as_extgdimage(return_value, im_crop);
3912 }
3913 /* }}} */
3914 
3915 /* {{{ Scale an image using the given new width and height. */
PHP_FUNCTION(imagescale)3916 PHP_FUNCTION(imagescale)
3917 {
3918 	zval *IM;
3919 	gdImagePtr im;
3920 	gdImagePtr im_scaled = NULL;
3921 	int new_width, new_height;
3922 	zend_long tmp_w, tmp_h=-1, tmp_m = GD_BILINEAR_FIXED;
3923 	gdInterpolationMethod method, old_method;
3924 
3925 	ZEND_PARSE_PARAMETERS_START(2, 4)
3926 		Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
3927 		Z_PARAM_LONG(tmp_w)
3928 		Z_PARAM_OPTIONAL
3929 		Z_PARAM_LONG(tmp_h)
3930 		Z_PARAM_LONG(tmp_m)
3931 	ZEND_PARSE_PARAMETERS_END();
3932 
3933 	if (tmp_m < GD_DEFAULT || tmp_m >= GD_METHOD_COUNT) {
3934 		zend_argument_value_error(4, "must be one of the GD_* constants");
3935 		RETURN_THROWS();
3936 	}
3937 
3938 	method = tmp_m;
3939 
3940 	im = php_gd_libgdimageptr_from_zval_p(IM);
3941 
3942 	if (tmp_h < 0 || tmp_w < 0) {
3943 		/* preserve ratio */
3944 		long src_x, src_y;
3945 
3946 		src_x = gdImageSX(im);
3947 		src_y = gdImageSY(im);
3948 
3949 		if (src_x && tmp_h < 0) {
3950 			tmp_h = tmp_w * src_y / src_x;
3951 		}
3952 		if (src_y && tmp_w < 0) {
3953 			tmp_w = tmp_h * src_x / src_y;
3954 		}
3955 	}
3956 
3957 	if (tmp_w <= 0 || ZEND_SIZE_T_INT_OVFL(tmp_w)) {
3958 		zend_argument_value_error(2, "must be between 1 and %d", INT_MAX);
3959 		RETURN_THROWS();
3960 	}
3961 
3962 	if (tmp_h <= 0 || ZEND_SIZE_T_INT_OVFL(tmp_h)) {
3963 		zend_argument_value_error(3, "must be between 1 and %d", INT_MAX);
3964 		RETURN_THROWS();
3965 	}
3966 
3967 
3968 	new_width = tmp_w;
3969 	new_height = tmp_h;
3970 
3971 	/* gdImageGetInterpolationMethod() is only available as of GD 2.1.1 */
3972 	old_method = im->interpolation_id;
3973 	if (gdImageSetInterpolationMethod(im, method)) {
3974 		im_scaled = gdImageScale(im, new_width, new_height);
3975 	}
3976 	gdImageSetInterpolationMethod(im, old_method);
3977 
3978 	if (im_scaled == NULL) {
3979 		RETURN_FALSE;
3980 	}
3981 
3982 	php_gd_assign_libgdimageptr_as_extgdimage(return_value, im_scaled);
3983 }
3984 /* }}} */
3985 
3986 /* {{{ Return an image containing the affine tramsformed src image, using an optional clipping area */
PHP_FUNCTION(imageaffine)3987 PHP_FUNCTION(imageaffine)
3988 {
3989 	zval *IM;
3990 	gdImagePtr src;
3991 	gdImagePtr dst;
3992 	gdRect rect;
3993 	gdRectPtr pRect = NULL;
3994 	zval *z_rect = NULL;
3995 	zval *z_affine;
3996 	zval *tmp;
3997 	double affine[6];
3998 	int i, nelems;
3999 	zval *zval_affine_elem = NULL;
4000 
4001 	ZEND_PARSE_PARAMETERS_START(2, 3)
4002 		Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
4003 		Z_PARAM_ARRAY(z_affine)
4004 		Z_PARAM_OPTIONAL
4005 		Z_PARAM_ARRAY_OR_NULL(z_rect)
4006 	ZEND_PARSE_PARAMETERS_END();
4007 
4008 
4009 	src = php_gd_libgdimageptr_from_zval_p(IM);
4010 
4011 	if ((nelems = zend_hash_num_elements(Z_ARRVAL_P(z_affine))) != 6) {
4012 		zend_argument_value_error(2, "must have 6 elements");
4013 		RETURN_THROWS();
4014 	}
4015 
4016 	for (i = 0; i < nelems; i++) {
4017 		if ((zval_affine_elem = zend_hash_index_find(Z_ARRVAL_P(z_affine), i)) != NULL) {
4018 			switch (Z_TYPE_P(zval_affine_elem)) {
4019 				case IS_LONG:
4020 					affine[i] = Z_LVAL_P(zval_affine_elem);
4021 					if (affine[i] < INT_MIN || affine[i] > INT_MAX) {
4022 						zend_argument_value_error(2, "element %i must be between %d and %d", i, INT_MIN, INT_MAX);
4023 						RETURN_THROWS();
4024 					}
4025 					break;
4026 				case IS_DOUBLE:
4027 					affine[i] = Z_DVAL_P(zval_affine_elem);
4028 					if (affine[i] < INT_MIN || affine[i] > INT_MAX) {
4029 						zend_argument_value_error(2, "element %i must be between %d and %d", i, INT_MIN, INT_MAX);
4030 						RETURN_THROWS();
4031 					}
4032 					break;
4033 				case IS_STRING:
4034 					affine[i] = zval_get_double(zval_affine_elem);
4035 					if (affine[i] < INT_MIN || affine[i] > INT_MAX) {
4036 						zend_argument_value_error(2, "element %i must be between %d and %d", i, INT_MIN, INT_MAX);
4037 						RETURN_THROWS();
4038 					}
4039 					break;
4040 				default:
4041 					zend_argument_type_error(3, "contains invalid type for element %i", i);
4042 					RETURN_THROWS();
4043 			}
4044 		}
4045 	}
4046 
4047 	if (z_rect != NULL) {
4048 		if ((tmp = zend_hash_str_find(Z_ARRVAL_P(z_rect), "x", sizeof("x") - 1)) != NULL) {
4049 			rect.x = zval_get_long(tmp);
4050 		} else {
4051 			zend_argument_value_error(3, "must have an \"x\" key");
4052 			RETURN_THROWS();
4053 		}
4054 
4055 		if ((tmp = zend_hash_str_find(Z_ARRVAL_P(z_rect), "y", sizeof("y") - 1)) != NULL) {
4056 			rect.y = zval_get_long(tmp);
4057 		} else {
4058 			zend_argument_value_error(3, "must have a \"y\" key");
4059 			RETURN_THROWS();
4060 		}
4061 
4062 		if ((tmp = zend_hash_str_find(Z_ARRVAL_P(z_rect), "width", sizeof("width") - 1)) != NULL) {
4063 			rect.width = zval_get_long(tmp);
4064 		} else {
4065 			zend_argument_value_error(3, "must have a \"width\" key");
4066 			RETURN_THROWS();
4067 		}
4068 
4069 		if ((tmp = zend_hash_str_find(Z_ARRVAL_P(z_rect), "height", sizeof("height") - 1)) != NULL) {
4070 			rect.height = zval_get_long(tmp);
4071 		} else {
4072 			zend_argument_value_error(3, "must have a \"height\" key");
4073 			RETURN_THROWS();
4074 		}
4075 		pRect = &rect;
4076 	}
4077 
4078 	if (gdTransformAffineGetImage(&dst, src, pRect, affine) != GD_TRUE) {
4079 		RETURN_FALSE;
4080 	}
4081 
4082 	if (dst == NULL) {
4083 		RETURN_FALSE;
4084 	}
4085 
4086 	php_gd_assign_libgdimageptr_as_extgdimage(return_value, dst);
4087 }
4088 /* }}} */
4089 
4090 /* {{{ Return an image containing the affine tramsformed src image, using an optional clipping area */
PHP_FUNCTION(imageaffinematrixget)4091 PHP_FUNCTION(imageaffinematrixget)
4092 {
4093 	double affine[6];
4094 	zend_long type;
4095 	zval *options = NULL;
4096 	zval *tmp;
4097 	int res = GD_FALSE, i;
4098 
4099 	ZEND_PARSE_PARAMETERS_START(2, 2)
4100 		Z_PARAM_LONG(type)
4101 		Z_PARAM_ZVAL(options)
4102 	ZEND_PARSE_PARAMETERS_END();
4103 
4104 	switch((gdAffineStandardMatrix)type) {
4105 		case GD_AFFINE_TRANSLATE:
4106 		case GD_AFFINE_SCALE: {
4107 			double x, y;
4108 			if (Z_TYPE_P(options) != IS_ARRAY) {
4109 				zend_argument_type_error(1, "must be of type array when using translate or scale");
4110 				RETURN_THROWS();
4111 			}
4112 
4113 			if ((tmp = zend_hash_str_find(Z_ARRVAL_P(options), "x", sizeof("x") - 1)) != NULL) {
4114 				x = zval_get_double(tmp);
4115 			} else {
4116 				zend_argument_value_error(2, "must have an \"x\" key");
4117 				RETURN_THROWS();
4118 			}
4119 
4120 			if ((tmp = zend_hash_str_find(Z_ARRVAL_P(options), "y", sizeof("y") - 1)) != NULL) {
4121 				y = zval_get_double(tmp);
4122 			} else {
4123 				zend_argument_value_error(2, "must have a \"y\" key");
4124 				RETURN_THROWS();
4125 			}
4126 
4127 			if (type == GD_AFFINE_TRANSLATE) {
4128 				res = gdAffineTranslate(affine, x, y);
4129 			} else {
4130 				res = gdAffineScale(affine, x, y);
4131 			}
4132 			break;
4133 		}
4134 
4135 		case GD_AFFINE_ROTATE:
4136 		case GD_AFFINE_SHEAR_HORIZONTAL:
4137 		case GD_AFFINE_SHEAR_VERTICAL: {
4138 			double angle;
4139 
4140 			angle = zval_get_double(options);
4141 
4142 			if (type == GD_AFFINE_SHEAR_HORIZONTAL) {
4143 				res = gdAffineShearHorizontal(affine, angle);
4144 			} else if (type == GD_AFFINE_SHEAR_VERTICAL) {
4145 				res = gdAffineShearVertical(affine, angle);
4146 			} else {
4147 				res = gdAffineRotate(affine, angle);
4148 			}
4149 			break;
4150 		}
4151 
4152 		default:
4153 			zend_argument_value_error(1, "must be a valid element type");
4154 			RETURN_THROWS();
4155 	}
4156 
4157 	if (res == GD_FALSE) {
4158 		RETURN_FALSE;
4159 	} else {
4160 		array_init(return_value);
4161 		for (i = 0; i < 6; i++) {
4162 			add_index_double(return_value, i, affine[i]);
4163 		}
4164 	}
4165 } /* }}} */
4166 
4167 /* {{{ Concat two matrices (as in doing many ops in one go) */
PHP_FUNCTION(imageaffinematrixconcat)4168 PHP_FUNCTION(imageaffinematrixconcat)
4169 {
4170 	double m1[6];
4171 	double m2[6];
4172 	double mr[6];
4173 
4174 	zval *tmp;
4175 	zval *z_m1;
4176 	zval *z_m2;
4177 	int i;
4178 
4179 	ZEND_PARSE_PARAMETERS_START(2, 2)
4180 		Z_PARAM_ARRAY(z_m1)
4181 		Z_PARAM_ARRAY(z_m2)
4182 	ZEND_PARSE_PARAMETERS_END();
4183 
4184 	if (zend_hash_num_elements(Z_ARRVAL_P(z_m1)) != 6) {
4185 		zend_argument_value_error(1, "must have 6 elements");
4186 		RETURN_THROWS();
4187 	}
4188 
4189 	if (zend_hash_num_elements(Z_ARRVAL_P(z_m2)) != 6) {
4190 		zend_argument_value_error(1, "must have 6 elements");
4191 		RETURN_THROWS();
4192 	}
4193 
4194 	for (i = 0; i < 6; i++) {
4195 		if ((tmp = zend_hash_index_find(Z_ARRVAL_P(z_m1), i)) != NULL) {
4196 			switch (Z_TYPE_P(tmp)) {
4197 				case IS_LONG:
4198 					m1[i]  = Z_LVAL_P(tmp);
4199 					break;
4200 				case IS_DOUBLE:
4201 					m1[i] = Z_DVAL_P(tmp);
4202 					break;
4203 				case IS_STRING:
4204 					m1[i] = zval_get_double(tmp);
4205 					break;
4206 				default:
4207 					zend_argument_type_error(1, "contains invalid type for element %i", i);
4208 					RETURN_THROWS();
4209 			}
4210 		}
4211 
4212 		if ((tmp = zend_hash_index_find(Z_ARRVAL_P(z_m2), i)) != NULL) {
4213 			switch (Z_TYPE_P(tmp)) {
4214 				case IS_LONG:
4215 					m2[i]  = Z_LVAL_P(tmp);
4216 					break;
4217 				case IS_DOUBLE:
4218 					m2[i] = Z_DVAL_P(tmp);
4219 					break;
4220 				case IS_STRING:
4221 					m2[i] = zval_get_double(tmp);
4222 					break;
4223 				default:
4224 					zend_argument_type_error(2, "contains invalid type for element %i", i);
4225 					RETURN_THROWS();
4226 			}
4227 		}
4228 	}
4229 
4230 	if (gdAffineConcat (mr, m1, m2) != GD_TRUE) {
4231 		RETURN_FALSE;
4232 	}
4233 
4234 	array_init(return_value);
4235 	for (i = 0; i < 6; i++) {
4236 		add_index_double(return_value, i, mr[i]);
4237 	}
4238 } /* }}} */
4239 
4240 /* {{{ Get the default interpolation method. */
PHP_FUNCTION(imagegetinterpolation)4241 PHP_FUNCTION(imagegetinterpolation)
4242 {
4243 	zval *IM;
4244 	gdImagePtr im;
4245 
4246 	ZEND_PARSE_PARAMETERS_START(1, 1)
4247 		Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
4248 	ZEND_PARSE_PARAMETERS_END();
4249 
4250 	im = php_gd_libgdimageptr_from_zval_p(IM);
4251 
4252 #ifdef HAVE_GD_GET_INTERPOLATION
4253 	RETURN_LONG(gdImageGetInterpolationMethod(im));
4254 #else
4255 	RETURN_LONG(im->interpolation_id);
4256 #endif
4257 }
4258 /* }}} */
4259 
4260 /* {{{ Set the default interpolation method, passing -1 or 0 sets it to the libgd default (bilinear). */
PHP_FUNCTION(imagesetinterpolation)4261 PHP_FUNCTION(imagesetinterpolation)
4262 {
4263 	zval *IM;
4264 	gdImagePtr im;
4265 	zend_long method = GD_BILINEAR_FIXED;
4266 
4267 	ZEND_PARSE_PARAMETERS_START(1, 2)
4268 		Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
4269 		Z_PARAM_OPTIONAL
4270 		Z_PARAM_LONG(method)
4271 	ZEND_PARSE_PARAMETERS_END();
4272 
4273 	im = php_gd_libgdimageptr_from_zval_p(IM);
4274 
4275 	if (method == -1) {
4276 		 method = GD_BILINEAR_FIXED;
4277 	}
4278 	RETURN_BOOL(gdImageSetInterpolationMethod(im, (gdInterpolationMethod) method));
4279 }
4280 /* }}} */
4281 
4282 /* {{{ Get or set the resolution of the image in DPI. */
PHP_FUNCTION(imageresolution)4283 PHP_FUNCTION(imageresolution)
4284 {
4285 	zval *IM;
4286 	gdImagePtr im;
4287 	zend_long res_x, res_y;
4288 	bool res_x_is_null = true, res_y_is_null = true;
4289 
4290 	ZEND_PARSE_PARAMETERS_START(1, 3)
4291 		Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
4292 		Z_PARAM_OPTIONAL
4293 		Z_PARAM_LONG_OR_NULL(res_x, res_x_is_null)
4294 		Z_PARAM_LONG_OR_NULL(res_y, res_y_is_null)
4295 	ZEND_PARSE_PARAMETERS_END();
4296 
4297 	im = php_gd_libgdimageptr_from_zval_p(IM);
4298 
4299 	if (!res_x_is_null && !res_y_is_null) {
4300 		if (res_x < 0 || ZEND_SIZE_T_UINT_OVFL(res_x)) {
4301 			zend_argument_value_error(2, "must be between 0 and %u", UINT_MAX);
4302 			RETURN_THROWS();
4303 		}
4304 		if (res_y < 0 || ZEND_SIZE_T_UINT_OVFL(res_y)) {
4305 			zend_argument_value_error(3, "must be between 0 and %u", UINT_MAX);
4306 			RETURN_THROWS();
4307 		}
4308 		gdImageSetResolution(im, res_x, res_y);
4309 		RETURN_TRUE;
4310 	} else if (!res_x_is_null && res_y_is_null) {
4311 		if (res_x < 0 || ZEND_SIZE_T_UINT_OVFL(res_x)) {
4312 			zend_argument_value_error(2, "must be between 0 and %u", UINT_MAX);
4313 			RETURN_THROWS();
4314 		}
4315 		gdImageSetResolution(im, res_x, res_x);
4316 		RETURN_TRUE;
4317 	} else if (res_x_is_null && !res_y_is_null) {
4318 		if (res_y < 0 || ZEND_SIZE_T_UINT_OVFL(res_y)) {
4319 			zend_argument_value_error(3, "must be between 0 and %u", UINT_MAX);
4320 			RETURN_THROWS();
4321 		}
4322 		gdImageSetResolution(im, res_y, res_y);
4323 		RETURN_TRUE;
4324 	}
4325 
4326 	array_init(return_value);
4327 	add_next_index_long(return_value, gdImageResolutionX(im));
4328 	add_next_index_long(return_value, gdImageResolutionY(im));
4329 }
4330 /* }}} */
4331 
4332 
4333 /*********************************************************
4334  *
4335  * Stream Handling
4336  * Formerly contained within ext/gd/gd_ctx.c and included
4337  * at the the top of this file
4338  *
4339  ********************************************************/
4340 
4341 #define CTX_PUTC(c,ctx) ctx->putC(ctx, c)
4342 
_php_image_output_putc(struct gdIOCtx * ctx,int c)4343 static void _php_image_output_putc(struct gdIOCtx *ctx, int c) /* {{{ */
4344 {
4345 	/* without the following downcast, the write will fail
4346 	 * (i.e., will write a zero byte) for all
4347 	 * big endian architectures:
4348 	 */
4349 	unsigned char ch = (unsigned char) c;
4350 	php_write(&ch, 1);
4351 } /* }}} */
4352 
_php_image_output_putbuf(struct gdIOCtx * ctx,const void * buf,int l)4353 static int _php_image_output_putbuf(struct gdIOCtx *ctx, const void* buf, int l) /* {{{ */
4354 {
4355 	return php_write((void *)buf, l);
4356 } /* }}} */
4357 
_php_image_output_ctxfree(struct gdIOCtx * ctx)4358 static void _php_image_output_ctxfree(struct gdIOCtx *ctx) /* {{{ */
4359 {
4360 	efree(ctx);
4361 } /* }}} */
4362 
_php_image_stream_putc(struct gdIOCtx * ctx,int c)4363 static void _php_image_stream_putc(struct gdIOCtx *ctx, int c) /* {{{ */ {
4364 	char ch = (char) c;
4365 	php_stream * stream = (php_stream *)ctx->data;
4366 	php_stream_write(stream, &ch, 1);
4367 } /* }}} */
4368 
_php_image_stream_putbuf(struct gdIOCtx * ctx,const void * buf,int l)4369 static int _php_image_stream_putbuf(struct gdIOCtx *ctx, const void* buf, int l) /* {{{ */
4370 {
4371 	php_stream * stream = (php_stream *)ctx->data;
4372 	return php_stream_write(stream, (void *)buf, l);
4373 } /* }}} */
4374 
_php_image_stream_ctxfree(struct gdIOCtx * ctx)4375 static void _php_image_stream_ctxfree(struct gdIOCtx *ctx) /* {{{ */
4376 {
4377 	if(ctx->data) {
4378 		ctx->data = NULL;
4379 	}
4380 	efree(ctx);
4381 } /* }}} */
4382 
_php_image_stream_ctxfreeandclose(struct gdIOCtx * ctx)4383 static void _php_image_stream_ctxfreeandclose(struct gdIOCtx *ctx) /* {{{ */
4384 {
4385 	if(ctx->data) {
4386 		php_stream_close((php_stream *) ctx->data);
4387 		ctx->data = NULL;
4388 	}
4389 	efree(ctx);
4390 } /* }}} */
4391 
create_stream_context(php_stream * stream,int close_stream)4392 static gdIOCtx *create_stream_context(php_stream *stream, int close_stream) {
4393 	gdIOCtx *ctx = ecalloc(1, sizeof(gdIOCtx));
4394 
4395 	ctx->putC = _php_image_stream_putc;
4396 	ctx->putBuf = _php_image_stream_putbuf;
4397 	if (close_stream) {
4398 		ctx->gd_free = _php_image_stream_ctxfreeandclose;
4399 	} else {
4400 		ctx->gd_free = _php_image_stream_ctxfree;
4401 	}
4402 	ctx->data = (void *)stream;
4403 
4404 	return ctx;
4405 }
4406 
create_output_context(zval * to_zval,uint32_t arg_num)4407 static gdIOCtx *create_output_context(zval *to_zval, uint32_t arg_num) {
4408 	gdIOCtx *ctx;
4409 
4410 	if (to_zval != NULL) {
4411 		php_stream *stream;
4412 		int close_stream = 1;
4413 
4414 		ZEND_ASSERT(arg_num > 0);
4415 
4416 		if (Z_TYPE_P(to_zval) == IS_RESOURCE) {
4417 			php_stream_from_zval_no_verify(stream, to_zval);
4418 			if (stream == NULL) {
4419 				return NULL;
4420 			}
4421 			close_stream = 0;
4422 		} else if (Z_TYPE_P(to_zval) == IS_STRING) {
4423 			if (CHECK_ZVAL_NULL_PATH(to_zval)) {
4424 				zend_argument_type_error(arg_num, "must not contain null bytes");
4425 				return NULL;
4426 			}
4427 
4428 			stream = php_stream_open_wrapper(Z_STRVAL_P(to_zval), "wb", REPORT_ERRORS|IGNORE_PATH, NULL);
4429 			if (stream == NULL) {
4430 				return NULL;
4431 			}
4432 		} else {
4433 			zend_argument_type_error(arg_num, "must be a file name or a stream resource, %s given", zend_zval_value_name(to_zval));
4434 			return NULL;
4435 		}
4436 
4437 		ctx = create_stream_context(stream, close_stream);
4438 	} else {
4439 		ctx = ecalloc(1, sizeof(gdIOCtx));
4440 
4441 		ctx->putC = _php_image_output_putc;
4442 		ctx->putBuf = _php_image_output_putbuf;
4443 		ctx->gd_free = _php_image_output_ctxfree;
4444 	}
4445 
4446 	return ctx;
4447 }
4448 
4449 /* }}} */
4450