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