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