php-src/ext/gd/gd.c
Arnaud Le Blanc 11accb5cdf
Preferably include from build dir (#13516)
* Include from build dir first

This fixes out of tree builds by ensuring that configure artifacts are included
from the build dir.

Before, out of tree builds would preferably include files from the src dir, as
the include path was defined as follows (ignoring includes from ext/ and sapi/) :

    -I$(top_builddir)/main
    -I$(top_srcdir)
    -I$(top_builddir)/TSRM
    -I$(top_builddir)/Zend
    -I$(top_srcdir)/main
    -I$(top_srcdir)/Zend
    -I$(top_srcdir)/TSRM
    -I$(top_builddir)/

As a result, an out of tree build would include configure artifacts such as
`main/php_config.h` from the src dir.

After this change, the include path is defined as follows:

    -I$(top_builddir)/main
    -I$(top_builddir)
    -I$(top_srcdir)/main
    -I$(top_srcdir)
    -I$(top_builddir)/TSRM
    -I$(top_builddir)/Zend
    -I$(top_srcdir)/Zend
    -I$(top_srcdir)/TSRM

* Fix extension include path for out of tree builds

* Include config.h with the brackets form

`#include "config.h"` searches in the directory containing the including-file
before any other include path. This can include the wrong config.h when building
out of tree and a config.h exists in the source tree.

Using `#include <config.h>` uses exclusively the include path, and gives
priority to the build dir.
2024-06-26 00:26:43 +02:00

4435 lines
102 KiB
C

/*
+----------------------------------------------------------------------+
| Copyright (c) The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| https://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Rasmus Lerdorf <rasmus@php.net> |
| Stig Bakken <ssb@php.net> |
| Jim Winstead <jimw@php.net> |
+----------------------------------------------------------------------+
*/
/* gd 1.2 is copyright 1994, 1995, Quest Protein Database Center,
Cold Spring Harbor Labs. */
/* Note that there is no code from the gd package in this file */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "php.h"
#include "php_ini.h"
#include "ext/standard/head.h"
#include <math.h>
#include "SAPI.h"
#include "php_gd.h"
#include "ext/standard/php_image.h"
#include "ext/standard/info.h"
#include "php_open_temporary_file.h"
#include "php_memory_streams.h"
#include "zend_object_handlers.h"
#ifdef HAVE_SYS_WAIT_H
# include <sys/wait.h>
#endif
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#ifdef PHP_WIN32
# include <io.h>
# include <fcntl.h>
# include <windows.h>
# include <Winuser.h>
# include <Wingdi.h>
#endif
#if defined(HAVE_GD_XPM) && defined(HAVE_GD_BUNDLED)
# include <X11/xpm.h>
#endif
#include "gd_compat.h"
#ifdef HAVE_GD_BUNDLED
# include "libgd/gd.h"
# include "libgd/gd_errors.h"
# include "libgd/gdfontt.h" /* 1 Tiny font */
# include "libgd/gdfonts.h" /* 2 Small font */
# include "libgd/gdfontmb.h" /* 3 Medium bold font */
# include "libgd/gdfontl.h" /* 4 Large font */
# include "libgd/gdfontg.h" /* 5 Giant font */
#else
# include <gd.h>
# include <gd_errors.h>
# include <gdfontt.h> /* 1 Tiny font */
# include <gdfonts.h> /* 2 Small font */
# include <gdfontmb.h> /* 3 Medium bold font */
# include <gdfontl.h> /* 4 Large font */
# include <gdfontg.h> /* 5 Giant font */
#endif
#if defined(HAVE_GD_FREETYPE) && defined(HAVE_GD_BUNDLED)
# include <ft2build.h>
# include FT_FREETYPE_H
#endif
#if defined(HAVE_GD_XPM) && defined(HAVE_GD_BUNDLED)
# include "X11/xpm.h"
#endif
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
/* don't used libgd constants, not used, so going to be removed */
#define PHP_GD_FLIP_HORIZONTAL 1
#define PHP_GD_FLIP_VERTICAL 2
#define PHP_GD_FLIP_BOTH 3
#ifdef HAVE_GD_FREETYPE
static void php_imagettftext_common(INTERNAL_FUNCTION_PARAMETERS, int);
#endif
#include "gd_arginfo.h"
/* as it is not really public, duplicate declaration here to avoid
pointless warnings */
int overflow2(int a, int b);
static void php_image_filter_negate(INTERNAL_FUNCTION_PARAMETERS);
static void php_image_filter_grayscale(INTERNAL_FUNCTION_PARAMETERS);
static void php_image_filter_brightness(INTERNAL_FUNCTION_PARAMETERS);
static void php_image_filter_contrast(INTERNAL_FUNCTION_PARAMETERS);
static void php_image_filter_colorize(INTERNAL_FUNCTION_PARAMETERS);
static void php_image_filter_edgedetect(INTERNAL_FUNCTION_PARAMETERS);
static void php_image_filter_emboss(INTERNAL_FUNCTION_PARAMETERS);
static void php_image_filter_gaussian_blur(INTERNAL_FUNCTION_PARAMETERS);
static void php_image_filter_selective_blur(INTERNAL_FUNCTION_PARAMETERS);
static void php_image_filter_mean_removal(INTERNAL_FUNCTION_PARAMETERS);
static void php_image_filter_smooth(INTERNAL_FUNCTION_PARAMETERS);
static void php_image_filter_pixelate(INTERNAL_FUNCTION_PARAMETERS);
static void php_image_filter_scatter(INTERNAL_FUNCTION_PARAMETERS);
/* End Section filters declarations */
static gdImagePtr _php_image_create_from_string(zend_string *Data, char *tn, gdImagePtr (*ioctx_func_p)(gdIOCtxPtr));
static void _php_image_create_from(INTERNAL_FUNCTION_PARAMETERS, int image_type, char *tn, gdImagePtr (*func_p)(FILE *), gdImagePtr (*ioctx_func_p)(gdIOCtxPtr));
static void _php_image_output(INTERNAL_FUNCTION_PARAMETERS, int image_type, char *tn);
static gdIOCtx *create_stream_context(php_stream *stream, int close_stream);
static gdIOCtx *create_output_context(zval *to_zval, uint32_t arg_num);
static int _php_image_type(zend_string *data);
/*********************************************************
*
* GD Object Representation
*
********************************************************/
zend_class_entry *gd_image_ce;
typedef struct _gd_ext_image_object {
gdImagePtr image;
zend_object std;
} php_gd_image_object;
static zend_object_handlers php_gd_image_object_handlers;
static zend_function *php_gd_image_object_get_constructor(zend_object *object)
{
zend_throw_error(NULL, "You cannot initialize a GdImage object except through helper functions");
return NULL;
}
/**
* Returns the underlying php_gd_image_object from a zend_object
*/
static zend_always_inline php_gd_image_object* php_gd_exgdimage_from_zobj_p(zend_object* obj)
{
return (php_gd_image_object *) ((char *) (obj) - XtOffsetOf(php_gd_image_object, std));
}
/**
* Converts an extension GdImage instance contained within a zval into the gdImagePtr
* for use with library APIs
*/
PHP_GD_API gdImagePtr php_gd_libgdimageptr_from_zval_p(zval* zp)
{
return php_gd_exgdimage_from_zobj_p(Z_OBJ_P(zp))->image;
}
zend_object *php_gd_image_object_create(zend_class_entry *class_type)
{
size_t block_len = sizeof(php_gd_image_object) + zend_object_properties_size(class_type);
php_gd_image_object *intern = emalloc(block_len);
memset(intern, 0, block_len);
zend_object_std_init(&intern->std, class_type);
object_properties_init(&intern->std, class_type);
return &intern->std;
}
static void php_gd_image_object_free(zend_object *intern)
{
php_gd_image_object *img_obj_ptr = php_gd_exgdimage_from_zobj_p(intern);
if (img_obj_ptr->image) {
gdImageDestroy(img_obj_ptr->image);
}
zend_object_std_dtor(intern);
}
/**
* Creates a new GdImage object wrapping the gdImagePtr and attaches it
* to the zval (usually return_value).
*
* This function must only be called once per valid gdImagePtr
*/
void php_gd_assign_libgdimageptr_as_extgdimage(zval *val, gdImagePtr image)
{
object_init_ex(val, gd_image_ce);
php_gd_exgdimage_from_zobj_p(Z_OBJ_P(val))->image = image;
}
static void php_gd_object_minit_helper(void)
{
gd_image_ce = register_class_GdImage();
gd_image_ce->create_object = php_gd_image_object_create;
gd_image_ce->default_object_handlers = &php_gd_image_object_handlers;
/* setting up the object handlers for the GdImage class */
memcpy(&php_gd_image_object_handlers, &std_object_handlers, sizeof(zend_object_handlers));
php_gd_image_object_handlers.clone_obj = NULL;
php_gd_image_object_handlers.free_obj = php_gd_image_object_free;
php_gd_image_object_handlers.get_constructor = php_gd_image_object_get_constructor;
php_gd_image_object_handlers.compare = zend_objects_not_comparable;
php_gd_image_object_handlers.offset = XtOffsetOf(php_gd_image_object, std);
}
static zend_class_entry *gd_font_ce = NULL;
static zend_object_handlers php_gd_font_object_handlers;
typedef struct _php_gd_font_object {
gdFontPtr font;
zend_object std;
} php_gd_font_object;
static php_gd_font_object *php_gd_font_object_from_zend_object(zend_object *zobj)
{
return ((php_gd_font_object*)(zobj + 1)) - 1;
}
static zend_object *php_gd_font_object_to_zend_object(php_gd_font_object *obj)
{
return ((zend_object*)(obj + 1)) - 1;
}
static zend_object *php_gd_font_object_create(zend_class_entry *ce)
{
php_gd_font_object *obj = zend_object_alloc(sizeof(php_gd_font_object), ce);
zend_object *zobj = php_gd_font_object_to_zend_object(obj);
obj->font = NULL;
zend_object_std_init(zobj, ce);
object_properties_init(zobj, ce);
zobj->handlers = &php_gd_font_object_handlers;
return zobj;
}
static void php_gd_font_object_free(zend_object *zobj)
{
php_gd_font_object *obj = php_gd_font_object_from_zend_object(zobj);
if (obj->font) {
if (obj->font->data) {
efree(obj->font->data);
}
efree(obj->font);
obj->font = NULL;
}
zend_object_std_dtor(zobj);
}
static zend_function *php_gd_font_object_get_constructor(zend_object *object)
{
zend_throw_error(NULL, "You cannot initialize a GdFont object except through helper functions");
return NULL;
}
static void php_gd_font_minit_helper(void)
{
gd_font_ce = register_class_GdFont();
gd_font_ce->create_object = php_gd_font_object_create;
/* setting up the object handlers for the GdFont class */
memcpy(&php_gd_font_object_handlers, &std_object_handlers, sizeof(zend_object_handlers));
php_gd_font_object_handlers.clone_obj = NULL;
php_gd_font_object_handlers.free_obj = php_gd_font_object_free;
php_gd_font_object_handlers.get_constructor = php_gd_font_object_get_constructor;
php_gd_font_object_handlers.offset = XtOffsetOf(php_gd_font_object, std);
}
/*********************************************************
*
* Extension Implementation
*
********************************************************/
zend_module_entry gd_module_entry = {
STANDARD_MODULE_HEADER,
"gd",
ext_functions,
PHP_MINIT(gd),
PHP_MSHUTDOWN(gd),
NULL,
PHP_RSHUTDOWN(gd),
PHP_MINFO(gd),
PHP_GD_VERSION,
STANDARD_MODULE_PROPERTIES
};
#ifdef COMPILE_DL_GD
ZEND_GET_MODULE(gd)
#endif
/* {{{ PHP_INI_BEGIN */
PHP_INI_BEGIN()
PHP_INI_ENTRY_EX("gd.jpeg_ignore_warning", "1", PHP_INI_ALL, NULL, zend_ini_boolean_displayer_cb)
PHP_INI_END()
/* }}} */
/* {{{ php_gd_error_method */
void php_gd_error_method(int type, const char *format, va_list args)
{
switch (type) {
#ifndef PHP_WIN32
case GD_DEBUG:
case GD_INFO:
#endif
case GD_NOTICE:
type = E_NOTICE;
break;
case GD_WARNING:
type = E_WARNING;
break;
default:
type = E_ERROR;
}
php_verror(NULL, "", type, format, args);
}
/* }}} */
/* {{{ PHP_MINIT_FUNCTION */
PHP_MINIT_FUNCTION(gd)
{
php_gd_object_minit_helper();
php_gd_font_minit_helper();
#if defined(HAVE_GD_FREETYPE) && defined(HAVE_GD_BUNDLED)
gdFontCacheMutexSetup();
#endif
gdSetErrorMethod(php_gd_error_method);
REGISTER_INI_ENTRIES();
register_gd_symbols(module_number);
return SUCCESS;
}
/* }}} */
/* {{{ PHP_MSHUTDOWN_FUNCTION */
PHP_MSHUTDOWN_FUNCTION(gd)
{
#if defined(HAVE_GD_FREETYPE) && defined(HAVE_GD_BUNDLED)
gdFontCacheMutexShutdown();
#endif
UNREGISTER_INI_ENTRIES();
return SUCCESS;
}
/* }}} */
/* {{{ PHP_RSHUTDOWN_FUNCTION */
PHP_RSHUTDOWN_FUNCTION(gd)
{
#ifdef HAVE_GD_FREETYPE
gdFontCacheShutdown();
#endif
return SUCCESS;
}
/* }}} */
#ifdef HAVE_GD_BUNDLED
#define PHP_GD_VERSION_STRING "bundled (2.1.0 compatible)"
#else
# define PHP_GD_VERSION_STRING GD_VERSION_STRING
#endif
/* {{{ PHP_MINFO_FUNCTION */
PHP_MINFO_FUNCTION(gd)
{
php_info_print_table_start();
php_info_print_table_row(2, "GD Support", "enabled");
/* need to use a PHPAPI function here because it is external module in windows */
#ifdef HAVE_GD_BUNDLED
php_info_print_table_row(2, "GD Version", PHP_GD_VERSION_STRING);
#else
php_info_print_table_row(2, "GD headers Version", PHP_GD_VERSION_STRING);
#ifdef HAVE_GD_LIBVERSION
php_info_print_table_row(2, "GD library Version", gdVersionString());
#endif
#endif
#ifdef HAVE_GD_FREETYPE
php_info_print_table_row(2, "FreeType Support", "enabled");
php_info_print_table_row(2, "FreeType Linkage", "with freetype");
#ifdef HAVE_GD_BUNDLED
{
char tmp[256];
#ifdef FREETYPE_PATCH
snprintf(tmp, sizeof(tmp), "%d.%d.%d", FREETYPE_MAJOR, FREETYPE_MINOR, FREETYPE_PATCH);
#elif defined(FREETYPE_MAJOR)
snprintf(tmp, sizeof(tmp), "%d.%d", FREETYPE_MAJOR, FREETYPE_MINOR);
#else
snprintf(tmp, sizeof(tmp), "1.x");
#endif
php_info_print_table_row(2, "FreeType Version", tmp);
}
#endif
#endif
php_info_print_table_row(2, "GIF Read Support", "enabled");
php_info_print_table_row(2, "GIF Create Support", "enabled");
#ifdef HAVE_GD_JPG
{
php_info_print_table_row(2, "JPEG Support", "enabled");
#ifdef HAVE_GD_BUNDLED
php_info_print_table_row(2, "libJPEG Version", gdJpegGetVersionString());
#endif
}
#endif
#ifdef HAVE_GD_PNG
php_info_print_table_row(2, "PNG Support", "enabled");
#ifdef HAVE_GD_BUNDLED
php_info_print_table_row(2, "libPNG Version", gdPngGetVersionString());
#endif
#endif
php_info_print_table_row(2, "WBMP Support", "enabled");
#ifdef HAVE_GD_XPM
php_info_print_table_row(2, "XPM Support", "enabled");
#ifdef HAVE_GD_BUNDLED
{
char tmp[12];
snprintf(tmp, sizeof(tmp), "%d", XpmLibraryVersion());
php_info_print_table_row(2, "libXpm Version", tmp);
}
#endif
#endif
php_info_print_table_row(2, "XBM Support", "enabled");
#ifdef USE_GD_JISX0208
php_info_print_table_row(2, "JIS-mapped Japanese Font Support", "enabled");
#endif
#ifdef HAVE_GD_WEBP
php_info_print_table_row(2, "WebP Support", "enabled");
#endif
#ifdef HAVE_GD_BMP
php_info_print_table_row(2, "BMP Support", "enabled");
#endif
#ifdef HAVE_GD_AVIF
php_info_print_table_row(2, "AVIF Support", "enabled");
#endif
#ifdef HAVE_GD_TGA
php_info_print_table_row(2, "TGA Read Support", "enabled");
#endif
php_info_print_table_end();
DISPLAY_INI_ENTRIES();
}
/* }}} */
/* {{{ */
PHP_FUNCTION(gd_info)
{
ZEND_PARSE_PARAMETERS_NONE();
array_init(return_value);
add_assoc_string(return_value, "GD Version", PHP_GD_VERSION_STRING);
#ifdef HAVE_GD_FREETYPE
add_assoc_bool(return_value, "FreeType Support", 1);
add_assoc_string(return_value, "FreeType Linkage", "with freetype");
#else
add_assoc_bool(return_value, "FreeType Support", 0);
#endif
add_assoc_bool(return_value, "GIF Read Support", 1);
add_assoc_bool(return_value, "GIF Create Support", 1);
#ifdef HAVE_GD_JPG
add_assoc_bool(return_value, "JPEG Support", 1);
#else
add_assoc_bool(return_value, "JPEG Support", 0);
#endif
#ifdef HAVE_GD_PNG
add_assoc_bool(return_value, "PNG Support", 1);
#else
add_assoc_bool(return_value, "PNG Support", 0);
#endif
add_assoc_bool(return_value, "WBMP Support", 1);
#ifdef HAVE_GD_XPM
add_assoc_bool(return_value, "XPM Support", 1);
#else
add_assoc_bool(return_value, "XPM Support", 0);
#endif
add_assoc_bool(return_value, "XBM Support", 1);
#ifdef HAVE_GD_WEBP
add_assoc_bool(return_value, "WebP Support", 1);
#else
add_assoc_bool(return_value, "WebP Support", 0);
#endif
#ifdef HAVE_GD_BMP
add_assoc_bool(return_value, "BMP Support", 1);
#else
add_assoc_bool(return_value, "BMP Support", 0);
#endif
#ifdef HAVE_GD_AVIF
add_assoc_bool(return_value, "AVIF Support", 1);
#else
add_assoc_bool(return_value, "AVIF Support", 0);
#endif
#ifdef HAVE_GD_TGA
add_assoc_bool(return_value, "TGA Read Support", 1);
#else
add_assoc_bool(return_value, "TGA Read Support", 0);
#endif
#ifdef USE_GD_JISX0208
add_assoc_bool(return_value, "JIS-mapped Japanese Font Support", 1);
#else
add_assoc_bool(return_value, "JIS-mapped Japanese Font Support", 0);
#endif
}
/* }}} */
#define FLIPWORD(a) (((a & 0xff000000) >> 24) | ((a & 0x00ff0000) >> 8) | ((a & 0x0000ff00) << 8) | ((a & 0x000000ff) << 24))
/* {{{ Load a new font */
PHP_FUNCTION(imageloadfont)
{
zend_string *file;
int hdr_size = sizeof(gdFont) - sizeof(char *);
int body_size, n = 0, b, i, body_size_check;
gdFontPtr font;
php_stream *stream;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_PATH_STR(file)
ZEND_PARSE_PARAMETERS_END();
stream = php_stream_open_wrapper(ZSTR_VAL(file), "rb", IGNORE_PATH | REPORT_ERRORS, NULL);
if (stream == NULL) {
RETURN_FALSE;
}
/* Only supports a architecture-dependent binary dump format
* at the moment.
* The file format is like this on machines with 32-byte integers:
*
* byte 0-3: (int) number of characters in the font
* byte 4-7: (int) value of first character in the font (often 32, space)
* byte 8-11: (int) pixel width of each character
* byte 12-15: (int) pixel height of each character
* bytes 16-: (char) array with character data, one byte per pixel
* in each character, for a total of
* (nchars*width*height) bytes.
*/
font = (gdFontPtr) emalloc(sizeof(gdFont));
b = 0;
while (b < hdr_size && (n = php_stream_read(stream, (char*)&font[b], hdr_size - b)) > 0) {
b += n;
}
if (n <= 0) {
efree(font);
if (php_stream_eof(stream)) {
php_error_docref(NULL, E_WARNING, "End of file while reading header");
} else {
php_error_docref(NULL, E_WARNING, "Error while reading header");
}
php_stream_close(stream);
RETURN_FALSE;
}
i = php_stream_tell(stream);
php_stream_seek(stream, 0, SEEK_END);
body_size_check = php_stream_tell(stream) - hdr_size;
php_stream_seek(stream, i, SEEK_SET);
if (overflow2(font->nchars, font->h) || overflow2(font->nchars * font->h, font->w )) {
php_error_docref(NULL, E_WARNING, "Error reading font, invalid font header");
efree(font);
php_stream_close(stream);
RETURN_FALSE;
}
body_size = font->w * font->h * font->nchars;
if (body_size != body_size_check) {
font->w = FLIPWORD(font->w);
font->h = FLIPWORD(font->h);
font->nchars = FLIPWORD(font->nchars);
if (overflow2(font->nchars, font->h) || overflow2(font->nchars * font->h, font->w )) {
php_error_docref(NULL, E_WARNING, "Error reading font, invalid font header");
efree(font);
php_stream_close(stream);
RETURN_FALSE;
}
body_size = font->w * font->h * font->nchars;
}
if (body_size != body_size_check) {
php_error_docref(NULL, E_WARNING, "Error reading font");
efree(font);
php_stream_close(stream);
RETURN_FALSE;
}
ZEND_ASSERT(body_size > 0);
font->data = emalloc(body_size);
b = 0;
while (b < body_size && (n = php_stream_read(stream, &font->data[b], body_size - b)) > 0) {
b += n;
}
if (n <= 0) {
efree(font->data);
efree(font);
if (php_stream_eof(stream)) {
php_error_docref(NULL, E_WARNING, "End of file while reading body");
} else {
php_error_docref(NULL, E_WARNING, "Error while reading body");
}
php_stream_close(stream);
RETURN_FALSE;
}
php_stream_close(stream);
object_init_ex(return_value, gd_font_ce);
php_gd_font_object_from_zend_object(Z_OBJ_P(return_value))->font = font;
}
/* }}} */
/* {{{ Set the line drawing styles for use with imageline and IMG_COLOR_STYLED. */
PHP_FUNCTION(imagesetstyle)
{
zval *IM, *styles, *item;
gdImagePtr im;
int *stylearr;
int index = 0;
uint32_t num_styles;
ZEND_PARSE_PARAMETERS_START(2, 2)
Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
Z_PARAM_ARRAY(styles)
ZEND_PARSE_PARAMETERS_END();
im = php_gd_libgdimageptr_from_zval_p(IM);
num_styles = zend_hash_num_elements(Z_ARRVAL_P(styles));
if (num_styles == 0) {
zend_argument_value_error(2, "cannot be empty");
RETURN_THROWS();
}
/* copy the style values in the stylearr */
stylearr = safe_emalloc(sizeof(int), num_styles, 0);
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(styles), item) {
stylearr[index++] = zval_get_long(item);
} ZEND_HASH_FOREACH_END();
gdImageSetStyle(im, stylearr, index);
efree(stylearr);
RETURN_TRUE;
}
/* }}} */
/* {{{ Create a new true color image */
PHP_FUNCTION(imagecreatetruecolor)
{
zend_long x_size, y_size;
gdImagePtr im;
ZEND_PARSE_PARAMETERS_START(2, 2)
Z_PARAM_LONG(x_size)
Z_PARAM_LONG(y_size)
ZEND_PARSE_PARAMETERS_END();
if (x_size <= 0 || x_size >= INT_MAX) {
zend_argument_value_error(1, "must be greater than 0");
RETURN_THROWS();
}
if (y_size <= 0 || y_size >= INT_MAX) {
zend_argument_value_error(2, "must be greater than 0");
RETURN_THROWS();
}
im = gdImageCreateTrueColor(x_size, y_size);
if (!im) {
RETURN_FALSE;
}
php_gd_assign_libgdimageptr_as_extgdimage(return_value, im);
}
/* }}} */
/* {{{ return true if the image uses truecolor */
PHP_FUNCTION(imageistruecolor)
{
zval *IM;
gdImagePtr im;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
ZEND_PARSE_PARAMETERS_END();
im = php_gd_libgdimageptr_from_zval_p(IM);
RETURN_BOOL(im->trueColor);
}
/* }}} */
/* {{{ Convert a true color image to a palette based image with a number of colors, optionally using dithering. */
PHP_FUNCTION(imagetruecolortopalette)
{
zval *IM;
bool dither;
zend_long ncolors;
gdImagePtr im;
ZEND_PARSE_PARAMETERS_START(3, 3)
Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
Z_PARAM_BOOL(dither)
Z_PARAM_LONG(ncolors)
ZEND_PARSE_PARAMETERS_END();
im = php_gd_libgdimageptr_from_zval_p(IM);
if (ncolors <= 0 || ZEND_LONG_INT_OVFL(ncolors)) {
zend_argument_value_error(3, "must be greater than 0 and less than %d", INT_MAX);
RETURN_THROWS();
}
if (gdImageTrueColorToPalette(im, dither, (int)ncolors)) {
RETURN_TRUE;
} else {
php_error_docref(NULL, E_WARNING, "Couldn't convert to palette");
RETURN_FALSE;
}
}
/* }}} */
/* {{{ Convert a palette based image to a true color image. */
PHP_FUNCTION(imagepalettetotruecolor)
{
zval *IM;
gdImagePtr im;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
ZEND_PARSE_PARAMETERS_END();
im = php_gd_libgdimageptr_from_zval_p(IM);
if (gdImagePaletteToTrueColor(im) == 0) {
RETURN_FALSE;
}
RETURN_TRUE;
}
/* }}} */
/* {{{ Makes the colors of the palette version of an image more closely match the true color version */
PHP_FUNCTION(imagecolormatch)
{
zval *IM1, *IM2;
gdImagePtr im1, im2;
int result;
ZEND_PARSE_PARAMETERS_START(2, 2)
Z_PARAM_OBJECT_OF_CLASS(IM1, gd_image_ce)
Z_PARAM_OBJECT_OF_CLASS(IM2, gd_image_ce)
ZEND_PARSE_PARAMETERS_END();
im1 = php_gd_libgdimageptr_from_zval_p(IM1);
im2 = php_gd_libgdimageptr_from_zval_p(IM2);
result = gdImageColorMatch(im1, im2);
switch (result) {
case -1:
zend_argument_value_error(1, "must be TrueColor");
RETURN_THROWS();
break;
case -2:
zend_argument_value_error(2, "must be Palette");
RETURN_THROWS();
break;
case -3:
zend_argument_value_error(2, "must be the same size as argument #1 ($im1)");
RETURN_THROWS();
break;
case -4:
zend_argument_value_error(2, "must have at least one color");
RETURN_THROWS();
break;
}
RETURN_TRUE;
}
/* }}} */
/* {{{ Set line thickness for drawing lines, ellipses, rectangles, polygons etc. */
PHP_FUNCTION(imagesetthickness)
{
zval *IM;
zend_long thick;
gdImagePtr im;
ZEND_PARSE_PARAMETERS_START(2, 2)
Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
Z_PARAM_LONG(thick)
ZEND_PARSE_PARAMETERS_END();
im = php_gd_libgdimageptr_from_zval_p(IM);
gdImageSetThickness(im, thick);
RETURN_TRUE;
}
/* }}} */
/* {{{ Draw an ellipse */
PHP_FUNCTION(imagefilledellipse)
{
zval *IM;
zend_long cx, cy, w, h, color;
gdImagePtr im;
ZEND_PARSE_PARAMETERS_START(6, 6)
Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
Z_PARAM_LONG(cx)
Z_PARAM_LONG(cy)
Z_PARAM_LONG(w)
Z_PARAM_LONG(h)
Z_PARAM_LONG(color)
ZEND_PARSE_PARAMETERS_END();
im = php_gd_libgdimageptr_from_zval_p(IM);
gdImageFilledEllipse(im, cx, cy, w, h, color);
RETURN_TRUE;
}
/* }}} */
/* {{{ Draw a filled partial ellipse */
PHP_FUNCTION(imagefilledarc)
{
zval *IM;
zend_long cx, cy, w, h, ST, E, col, style;
gdImagePtr im;
int e, st;
ZEND_PARSE_PARAMETERS_START(9, 9)
Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
Z_PARAM_LONG(cx)
Z_PARAM_LONG(cy)
Z_PARAM_LONG(w)
Z_PARAM_LONG(h)
Z_PARAM_LONG(ST)
Z_PARAM_LONG(E)
Z_PARAM_LONG(col)
Z_PARAM_LONG(style)
ZEND_PARSE_PARAMETERS_END();
im = php_gd_libgdimageptr_from_zval_p(IM);
e = E;
if (e < 0) {
e %= 360;
}
st = ST;
if (st < 0) {
st %= 360;
}
gdImageFilledArc(im, cx, cy, w, h, st, e, col, style);
RETURN_TRUE;
}
/* }}} */
/* {{{ Turn alpha blending mode on or off for the given image */
PHP_FUNCTION(imagealphablending)
{
zval *IM;
bool blend;
gdImagePtr im;
ZEND_PARSE_PARAMETERS_START(2, 2)
Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
Z_PARAM_BOOL(blend)
ZEND_PARSE_PARAMETERS_END();
im = php_gd_libgdimageptr_from_zval_p(IM);
gdImageAlphaBlending(im, blend);
RETURN_TRUE;
}
/* }}} */
/* {{{ Include alpha channel to a saved image */
PHP_FUNCTION(imagesavealpha)
{
zval *IM;
bool save;
gdImagePtr im;
ZEND_PARSE_PARAMETERS_START(2, 2)
Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
Z_PARAM_BOOL(save)
ZEND_PARSE_PARAMETERS_END();
im = php_gd_libgdimageptr_from_zval_p(IM);
gdImageSaveAlpha(im, save);
RETURN_TRUE;
}
/* }}} */
/* {{{ Set the alpha blending flag to use the bundled libgd layering effects */
PHP_FUNCTION(imagelayereffect)
{
zval *IM;
zend_long effect;
gdImagePtr im;
ZEND_PARSE_PARAMETERS_START(2, 2)
Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
Z_PARAM_LONG(effect)
ZEND_PARSE_PARAMETERS_END();
im = php_gd_libgdimageptr_from_zval_p(IM);
gdImageAlphaBlending(im, effect);
RETURN_TRUE;
}
/* }}} */
#define CHECK_RGBA_RANGE(component, name, argument_number) \
if (component < 0 || component > gd##name##Max) { \
zend_argument_value_error(argument_number, "must be between 0 and %d (inclusive)", gd##name##Max); \
RETURN_THROWS(); \
}
/* {{{ Allocate a color with an alpha level. Works for true color and palette based images */
PHP_FUNCTION(imagecolorallocatealpha)
{
zval *IM;
zend_long red, green, blue, alpha;
gdImagePtr im;
int ct = (-1);
ZEND_PARSE_PARAMETERS_START(5, 5)
Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
Z_PARAM_LONG(red)
Z_PARAM_LONG(green)
Z_PARAM_LONG(blue)
Z_PARAM_LONG(alpha)
ZEND_PARSE_PARAMETERS_END();
im = php_gd_libgdimageptr_from_zval_p(IM);
CHECK_RGBA_RANGE(red, Red, 2);
CHECK_RGBA_RANGE(green, Green, 3);
CHECK_RGBA_RANGE(blue, Blue, 4);
CHECK_RGBA_RANGE(alpha, Alpha, 5);
ct = gdImageColorAllocateAlpha(im, red, green, blue, alpha);
if (ct < 0) {
RETURN_FALSE;
}
RETURN_LONG((zend_long)ct);
}
/* }}} */
/* {{{ Resolve/Allocate a colour with an alpha level. Works for true colour and palette based images */
PHP_FUNCTION(imagecolorresolvealpha)
{
zval *IM;
zend_long red, green, blue, alpha;
gdImagePtr im;
ZEND_PARSE_PARAMETERS_START(5, 5)
Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
Z_PARAM_LONG(red)
Z_PARAM_LONG(green)
Z_PARAM_LONG(blue)
Z_PARAM_LONG(alpha)
ZEND_PARSE_PARAMETERS_END();
im = php_gd_libgdimageptr_from_zval_p(IM);
CHECK_RGBA_RANGE(red, Red, 2);
CHECK_RGBA_RANGE(green, Green, 3);
CHECK_RGBA_RANGE(blue, Blue, 4);
CHECK_RGBA_RANGE(alpha, Alpha, 5);
RETURN_LONG(gdImageColorResolveAlpha(im, red, green, blue, alpha));
}
/* }}} */
/* {{{ Find the closest matching colour with alpha transparency */
PHP_FUNCTION(imagecolorclosestalpha)
{
zval *IM;
zend_long red, green, blue, alpha;
gdImagePtr im;
ZEND_PARSE_PARAMETERS_START(5, 5)
Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
Z_PARAM_LONG(red)
Z_PARAM_LONG(green)
Z_PARAM_LONG(blue)
Z_PARAM_LONG(alpha)
ZEND_PARSE_PARAMETERS_END();
im = php_gd_libgdimageptr_from_zval_p(IM);
CHECK_RGBA_RANGE(red, Red, 2);
CHECK_RGBA_RANGE(green, Green, 3);
CHECK_RGBA_RANGE(blue, Blue, 4);
CHECK_RGBA_RANGE(alpha, Alpha, 5);
RETURN_LONG(gdImageColorClosestAlpha(im, red, green, blue, alpha));
}
/* }}} */
/* {{{ Find exact match for colour with transparency */
PHP_FUNCTION(imagecolorexactalpha)
{
zval *IM;
zend_long red, green, blue, alpha;
gdImagePtr im;
ZEND_PARSE_PARAMETERS_START(5, 5)
Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
Z_PARAM_LONG(red)
Z_PARAM_LONG(green)
Z_PARAM_LONG(blue)
Z_PARAM_LONG(alpha)
ZEND_PARSE_PARAMETERS_END();
im = php_gd_libgdimageptr_from_zval_p(IM);
CHECK_RGBA_RANGE(red, Red, 2);
CHECK_RGBA_RANGE(green, Green, 3);
CHECK_RGBA_RANGE(blue, Blue, 4);
CHECK_RGBA_RANGE(alpha, Alpha, 5);
RETURN_LONG(gdImageColorExactAlpha(im, red, green, blue, alpha));
}
/* }}} */
/* {{{ Copy and resize part of an image using resampling to help ensure clarity */
PHP_FUNCTION(imagecopyresampled)
{
zval *SIM, *DIM;
zend_long SX, SY, SW, SH, DX, DY, DW, DH;
gdImagePtr im_dst, im_src;
int srcH, srcW, dstH, dstW, srcY, srcX, dstY, dstX;
ZEND_PARSE_PARAMETERS_START(10, 10)
Z_PARAM_OBJECT_OF_CLASS(DIM, gd_image_ce)
Z_PARAM_OBJECT_OF_CLASS(SIM, gd_image_ce)
Z_PARAM_LONG(DX)
Z_PARAM_LONG(DY)
Z_PARAM_LONG(SX)
Z_PARAM_LONG(SY)
Z_PARAM_LONG(DW)
Z_PARAM_LONG(DH)
Z_PARAM_LONG(SW)
Z_PARAM_LONG(SH)
ZEND_PARSE_PARAMETERS_END();
im_src = php_gd_libgdimageptr_from_zval_p(SIM);
im_dst = php_gd_libgdimageptr_from_zval_p(DIM);
srcX = SX;
srcY = SY;
srcH = SH;
srcW = SW;
dstX = DX;
dstY = DY;
dstH = DH;
dstW = DW;
gdImageCopyResampled(im_dst, im_src, dstX, dstY, srcX, srcY, dstW, dstH, srcW, srcH);
RETURN_TRUE;
}
/* }}} */
#ifdef PHP_WIN32
/* {{{ Grab a window or its client area using a windows handle (HWND property in COM instance) */
PHP_FUNCTION(imagegrabwindow)
{
HWND window;
bool client_area = false;
RECT rc = {0};
int Width, Height;
HDC hdc;
HDC memDC;
HBITMAP memBM;
HBITMAP hOld;
zend_long lwindow_handle;
gdImagePtr im = NULL;
ZEND_PARSE_PARAMETERS_START(1, 2)
Z_PARAM_LONG(lwindow_handle)
Z_PARAM_OPTIONAL
Z_PARAM_BOOL(client_area)
ZEND_PARSE_PARAMETERS_END();
window = (HWND) lwindow_handle;
if (!IsWindow(window)) {
php_error_docref(NULL, E_NOTICE, "Invalid window handle");
RETURN_FALSE;
}
hdc = GetDC(0);
if (client_area) {
GetClientRect(window, &rc);
Width = rc.right;
Height = rc.bottom;
} else {
GetWindowRect(window, &rc);
Width = rc.right - rc.left;
Height = rc.bottom - rc.top;
}
Width = (Width/4)*4;
memDC = CreateCompatibleDC(hdc);
memBM = CreateCompatibleBitmap(hdc, Width, Height);
hOld = (HBITMAP) SelectObject (memDC, memBM);
PrintWindow(window, memDC, (UINT) client_area);
im = gdImageCreateTrueColor(Width, Height);
if (im) {
int x,y;
for (y=0; y <= Height; y++) {
for (x=0; x <= Width; x++) {
int c = GetPixel(memDC, x,y);
gdImageSetPixel(im, x, y, gdTrueColor(GetRValue(c), GetGValue(c), GetBValue(c)));
}
}
}
SelectObject(memDC,hOld);
DeleteObject(memBM);
DeleteDC(memDC);
ReleaseDC( 0, hdc );
if (!im) {
RETURN_FALSE;
}
php_gd_assign_libgdimageptr_as_extgdimage(return_value, im);
}
/* }}} */
/* {{{ Grab a screenshot */
PHP_FUNCTION(imagegrabscreen)
{
HWND window = GetDesktopWindow();
RECT rc = {0};
int Width, Height;
HDC hdc;
HDC memDC;
HBITMAP memBM;
HBITMAP hOld;
gdImagePtr im;
hdc = GetDC(0);
ZEND_PARSE_PARAMETERS_NONE();
if (!hdc) {
RETURN_FALSE;
}
GetWindowRect(window, &rc);
Width = rc.right - rc.left;
Height = rc.bottom - rc.top;
Width = (Width/4)*4;
memDC = CreateCompatibleDC(hdc);
memBM = CreateCompatibleBitmap(hdc, Width, Height);
hOld = (HBITMAP) SelectObject (memDC, memBM);
BitBlt( memDC, 0, 0, Width, Height , hdc, rc.left, rc.top , SRCCOPY );
im = gdImageCreateTrueColor(Width, Height);
if (im) {
int x,y;
for (y=0; y <= Height; y++) {
for (x=0; x <= Width; x++) {
int c = GetPixel(memDC, x,y);
gdImageSetPixel(im, x, y, gdTrueColor(GetRValue(c), GetGValue(c), GetBValue(c)));
}
}
}
SelectObject(memDC,hOld);
DeleteObject(memBM);
DeleteDC(memDC);
ReleaseDC( 0, hdc );
if (!im) {
RETURN_FALSE;
}
php_gd_assign_libgdimageptr_as_extgdimage(return_value, im);
}
/* }}} */
#endif /* PHP_WIN32 */
/* {{{ Rotate an image using a custom angle */
PHP_FUNCTION(imagerotate)
{
zval *SIM;
gdImagePtr im_dst, im_src;
double degrees;
zend_long color;
ZEND_PARSE_PARAMETERS_START(3, 3)
Z_PARAM_OBJECT_OF_CLASS(SIM, gd_image_ce)
Z_PARAM_DOUBLE(degrees)
Z_PARAM_LONG(color)
ZEND_PARSE_PARAMETERS_END();
im_src = php_gd_libgdimageptr_from_zval_p(SIM);
im_dst = gdImageRotateInterpolated(im_src, (const float)degrees, color);
if (im_dst == NULL) {
RETURN_FALSE;
}
php_gd_assign_libgdimageptr_as_extgdimage(return_value, im_dst);
}
/* }}} */
/* {{{ Set the tile image to $tile when filling $image with the "IMG_COLOR_TILED" color */
PHP_FUNCTION(imagesettile)
{
zval *IM, *TILE;
gdImagePtr im, tile;
ZEND_PARSE_PARAMETERS_START(2, 2)
Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
Z_PARAM_OBJECT_OF_CLASS(TILE, gd_image_ce)
ZEND_PARSE_PARAMETERS_END();
im = php_gd_libgdimageptr_from_zval_p(IM);
tile = php_gd_libgdimageptr_from_zval_p(TILE);
gdImageSetTile(im, tile);
RETURN_TRUE;
}
/* }}} */
/* {{{ Set the brush image to $brush when filling $image with the "IMG_COLOR_BRUSHED" color */
PHP_FUNCTION(imagesetbrush)
{
zval *IM, *TILE;
gdImagePtr im, tile;
ZEND_PARSE_PARAMETERS_START(2, 2)
Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
Z_PARAM_OBJECT_OF_CLASS(TILE, gd_image_ce)
ZEND_PARSE_PARAMETERS_END();
im = php_gd_libgdimageptr_from_zval_p(IM);
tile = php_gd_libgdimageptr_from_zval_p(TILE);
gdImageSetBrush(im, tile);
RETURN_TRUE;
}
/* }}} */
/* {{{ Create a new image */
PHP_FUNCTION(imagecreate)
{
zend_long x_size, y_size;
gdImagePtr im;
ZEND_PARSE_PARAMETERS_START(2, 2)
Z_PARAM_LONG(x_size)
Z_PARAM_LONG(y_size)
ZEND_PARSE_PARAMETERS_END();
if (x_size <= 0 || x_size >= INT_MAX) {
zend_argument_value_error(1, "must be greater than 0");
RETURN_THROWS();
}
if (y_size <= 0 || y_size >= INT_MAX) {
zend_argument_value_error(2, "must be greater than 0");
RETURN_THROWS();
}
im = gdImageCreate(x_size, y_size);
if (!im) {
RETURN_FALSE;
}
php_gd_assign_libgdimageptr_as_extgdimage(return_value, im);
}
/* }}} */
/* {{{ Return the types of images supported in a bitfield - 1=GIF, 2=JPEG, 4=PNG, 8=WBMP, 16=XPM, etc */
PHP_FUNCTION(imagetypes)
{
int ret = 0;
ret = PHP_IMG_GIF;
#ifdef HAVE_GD_JPG
ret |= PHP_IMG_JPG;
#endif
#ifdef HAVE_GD_PNG
ret |= PHP_IMG_PNG;
#endif
ret |= PHP_IMG_WBMP;
#ifdef HAVE_GD_XPM
ret |= PHP_IMG_XPM;
#endif
#ifdef HAVE_GD_WEBP
ret |= PHP_IMG_WEBP;
#endif
#ifdef HAVE_GD_BMP
ret |= PHP_IMG_BMP;
#endif
#ifdef HAVE_GD_TGA
ret |= PHP_IMG_TGA;
#endif
#ifdef HAVE_GD_AVIF
ret |= PHP_IMG_AVIF;
#endif
ZEND_PARSE_PARAMETERS_NONE();
RETURN_LONG(ret);
}
/* }}} */
/* {{{ _php_ctx_getmbi */
static int _php_ctx_getmbi(gdIOCtx *ctx)
{
int i, mbi = 0;
do {
i = (ctx->getC)(ctx);
if (i < 0) {
return -1;
}
mbi = (mbi << 7) | (i & 0x7f);
} while (i & 0x80);
return mbi;
}
/* }}} */
/* {{{ _php_image_type
* Based on ext/standard/image.c
*/
static const char php_sig_gd2[3] = {'g', 'd', '2'};
static int _php_image_type(zend_string *data)
{
if (ZSTR_LEN(data) < 12) {
/* Handle this the same way as an unknown image type. */
return -1;
}
if (!memcmp(ZSTR_VAL(data), php_sig_gd2, sizeof(php_sig_gd2))) {
return PHP_GDIMG_TYPE_GD2;
} else if (!memcmp(ZSTR_VAL(data), php_sig_jpg, sizeof(php_sig_jpg))) {
return PHP_GDIMG_TYPE_JPG;
} else if (!memcmp(ZSTR_VAL(data), php_sig_png, sizeof(php_sig_png))) {
return PHP_GDIMG_TYPE_PNG;
} else if (!memcmp(ZSTR_VAL(data), php_sig_gif, sizeof(php_sig_gif))) {
return PHP_GDIMG_TYPE_GIF;
} else if (!memcmp(ZSTR_VAL(data), php_sig_bmp, sizeof(php_sig_bmp))) {
return PHP_GDIMG_TYPE_BMP;
} 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))) {
return PHP_GDIMG_TYPE_WEBP;
}
php_stream *image_stream = php_stream_memory_open(TEMP_STREAM_READONLY, data);
if (image_stream != NULL) {
bool is_avif = php_is_image_avif(image_stream);
php_stream_close(image_stream);
if (is_avif) {
return PHP_GDIMG_TYPE_AVIF;
}
}
gdIOCtx *io_ctx;
io_ctx = gdNewDynamicCtxEx(8, ZSTR_VAL(data), 0);
if (io_ctx) {
if (_php_ctx_getmbi(io_ctx) == 0 && _php_ctx_getmbi(io_ctx) >= 0) {
io_ctx->gd_free(io_ctx);
return PHP_GDIMG_TYPE_WBM;
} else {
io_ctx->gd_free(io_ctx);
}
}
return -1;
}
/* }}} */
/* {{{ _php_image_create_from_string */
gdImagePtr _php_image_create_from_string(zend_string *data, char *tn, gdImagePtr (*ioctx_func_p)(gdIOCtxPtr))
{
gdImagePtr im;
gdIOCtx *io_ctx;
io_ctx = gdNewDynamicCtxEx(ZSTR_LEN(data), ZSTR_VAL(data), 0);
if (!io_ctx) {
return NULL;
}
im = (*ioctx_func_p)(io_ctx);
if (!im) {
php_error_docref(NULL, E_WARNING, "Passed data is not in \"%s\" format", tn);
io_ctx->gd_free(io_ctx);
return NULL;
}
io_ctx->gd_free(io_ctx);
return im;
}
/* }}} */
/* {{{ Create a new image from the image stream in the string */
PHP_FUNCTION(imagecreatefromstring)
{
zend_string *data;
gdImagePtr im;
int imtype;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_STR(data)
ZEND_PARSE_PARAMETERS_END();
imtype = _php_image_type(data);
switch (imtype) {
case PHP_GDIMG_TYPE_JPG:
#ifdef HAVE_GD_JPG
im = _php_image_create_from_string(data, "JPEG", gdImageCreateFromJpegCtx);
#else
php_error_docref(NULL, E_WARNING, "No JPEG support in this PHP build");
RETURN_FALSE;
#endif
break;
case PHP_GDIMG_TYPE_PNG:
#ifdef HAVE_GD_PNG
im = _php_image_create_from_string(data, "PNG", gdImageCreateFromPngCtx);
#else
php_error_docref(NULL, E_WARNING, "No PNG support in this PHP build");
RETURN_FALSE;
#endif
break;
case PHP_GDIMG_TYPE_GIF:
im = _php_image_create_from_string(data, "GIF", gdImageCreateFromGifCtx);
break;
case PHP_GDIMG_TYPE_WBM:
im = _php_image_create_from_string(data, "WBMP", gdImageCreateFromWBMPCtx);
break;
case PHP_GDIMG_TYPE_GD2:
im = _php_image_create_from_string(data, "GD2", gdImageCreateFromGd2Ctx);
break;
case PHP_GDIMG_TYPE_BMP:
im = _php_image_create_from_string(data, "BMP", gdImageCreateFromBmpCtx);
break;
case PHP_GDIMG_TYPE_WEBP:
#ifdef HAVE_GD_WEBP
im = _php_image_create_from_string(data, "WEBP", gdImageCreateFromWebpCtx);
break;
#else
php_error_docref(NULL, E_WARNING, "No WEBP support in this PHP build");
RETURN_FALSE;
#endif
case PHP_GDIMG_TYPE_AVIF:
#ifdef HAVE_GD_AVIF
im = _php_image_create_from_string(data, "AVIF", gdImageCreateFromAvifCtx);
break;
#else
php_error_docref(NULL, E_WARNING, "No AVIF support in this PHP build");
RETURN_FALSE;
#endif
default:
php_error_docref(NULL, E_WARNING, "Data is not in a recognized format");
RETURN_FALSE;
}
if (!im) {
php_error_docref(NULL, E_WARNING, "Couldn't create GD Image Stream out of Data");
RETURN_FALSE;
}
php_gd_assign_libgdimageptr_as_extgdimage(return_value, im);
}
/* }}} */
/* {{{ _php_image_create_from */
static void _php_image_create_from(INTERNAL_FUNCTION_PARAMETERS, int image_type, char *tn, gdImagePtr (*func_p)(FILE *), gdImagePtr (*ioctx_func_p)(gdIOCtxPtr))
{
char *file;
size_t file_len;
zend_long srcx, srcy, width, height;
gdImagePtr im = NULL;
php_stream *stream;
FILE * fp = NULL;
#ifdef HAVE_GD_JPG
long ignore_warning;
#endif
if (image_type == PHP_GDIMG_TYPE_GD2PART) {
if (zend_parse_parameters(ZEND_NUM_ARGS(), "pllll", &file, &file_len, &srcx, &srcy, &width, &height) == FAILURE) {
RETURN_THROWS();
}
if (width < 1) {
zend_argument_value_error(4, "must be greater than or equal to 1");
RETURN_THROWS();
}
if (height < 1) {
zend_argument_value_error(5, "must be greater than or equal to 1");
RETURN_THROWS();
}
} else {
if (zend_parse_parameters(ZEND_NUM_ARGS(), "p", &file, &file_len) == FAILURE) {
RETURN_THROWS();
}
}
stream = php_stream_open_wrapper(file, "rb", REPORT_ERRORS|IGNORE_PATH, NULL);
if (stream == NULL) {
RETURN_FALSE;
}
/* try and avoid allocating a FILE* if the stream is not naturally a FILE* */
if (php_stream_is(stream, PHP_STREAM_IS_STDIO)) {
if (FAILURE == php_stream_cast(stream, PHP_STREAM_AS_STDIO, (void**)&fp, REPORT_ERRORS)) {
goto out_err;
}
} else if (ioctx_func_p || image_type == PHP_GDIMG_TYPE_GD2PART) {
/* we can create an io context */
gdIOCtx* io_ctx;
zend_string *buff;
char *pstr;
buff = php_stream_copy_to_mem(stream, PHP_STREAM_COPY_ALL, 0);
if (!buff) {
php_error_docref(NULL, E_WARNING,"Cannot read image data");
goto out_err;
}
/* needs to be malloc (persistent) - GD will free() it later */
pstr = pestrndup(ZSTR_VAL(buff), ZSTR_LEN(buff), 1);
io_ctx = gdNewDynamicCtxEx(ZSTR_LEN(buff), pstr, 0);
if (!io_ctx) {
pefree(pstr, 1);
zend_string_release_ex(buff, 0);
php_error_docref(NULL, E_WARNING,"Cannot allocate GD IO context");
goto out_err;
}
if (image_type == PHP_GDIMG_TYPE_GD2PART) {
im = gdImageCreateFromGd2PartCtx(io_ctx, srcx, srcy, width, height);
} else {
im = (*ioctx_func_p)(io_ctx);
}
io_ctx->gd_free(io_ctx);
pefree(pstr, 1);
zend_string_release_ex(buff, 0);
}
else if (php_stream_can_cast(stream, PHP_STREAM_AS_STDIO)) {
/* try and force the stream to be FILE* */
if (FAILURE == php_stream_cast(stream, PHP_STREAM_AS_STDIO | PHP_STREAM_CAST_TRY_HARD, (void **) &fp, REPORT_ERRORS)) {
goto out_err;
}
}
if (!im && fp) {
switch (image_type) {
case PHP_GDIMG_TYPE_GD2PART:
im = gdImageCreateFromGd2Part(fp, srcx, srcy, width, height);
break;
#ifdef HAVE_GD_XPM
case PHP_GDIMG_TYPE_XPM:
im = gdImageCreateFromXpm(file);
break;
#endif
#ifdef HAVE_GD_JPG
case PHP_GDIMG_TYPE_JPG:
ignore_warning = INI_INT("gd.jpeg_ignore_warning");
im = gdImageCreateFromJpegEx(fp, ignore_warning);
break;
#endif
default:
im = (*func_p)(fp);
break;
}
fflush(fp);
}
/* register_im: */
if (im) {
php_stream_close(stream);
php_gd_assign_libgdimageptr_as_extgdimage(return_value, im);
return;
}
php_error_docref(NULL, E_WARNING, "\"%s\" is not a valid %s file", file, tn);
out_err:
php_stream_close(stream);
RETURN_FALSE;
}
/* }}} */
/* {{{ Create a new image from GIF file or URL */
PHP_FUNCTION(imagecreatefromgif)
{
_php_image_create_from(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_GIF, "GIF", gdImageCreateFromGif, gdImageCreateFromGifCtx);
}
/* }}} */
#ifdef HAVE_GD_JPG
/* {{{ Create a new image from JPEG file or URL */
PHP_FUNCTION(imagecreatefromjpeg)
{
_php_image_create_from(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_JPG, "JPEG", gdImageCreateFromJpeg, gdImageCreateFromJpegCtx);
}
/* }}} */
#endif /* HAVE_GD_JPG */
#ifdef HAVE_GD_PNG
/* {{{ Create a new image from PNG file or URL */
PHP_FUNCTION(imagecreatefrompng)
{
_php_image_create_from(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_PNG, "PNG", gdImageCreateFromPng, gdImageCreateFromPngCtx);
}
/* }}} */
#endif /* HAVE_GD_PNG */
#ifdef HAVE_GD_WEBP
/* {{{ Create a new image from WEBP file or URL */
PHP_FUNCTION(imagecreatefromwebp)
{
_php_image_create_from(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_WEBP, "WEBP", gdImageCreateFromWebp, gdImageCreateFromWebpCtx);
}
/* }}} */
#endif /* HAVE_GD_WEBP */
/* {{{ Create a new image from XBM file or URL */
PHP_FUNCTION(imagecreatefromxbm)
{
_php_image_create_from(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_XBM, "XBM", gdImageCreateFromXbm, NULL);
}
/* }}} */
#ifdef HAVE_GD_AVIF
/* {{{ Create a new image from AVIF file or URL */
PHP_FUNCTION(imagecreatefromavif)
{
_php_image_create_from(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_AVIF, "AVIF", gdImageCreateFromAvif, gdImageCreateFromAvifCtx);
}
/* }}} */
#endif /* HAVE_GD_AVIF */
#ifdef HAVE_GD_XPM
/* {{{ Create a new image from XPM file or URL */
PHP_FUNCTION(imagecreatefromxpm)
{
_php_image_create_from(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_XPM, "XPM", NULL, NULL);
}
/* }}} */
#endif
/* {{{ Create a new image from WBMP file or URL */
PHP_FUNCTION(imagecreatefromwbmp)
{
_php_image_create_from(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_WBM, "WBMP", gdImageCreateFromWBMP, gdImageCreateFromWBMPCtx);
}
/* }}} */
/* {{{ Create a new image from GD file or URL */
PHP_FUNCTION(imagecreatefromgd)
{
_php_image_create_from(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_GD, "GD", gdImageCreateFromGd, gdImageCreateFromGdCtx);
}
/* }}} */
/* {{{ Create a new image from GD2 file or URL */
PHP_FUNCTION(imagecreatefromgd2)
{
_php_image_create_from(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_GD2, "GD2", gdImageCreateFromGd2, gdImageCreateFromGd2Ctx);
}
/* }}} */
/* {{{ Create a new image from a given part of GD2 file or URL */
PHP_FUNCTION(imagecreatefromgd2part)
{
_php_image_create_from(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_GD2PART, "GD2", NULL, NULL);
}
/* }}} */
#ifdef HAVE_GD_BMP
/* {{{ Create a new image from BMP file or URL */
PHP_FUNCTION(imagecreatefrombmp)
{
_php_image_create_from(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_BMP, "BMP", gdImageCreateFromBmp, gdImageCreateFromBmpCtx);
}
/* }}} */
#endif
#ifdef HAVE_GD_TGA
/* {{{ Create a new image from TGA file or URL */
PHP_FUNCTION(imagecreatefromtga)
{
_php_image_create_from(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_TGA, "TGA", gdImageCreateFromTga, gdImageCreateFromTgaCtx);
}
/* }}} */
#endif
/* {{{ _php_image_output */
static void _php_image_output(INTERNAL_FUNCTION_PARAMETERS, int image_type, char *tn)
{
zval *imgind;
char *file = NULL;
zend_long quality = 128, type = 1;
gdImagePtr im;
FILE *fp;
size_t file_len = 0;
/* The quality parameter for gd2 stands for chunk size */
switch (image_type) {
case PHP_GDIMG_TYPE_GD:
if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|p!", &imgind, gd_image_ce, &file, &file_len) == FAILURE) {
RETURN_THROWS();
}
break;
case PHP_GDIMG_TYPE_GD2:
if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|p!ll", &imgind, gd_image_ce, &file, &file_len, &quality, &type) == FAILURE) {
RETURN_THROWS();
}
break;
EMPTY_SWITCH_DEFAULT_CASE()
}
/* quality must fit in an int */
if (quality < INT_MIN || quality > INT_MAX) {
php_error_docref(NULL, E_WARNING, "Argument #3 ($chunk_size) must be between %d and %d", INT_MIN, INT_MAX);
RETURN_FALSE;
}
im = php_gd_libgdimageptr_from_zval_p(imgind);
if (file_len) {
PHP_GD_CHECK_OPEN_BASEDIR(file, "Invalid filename");
fp = VCWD_FOPEN(file, "wb");
if (!fp) {
php_error_docref(NULL, E_WARNING, "Unable to open \"%s\" for writing", file);
RETURN_FALSE;
}
switch (image_type) {
case PHP_GDIMG_TYPE_GD:
gdImageGd(im, fp);
break;
case PHP_GDIMG_TYPE_GD2:
if (quality == -1) {
quality = 128;
}
gdImageGd2(im, fp, quality, type);
break;
EMPTY_SWITCH_DEFAULT_CASE()
}
fflush(fp);
fclose(fp);
} else {
int b;
FILE *tmp;
char buf[4096];
zend_string *path;
tmp = php_open_temporary_file(NULL, NULL, &path);
if (tmp == NULL) {
php_error_docref(NULL, E_WARNING, "Unable to open temporary file");
RETURN_FALSE;
}
switch (image_type) {
case PHP_GDIMG_TYPE_GD:
gdImageGd(im, tmp);
break;
case PHP_GDIMG_TYPE_GD2:
if (quality == -1) {
quality = 128;
}
gdImageGd2(im, tmp, quality, type);
break;
EMPTY_SWITCH_DEFAULT_CASE()
}
fseek(tmp, 0, SEEK_SET);
while ((b = fread(buf, 1, sizeof(buf), tmp)) > 0) {
php_write(buf, b);
}
fclose(tmp);
VCWD_UNLINK((const char *)ZSTR_VAL(path)); /* make sure that the temporary file is removed */
zend_string_release_ex(path, 0);
}
RETURN_TRUE;
}
/* }}} */
/* {{{ Output XBM image to browser or file */
PHP_FUNCTION(imagexbm)
{
zval *imgind;
char *file = NULL;
size_t file_len = 0;
zend_long foreground_color;
bool foreground_color_is_null = true;
gdImagePtr im;
int i;
gdIOCtx *ctx = NULL;
php_stream *stream;
ZEND_PARSE_PARAMETERS_START(2, 3)
Z_PARAM_OBJECT_OF_CLASS(imgind, gd_image_ce)
Z_PARAM_PATH_OR_NULL(file, file_len)
Z_PARAM_OPTIONAL
Z_PARAM_LONG_OR_NULL(foreground_color, foreground_color_is_null)
ZEND_PARSE_PARAMETERS_END();
im = php_gd_libgdimageptr_from_zval_p(imgind);
if (file != NULL) {
stream = php_stream_open_wrapper(file, "wb", REPORT_ERRORS|IGNORE_PATH, NULL);
if (stream == NULL) {
RETURN_FALSE;
}
ctx = create_stream_context(stream, 1);
} else {
ctx = create_output_context(NULL, 0);
}
if (foreground_color_is_null) {
for (i = 0; i < gdImageColorsTotal(im); i++) {
if (!gdImageRed(im, i) && !gdImageGreen(im, i) && !gdImageBlue(im, i)) {
break;
}
}
foreground_color = i;
}
gdImageXbmCtx(im, file ? file : "", (int) foreground_color, ctx);
ctx->gd_free(ctx);
RETURN_TRUE;
}
/* }}} */
/* {{{ Output GIF image to browser or file */
PHP_FUNCTION(imagegif)
{
zval *imgind;
gdImagePtr im;
gdIOCtx *ctx;
zval *to_zval = NULL;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|z!", &imgind, gd_image_ce, &to_zval) == FAILURE) {
RETURN_THROWS();
}
im = php_gd_libgdimageptr_from_zval_p(imgind);
ctx = create_output_context(to_zval, 2);
if (!ctx) {
RETURN_FALSE;
}
gdImageGifCtx(im, ctx);
ctx->gd_free(ctx);
RETURN_TRUE;
}
/* }}} */
#ifdef HAVE_GD_PNG
/* {{{ Output PNG image to browser or file */
PHP_FUNCTION(imagepng)
{
zval *imgind;
zend_long quality = -1, basefilter = -1;
gdImagePtr im;
gdIOCtx *ctx;
zval *to_zval = NULL;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|z!ll", &imgind, gd_image_ce, &to_zval, &quality, &basefilter) == FAILURE) {
RETURN_THROWS();
}
im = php_gd_libgdimageptr_from_zval_p(imgind);
ctx = create_output_context(to_zval, 2);
if (!ctx) {
RETURN_FALSE;
}
if (quality < -1 || quality > 9) {
zend_argument_value_error(3, "must be between -1 and 9");
ctx->gd_free(ctx);
RETURN_THROWS();
}
#ifdef HAVE_GD_BUNDLED
gdImagePngCtxEx(im, ctx, (int) quality, (int) basefilter);
#else
gdImagePngCtxEx(im, ctx, (int) quality);
#endif
ctx->gd_free(ctx);
RETURN_TRUE;
}
/* }}} */
#endif /* HAVE_GD_PNG */
#ifdef HAVE_GD_WEBP
/* {{{ Output WEBP image to browser or file */
PHP_FUNCTION(imagewebp)
{
zval *imgind;
zend_long quality = -1;
gdImagePtr im;
gdIOCtx *ctx;
zval *to_zval = NULL;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|z!l", &imgind, gd_image_ce, &to_zval, &quality) == FAILURE) {
RETURN_THROWS();
}
im = php_gd_libgdimageptr_from_zval_p(imgind);
ctx = create_output_context(to_zval, 2);
if (!ctx) {
RETURN_FALSE;
}
if (quality < -1) {
zend_argument_value_error(3, "must be greater than or equal to -1");
ctx->gd_free(ctx);
RETURN_THROWS();
}
gdImageWebpCtx(im, ctx, (int) quality);
ctx->gd_free(ctx);
RETURN_TRUE;
}
/* }}} */
#endif /* HAVE_GD_WEBP */
#ifdef HAVE_GD_AVIF
/* {{{ Output AVIF image to browser or file */
PHP_FUNCTION(imageavif)
{
zval *imgind;
zend_long quality = -1, speed = -1;
gdImagePtr im;
gdIOCtx *ctx;
zval *to_zval = NULL;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|z!ll", &imgind, gd_image_ce, &to_zval, &quality, &speed) == FAILURE) {
RETURN_THROWS();
}
im = php_gd_libgdimageptr_from_zval_p(imgind);
ctx = create_output_context(to_zval, 2);
if (!ctx) {
RETURN_FALSE;
}
if (quality < -1 || quality > 100) {
zend_argument_value_error(3, "must be between -1 and 100");
ctx->gd_free(ctx);
RETURN_THROWS();
}
if (speed < -1 || speed > 10) {
zend_argument_value_error(4, "must be between -1 and 10");
ctx->gd_free(ctx);
RETURN_THROWS();
} else if (speed == -1) {
speed = 6;
}
gdImageAvifCtx(im, ctx, (int) quality, (int) speed);
ctx->gd_free(ctx);
RETURN_TRUE;
}
/* }}} */
#endif /* HAVE_GD_AVIF */
#ifdef HAVE_GD_JPG
/* {{{ Output JPEG image to browser or file */
PHP_FUNCTION(imagejpeg)
{
zval *imgind;
zend_long quality = -1;
gdImagePtr im;
gdIOCtx *ctx;
zval *to_zval = NULL;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|z!l", &imgind, gd_image_ce, &to_zval, &quality) == FAILURE) {
RETURN_THROWS();
}
im = php_gd_libgdimageptr_from_zval_p(imgind);
ctx = create_output_context(to_zval, 2);
if (!ctx) {
RETURN_FALSE;
}
if (quality < -1 || quality > 100) {
zend_argument_value_error(3, "must be at between -1 and 100");
ctx->gd_free(ctx);
RETURN_THROWS();
}
gdImageJpegCtx(im, ctx, (int) quality);
ctx->gd_free(ctx);
RETURN_TRUE;
}
/* }}} */
#endif /* HAVE_GD_JPG */
/* {{{ Output WBMP image to browser or file */
PHP_FUNCTION(imagewbmp)
{
zval *imgind;
zend_long foreground_color;
bool foreground_color_is_null = true;
gdImagePtr im;
int i;
gdIOCtx *ctx;
zval *to_zval = NULL;
ZEND_PARSE_PARAMETERS_START(1, 3)
Z_PARAM_OBJECT_OF_CLASS(imgind, gd_image_ce)
Z_PARAM_OPTIONAL
Z_PARAM_ZVAL_OR_NULL(to_zval)
Z_PARAM_LONG_OR_NULL(foreground_color, foreground_color_is_null)
ZEND_PARSE_PARAMETERS_END();
im = php_gd_libgdimageptr_from_zval_p(imgind);
ctx = create_output_context(to_zval, 2);
if (!ctx) {
RETURN_FALSE;
}
if (foreground_color_is_null) {
for (i = 0; i < gdImageColorsTotal(im); i++) {
if (!gdImageRed(im, i) && !gdImageGreen(im, i) && !gdImageBlue(im, i)) {
break;
}
}
foreground_color = i;
}
gdImageWBMPCtx(im, foreground_color, ctx);
ctx->gd_free(ctx);
RETURN_TRUE;
}
/* }}} */
/* {{{ Output GD image to browser or file */
PHP_FUNCTION(imagegd)
{
_php_image_output(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_GD, "GD");
}
/* }}} */
/* {{{ Output GD2 image to browser or file */
PHP_FUNCTION(imagegd2)
{
_php_image_output(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_GD2, "GD2");
}
/* }}} */
#ifdef HAVE_GD_BMP
/* {{{ Output BMP image to browser or file */
PHP_FUNCTION(imagebmp)
{
zval *imgind;
bool compressed = true;
gdImagePtr im;
gdIOCtx *ctx;
zval *to_zval = NULL;
ZEND_PARSE_PARAMETERS_START(1, 3)
Z_PARAM_OBJECT_OF_CLASS(imgind, gd_image_ce)
Z_PARAM_OPTIONAL
Z_PARAM_ZVAL_OR_NULL(to_zval)
Z_PARAM_BOOL(compressed)
ZEND_PARSE_PARAMETERS_END();
im = php_gd_libgdimageptr_from_zval_p(imgind);
ctx = create_output_context(to_zval, 2);
if (!ctx) {
RETURN_FALSE;
}
gdImageBmpCtx(im, ctx, (int) compressed);
ctx->gd_free(ctx);
RETURN_TRUE;
}
/* }}} */
#endif
/* {{{ Destroy an image - No effect as of PHP 8.0 */
PHP_FUNCTION(imagedestroy)
{
/* This function used to free the resource, as resources are no longer used, it does nothing */
zval *IM;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
ZEND_PARSE_PARAMETERS_END();
RETURN_TRUE;
}
/* }}} */
/* {{{ Allocate a color for an image */
PHP_FUNCTION(imagecolorallocate)
{
zval *IM;
zend_long red, green, blue;
gdImagePtr im;
int ct = -1;
ZEND_PARSE_PARAMETERS_START(4, 4)
Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
Z_PARAM_LONG(red)
Z_PARAM_LONG(green)
Z_PARAM_LONG(blue)
ZEND_PARSE_PARAMETERS_END();
im = php_gd_libgdimageptr_from_zval_p(IM);
CHECK_RGBA_RANGE(red, Red, 2);
CHECK_RGBA_RANGE(green, Green, 3);
CHECK_RGBA_RANGE(blue, Blue, 4);
ct = gdImageColorAllocate(im, red, green, blue);
if (ct < 0) {
RETURN_FALSE;
}
RETURN_LONG(ct);
}
/* }}} */
/* {{{ Copy the palette from the src image onto the dst image */
PHP_FUNCTION(imagepalettecopy)
{
zval *dstim, *srcim;
gdImagePtr dst, src;
ZEND_PARSE_PARAMETERS_START(2, 2)
Z_PARAM_OBJECT_OF_CLASS(dstim, gd_image_ce)
Z_PARAM_OBJECT_OF_CLASS(srcim, gd_image_ce)
ZEND_PARSE_PARAMETERS_END();
src = php_gd_libgdimageptr_from_zval_p(srcim);
dst = php_gd_libgdimageptr_from_zval_p(dstim);
gdImagePaletteCopy(dst, src);
}
/* }}} */
/* {{{ Get the index of the color of a pixel */
PHP_FUNCTION(imagecolorat)
{
zval *IM;
zend_long x, y;
gdImagePtr im;
ZEND_PARSE_PARAMETERS_START(3, 3)
Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
Z_PARAM_LONG(x)
Z_PARAM_LONG(y)
ZEND_PARSE_PARAMETERS_END();
im = php_gd_libgdimageptr_from_zval_p(IM);
if (gdImageTrueColor(im)) {
if (im->tpixels && gdImageBoundsSafe(im, x, y)) {
RETURN_LONG(gdImageTrueColorPixel(im, x, y));
} else {
php_error_docref(NULL, E_NOTICE, "" ZEND_LONG_FMT "," ZEND_LONG_FMT " is out of bounds", x, y);
RETURN_FALSE;
}
} else {
if (im->pixels && gdImageBoundsSafe(im, x, y)) {
RETURN_LONG(im->pixels[y][x]);
} else {
php_error_docref(NULL, E_NOTICE, "" ZEND_LONG_FMT "," ZEND_LONG_FMT " is out of bounds", x, y);
RETURN_FALSE;
}
}
}
/* }}} */
/* {{{ Get the index of the closest color to the specified color */
PHP_FUNCTION(imagecolorclosest)
{
zval *IM;
zend_long red, green, blue;
gdImagePtr im;
ZEND_PARSE_PARAMETERS_START(4, 4)
Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
Z_PARAM_LONG(red)
Z_PARAM_LONG(green)
Z_PARAM_LONG(blue)
ZEND_PARSE_PARAMETERS_END();
im = php_gd_libgdimageptr_from_zval_p(IM);
CHECK_RGBA_RANGE(red, Red, 2);
CHECK_RGBA_RANGE(green, Green, 3);
CHECK_RGBA_RANGE(blue, Blue, 4);
RETURN_LONG(gdImageColorClosest(im, red, green, blue));
}
/* }}} */
/* {{{ Get the index of the color which has the hue, white and blackness nearest to the given color */
PHP_FUNCTION(imagecolorclosesthwb)
{
zval *IM;
zend_long red, green, blue;
gdImagePtr im;
ZEND_PARSE_PARAMETERS_START(4, 4)
Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
Z_PARAM_LONG(red)
Z_PARAM_LONG(green)
Z_PARAM_LONG(blue)
ZEND_PARSE_PARAMETERS_END();
im = php_gd_libgdimageptr_from_zval_p(IM);
CHECK_RGBA_RANGE(red, Red, 2);
CHECK_RGBA_RANGE(green, Green, 3);
CHECK_RGBA_RANGE(blue, Blue, 4);
RETURN_LONG(gdImageColorClosestHWB(im, red, green, blue));
}
/* }}} */
/* {{{ De-allocate a color for an image */
PHP_FUNCTION(imagecolordeallocate)
{
zval *IM;
zend_long index;
int col;
gdImagePtr im;
ZEND_PARSE_PARAMETERS_START(2, 2)
Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
Z_PARAM_LONG(index)
ZEND_PARSE_PARAMETERS_END();
im = php_gd_libgdimageptr_from_zval_p(IM);
/* We can return right away for a truecolor image as deallocating colours is meaningless here */
if (gdImageTrueColor(im)) {
RETURN_TRUE;
}
col = index;
if (col >= 0 && col < gdImageColorsTotal(im)) {
gdImageColorDeallocate(im, col);
RETURN_TRUE;
} else {
zend_argument_value_error(2, "must be between 0 and %d", gdImageColorsTotal(im));
RETURN_THROWS();
}
}
/* }}} */
/* {{{ Get the index of the specified color or its closest possible alternative */
PHP_FUNCTION(imagecolorresolve)
{
zval *IM;
zend_long red, green, blue;
gdImagePtr im;
ZEND_PARSE_PARAMETERS_START(4, 4)
Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
Z_PARAM_LONG(red)
Z_PARAM_LONG(green)
Z_PARAM_LONG(blue)
ZEND_PARSE_PARAMETERS_END();
im = php_gd_libgdimageptr_from_zval_p(IM);
CHECK_RGBA_RANGE(red, Red, 2);
CHECK_RGBA_RANGE(green, Green, 3);
CHECK_RGBA_RANGE(blue, Blue, 4);
RETURN_LONG(gdImageColorResolve(im, red, green, blue));
}
/* }}} */
/* {{{ Get the index of the specified color */
PHP_FUNCTION(imagecolorexact)
{
zval *IM;
zend_long red, green, blue;
gdImagePtr im;
ZEND_PARSE_PARAMETERS_START(4, 4)
Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
Z_PARAM_LONG(red)
Z_PARAM_LONG(green)
Z_PARAM_LONG(blue)
ZEND_PARSE_PARAMETERS_END();
im = php_gd_libgdimageptr_from_zval_p(IM);
CHECK_RGBA_RANGE(red, Red, 2);
CHECK_RGBA_RANGE(green, Green, 3);
CHECK_RGBA_RANGE(blue, Blue, 4);
RETURN_LONG(gdImageColorExact(im, red, green, blue));
}
/* }}} */
/* {{{ Set the color for the specified palette index */
PHP_FUNCTION(imagecolorset)
{
zval *IM;
zend_long color, red, green, blue, alpha = 0;
int col;
gdImagePtr im;
ZEND_PARSE_PARAMETERS_START(5, 6)
Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
Z_PARAM_LONG(color)
Z_PARAM_LONG(red)
Z_PARAM_LONG(green)
Z_PARAM_LONG(blue)
Z_PARAM_OPTIONAL
Z_PARAM_LONG(alpha)
ZEND_PARSE_PARAMETERS_END();
im = php_gd_libgdimageptr_from_zval_p(IM);
CHECK_RGBA_RANGE(red, Red, 3);
CHECK_RGBA_RANGE(green, Green, 4);
CHECK_RGBA_RANGE(blue, Blue, 5);
CHECK_RGBA_RANGE(alpha, Alpha, 6);
col = color;
if (col >= 0 && col < gdImageColorsTotal(im)) {
im->red[col] = red;
im->green[col] = green;
im->blue[col] = blue;
im->alpha[col] = alpha;
} else {
RETURN_FALSE;
}
}
/* }}} */
/* {{{ Get the colors for an index */
PHP_FUNCTION(imagecolorsforindex)
{
zval *IM;
zend_long index;
int col;
gdImagePtr im;
ZEND_PARSE_PARAMETERS_START(2, 2)
Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
Z_PARAM_LONG(index)
ZEND_PARSE_PARAMETERS_END();
im = php_gd_libgdimageptr_from_zval_p(IM);
col = index;
if ((col >= 0 && gdImageTrueColor(im)) || (!gdImageTrueColor(im) && col >= 0 && col < gdImageColorsTotal(im))) {
array_init(return_value);
add_assoc_long(return_value,"red", gdImageRed(im,col));
add_assoc_long(return_value,"green", gdImageGreen(im,col));
add_assoc_long(return_value,"blue", gdImageBlue(im,col));
add_assoc_long(return_value,"alpha", gdImageAlpha(im,col));
} else {
zend_argument_value_error(2, "is out of range");
RETURN_THROWS();
}
}
/* }}} */
/* {{{ Apply a gamma correction to a GD image */
PHP_FUNCTION(imagegammacorrect)
{
zval *IM;
gdImagePtr im;
int i;
double input, output, gamma;
ZEND_PARSE_PARAMETERS_START(3, 3)
Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
Z_PARAM_DOUBLE(input)
Z_PARAM_DOUBLE(output)
ZEND_PARSE_PARAMETERS_END();
if (input <= 0.0) {
zend_argument_value_error(2, "must be greater than 0");
RETURN_THROWS();
}
if (output <= 0.0) {
zend_argument_value_error(3, "must be greater than 0");
RETURN_THROWS();
}
gamma = input / output;
im = php_gd_libgdimageptr_from_zval_p(IM);
if (gdImageTrueColor(im)) {
int x, y, c;
for (y = 0; y < gdImageSY(im); y++) {
for (x = 0; x < gdImageSX(im); x++) {
c = gdImageGetPixel(im, x, y);
gdImageSetPixel(im, x, y,
gdTrueColorAlpha(
(int) ((pow((gdTrueColorGetRed(c) / 255.0), gamma) * 255) + .5),
(int) ((pow((gdTrueColorGetGreen(c) / 255.0), gamma) * 255) + .5),
(int) ((pow((gdTrueColorGetBlue(c) / 255.0), gamma) * 255) + .5),
gdTrueColorGetAlpha(c)
)
);
}
}
RETURN_TRUE;
}
for (i = 0; i < gdImageColorsTotal(im); i++) {
im->red[i] = (int)((pow((im->red[i] / 255.0), gamma) * 255) + .5);
im->green[i] = (int)((pow((im->green[i] / 255.0), gamma) * 255) + .5);
im->blue[i] = (int)((pow((im->blue[i] / 255.0), gamma) * 255) + .5);
}
RETURN_TRUE;
}
/* }}} */
/* {{{ Set a single pixel */
PHP_FUNCTION(imagesetpixel)
{
zval *IM;
zend_long x, y, col;
gdImagePtr im;
ZEND_PARSE_PARAMETERS_START(4, 4)
Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
Z_PARAM_LONG(x)
Z_PARAM_LONG(y)
Z_PARAM_LONG(col)
ZEND_PARSE_PARAMETERS_END();
im = php_gd_libgdimageptr_from_zval_p(IM);
gdImageSetPixel(im, x, y, col);
RETURN_TRUE;
}
/* }}} */
/* {{{ Draw a line */
PHP_FUNCTION(imageline)
{
zval *IM;
zend_long x1, y1, x2, y2, col;
gdImagePtr im;
ZEND_PARSE_PARAMETERS_START(6, 6)
Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
Z_PARAM_LONG(x1)
Z_PARAM_LONG(y1)
Z_PARAM_LONG(x2)
Z_PARAM_LONG(y2)
Z_PARAM_LONG(col)
ZEND_PARSE_PARAMETERS_END();
im = php_gd_libgdimageptr_from_zval_p(IM);
if (im->AA) {
gdImageSetAntiAliased(im, col);
col = gdAntiAliased;
}
gdImageLine(im, x1, y1, x2, y2, col);
RETURN_TRUE;
}
/* }}} */
/* {{{ Draw a dashed line */
PHP_FUNCTION(imagedashedline)
{
zval *IM;
zend_long x1, y1, x2, y2, col;
gdImagePtr im;
ZEND_PARSE_PARAMETERS_START(6, 6)
Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
Z_PARAM_LONG(x1)
Z_PARAM_LONG(y1)
Z_PARAM_LONG(x2)
Z_PARAM_LONG(y2)
Z_PARAM_LONG(col)
ZEND_PARSE_PARAMETERS_END();
im = php_gd_libgdimageptr_from_zval_p(IM);
gdImageDashedLine(im, x1, y1, x2, y2, col);
RETURN_TRUE;
}
/* }}} */
/* {{{ Draw a rectangle */
PHP_FUNCTION(imagerectangle)
{
zval *IM;
zend_long x1, y1, x2, y2, col;
gdImagePtr im;
ZEND_PARSE_PARAMETERS_START(6, 6)
Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
Z_PARAM_LONG(x1)
Z_PARAM_LONG(y1)
Z_PARAM_LONG(x2)
Z_PARAM_LONG(y2)
Z_PARAM_LONG(col)
ZEND_PARSE_PARAMETERS_END();
im = php_gd_libgdimageptr_from_zval_p(IM);
gdImageRectangle(im, x1, y1, x2, y2, col);
RETURN_TRUE;
}
/* }}} */
/* {{{ Draw a filled rectangle */
PHP_FUNCTION(imagefilledrectangle)
{
zval *IM;
zend_long x1, y1, x2, y2, col;
gdImagePtr im;
ZEND_PARSE_PARAMETERS_START(6, 6)
Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
Z_PARAM_LONG(x1)
Z_PARAM_LONG(y1)
Z_PARAM_LONG(x2)
Z_PARAM_LONG(y2)
Z_PARAM_LONG(col)
ZEND_PARSE_PARAMETERS_END();
im = php_gd_libgdimageptr_from_zval_p(IM);
gdImageFilledRectangle(im, x1, y1, x2, y2, col);
RETURN_TRUE;
}
/* }}} */
/* {{{ Draw a partial ellipse */
PHP_FUNCTION(imagearc)
{
zval *IM;
zend_long cx, cy, w, h, ST, E, col;
gdImagePtr im;
int e, st;
ZEND_PARSE_PARAMETERS_START(8, 8)
Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
Z_PARAM_LONG(cx)
Z_PARAM_LONG(cy)
Z_PARAM_LONG(w)
Z_PARAM_LONG(h)
Z_PARAM_LONG(ST)
Z_PARAM_LONG(E)
Z_PARAM_LONG(col)
ZEND_PARSE_PARAMETERS_END();
im = php_gd_libgdimageptr_from_zval_p(IM);
e = E;
if (e < 0) {
e %= 360;
}
st = ST;
if (st < 0) {
st %= 360;
}
gdImageArc(im, cx, cy, w, h, st, e, col);
RETURN_TRUE;
}
/* }}} */
/* {{{ Draw an ellipse */
PHP_FUNCTION(imageellipse)
{
zval *IM;
zend_long cx, cy, w, h, color;
gdImagePtr im;
ZEND_PARSE_PARAMETERS_START(6, 6)
Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
Z_PARAM_LONG(cx)
Z_PARAM_LONG(cy)
Z_PARAM_LONG(w)
Z_PARAM_LONG(h)
Z_PARAM_LONG(color)
ZEND_PARSE_PARAMETERS_END();
im = php_gd_libgdimageptr_from_zval_p(IM);
gdImageEllipse(im, cx, cy, w, h, color);
RETURN_TRUE;
}
/* }}} */
/* {{{ Flood fill to specific color */
PHP_FUNCTION(imagefilltoborder)
{
zval *IM;
zend_long x, y, border, col;
gdImagePtr im;
ZEND_PARSE_PARAMETERS_START(5, 5)
Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
Z_PARAM_LONG(x)
Z_PARAM_LONG(y)
Z_PARAM_LONG(border)
Z_PARAM_LONG(col)
ZEND_PARSE_PARAMETERS_END();
im = php_gd_libgdimageptr_from_zval_p(IM);
gdImageFillToBorder(im, x, y, border, col);
RETURN_TRUE;
}
/* }}} */
/* {{{ Flood fill */
PHP_FUNCTION(imagefill)
{
zval *IM;
zend_long x, y, col;
gdImagePtr im;
ZEND_PARSE_PARAMETERS_START(4, 4)
Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
Z_PARAM_LONG(x)
Z_PARAM_LONG(y)
Z_PARAM_LONG(col)
ZEND_PARSE_PARAMETERS_END();
im = php_gd_libgdimageptr_from_zval_p(IM);
gdImageFill(im, x, y, col);
RETURN_TRUE;
}
/* }}} */
/* {{{ Find out the number of colors in an image's palette */
PHP_FUNCTION(imagecolorstotal)
{
zval *IM;
gdImagePtr im;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
ZEND_PARSE_PARAMETERS_END();
im = php_gd_libgdimageptr_from_zval_p(IM);
RETURN_LONG(gdImageColorsTotal(im));
}
/* }}} */
/* {{{ Define a color as transparent */
PHP_FUNCTION(imagecolortransparent)
{
zval *IM;
zend_long COL = 0;
bool COL_IS_NULL = true;
gdImagePtr im;
ZEND_PARSE_PARAMETERS_START(1, 2)
Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
Z_PARAM_OPTIONAL
Z_PARAM_LONG_OR_NULL(COL, COL_IS_NULL)
ZEND_PARSE_PARAMETERS_END();
im = php_gd_libgdimageptr_from_zval_p(IM);
if (!COL_IS_NULL) {
gdImageColorTransparent(im, COL);
}
RETURN_LONG(gdImageGetTransparent(im));
}
/* }}} */
/* {{{ Enable or disable interlace */
PHP_FUNCTION(imageinterlace)
{
zval *IM;
bool INT = false;
bool INT_IS_NULL = true;
gdImagePtr im;
ZEND_PARSE_PARAMETERS_START(1, 2)
Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
Z_PARAM_OPTIONAL
Z_PARAM_BOOL_OR_NULL(INT, INT_IS_NULL)
ZEND_PARSE_PARAMETERS_END();
im = php_gd_libgdimageptr_from_zval_p(IM);
if (!INT_IS_NULL) {
gdImageInterlace(im, INT);
}
RETURN_BOOL(gdImageGetInterlaced(im));
}
/* }}} */
/* {{{ php_imagepolygon
arg = -1 open polygon
arg = 0 normal polygon
arg = 1 filled polygon */
/* im, points, num_points, col */
static void php_imagepolygon(INTERNAL_FUNCTION_PARAMETERS, int filled)
{
zval *IM, *POINTS;
zend_long NPOINTS, COL;
bool COL_IS_NULL = true;
zval *var = NULL;
gdImagePtr im;
gdPointPtr points;
int npoints, col, nelem, i;
ZEND_PARSE_PARAMETERS_START(3, 4)
Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
Z_PARAM_ARRAY(POINTS)
Z_PARAM_LONG(NPOINTS)
Z_PARAM_OPTIONAL
Z_PARAM_LONG_OR_NULL(COL, COL_IS_NULL)
ZEND_PARSE_PARAMETERS_END();
if (COL_IS_NULL) {
COL = NPOINTS;
NPOINTS = zend_hash_num_elements(Z_ARRVAL_P(POINTS));
if (NPOINTS % 2 != 0) {
zend_argument_value_error(2, "must have an even number of elements");
RETURN_THROWS();
}
NPOINTS /= 2;
} else {
php_error_docref(NULL, E_DEPRECATED, "Using the $num_points parameter is deprecated");
}
im = php_gd_libgdimageptr_from_zval_p(IM);
npoints = NPOINTS;
col = COL;
nelem = zend_hash_num_elements(Z_ARRVAL_P(POINTS));
if (npoints < 3) {
zend_argument_value_error(3, "must be greater than or equal to 3");
RETURN_THROWS();
}
if (nelem < npoints * 2) {
zend_value_error("Trying to use %d points in array with only %d points", npoints, nelem/2);
RETURN_THROWS();
}
points = (gdPointPtr) safe_emalloc(npoints, sizeof(gdPoint), 0);
for (i = 0; i < npoints; i++) {
if ((var = zend_hash_index_find(Z_ARRVAL_P(POINTS), (i * 2))) != NULL) {
points[i].x = zval_get_long(var);
}
if ((var = zend_hash_index_find(Z_ARRVAL_P(POINTS), (i * 2) + 1)) != NULL) {
points[i].y = zval_get_long(var);
}
}
if (im->AA) {
gdImageSetAntiAliased(im, col);
col = gdAntiAliased;
}
switch (filled) {
case -1:
gdImageOpenPolygon(im, points, npoints, col);
break;
case 0:
gdImagePolygon(im, points, npoints, col);
break;
case 1:
gdImageFilledPolygon(im, points, npoints, col);
break;
}
efree(points);
RETURN_TRUE;
}
/* }}} */
/* {{{ Draw a polygon */
PHP_FUNCTION(imagepolygon)
{
php_imagepolygon(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
}
/* }}} */
/* {{{ Draw a polygon */
PHP_FUNCTION(imageopenpolygon)
{
php_imagepolygon(INTERNAL_FUNCTION_PARAM_PASSTHRU, -1);
}
/* }}} */
/* {{{ Draw a filled polygon */
PHP_FUNCTION(imagefilledpolygon)
{
php_imagepolygon(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
}
/* }}} */
/* {{{ php_find_gd_font */
static gdFontPtr php_find_gd_font(zend_object *font_obj, zend_long font_int)
{
if (font_obj) {
return php_gd_font_object_from_zend_object(font_obj)->font;
}
switch (font_int) {
case 1: return gdFontTiny;
case 2: return gdFontSmall;
case 3: return gdFontMediumBold;
case 4: return gdFontLarge;
case 5: return gdFontGiant;
}
return font_int < 1 ? gdFontTiny : gdFontGiant;
}
/* }}} */
/* {{{ php_imagefontsize
* arg = 0 ImageFontWidth
* arg = 1 ImageFontHeight
*/
static void php_imagefontsize(INTERNAL_FUNCTION_PARAMETERS, int arg)
{
zend_object *font_obj = NULL;
zend_long font_int = 0;
gdFontPtr font;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_OBJ_OF_CLASS_OR_LONG(font_obj, gd_font_ce, font_int)
ZEND_PARSE_PARAMETERS_END();
font = php_find_gd_font(font_obj, font_int);
RETURN_LONG(arg ? font->h : font->w);
}
/* }}} */
/* {{{ Get font width */
PHP_FUNCTION(imagefontwidth)
{
php_imagefontsize(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
}
/* }}} */
/* {{{ Get font height */
PHP_FUNCTION(imagefontheight)
{
php_imagefontsize(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
}
/* }}} */
/* {{{ php_gdimagecharup
* workaround for a bug in gd 1.2 */
static void php_gdimagecharup(gdImagePtr im, gdFontPtr f, int x, int y, int c, int color)
{
int cx, cy, px, py, fline;
cx = 0;
cy = 0;
if ((c < f->offset) || (c >= (f->offset + f->nchars))) {
return;
}
fline = (c - f->offset) * f->h * f->w;
for (py = y; (py > (y - f->w)); py--) {
for (px = x; (px < (x + f->h)); px++) {
if (f->data[fline + cy * f->w + cx]) {
gdImageSetPixel(im, px, py, color);
}
cy++;
}
cy = 0;
cx++;
}
}
/* }}} */
/* {{{ php_imagechar
* arg = 0 ImageChar
* arg = 1 ImageCharUp
* arg = 2 ImageString
* arg = 3 ImageStringUp
*/
static void php_imagechar(INTERNAL_FUNCTION_PARAMETERS, int mode)
{
zval *IM;
zend_long X, Y, COL;
char *C;
size_t C_len;
gdImagePtr im;
int ch = 0, col, x, y, i, l = 0;
unsigned char *str = NULL;
zend_object *font_obj = NULL;
zend_long font_int = 0;
ZEND_PARSE_PARAMETERS_START(6, 6)
Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
Z_PARAM_OBJ_OF_CLASS_OR_LONG(font_obj, gd_font_ce, font_int)
Z_PARAM_LONG(X)
Z_PARAM_LONG(Y)
Z_PARAM_STRING(C, C_len)
Z_PARAM_LONG(COL)
ZEND_PARSE_PARAMETERS_END();
im = php_gd_libgdimageptr_from_zval_p(IM);
col = COL;
if (mode < 2) {
ch = (int)((unsigned char)*C);
} else {
str = (unsigned char *) estrndup(C, C_len);
l = strlen((char *)str);
}
y = Y;
x = X;
gdFontPtr font = php_find_gd_font(font_obj, font_int);
switch (mode) {
case 0:
gdImageChar(im, font, x, y, ch, col);
break;
case 1:
php_gdimagecharup(im, font, x, y, ch, col);
break;
case 2:
for (i = 0; (i < l); i++) {
gdImageChar(im, font, x, y, (int) ((unsigned char) str[i]), col);
x += font->w;
}
break;
case 3: {
for (i = 0; (i < l); i++) {
/* php_gdimagecharup(im, font, x, y, (int) str[i], col); */
gdImageCharUp(im, font, x, y, (int) str[i], col);
y -= font->w;
}
break;
}
}
if (str) {
efree(str);
}
RETURN_TRUE;
}
/* }}} */
/* {{{ Draw a character */
PHP_FUNCTION(imagechar)
{
php_imagechar(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
}
/* }}} */
/* {{{ Draw a character rotated 90 degrees counter-clockwise */
PHP_FUNCTION(imagecharup)
{
php_imagechar(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
}
/* }}} */
/* {{{ Draw a string horizontally */
PHP_FUNCTION(imagestring)
{
php_imagechar(INTERNAL_FUNCTION_PARAM_PASSTHRU, 2);
}
/* }}} */
/* {{{ Draw a string vertically - rotated 90 degrees counter-clockwise */
PHP_FUNCTION(imagestringup)
{
php_imagechar(INTERNAL_FUNCTION_PARAM_PASSTHRU, 3);
}
/* }}} */
/* {{{ Copy part of an image */
PHP_FUNCTION(imagecopy)
{
zval *SIM, *DIM;
zend_long SX, SY, SW, SH, DX, DY;
gdImagePtr im_dst, im_src;
int srcH, srcW, srcY, srcX, dstY, dstX;
ZEND_PARSE_PARAMETERS_START(8, 8)
Z_PARAM_OBJECT_OF_CLASS(DIM, gd_image_ce)
Z_PARAM_OBJECT_OF_CLASS(SIM, gd_image_ce)
Z_PARAM_LONG(DX)
Z_PARAM_LONG(DY)
Z_PARAM_LONG(SX)
Z_PARAM_LONG(SY)
Z_PARAM_LONG(SW)
Z_PARAM_LONG(SH)
ZEND_PARSE_PARAMETERS_END();
im_dst = php_gd_libgdimageptr_from_zval_p(DIM);
im_src = php_gd_libgdimageptr_from_zval_p(SIM);
srcX = SX;
srcY = SY;
srcH = SH;
srcW = SW;
dstX = DX;
dstY = DY;
gdImageCopy(im_dst, im_src, dstX, dstY, srcX, srcY, srcW, srcH);
RETURN_TRUE;
}
/* }}} */
/* {{{ Merge one part of an image with another */
PHP_FUNCTION(imagecopymerge)
{
zval *SIM, *DIM;
zend_long SX, SY, SW, SH, DX, DY, PCT;
gdImagePtr im_dst, im_src;
int srcH, srcW, srcY, srcX, dstY, dstX, pct;
ZEND_PARSE_PARAMETERS_START(9, 9)
Z_PARAM_OBJECT_OF_CLASS(DIM, gd_image_ce)
Z_PARAM_OBJECT_OF_CLASS(SIM, gd_image_ce)
Z_PARAM_LONG(DX)
Z_PARAM_LONG(DY)
Z_PARAM_LONG(SX)
Z_PARAM_LONG(SY)
Z_PARAM_LONG(SW)
Z_PARAM_LONG(SH)
Z_PARAM_LONG(PCT)
ZEND_PARSE_PARAMETERS_END();
im_src = php_gd_libgdimageptr_from_zval_p(SIM);
im_dst = php_gd_libgdimageptr_from_zval_p(DIM);
srcX = SX;
srcY = SY;
srcH = SH;
srcW = SW;
dstX = DX;
dstY = DY;
pct = PCT;
gdImageCopyMerge(im_dst, im_src, dstX, dstY, srcX, srcY, srcW, srcH, pct);
RETURN_TRUE;
}
/* }}} */
/* {{{ Merge one part of an image with another */
PHP_FUNCTION(imagecopymergegray)
{
zval *SIM, *DIM;
zend_long SX, SY, SW, SH, DX, DY, PCT;
gdImagePtr im_dst, im_src;
int srcH, srcW, srcY, srcX, dstY, dstX, pct;
ZEND_PARSE_PARAMETERS_START(9, 9)
Z_PARAM_OBJECT_OF_CLASS(DIM, gd_image_ce)
Z_PARAM_OBJECT_OF_CLASS(SIM, gd_image_ce)
Z_PARAM_LONG(DX)
Z_PARAM_LONG(DY)
Z_PARAM_LONG(SX)
Z_PARAM_LONG(SY)
Z_PARAM_LONG(SW)
Z_PARAM_LONG(SH)
Z_PARAM_LONG(PCT)
ZEND_PARSE_PARAMETERS_END();
im_src = php_gd_libgdimageptr_from_zval_p(SIM);
im_dst = php_gd_libgdimageptr_from_zval_p(DIM);
srcX = SX;
srcY = SY;
srcH = SH;
srcW = SW;
dstX = DX;
dstY = DY;
pct = PCT;
gdImageCopyMergeGray(im_dst, im_src, dstX, dstY, srcX, srcY, srcW, srcH, pct);
RETURN_TRUE;
}
/* }}} */
/* {{{ Copy and resize part of an image */
PHP_FUNCTION(imagecopyresized)
{
zval *SIM, *DIM;
zend_long SX, SY, SW, SH, DX, DY, DW, DH;
gdImagePtr im_dst, im_src;
int srcH, srcW, dstH, dstW, srcY, srcX, dstY, dstX;
ZEND_PARSE_PARAMETERS_START(10, 10)
Z_PARAM_OBJECT_OF_CLASS(DIM, gd_image_ce)
Z_PARAM_OBJECT_OF_CLASS(SIM, gd_image_ce)
Z_PARAM_LONG(DX)
Z_PARAM_LONG(DY)
Z_PARAM_LONG(SX)
Z_PARAM_LONG(SY)
Z_PARAM_LONG(DW)
Z_PARAM_LONG(DH)
Z_PARAM_LONG(SW)
Z_PARAM_LONG(SH)
ZEND_PARSE_PARAMETERS_END();
im_src = php_gd_libgdimageptr_from_zval_p(SIM);
im_dst = php_gd_libgdimageptr_from_zval_p(DIM);
srcX = SX;
srcY = SY;
srcH = SH;
srcW = SW;
dstX = DX;
dstY = DY;
dstH = DH;
dstW = DW;
if (dstW <= 0) {
zend_argument_value_error(7, "must be greater than 0");
RETURN_THROWS();
}
if (dstH <= 0) {
zend_argument_value_error(8, "must be greater than 0");
RETURN_THROWS();
}
if (srcW <= 0) {
zend_argument_value_error(9, "must be greater than 0");
RETURN_THROWS();
}
if (srcH <= 0) {
zend_argument_value_error(10, "must be greater than 0");
RETURN_THROWS();
}
gdImageCopyResized(im_dst, im_src, dstX, dstY, srcX, srcY, dstW, dstH, srcW, srcH);
RETURN_TRUE;
}
/* }}} */
/* {{{ Get image width */
PHP_FUNCTION(imagesx)
{
zval *IM;
gdImagePtr im;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
ZEND_PARSE_PARAMETERS_END();
im = php_gd_libgdimageptr_from_zval_p(IM);
RETURN_LONG(gdImageSX(im));
}
/* }}} */
/* {{{ Get image height */
PHP_FUNCTION(imagesy)
{
zval *IM;
gdImagePtr im;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
ZEND_PARSE_PARAMETERS_END();
im = php_gd_libgdimageptr_from_zval_p(IM);
RETURN_LONG(gdImageSY(im));
}
/* }}} */
/* {{{ Set the clipping rectangle. */
PHP_FUNCTION(imagesetclip)
{
zval *im_zval;
gdImagePtr im;
zend_long x1, y1, x2, y2;
ZEND_PARSE_PARAMETERS_START(5, 5)
Z_PARAM_OBJECT_OF_CLASS(im_zval, gd_image_ce)
Z_PARAM_LONG(x1)
Z_PARAM_LONG(y1)
Z_PARAM_LONG(x2)
Z_PARAM_LONG(y2)
ZEND_PARSE_PARAMETERS_END();
im = php_gd_libgdimageptr_from_zval_p(im_zval);
gdImageSetClip(im, x1, y1, x2, y2);
RETURN_TRUE;
}
/* }}} */
/* {{{ Get the clipping rectangle. */
PHP_FUNCTION(imagegetclip)
{
zval *im_zval;
gdImagePtr im;
int x1, y1, x2, y2;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_OBJECT_OF_CLASS(im_zval, gd_image_ce)
ZEND_PARSE_PARAMETERS_END();
im = php_gd_libgdimageptr_from_zval_p(im_zval);
gdImageGetClip(im, &x1, &y1, &x2, &y2);
array_init(return_value);
add_next_index_long(return_value, x1);
add_next_index_long(return_value, y1);
add_next_index_long(return_value, x2);
add_next_index_long(return_value, y2);
}
/* }}} */
#define TTFTEXT_DRAW 0
#define TTFTEXT_BBOX 1
#ifdef HAVE_GD_FREETYPE
/* {{{ Give the bounding box of a text using fonts via freetype2 */
PHP_FUNCTION(imageftbbox)
{
php_imagettftext_common(INTERNAL_FUNCTION_PARAM_PASSTHRU, TTFTEXT_BBOX);
}
/* }}} */
/* {{{ Write text to the image using fonts via freetype2 */
PHP_FUNCTION(imagefttext)
{
php_imagettftext_common(INTERNAL_FUNCTION_PARAM_PASSTHRU, TTFTEXT_DRAW);
}
/* }}} */
/* {{{ php_imagettftext_common */
static void php_imagettftext_common(INTERNAL_FUNCTION_PARAMETERS, int mode)
{
zval *IM, *EXT = NULL;
gdImagePtr im=NULL;
zend_long col = -1, x = 0, y = 0;
size_t str_len, fontname_len;
int i, brect[8];
double ptsize, angle;
char *str = NULL, *fontname = NULL;
char *error = NULL;
gdFTStringExtra strex = {0};
if (mode == TTFTEXT_BBOX) {
if (zend_parse_parameters(ZEND_NUM_ARGS(), "ddss|a", &ptsize, &angle, &fontname, &fontname_len, &str, &str_len, &EXT) == FAILURE) {
RETURN_THROWS();
}
} else {
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) {
RETURN_THROWS();
}
im = php_gd_libgdimageptr_from_zval_p(IM);
}
/* convert angle to radians */
angle = angle * (M_PI/180);
if (EXT) { /* parse extended info */
zval *item;
zend_string *key;
/* walk the assoc array */
if (!HT_IS_PACKED(Z_ARRVAL_P(EXT))) {
ZEND_HASH_MAP_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(EXT), key, item) {
if (key == NULL) {
continue;
}
if (zend_string_equals_literal(key, "linespacing")) {
strex.flags |= gdFTEX_LINESPACE;
strex.linespacing = zval_get_double(item);
}
} ZEND_HASH_FOREACH_END();
}
}
#ifdef VIRTUAL_DIR
{
char tmp_font_path[MAXPATHLEN];
if (!VCWD_REALPATH(fontname, tmp_font_path)) {
fontname = NULL;
}
}
#endif /* VIRTUAL_DIR */
PHP_GD_CHECK_OPEN_BASEDIR(fontname, "Invalid font filename");
if (EXT) {
error = gdImageStringFTEx(im, brect, col, fontname, ptsize, angle, x, y, str, &strex);
} else {
error = gdImageStringFT(im, brect, col, fontname, ptsize, angle, x, y, str);
}
if (error) {
php_error_docref(NULL, E_WARNING, "%s", error);
RETURN_FALSE;
}
array_init(return_value);
/* return array with the text's bounding box */
for (i = 0; i < 8; i++) {
add_next_index_long(return_value, brect[i]);
}
}
/* }}} */
#endif /* HAVE_GD_FREETYPE */
/* Section Filters */
#define PHP_GD_SINGLE_RES \
zval *SIM; \
gdImagePtr im_src; \
if (zend_parse_parameters(1, "O", &SIM, gd_image_ce) == FAILURE) { \
RETURN_THROWS(); \
} \
im_src = php_gd_libgdimageptr_from_zval_p(SIM);
static void php_image_filter_negate(INTERNAL_FUNCTION_PARAMETERS)
{
PHP_GD_SINGLE_RES
if (gdImageNegate(im_src) == 1) {
RETURN_TRUE;
}
RETURN_FALSE;
}
static void php_image_filter_grayscale(INTERNAL_FUNCTION_PARAMETERS)
{
PHP_GD_SINGLE_RES
if (gdImageGrayScale(im_src) == 1) {
RETURN_TRUE;
}
RETURN_FALSE;
}
static void php_image_filter_brightness(INTERNAL_FUNCTION_PARAMETERS)
{
zval *SIM;
gdImagePtr im_src;
zend_long brightness, tmp;
ZEND_PARSE_PARAMETERS_START(3, 3)
Z_PARAM_OBJECT_OF_CLASS(SIM, gd_image_ce)
Z_PARAM_LONG(tmp)
Z_PARAM_LONG(brightness)
ZEND_PARSE_PARAMETERS_END();
im_src = php_gd_libgdimageptr_from_zval_p(SIM);
if (gdImageBrightness(im_src, (int)brightness) == 1) {
RETURN_TRUE;
}
RETURN_FALSE;
}
static void php_image_filter_contrast(INTERNAL_FUNCTION_PARAMETERS)
{
zval *SIM;
gdImagePtr im_src;
zend_long contrast, tmp;
ZEND_PARSE_PARAMETERS_START(3, 3)
Z_PARAM_OBJECT_OF_CLASS(SIM, gd_image_ce)
Z_PARAM_LONG(tmp)
Z_PARAM_LONG(contrast)
ZEND_PARSE_PARAMETERS_END();
im_src = php_gd_libgdimageptr_from_zval_p(SIM);
if (gdImageContrast(im_src, (int)contrast) == 1) {
RETURN_TRUE;
}
RETURN_FALSE;
}
static void php_image_filter_colorize(INTERNAL_FUNCTION_PARAMETERS)
{
zval *SIM;
gdImagePtr im_src;
zend_long r,g,b,tmp;
zend_long a = 0;
ZEND_PARSE_PARAMETERS_START(5, 6)
Z_PARAM_OBJECT_OF_CLASS(SIM, gd_image_ce)
Z_PARAM_LONG(tmp)
Z_PARAM_LONG(r)
Z_PARAM_LONG(g)
Z_PARAM_LONG(b)
Z_PARAM_OPTIONAL
Z_PARAM_LONG(a)
ZEND_PARSE_PARAMETERS_END();
im_src = php_gd_libgdimageptr_from_zval_p(SIM);
if (gdImageColor(im_src, (int) r, (int) g, (int) b, (int) a) == 1) {
RETURN_TRUE;
}
RETURN_FALSE;
}
static void php_image_filter_edgedetect(INTERNAL_FUNCTION_PARAMETERS)
{
PHP_GD_SINGLE_RES
if (gdImageEdgeDetectQuick(im_src) == 1) {
RETURN_TRUE;
}
RETURN_FALSE;
}
static void php_image_filter_emboss(INTERNAL_FUNCTION_PARAMETERS)
{
PHP_GD_SINGLE_RES
if (gdImageEmboss(im_src) == 1) {
RETURN_TRUE;
}
RETURN_FALSE;
}
static void php_image_filter_gaussian_blur(INTERNAL_FUNCTION_PARAMETERS)
{
PHP_GD_SINGLE_RES
if (gdImageGaussianBlur(im_src) == 1) {
RETURN_TRUE;
}
RETURN_FALSE;
}
static void php_image_filter_selective_blur(INTERNAL_FUNCTION_PARAMETERS)
{
PHP_GD_SINGLE_RES
if (gdImageSelectiveBlur(im_src) == 1) {
RETURN_TRUE;
}
RETURN_FALSE;
}
static void php_image_filter_mean_removal(INTERNAL_FUNCTION_PARAMETERS)
{
PHP_GD_SINGLE_RES
if (gdImageMeanRemoval(im_src) == 1) {
RETURN_TRUE;
}
RETURN_FALSE;
}
static void php_image_filter_smooth(INTERNAL_FUNCTION_PARAMETERS)
{
zval *SIM;
zend_long tmp;
gdImagePtr im_src;
double weight;
ZEND_PARSE_PARAMETERS_START(3, 3)
Z_PARAM_OBJECT_OF_CLASS(SIM, gd_image_ce)
Z_PARAM_LONG(tmp)
Z_PARAM_DOUBLE(weight)
ZEND_PARSE_PARAMETERS_END();
im_src = php_gd_libgdimageptr_from_zval_p(SIM);
if (gdImageSmooth(im_src, (float)weight)==1) {
RETURN_TRUE;
}
RETURN_FALSE;
}
static void php_image_filter_pixelate(INTERNAL_FUNCTION_PARAMETERS)
{
zval *IM;
gdImagePtr im;
zend_long tmp, blocksize;
bool mode = false;
ZEND_PARSE_PARAMETERS_START(3, 4)
Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
Z_PARAM_LONG(tmp)
Z_PARAM_LONG(blocksize)
Z_PARAM_OPTIONAL
Z_PARAM_BOOL(mode)
ZEND_PARSE_PARAMETERS_END();
im = php_gd_libgdimageptr_from_zval_p(IM);
if (gdImagePixelate(im, (int) blocksize, (const unsigned int) mode)) {
RETURN_TRUE;
}
RETURN_FALSE;
}
static void php_image_filter_scatter(INTERNAL_FUNCTION_PARAMETERS)
{
zval *IM;
zval *hash_colors = NULL;
gdImagePtr im;
zend_long tmp;
zend_long scatter_sub, scatter_plus;
ZEND_PARSE_PARAMETERS_START(4, 5)
Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
Z_PARAM_LONG(tmp)
Z_PARAM_LONG(scatter_sub)
Z_PARAM_LONG(scatter_plus)
Z_PARAM_OPTIONAL
Z_PARAM_ARRAY(hash_colors)
ZEND_PARSE_PARAMETERS_END();
im = php_gd_libgdimageptr_from_zval_p(IM);
if (hash_colors) {
uint32_t i = 0;
uint32_t num_colors = zend_hash_num_elements(Z_ARRVAL_P(hash_colors));
zval *color;
int *colors;
if (num_colors == 0) {
RETURN_BOOL(gdImageScatter(im, (int)scatter_sub, (int)scatter_plus));
}
colors = emalloc(num_colors * sizeof(int));
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(hash_colors), color) {
*(colors + i++) = (int) zval_get_long(color);
} ZEND_HASH_FOREACH_END();
RETVAL_BOOL(gdImageScatterColor(im, (int)scatter_sub, (int)scatter_plus, colors, num_colors));
efree(colors);
} else {
RETURN_BOOL(gdImageScatter(im, (int) scatter_sub, (int) scatter_plus));
}
}
/* {{{ Applies Filter an image using a custom angle */
PHP_FUNCTION(imagefilter)
{
zval *tmp;
typedef void (*image_filter)(INTERNAL_FUNCTION_PARAMETERS);
zend_long filtertype;
image_filter filters[] =
{
php_image_filter_negate ,
php_image_filter_grayscale,
php_image_filter_brightness,
php_image_filter_contrast,
php_image_filter_colorize,
php_image_filter_edgedetect,
php_image_filter_emboss,
php_image_filter_gaussian_blur,
php_image_filter_selective_blur,
php_image_filter_mean_removal,
php_image_filter_smooth,
php_image_filter_pixelate,
php_image_filter_scatter
};
if (ZEND_NUM_ARGS() < 2 || ZEND_NUM_ARGS() > IMAGE_FILTER_MAX_ARGS) {
WRONG_PARAM_COUNT;
} else if (zend_parse_parameters(2, "Ol", &tmp, gd_image_ce, &filtertype) == FAILURE) {
RETURN_THROWS();
}
if (filtertype >= 0 && filtertype <= IMAGE_FILTER_MAX) {
filters[filtertype](INTERNAL_FUNCTION_PARAM_PASSTHRU);
}
}
/* }}} */
/* {{{ Apply a 3x3 convolution matrix, using coefficient div and offset */
PHP_FUNCTION(imageconvolution)
{
zval *SIM, *hash_matrix;
zval *var = NULL, *var2 = NULL;
gdImagePtr im_src = NULL;
double div, offset;
int nelem, i, j, res;
float matrix[3][3] = {{0,0,0}, {0,0,0}, {0,0,0}};
ZEND_PARSE_PARAMETERS_START(4, 4)
Z_PARAM_OBJECT_OF_CLASS(SIM, gd_image_ce)
Z_PARAM_ARRAY(hash_matrix)
Z_PARAM_DOUBLE(div)
Z_PARAM_DOUBLE(offset)
ZEND_PARSE_PARAMETERS_END();
im_src = php_gd_libgdimageptr_from_zval_p(SIM);
nelem = zend_hash_num_elements(Z_ARRVAL_P(hash_matrix));
if (nelem != 3) {
zend_argument_value_error(2, "must be a 3x3 array");
RETURN_THROWS();
}
for (i=0; i<3; i++) {
if ((var = zend_hash_index_find(Z_ARRVAL_P(hash_matrix), (i))) != NULL && Z_TYPE_P(var) == IS_ARRAY) {
if (zend_hash_num_elements(Z_ARRVAL_P(var)) != 3 ) {
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)));
RETURN_THROWS();
}
for (j=0; j<3; j++) {
if ((var2 = zend_hash_index_find(Z_ARRVAL_P(var), j)) != NULL) {
matrix[i][j] = (float) zval_get_double(var2);
} else {
zend_argument_value_error(2, "must be a 3x3 array, matrix[%d][%d] cannot be found (missing integer key)", i, j);
RETURN_THROWS();
}
}
}
}
res = gdImageConvolution(im_src, matrix, (float)div, (float)offset);
if (res) {
RETURN_TRUE;
} else {
RETURN_FALSE;
}
}
/* }}} */
/* End section: Filters */
/* {{{ Flip an image (in place) horizontally, vertically or both directions. */
PHP_FUNCTION(imageflip)
{
zval *IM;
zend_long mode;
gdImagePtr im;
ZEND_PARSE_PARAMETERS_START(2, 2)
Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
Z_PARAM_LONG(mode)
ZEND_PARSE_PARAMETERS_END();
im = php_gd_libgdimageptr_from_zval_p(IM);
switch (mode) {
case PHP_GD_FLIP_VERTICAL:
gdImageFlipVertical(im);
break;
case PHP_GD_FLIP_HORIZONTAL:
gdImageFlipHorizontal(im);
break;
case PHP_GD_FLIP_BOTH:
gdImageFlipBoth(im);
break;
default:
zend_argument_value_error(2, "must be one of IMG_FLIP_VERTICAL, IMG_FLIP_HORIZONTAL, or IMG_FLIP_BOTH");
RETURN_THROWS();
}
RETURN_TRUE;
}
/* }}} */
/* {{{ Should antialiased functions used or not*/
PHP_FUNCTION(imageantialias)
{
zval *IM;
bool alias;
gdImagePtr im;
ZEND_PARSE_PARAMETERS_START(2, 2)
Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
Z_PARAM_BOOL(alias)
ZEND_PARSE_PARAMETERS_END();
im = php_gd_libgdimageptr_from_zval_p(IM);
if (im->trueColor) {
im->AA = alias;
}
RETURN_TRUE;
}
/* }}} */
/* {{{ Crop an image using the given coordinates and size, x, y, width and height. */
PHP_FUNCTION(imagecrop)
{
zval *IM;
gdImagePtr im;
gdImagePtr im_crop;
gdRect rect;
zval *z_rect;
zval *tmp;
ZEND_PARSE_PARAMETERS_START(2, 2)
Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
Z_PARAM_ARRAY(z_rect)
ZEND_PARSE_PARAMETERS_END();
im = php_gd_libgdimageptr_from_zval_p(IM);
if ((tmp = zend_hash_str_find(Z_ARRVAL_P(z_rect), "x", sizeof("x") -1)) != NULL) {
rect.x = zval_get_long(tmp);
} else {
zend_argument_value_error(2, "must have an \"x\" key");
RETURN_THROWS();
}
if ((tmp = zend_hash_str_find(Z_ARRVAL_P(z_rect), "y", sizeof("y") - 1)) != NULL) {
rect.y = zval_get_long(tmp);
} else {
zend_argument_value_error(2, "must have a \"y\" key");
RETURN_THROWS();
}
if ((tmp = zend_hash_str_find(Z_ARRVAL_P(z_rect), "width", sizeof("width") - 1)) != NULL) {
rect.width = zval_get_long(tmp);
} else {
zend_argument_value_error(2, "must have a \"width\" key");
RETURN_THROWS();
}
if ((tmp = zend_hash_str_find(Z_ARRVAL_P(z_rect), "height", sizeof("height") - 1)) != NULL) {
rect.height = zval_get_long(tmp);
} else {
zend_argument_value_error(2, "must have a \"height\" key");
RETURN_THROWS();
}
im_crop = gdImageCrop(im, &rect);
if (im_crop == NULL) {
RETURN_FALSE;
}
php_gd_assign_libgdimageptr_as_extgdimage(return_value, im_crop);
}
/* }}} */
/* {{{ Crop an image automatically using one of the available modes. */
PHP_FUNCTION(imagecropauto)
{
zval *IM;
zend_long mode = GD_CROP_DEFAULT;
zend_long color = -1;
double threshold = 0.5f;
gdImagePtr im;
gdImagePtr im_crop;
ZEND_PARSE_PARAMETERS_START(1, 4)
Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
Z_PARAM_OPTIONAL
Z_PARAM_LONG(mode)
Z_PARAM_DOUBLE(threshold)
Z_PARAM_LONG(color)
ZEND_PARSE_PARAMETERS_END();
im = php_gd_libgdimageptr_from_zval_p(IM);
switch (mode) {
case GD_CROP_DEFAULT:
case GD_CROP_TRANSPARENT:
case GD_CROP_BLACK:
case GD_CROP_WHITE:
case GD_CROP_SIDES:
im_crop = gdImageCropAuto(im, mode);
break;
case GD_CROP_THRESHOLD:
if (color < 0 || (!gdImageTrueColor(im) && color >= gdImageColorsTotal(im))) {
zend_argument_value_error(4, "must be greater than or equal to 0 when using the threshold mode");
RETURN_THROWS();
}
im_crop = gdImageCropThreshold(im, color, (float) threshold);
break;
default:
zend_argument_value_error(2, "must be a valid mode");
RETURN_THROWS();
}
if (im_crop == NULL) {
RETURN_FALSE;
}
php_gd_assign_libgdimageptr_as_extgdimage(return_value, im_crop);
}
/* }}} */
/* {{{ Scale an image using the given new width and height. */
PHP_FUNCTION(imagescale)
{
zval *IM;
gdImagePtr im;
gdImagePtr im_scaled = NULL;
int new_width, new_height;
zend_long tmp_w, tmp_h=-1, tmp_m = GD_BILINEAR_FIXED;
gdInterpolationMethod method, old_method;
ZEND_PARSE_PARAMETERS_START(2, 4)
Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
Z_PARAM_LONG(tmp_w)
Z_PARAM_OPTIONAL
Z_PARAM_LONG(tmp_h)
Z_PARAM_LONG(tmp_m)
ZEND_PARSE_PARAMETERS_END();
method = tmp_m;
im = php_gd_libgdimageptr_from_zval_p(IM);
if (tmp_h < 0 || tmp_w < 0) {
/* preserve ratio */
long src_x, src_y;
src_x = gdImageSX(im);
src_y = gdImageSY(im);
if (src_x && tmp_h < 0) {
tmp_h = tmp_w * src_y / src_x;
}
if (src_y && tmp_w < 0) {
tmp_w = tmp_h * src_x / src_y;
}
}
if (tmp_h <= 0 || tmp_h > INT_MAX || tmp_w <= 0 || tmp_w > INT_MAX) {
RETURN_FALSE;
}
new_width = tmp_w;
new_height = tmp_h;
/* gdImageGetInterpolationMethod() is only available as of GD 2.1.1 */
old_method = im->interpolation_id;
if (gdImageSetInterpolationMethod(im, method)) {
im_scaled = gdImageScale(im, new_width, new_height);
}
gdImageSetInterpolationMethod(im, old_method);
if (im_scaled == NULL) {
RETURN_FALSE;
}
php_gd_assign_libgdimageptr_as_extgdimage(return_value, im_scaled);
}
/* }}} */
/* {{{ Return an image containing the affine tramsformed src image, using an optional clipping area */
PHP_FUNCTION(imageaffine)
{
zval *IM;
gdImagePtr src;
gdImagePtr dst;
gdRect rect;
gdRectPtr pRect = NULL;
zval *z_rect = NULL;
zval *z_affine;
zval *tmp;
double affine[6];
int i, nelems;
zval *zval_affine_elem = NULL;
ZEND_PARSE_PARAMETERS_START(2, 3)
Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
Z_PARAM_ARRAY(z_affine)
Z_PARAM_OPTIONAL
Z_PARAM_ARRAY_OR_NULL(z_rect)
ZEND_PARSE_PARAMETERS_END();
src = php_gd_libgdimageptr_from_zval_p(IM);
if ((nelems = zend_hash_num_elements(Z_ARRVAL_P(z_affine))) != 6) {
zend_argument_value_error(2, "must have 6 elements");
RETURN_THROWS();
}
for (i = 0; i < nelems; i++) {
if ((zval_affine_elem = zend_hash_index_find(Z_ARRVAL_P(z_affine), i)) != NULL) {
switch (Z_TYPE_P(zval_affine_elem)) {
case IS_LONG:
affine[i] = Z_LVAL_P(zval_affine_elem);
break;
case IS_DOUBLE:
affine[i] = Z_DVAL_P(zval_affine_elem);
break;
case IS_STRING:
affine[i] = zval_get_double(zval_affine_elem);
break;
default:
zend_argument_type_error(3, "contains invalid type for element %i", i);
RETURN_THROWS();
}
}
}
if (z_rect != NULL) {
if ((tmp = zend_hash_str_find(Z_ARRVAL_P(z_rect), "x", sizeof("x") - 1)) != NULL) {
rect.x = zval_get_long(tmp);
} else {
zend_argument_value_error(3, "must have an \"x\" key");
RETURN_THROWS();
}
if ((tmp = zend_hash_str_find(Z_ARRVAL_P(z_rect), "y", sizeof("y") - 1)) != NULL) {
rect.y = zval_get_long(tmp);
} else {
zend_argument_value_error(3, "must have a \"y\" key");
RETURN_THROWS();
}
if ((tmp = zend_hash_str_find(Z_ARRVAL_P(z_rect), "width", sizeof("width") - 1)) != NULL) {
rect.width = zval_get_long(tmp);
} else {
zend_argument_value_error(3, "must have a \"width\" key");
RETURN_THROWS();
}
if ((tmp = zend_hash_str_find(Z_ARRVAL_P(z_rect), "height", sizeof("height") - 1)) != NULL) {
rect.height = zval_get_long(tmp);
} else {
zend_argument_value_error(3, "must have a \"height\" key");
RETURN_THROWS();
}
pRect = &rect;
}
if (gdTransformAffineGetImage(&dst, src, pRect, affine) != GD_TRUE) {
RETURN_FALSE;
}
if (dst == NULL) {
RETURN_FALSE;
}
php_gd_assign_libgdimageptr_as_extgdimage(return_value, dst);
}
/* }}} */
/* {{{ Return an image containing the affine tramsformed src image, using an optional clipping area */
PHP_FUNCTION(imageaffinematrixget)
{
double affine[6];
zend_long type;
zval *options = NULL;
zval *tmp;
int res = GD_FALSE, i;
ZEND_PARSE_PARAMETERS_START(2, 2)
Z_PARAM_LONG(type)
Z_PARAM_ZVAL(options)
ZEND_PARSE_PARAMETERS_END();
switch((gdAffineStandardMatrix)type) {
case GD_AFFINE_TRANSLATE:
case GD_AFFINE_SCALE: {
double x, y;
if (Z_TYPE_P(options) != IS_ARRAY) {
zend_argument_type_error(1, "must be of type array when using translate or scale");
RETURN_THROWS();
}
if ((tmp = zend_hash_str_find(Z_ARRVAL_P(options), "x", sizeof("x") - 1)) != NULL) {
x = zval_get_double(tmp);
} else {
zend_argument_value_error(2, "must have an \"x\" key");
RETURN_THROWS();
}
if ((tmp = zend_hash_str_find(Z_ARRVAL_P(options), "y", sizeof("y") - 1)) != NULL) {
y = zval_get_double(tmp);
} else {
zend_argument_value_error(2, "must have a \"y\" key");
RETURN_THROWS();
}
if (type == GD_AFFINE_TRANSLATE) {
res = gdAffineTranslate(affine, x, y);
} else {
res = gdAffineScale(affine, x, y);
}
break;
}
case GD_AFFINE_ROTATE:
case GD_AFFINE_SHEAR_HORIZONTAL:
case GD_AFFINE_SHEAR_VERTICAL: {
double angle;
angle = zval_get_double(options);
if (type == GD_AFFINE_SHEAR_HORIZONTAL) {
res = gdAffineShearHorizontal(affine, angle);
} else if (type == GD_AFFINE_SHEAR_VERTICAL) {
res = gdAffineShearVertical(affine, angle);
} else {
res = gdAffineRotate(affine, angle);
}
break;
}
default:
zend_argument_value_error(1, "must be a valid element type");
RETURN_THROWS();
}
if (res == GD_FALSE) {
RETURN_FALSE;
} else {
array_init(return_value);
for (i = 0; i < 6; i++) {
add_index_double(return_value, i, affine[i]);
}
}
} /* }}} */
/* {{{ Concat two matrices (as in doing many ops in one go) */
PHP_FUNCTION(imageaffinematrixconcat)
{
double m1[6];
double m2[6];
double mr[6];
zval *tmp;
zval *z_m1;
zval *z_m2;
int i;
ZEND_PARSE_PARAMETERS_START(2, 2)
Z_PARAM_ARRAY(z_m1)
Z_PARAM_ARRAY(z_m2)
ZEND_PARSE_PARAMETERS_END();
if (zend_hash_num_elements(Z_ARRVAL_P(z_m1)) != 6) {
zend_argument_value_error(1, "must have 6 elements");
RETURN_THROWS();
}
if (zend_hash_num_elements(Z_ARRVAL_P(z_m2)) != 6) {
zend_argument_value_error(1, "must have 6 elements");
RETURN_THROWS();
}
for (i = 0; i < 6; i++) {
if ((tmp = zend_hash_index_find(Z_ARRVAL_P(z_m1), i)) != NULL) {
switch (Z_TYPE_P(tmp)) {
case IS_LONG:
m1[i] = Z_LVAL_P(tmp);
break;
case IS_DOUBLE:
m1[i] = Z_DVAL_P(tmp);
break;
case IS_STRING:
m1[i] = zval_get_double(tmp);
break;
default:
zend_argument_type_error(1, "contains invalid type for element %i", i);
RETURN_THROWS();
}
}
if ((tmp = zend_hash_index_find(Z_ARRVAL_P(z_m2), i)) != NULL) {
switch (Z_TYPE_P(tmp)) {
case IS_LONG:
m2[i] = Z_LVAL_P(tmp);
break;
case IS_DOUBLE:
m2[i] = Z_DVAL_P(tmp);
break;
case IS_STRING:
m2[i] = zval_get_double(tmp);
break;
default:
zend_argument_type_error(2, "contains invalid type for element %i", i);
RETURN_THROWS();
}
}
}
if (gdAffineConcat (mr, m1, m2) != GD_TRUE) {
RETURN_FALSE;
}
array_init(return_value);
for (i = 0; i < 6; i++) {
add_index_double(return_value, i, mr[i]);
}
} /* }}} */
/* {{{ Get the default interpolation method. */
PHP_FUNCTION(imagegetinterpolation)
{
zval *IM;
gdImagePtr im;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
ZEND_PARSE_PARAMETERS_END();
im = php_gd_libgdimageptr_from_zval_p(IM);
#ifdef HAVE_GD_GET_INTERPOLATION
RETURN_LONG(gdImageGetInterpolationMethod(im));
#else
RETURN_LONG(im->interpolation_id);
#endif
}
/* }}} */
/* {{{ Set the default interpolation method, passing -1 or 0 sets it to the libgd default (bilinear). */
PHP_FUNCTION(imagesetinterpolation)
{
zval *IM;
gdImagePtr im;
zend_long method = GD_BILINEAR_FIXED;
ZEND_PARSE_PARAMETERS_START(1, 2)
Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
Z_PARAM_OPTIONAL
Z_PARAM_LONG(method)
ZEND_PARSE_PARAMETERS_END();
im = php_gd_libgdimageptr_from_zval_p(IM);
if (method == -1) {
method = GD_BILINEAR_FIXED;
}
RETURN_BOOL(gdImageSetInterpolationMethod(im, (gdInterpolationMethod) method));
}
/* }}} */
/* {{{ Get or set the resolution of the image in DPI. */
PHP_FUNCTION(imageresolution)
{
zval *IM;
gdImagePtr im;
zend_long res_x, res_y;
bool res_x_is_null = true, res_y_is_null = true;
ZEND_PARSE_PARAMETERS_START(1, 3)
Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
Z_PARAM_OPTIONAL
Z_PARAM_LONG_OR_NULL(res_x, res_x_is_null)
Z_PARAM_LONG_OR_NULL(res_y, res_y_is_null)
ZEND_PARSE_PARAMETERS_END();
im = php_gd_libgdimageptr_from_zval_p(IM);
if (!res_x_is_null && !res_y_is_null) {
if (res_x < 0 || ZEND_SIZE_T_UINT_OVFL(res_x)) {
zend_argument_value_error(2, "must be between 0 and %u", UINT_MAX);
RETURN_THROWS();
}
if (res_y < 0 || ZEND_SIZE_T_UINT_OVFL(res_y)) {
zend_argument_value_error(3, "must be between 0 and %u", UINT_MAX);
RETURN_THROWS();
}
gdImageSetResolution(im, res_x, res_y);
RETURN_TRUE;
} else if (!res_x_is_null && res_y_is_null) {
if (res_x < 0 || ZEND_SIZE_T_UINT_OVFL(res_x)) {
zend_argument_value_error(2, "must be between 0 and %u", UINT_MAX);
RETURN_THROWS();
}
gdImageSetResolution(im, res_x, res_x);
RETURN_TRUE;
} else if (res_x_is_null && !res_y_is_null) {
if (res_y < 0 || ZEND_SIZE_T_UINT_OVFL(res_y)) {
zend_argument_value_error(3, "must be between 0 and %u", UINT_MAX);
RETURN_THROWS();
}
gdImageSetResolution(im, res_y, res_y);
RETURN_TRUE;
}
array_init(return_value);
add_next_index_long(return_value, gdImageResolutionX(im));
add_next_index_long(return_value, gdImageResolutionY(im));
}
/* }}} */
/*********************************************************
*
* Stream Handling
* Formerly contained within ext/gd/gd_ctx.c and included
* at the the top of this file
*
********************************************************/
#define CTX_PUTC(c,ctx) ctx->putC(ctx, c)
static void _php_image_output_putc(struct gdIOCtx *ctx, int c) /* {{{ */
{
/* without the following downcast, the write will fail
* (i.e., will write a zero byte) for all
* big endian architectures:
*/
unsigned char ch = (unsigned char) c;
php_write(&ch, 1);
} /* }}} */
static int _php_image_output_putbuf(struct gdIOCtx *ctx, const void* buf, int l) /* {{{ */
{
return php_write((void *)buf, l);
} /* }}} */
static void _php_image_output_ctxfree(struct gdIOCtx *ctx) /* {{{ */
{
efree(ctx);
} /* }}} */
static void _php_image_stream_putc(struct gdIOCtx *ctx, int c) /* {{{ */ {
char ch = (char) c;
php_stream * stream = (php_stream *)ctx->data;
php_stream_write(stream, &ch, 1);
} /* }}} */
static int _php_image_stream_putbuf(struct gdIOCtx *ctx, const void* buf, int l) /* {{{ */
{
php_stream * stream = (php_stream *)ctx->data;
return php_stream_write(stream, (void *)buf, l);
} /* }}} */
static void _php_image_stream_ctxfree(struct gdIOCtx *ctx) /* {{{ */
{
if(ctx->data) {
ctx->data = NULL;
}
efree(ctx);
} /* }}} */
static void _php_image_stream_ctxfreeandclose(struct gdIOCtx *ctx) /* {{{ */
{
if(ctx->data) {
php_stream_close((php_stream *) ctx->data);
ctx->data = NULL;
}
efree(ctx);
} /* }}} */
static gdIOCtx *create_stream_context(php_stream *stream, int close_stream) {
gdIOCtx *ctx = ecalloc(1, sizeof(gdIOCtx));
ctx->putC = _php_image_stream_putc;
ctx->putBuf = _php_image_stream_putbuf;
if (close_stream) {
ctx->gd_free = _php_image_stream_ctxfreeandclose;
} else {
ctx->gd_free = _php_image_stream_ctxfree;
}
ctx->data = (void *)stream;
return ctx;
}
static gdIOCtx *create_output_context(zval *to_zval, uint32_t arg_num) {
gdIOCtx *ctx;
if (to_zval != NULL) {
php_stream *stream;
int close_stream = 1;
ZEND_ASSERT(arg_num > 0);
if (Z_TYPE_P(to_zval) == IS_RESOURCE) {
php_stream_from_zval_no_verify(stream, to_zval);
if (stream == NULL) {
return NULL;
}
close_stream = 0;
} else if (Z_TYPE_P(to_zval) == IS_STRING) {
if (CHECK_ZVAL_NULL_PATH(to_zval)) {
zend_argument_type_error(arg_num, "must not contain null bytes");
return NULL;
}
stream = php_stream_open_wrapper(Z_STRVAL_P(to_zval), "wb", REPORT_ERRORS|IGNORE_PATH, NULL);
if (stream == NULL) {
return NULL;
}
} else {
zend_argument_type_error(arg_num, "must be a file name or a stream resource, %s given", zend_zval_value_name(to_zval));
return NULL;
}
ctx = create_stream_context(stream, close_stream);
} else {
ctx = ecalloc(1, sizeof(gdIOCtx));
ctx->putC = _php_image_output_putc;
ctx->putBuf = _php_image_output_putbuf;
ctx->gd_free = _php_image_output_ctxfree;
}
return ctx;
}
/* }}} */