mirror of
https://github.com/php/php-src.git
synced 2024-09-22 10:27:25 +00:00
11accb5cdf
* 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.
4435 lines
102 KiB
C
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 = ▭
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
/* }}} */
|