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