PageRenderTime 68ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 1ms

/ext/gd/gd.c

http://github.com/php/php-src
C | 4256 lines | 3054 code | 701 blank | 501 comment | 590 complexity | 9e81e9c1306da0033bb79831aabab579 MD5 | raw file
Possible License(s): BSD-2-Clause, BSD-3-Clause, MPL-2.0-no-copyleft-exception, LGPL-2.1
  1. /*
  2. +----------------------------------------------------------------------+
  3. | Copyright (c) The PHP Group |
  4. +----------------------------------------------------------------------+
  5. | This source file is subject to version 3.01 of the PHP license, |
  6. | that is bundled with this package in the file LICENSE, and is |
  7. | available through the world-wide-web at the following url: |
  8. | http://www.php.net/license/3_01.txt |
  9. | If you did not receive a copy of the PHP license and are unable to |
  10. | obtain it through the world-wide-web, please send a note to |
  11. | license@php.net so we can mail you a copy immediately. |
  12. +----------------------------------------------------------------------+
  13. | Authors: Rasmus Lerdorf <rasmus@php.net> |
  14. | Stig Bakken <ssb@php.net> |
  15. | Jim Winstead <jimw@php.net> |
  16. +----------------------------------------------------------------------+
  17. */
  18. /* gd 1.2 is copyright 1994, 1995, Quest Protein Database Center,
  19. Cold Spring Harbor Labs. */
  20. /* Note that there is no code from the gd package in this file */
  21. #ifdef HAVE_CONFIG_H
  22. #include "config.h"
  23. #endif
  24. #include "php.h"
  25. #include "php_ini.h"
  26. #include "ext/standard/head.h"
  27. #include <math.h>
  28. #include "SAPI.h"
  29. #include "php_gd.h"
  30. #include "ext/standard/info.h"
  31. #include "php_open_temporary_file.h"
  32. #include "zend_object_handlers.h"
  33. #include "zend_interfaces.h"
  34. #ifdef HAVE_SYS_WAIT_H
  35. # include <sys/wait.h>
  36. #endif
  37. #ifdef HAVE_UNISTD_H
  38. # include <unistd.h>
  39. #endif
  40. #ifdef PHP_WIN32
  41. # include <io.h>
  42. # include <fcntl.h>
  43. # include <windows.h>
  44. # include <Winuser.h>
  45. # include <Wingdi.h>
  46. #endif
  47. #if defined(HAVE_GD_XPM) && defined(HAVE_GD_BUNDLED)
  48. # include <X11/xpm.h>
  49. #endif
  50. #include "gd_compat.h"
  51. static int le_gd_font;
  52. #include <gd.h>
  53. #include <gd_errors.h>
  54. #include <gdfontt.h> /* 1 Tiny font */
  55. #include <gdfonts.h> /* 2 Small font */
  56. #include <gdfontmb.h> /* 3 Medium bold font */
  57. #include <gdfontl.h> /* 4 Large font */
  58. #include <gdfontg.h> /* 5 Giant font */
  59. #if defined(HAVE_GD_FREETYPE) && defined(HAVE_GD_BUNDLED)
  60. # include <ft2build.h>
  61. # include FT_FREETYPE_H
  62. #endif
  63. #if defined(HAVE_GD_XPM) && defined(HAVE_GD_BUNDLED)
  64. # include "X11/xpm.h"
  65. #endif
  66. #ifndef M_PI
  67. #define M_PI 3.14159265358979323846
  68. #endif
  69. /* workaround typo in system libgd 2.3.0 */
  70. #if defined(GD_FLIP_HORINZONTAL) && !defined(GD_FLIP_HORIZONTAL)
  71. #define GD_FLIP_HORIZONTAL GD_FLIP_HORINZONTAL
  72. #endif
  73. #ifdef HAVE_GD_FREETYPE
  74. static void php_imagettftext_common(INTERNAL_FUNCTION_PARAMETERS, int, int);
  75. #endif
  76. #include "gd_arginfo.h"
  77. /* as it is not really public, duplicate declaration here to avoid
  78. pointless warnings */
  79. int overflow2(int a, int b);
  80. /* Section Filters Declarations */
  81. /* IMPORTANT NOTE FOR NEW FILTER
  82. * Do not forget to update:
  83. * IMAGE_FILTER_MAX: define the last filter index
  84. * IMAGE_FILTER_MAX_ARGS: define the biggest amount of arguments
  85. * image_filter array in PHP_FUNCTION(imagefilter)
  86. * */
  87. #define IMAGE_FILTER_NEGATE 0
  88. #define IMAGE_FILTER_GRAYSCALE 1
  89. #define IMAGE_FILTER_BRIGHTNESS 2
  90. #define IMAGE_FILTER_CONTRAST 3
  91. #define IMAGE_FILTER_COLORIZE 4
  92. #define IMAGE_FILTER_EDGEDETECT 5
  93. #define IMAGE_FILTER_EMBOSS 6
  94. #define IMAGE_FILTER_GAUSSIAN_BLUR 7
  95. #define IMAGE_FILTER_SELECTIVE_BLUR 8
  96. #define IMAGE_FILTER_MEAN_REMOVAL 9
  97. #define IMAGE_FILTER_SMOOTH 10
  98. #define IMAGE_FILTER_PIXELATE 11
  99. #define IMAGE_FILTER_SCATTER 12
  100. #define IMAGE_FILTER_MAX 12
  101. #define IMAGE_FILTER_MAX_ARGS 6
  102. static void php_image_filter_negate(INTERNAL_FUNCTION_PARAMETERS);
  103. static void php_image_filter_grayscale(INTERNAL_FUNCTION_PARAMETERS);
  104. static void php_image_filter_brightness(INTERNAL_FUNCTION_PARAMETERS);
  105. static void php_image_filter_contrast(INTERNAL_FUNCTION_PARAMETERS);
  106. static void php_image_filter_colorize(INTERNAL_FUNCTION_PARAMETERS);
  107. static void php_image_filter_edgedetect(INTERNAL_FUNCTION_PARAMETERS);
  108. static void php_image_filter_emboss(INTERNAL_FUNCTION_PARAMETERS);
  109. static void php_image_filter_gaussian_blur(INTERNAL_FUNCTION_PARAMETERS);
  110. static void php_image_filter_selective_blur(INTERNAL_FUNCTION_PARAMETERS);
  111. static void php_image_filter_mean_removal(INTERNAL_FUNCTION_PARAMETERS);
  112. static void php_image_filter_smooth(INTERNAL_FUNCTION_PARAMETERS);
  113. static void php_image_filter_pixelate(INTERNAL_FUNCTION_PARAMETERS);
  114. static void php_image_filter_scatter(INTERNAL_FUNCTION_PARAMETERS);
  115. /* End Section filters declarations */
  116. static gdImagePtr _php_image_create_from_string(zend_string *Data, char *tn, gdImagePtr (*ioctx_func_p)());
  117. static void _php_image_create_from(INTERNAL_FUNCTION_PARAMETERS, int image_type, char *tn, gdImagePtr (*func_p)(), gdImagePtr (*ioctx_func_p)());
  118. static void _php_image_output(INTERNAL_FUNCTION_PARAMETERS, int image_type, char *tn, void (*func_p)());
  119. static int _php_image_type(char data[12]);
  120. /* output streaming (formerly gd_ctx.c) */
  121. static void _php_image_output_ctx(INTERNAL_FUNCTION_PARAMETERS, int image_type, char *tn, void (*func_p)());
  122. /*********************************************************
  123. *
  124. * GD Object Representation
  125. *
  126. ********************************************************/
  127. zend_class_entry *gd_image_ce;
  128. typedef struct _gd_ext_image_object {
  129. gdImagePtr image;
  130. zend_object std;
  131. } php_gd_image_object;
  132. static zend_object_handlers php_gd_image_object_handlers;
  133. static const zend_function_entry gd_image_object_methods[] = {
  134. PHP_FE_END
  135. };
  136. static zend_function *php_gd_image_object_get_constructor(zend_object *object)
  137. {
  138. zend_throw_error(NULL, "You cannot initialize a GdImage object except through helper functions");
  139. return NULL;
  140. }
  141. /**
  142. * Returns the underlying php_gd_image_object from a zend_object
  143. */
  144. static zend_always_inline php_gd_image_object* php_gd_exgdimage_from_zobj_p(zend_object* obj)
  145. {
  146. return (php_gd_image_object *) ((char *) (obj) - XtOffsetOf(php_gd_image_object, std));
  147. }
  148. /**
  149. * Converts an extension GdImage instance contained within a zval into the gdImagePtr
  150. * for use with library APIs
  151. */
  152. static zend_always_inline gdImagePtr php_gd_libgdimageptr_from_zval_p(zval* zp)
  153. {
  154. return php_gd_exgdimage_from_zobj_p(Z_OBJ_P(zp))->image;
  155. }
  156. zend_object *php_gd_image_object_create(zend_class_entry *class_type)
  157. {
  158. size_t block_len = sizeof(php_gd_image_object) + zend_object_properties_size(class_type);
  159. php_gd_image_object *intern = emalloc(block_len);
  160. memset(intern, 0, block_len);
  161. zend_object_std_init(&intern->std, class_type);
  162. object_properties_init(&intern->std, class_type);
  163. intern->std.handlers = &php_gd_image_object_handlers;
  164. return &intern->std;
  165. }
  166. static void php_gd_image_object_free(zend_object *intern)
  167. {
  168. php_gd_image_object *img_obj_ptr = php_gd_exgdimage_from_zobj_p(intern);
  169. gdImageDestroy(img_obj_ptr->image);
  170. img_obj_ptr->image = NULL;
  171. zend_object_std_dtor(intern);
  172. }
  173. /**
  174. * Creates a new GdImage object wrapping the gdImagePtr and attaches it
  175. * to the zval (usually return_value).
  176. *
  177. * This function must only be called once per valid gdImagePtr
  178. */
  179. void php_gd_assign_libgdimageptr_as_extgdimage(zval *val, gdImagePtr image)
  180. {
  181. object_init_ex(val, gd_image_ce);
  182. php_gd_exgdimage_from_zobj_p(Z_OBJ_P(val))->image = image;
  183. }
  184. static void php_gd_object_minit_helper()
  185. {
  186. zend_class_entry ce;
  187. INIT_CLASS_ENTRY(ce, "GdImage", gd_image_object_methods);
  188. gd_image_ce = zend_register_internal_class(&ce);
  189. gd_image_ce->ce_flags |= ZEND_ACC_FINAL;
  190. gd_image_ce->create_object = php_gd_image_object_create;
  191. gd_image_ce->serialize = zend_class_serialize_deny;
  192. gd_image_ce->unserialize = zend_class_unserialize_deny;
  193. /* setting up the object handlers for the GdImage class */
  194. memcpy(&php_gd_image_object_handlers, &std_object_handlers, sizeof(zend_object_handlers));
  195. php_gd_image_object_handlers.clone_obj = NULL;
  196. php_gd_image_object_handlers.free_obj = php_gd_image_object_free;
  197. php_gd_image_object_handlers.get_constructor = php_gd_image_object_get_constructor;
  198. php_gd_image_object_handlers.offset = XtOffsetOf(php_gd_image_object, std);
  199. }
  200. /*********************************************************
  201. *
  202. * Extension Implementation
  203. *
  204. ********************************************************/
  205. zend_module_entry gd_module_entry = {
  206. STANDARD_MODULE_HEADER,
  207. "gd",
  208. ext_functions,
  209. PHP_MINIT(gd),
  210. PHP_MSHUTDOWN(gd),
  211. NULL,
  212. PHP_RSHUTDOWN(gd),
  213. PHP_MINFO(gd),
  214. PHP_GD_VERSION,
  215. STANDARD_MODULE_PROPERTIES
  216. };
  217. #ifdef COMPILE_DL_GD
  218. ZEND_GET_MODULE(gd)
  219. #endif
  220. /* {{{ PHP_INI_BEGIN */
  221. PHP_INI_BEGIN()
  222. PHP_INI_ENTRY("gd.jpeg_ignore_warning", "1", PHP_INI_ALL, NULL)
  223. PHP_INI_END()
  224. /* }}} */
  225. /* {{{ php_free_gd_font
  226. */
  227. static void php_free_gd_font(zend_resource *rsrc)
  228. {
  229. gdFontPtr fp = (gdFontPtr) rsrc->ptr;
  230. if (fp->data) {
  231. efree(fp->data);
  232. }
  233. efree(fp);
  234. }
  235. /* }}} */
  236. /* {{{ php_gd_error_method
  237. */
  238. void php_gd_error_method(int type, const char *format, va_list args)
  239. {
  240. switch (type) {
  241. #ifndef PHP_WIN32
  242. case GD_DEBUG:
  243. case GD_INFO:
  244. #endif
  245. case GD_NOTICE:
  246. type = E_NOTICE;
  247. break;
  248. case GD_WARNING:
  249. type = E_WARNING;
  250. break;
  251. default:
  252. type = E_ERROR;
  253. }
  254. php_verror(NULL, "", type, format, args);
  255. }
  256. /* }}} */
  257. /* {{{ PHP_MINIT_FUNCTION
  258. */
  259. PHP_MINIT_FUNCTION(gd)
  260. {
  261. le_gd_font = zend_register_list_destructors_ex(php_free_gd_font, NULL, "gd font", module_number);
  262. php_gd_object_minit_helper();
  263. #if defined(HAVE_GD_FREETYPE) && defined(HAVE_GD_BUNDLED)
  264. gdFontCacheMutexSetup();
  265. #endif
  266. gdSetErrorMethod(php_gd_error_method);
  267. REGISTER_INI_ENTRIES();
  268. REGISTER_LONG_CONSTANT("IMG_GIF", PHP_IMG_GIF, CONST_CS | CONST_PERSISTENT);
  269. REGISTER_LONG_CONSTANT("IMG_JPG", PHP_IMG_JPG, CONST_CS | CONST_PERSISTENT);
  270. REGISTER_LONG_CONSTANT("IMG_JPEG", PHP_IMG_JPEG, CONST_CS | CONST_PERSISTENT);
  271. REGISTER_LONG_CONSTANT("IMG_PNG", PHP_IMG_PNG, CONST_CS | CONST_PERSISTENT);
  272. REGISTER_LONG_CONSTANT("IMG_WBMP", PHP_IMG_WBMP, CONST_CS | CONST_PERSISTENT);
  273. REGISTER_LONG_CONSTANT("IMG_XPM", PHP_IMG_XPM, CONST_CS | CONST_PERSISTENT);
  274. REGISTER_LONG_CONSTANT("IMG_WEBP", PHP_IMG_WEBP, CONST_CS | CONST_PERSISTENT);
  275. REGISTER_LONG_CONSTANT("IMG_BMP", PHP_IMG_BMP, CONST_CS | CONST_PERSISTENT);
  276. REGISTER_LONG_CONSTANT("IMG_TGA", PHP_IMG_TGA, CONST_CS | CONST_PERSISTENT);
  277. /* special colours for gd */
  278. REGISTER_LONG_CONSTANT("IMG_COLOR_TILED", gdTiled, CONST_CS | CONST_PERSISTENT);
  279. REGISTER_LONG_CONSTANT("IMG_COLOR_STYLED", gdStyled, CONST_CS | CONST_PERSISTENT);
  280. REGISTER_LONG_CONSTANT("IMG_COLOR_BRUSHED", gdBrushed, CONST_CS | CONST_PERSISTENT);
  281. REGISTER_LONG_CONSTANT("IMG_COLOR_STYLEDBRUSHED", gdStyledBrushed, CONST_CS | CONST_PERSISTENT);
  282. REGISTER_LONG_CONSTANT("IMG_COLOR_TRANSPARENT", gdTransparent, CONST_CS | CONST_PERSISTENT);
  283. /* for imagefilledarc */
  284. REGISTER_LONG_CONSTANT("IMG_ARC_ROUNDED", gdArc, CONST_CS | CONST_PERSISTENT);
  285. REGISTER_LONG_CONSTANT("IMG_ARC_PIE", gdPie, CONST_CS | CONST_PERSISTENT);
  286. REGISTER_LONG_CONSTANT("IMG_ARC_CHORD", gdChord, CONST_CS | CONST_PERSISTENT);
  287. REGISTER_LONG_CONSTANT("IMG_ARC_NOFILL", gdNoFill, CONST_CS | CONST_PERSISTENT);
  288. REGISTER_LONG_CONSTANT("IMG_ARC_EDGED", gdEdged, CONST_CS | CONST_PERSISTENT);
  289. /* GD2 image format types */
  290. REGISTER_LONG_CONSTANT("IMG_GD2_RAW", GD2_FMT_RAW, CONST_CS | CONST_PERSISTENT);
  291. REGISTER_LONG_CONSTANT("IMG_GD2_COMPRESSED", GD2_FMT_COMPRESSED, CONST_CS | CONST_PERSISTENT);
  292. REGISTER_LONG_CONSTANT("IMG_FLIP_HORIZONTAL", GD_FLIP_HORIZONTAL, CONST_CS | CONST_PERSISTENT);
  293. REGISTER_LONG_CONSTANT("IMG_FLIP_VERTICAL", GD_FLIP_VERTICAL, CONST_CS | CONST_PERSISTENT);
  294. REGISTER_LONG_CONSTANT("IMG_FLIP_BOTH", GD_FLIP_BOTH, CONST_CS | CONST_PERSISTENT);
  295. REGISTER_LONG_CONSTANT("IMG_EFFECT_REPLACE", gdEffectReplace, CONST_CS | CONST_PERSISTENT);
  296. REGISTER_LONG_CONSTANT("IMG_EFFECT_ALPHABLEND", gdEffectAlphaBlend, CONST_CS | CONST_PERSISTENT);
  297. REGISTER_LONG_CONSTANT("IMG_EFFECT_NORMAL", gdEffectNormal, CONST_CS | CONST_PERSISTENT);
  298. REGISTER_LONG_CONSTANT("IMG_EFFECT_OVERLAY", gdEffectOverlay, CONST_CS | CONST_PERSISTENT);
  299. #ifdef gdEffectMultiply
  300. REGISTER_LONG_CONSTANT("IMG_EFFECT_MULTIPLY", gdEffectMultiply, CONST_CS | CONST_PERSISTENT);
  301. #endif
  302. REGISTER_LONG_CONSTANT("IMG_CROP_DEFAULT", GD_CROP_DEFAULT, CONST_CS | CONST_PERSISTENT);
  303. REGISTER_LONG_CONSTANT("IMG_CROP_TRANSPARENT", GD_CROP_TRANSPARENT, CONST_CS | CONST_PERSISTENT);
  304. REGISTER_LONG_CONSTANT("IMG_CROP_BLACK", GD_CROP_BLACK, CONST_CS | CONST_PERSISTENT);
  305. REGISTER_LONG_CONSTANT("IMG_CROP_WHITE", GD_CROP_WHITE, CONST_CS | CONST_PERSISTENT);
  306. REGISTER_LONG_CONSTANT("IMG_CROP_SIDES", GD_CROP_SIDES, CONST_CS | CONST_PERSISTENT);
  307. REGISTER_LONG_CONSTANT("IMG_CROP_THRESHOLD", GD_CROP_THRESHOLD, CONST_CS | CONST_PERSISTENT);
  308. REGISTER_LONG_CONSTANT("IMG_BELL", GD_BELL, CONST_CS | CONST_PERSISTENT);
  309. REGISTER_LONG_CONSTANT("IMG_BESSEL", GD_BESSEL, CONST_CS | CONST_PERSISTENT);
  310. REGISTER_LONG_CONSTANT("IMG_BILINEAR_FIXED", GD_BILINEAR_FIXED, CONST_CS | CONST_PERSISTENT);
  311. REGISTER_LONG_CONSTANT("IMG_BICUBIC", GD_BICUBIC, CONST_CS | CONST_PERSISTENT);
  312. REGISTER_LONG_CONSTANT("IMG_BICUBIC_FIXED", GD_BICUBIC_FIXED, CONST_CS | CONST_PERSISTENT);
  313. REGISTER_LONG_CONSTANT("IMG_BLACKMAN", GD_BLACKMAN, CONST_CS | CONST_PERSISTENT);
  314. REGISTER_LONG_CONSTANT("IMG_BOX", GD_BOX, CONST_CS | CONST_PERSISTENT);
  315. REGISTER_LONG_CONSTANT("IMG_BSPLINE", GD_BSPLINE, CONST_CS | CONST_PERSISTENT);
  316. REGISTER_LONG_CONSTANT("IMG_CATMULLROM", GD_CATMULLROM, CONST_CS | CONST_PERSISTENT);
  317. REGISTER_LONG_CONSTANT("IMG_GAUSSIAN", GD_GAUSSIAN, CONST_CS | CONST_PERSISTENT);
  318. REGISTER_LONG_CONSTANT("IMG_GENERALIZED_CUBIC", GD_GENERALIZED_CUBIC, CONST_CS | CONST_PERSISTENT);
  319. REGISTER_LONG_CONSTANT("IMG_HERMITE", GD_HERMITE, CONST_CS | CONST_PERSISTENT);
  320. REGISTER_LONG_CONSTANT("IMG_HAMMING", GD_HAMMING, CONST_CS | CONST_PERSISTENT);
  321. REGISTER_LONG_CONSTANT("IMG_HANNING", GD_HANNING, CONST_CS | CONST_PERSISTENT);
  322. REGISTER_LONG_CONSTANT("IMG_MITCHELL", GD_MITCHELL, CONST_CS | CONST_PERSISTENT);
  323. REGISTER_LONG_CONSTANT("IMG_POWER", GD_POWER, CONST_CS | CONST_PERSISTENT);
  324. REGISTER_LONG_CONSTANT("IMG_QUADRATIC", GD_QUADRATIC, CONST_CS | CONST_PERSISTENT);
  325. REGISTER_LONG_CONSTANT("IMG_SINC", GD_SINC, CONST_CS | CONST_PERSISTENT);
  326. REGISTER_LONG_CONSTANT("IMG_NEAREST_NEIGHBOUR", GD_NEAREST_NEIGHBOUR, CONST_CS | CONST_PERSISTENT);
  327. REGISTER_LONG_CONSTANT("IMG_WEIGHTED4", GD_WEIGHTED4, CONST_CS | CONST_PERSISTENT);
  328. REGISTER_LONG_CONSTANT("IMG_TRIANGLE", GD_TRIANGLE, CONST_CS | CONST_PERSISTENT);
  329. REGISTER_LONG_CONSTANT("IMG_AFFINE_TRANSLATE", GD_AFFINE_TRANSLATE, CONST_CS | CONST_PERSISTENT);
  330. REGISTER_LONG_CONSTANT("IMG_AFFINE_SCALE", GD_AFFINE_SCALE, CONST_CS | CONST_PERSISTENT);
  331. REGISTER_LONG_CONSTANT("IMG_AFFINE_ROTATE", GD_AFFINE_ROTATE, CONST_CS | CONST_PERSISTENT);
  332. REGISTER_LONG_CONSTANT("IMG_AFFINE_SHEAR_HORIZONTAL", GD_AFFINE_SHEAR_HORIZONTAL, CONST_CS | CONST_PERSISTENT);
  333. REGISTER_LONG_CONSTANT("IMG_AFFINE_SHEAR_VERTICAL", GD_AFFINE_SHEAR_VERTICAL, CONST_CS | CONST_PERSISTENT);
  334. #if defined(HAVE_GD_BUNDLED)
  335. REGISTER_LONG_CONSTANT("GD_BUNDLED", 1, CONST_CS | CONST_PERSISTENT);
  336. #else
  337. REGISTER_LONG_CONSTANT("GD_BUNDLED", 0, CONST_CS | CONST_PERSISTENT);
  338. #endif
  339. /* Section Filters */
  340. REGISTER_LONG_CONSTANT("IMG_FILTER_NEGATE", IMAGE_FILTER_NEGATE, CONST_CS | CONST_PERSISTENT);
  341. REGISTER_LONG_CONSTANT("IMG_FILTER_GRAYSCALE", IMAGE_FILTER_GRAYSCALE, CONST_CS | CONST_PERSISTENT);
  342. REGISTER_LONG_CONSTANT("IMG_FILTER_BRIGHTNESS", IMAGE_FILTER_BRIGHTNESS, CONST_CS | CONST_PERSISTENT);
  343. REGISTER_LONG_CONSTANT("IMG_FILTER_CONTRAST", IMAGE_FILTER_CONTRAST, CONST_CS | CONST_PERSISTENT);
  344. REGISTER_LONG_CONSTANT("IMG_FILTER_COLORIZE", IMAGE_FILTER_COLORIZE, CONST_CS | CONST_PERSISTENT);
  345. REGISTER_LONG_CONSTANT("IMG_FILTER_EDGEDETECT", IMAGE_FILTER_EDGEDETECT, CONST_CS | CONST_PERSISTENT);
  346. REGISTER_LONG_CONSTANT("IMG_FILTER_GAUSSIAN_BLUR", IMAGE_FILTER_GAUSSIAN_BLUR, CONST_CS | CONST_PERSISTENT);
  347. REGISTER_LONG_CONSTANT("IMG_FILTER_SELECTIVE_BLUR", IMAGE_FILTER_SELECTIVE_BLUR, CONST_CS | CONST_PERSISTENT);
  348. REGISTER_LONG_CONSTANT("IMG_FILTER_EMBOSS", IMAGE_FILTER_EMBOSS, CONST_CS | CONST_PERSISTENT);
  349. REGISTER_LONG_CONSTANT("IMG_FILTER_MEAN_REMOVAL", IMAGE_FILTER_MEAN_REMOVAL, CONST_CS | CONST_PERSISTENT);
  350. REGISTER_LONG_CONSTANT("IMG_FILTER_SMOOTH", IMAGE_FILTER_SMOOTH, CONST_CS | CONST_PERSISTENT);
  351. REGISTER_LONG_CONSTANT("IMG_FILTER_PIXELATE", IMAGE_FILTER_PIXELATE, CONST_CS | CONST_PERSISTENT);
  352. REGISTER_LONG_CONSTANT("IMG_FILTER_SCATTER", IMAGE_FILTER_SCATTER, CONST_CS | CONST_PERSISTENT);
  353. /* End Section Filters */
  354. #ifdef GD_VERSION_STRING
  355. REGISTER_STRING_CONSTANT("GD_VERSION", GD_VERSION_STRING, CONST_CS | CONST_PERSISTENT);
  356. #endif
  357. #if defined(GD_MAJOR_VERSION) && defined(GD_MINOR_VERSION) && defined(GD_RELEASE_VERSION) && defined(GD_EXTRA_VERSION)
  358. REGISTER_LONG_CONSTANT("GD_MAJOR_VERSION", GD_MAJOR_VERSION, CONST_CS | CONST_PERSISTENT);
  359. REGISTER_LONG_CONSTANT("GD_MINOR_VERSION", GD_MINOR_VERSION, CONST_CS | CONST_PERSISTENT);
  360. REGISTER_LONG_CONSTANT("GD_RELEASE_VERSION", GD_RELEASE_VERSION, CONST_CS | CONST_PERSISTENT);
  361. REGISTER_STRING_CONSTANT("GD_EXTRA_VERSION", GD_EXTRA_VERSION, CONST_CS | CONST_PERSISTENT);
  362. #endif
  363. #ifdef HAVE_GD_PNG
  364. /*
  365. * cannot include #include "png.h"
  366. * /usr/include/pngconf.h:310:2: error: #error png.h already includes setjmp.h with some additional fixup.
  367. * as error, use the values for now...
  368. */
  369. REGISTER_LONG_CONSTANT("PNG_NO_FILTER", 0x00, CONST_CS | CONST_PERSISTENT);
  370. REGISTER_LONG_CONSTANT("PNG_FILTER_NONE", 0x08, CONST_CS | CONST_PERSISTENT);
  371. REGISTER_LONG_CONSTANT("PNG_FILTER_SUB", 0x10, CONST_CS | CONST_PERSISTENT);
  372. REGISTER_LONG_CONSTANT("PNG_FILTER_UP", 0x20, CONST_CS | CONST_PERSISTENT);
  373. REGISTER_LONG_CONSTANT("PNG_FILTER_AVG", 0x40, CONST_CS | CONST_PERSISTENT);
  374. REGISTER_LONG_CONSTANT("PNG_FILTER_PAETH", 0x80, CONST_CS | CONST_PERSISTENT);
  375. REGISTER_LONG_CONSTANT("PNG_ALL_FILTERS", 0x08 | 0x10 | 0x20 | 0x40 | 0x80, CONST_CS | CONST_PERSISTENT);
  376. #endif
  377. return SUCCESS;
  378. }
  379. /* }}} */
  380. /* {{{ PHP_MSHUTDOWN_FUNCTION
  381. */
  382. PHP_MSHUTDOWN_FUNCTION(gd)
  383. {
  384. #if defined(HAVE_GD_FREETYPE) && defined(HAVE_GD_BUNDLED)
  385. gdFontCacheMutexShutdown();
  386. #endif
  387. UNREGISTER_INI_ENTRIES();
  388. return SUCCESS;
  389. }
  390. /* }}} */
  391. /* {{{ PHP_RSHUTDOWN_FUNCTION
  392. */
  393. PHP_RSHUTDOWN_FUNCTION(gd)
  394. {
  395. #ifdef HAVE_GD_FREETYPE
  396. gdFontCacheShutdown();
  397. #endif
  398. return SUCCESS;
  399. }
  400. /* }}} */
  401. #if defined(HAVE_GD_BUNDLED)
  402. #define PHP_GD_VERSION_STRING "bundled (2.1.0 compatible)"
  403. #else
  404. # define PHP_GD_VERSION_STRING GD_VERSION_STRING
  405. #endif
  406. /* {{{ PHP_MINFO_FUNCTION
  407. */
  408. PHP_MINFO_FUNCTION(gd)
  409. {
  410. php_info_print_table_start();
  411. php_info_print_table_row(2, "GD Support", "enabled");
  412. /* need to use a PHPAPI function here because it is external module in windows */
  413. #if defined(HAVE_GD_BUNDLED)
  414. php_info_print_table_row(2, "GD Version", PHP_GD_VERSION_STRING);
  415. #else
  416. php_info_print_table_row(2, "GD headers Version", PHP_GD_VERSION_STRING);
  417. #if defined(HAVE_GD_LIBVERSION)
  418. php_info_print_table_row(2, "GD library Version", gdVersionString());
  419. #endif
  420. #endif
  421. #ifdef HAVE_GD_FREETYPE
  422. php_info_print_table_row(2, "FreeType Support", "enabled");
  423. php_info_print_table_row(2, "FreeType Linkage", "with freetype");
  424. #ifdef HAVE_GD_BUNDLED
  425. {
  426. char tmp[256];
  427. #ifdef FREETYPE_PATCH
  428. snprintf(tmp, sizeof(tmp), "%d.%d.%d", FREETYPE_MAJOR, FREETYPE_MINOR, FREETYPE_PATCH);
  429. #elif defined(FREETYPE_MAJOR)
  430. snprintf(tmp, sizeof(tmp), "%d.%d", FREETYPE_MAJOR, FREETYPE_MINOR);
  431. #else
  432. snprintf(tmp, sizeof(tmp), "1.x");
  433. #endif
  434. php_info_print_table_row(2, "FreeType Version", tmp);
  435. }
  436. #endif
  437. #endif
  438. php_info_print_table_row(2, "GIF Read Support", "enabled");
  439. php_info_print_table_row(2, "GIF Create Support", "enabled");
  440. #ifdef HAVE_GD_JPG
  441. {
  442. php_info_print_table_row(2, "JPEG Support", "enabled");
  443. #if defined(HAVE_GD_BUNDLED)
  444. php_info_print_table_row(2, "libJPEG Version", gdJpegGetVersionString());
  445. #endif
  446. }
  447. #endif
  448. #ifdef HAVE_GD_PNG
  449. php_info_print_table_row(2, "PNG Support", "enabled");
  450. #if defined(HAVE_GD_BUNDLED)
  451. php_info_print_table_row(2, "libPNG Version", gdPngGetVersionString());
  452. #endif
  453. #endif
  454. php_info_print_table_row(2, "WBMP Support", "enabled");
  455. #if defined(HAVE_GD_XPM)
  456. php_info_print_table_row(2, "XPM Support", "enabled");
  457. #if defined(HAVE_GD_BUNDLED)
  458. {
  459. char tmp[12];
  460. snprintf(tmp, sizeof(tmp), "%d", XpmLibraryVersion());
  461. php_info_print_table_row(2, "libXpm Version", tmp);
  462. }
  463. #endif
  464. #endif
  465. php_info_print_table_row(2, "XBM Support", "enabled");
  466. #if defined(USE_GD_JISX0208)
  467. php_info_print_table_row(2, "JIS-mapped Japanese Font Support", "enabled");
  468. #endif
  469. #ifdef HAVE_GD_WEBP
  470. php_info_print_table_row(2, "WebP Support", "enabled");
  471. #endif
  472. #ifdef HAVE_GD_BMP
  473. php_info_print_table_row(2, "BMP Support", "enabled");
  474. #endif
  475. #ifdef HAVE_GD_TGA
  476. php_info_print_table_row(2, "TGA Read Support", "enabled");
  477. #endif
  478. php_info_print_table_end();
  479. DISPLAY_INI_ENTRIES();
  480. }
  481. /* }}} */
  482. /* {{{ proto array gd_info()
  483. */
  484. PHP_FUNCTION(gd_info)
  485. {
  486. if (zend_parse_parameters_none() == FAILURE) {
  487. RETURN_THROWS();
  488. }
  489. array_init(return_value);
  490. add_assoc_string(return_value, "GD Version", PHP_GD_VERSION_STRING);
  491. #ifdef HAVE_GD_FREETYPE
  492. add_assoc_bool(return_value, "FreeType Support", 1);
  493. add_assoc_string(return_value, "FreeType Linkage", "with freetype");
  494. #else
  495. add_assoc_bool(return_value, "FreeType Support", 0);
  496. #endif
  497. add_assoc_bool(return_value, "GIF Read Support", 1);
  498. add_assoc_bool(return_value, "GIF Create Support", 1);
  499. #ifdef HAVE_GD_JPG
  500. add_assoc_bool(return_value, "JPEG Support", 1);
  501. #else
  502. add_assoc_bool(return_value, "JPEG Support", 0);
  503. #endif
  504. #ifdef HAVE_GD_PNG
  505. add_assoc_bool(return_value, "PNG Support", 1);
  506. #else
  507. add_assoc_bool(return_value, "PNG Support", 0);
  508. #endif
  509. add_assoc_bool(return_value, "WBMP Support", 1);
  510. #if defined(HAVE_GD_XPM)
  511. add_assoc_bool(return_value, "XPM Support", 1);
  512. #else
  513. add_assoc_bool(return_value, "XPM Support", 0);
  514. #endif
  515. add_assoc_bool(return_value, "XBM Support", 1);
  516. #ifdef HAVE_GD_WEBP
  517. add_assoc_bool(return_value, "WebP Support", 1);
  518. #else
  519. add_assoc_bool(return_value, "WebP Support", 0);
  520. #endif
  521. #ifdef HAVE_GD_BMP
  522. add_assoc_bool(return_value, "BMP Support", 1);
  523. #else
  524. add_assoc_bool(return_value, "BMP Support", 0);
  525. #endif
  526. #ifdef HAVE_GD_TGA
  527. add_assoc_bool(return_value, "TGA Read Support", 1);
  528. #else
  529. add_assoc_bool(return_value, "TGA Read Support", 0);
  530. #endif
  531. #if defined(USE_GD_JISX0208)
  532. add_assoc_bool(return_value, "JIS-mapped Japanese Font Support", 1);
  533. #else
  534. add_assoc_bool(return_value, "JIS-mapped Japanese Font Support", 0);
  535. #endif
  536. }
  537. /* }}} */
  538. #define FLIPWORD(a) (((a & 0xff000000) >> 24) | ((a & 0x00ff0000) >> 8) | ((a & 0x0000ff00) << 8) | ((a & 0x000000ff) << 24))
  539. /* {{{ proto int imageloadfont(string filename)
  540. Load a new font */
  541. PHP_FUNCTION(imageloadfont)
  542. {
  543. zval *ind;
  544. zend_string *file;
  545. int hdr_size = sizeof(gdFont) - sizeof(char *);
  546. int body_size, n = 0, b, i, body_size_check;
  547. gdFontPtr font;
  548. php_stream *stream;
  549. if (zend_parse_parameters(ZEND_NUM_ARGS(), "P", &file) == FAILURE) {
  550. RETURN_THROWS();
  551. }
  552. stream = php_stream_open_wrapper(ZSTR_VAL(file), "rb", IGNORE_PATH | IGNORE_URL_WIN | REPORT_ERRORS, NULL);
  553. if (stream == NULL) {
  554. RETURN_FALSE;
  555. }
  556. /* Only supports a architecture-dependent binary dump format
  557. * at the moment.
  558. * The file format is like this on machines with 32-byte integers:
  559. *
  560. * byte 0-3: (int) number of characters in the font
  561. * byte 4-7: (int) value of first character in the font (often 32, space)
  562. * byte 8-11: (int) pixel width of each character
  563. * byte 12-15: (int) pixel height of each character
  564. * bytes 16-: (char) array with character data, one byte per pixel
  565. * in each character, for a total of
  566. * (nchars*width*height) bytes.
  567. */
  568. font = (gdFontPtr) emalloc(sizeof(gdFont));
  569. b = 0;
  570. while (b < hdr_size && (n = php_stream_read(stream, (char*)&font[b], hdr_size - b)) > 0) {
  571. b += n;
  572. }
  573. if (n <= 0) {
  574. efree(font);
  575. if (php_stream_eof(stream)) {
  576. php_error_docref(NULL, E_WARNING, "End of file while reading header");
  577. } else {
  578. php_error_docref(NULL, E_WARNING, "Error while reading header");
  579. }
  580. php_stream_close(stream);
  581. RETURN_FALSE;
  582. }
  583. i = php_stream_tell(stream);
  584. php_stream_seek(stream, 0, SEEK_END);
  585. body_size_check = php_stream_tell(stream) - hdr_size;
  586. php_stream_seek(stream, i, SEEK_SET);
  587. if (overflow2(font->nchars, font->h) || overflow2(font->nchars * font->h, font->w )) {
  588. php_error_docref(NULL, E_WARNING, "Error reading font, invalid font header");
  589. efree(font);
  590. php_stream_close(stream);
  591. RETURN_FALSE;
  592. }
  593. body_size = font->w * font->h * font->nchars;
  594. if (body_size != body_size_check) {
  595. font->w = FLIPWORD(font->w);
  596. font->h = FLIPWORD(font->h);
  597. font->nchars = FLIPWORD(font->nchars);
  598. body_size = font->w * font->h * font->nchars;
  599. }
  600. if (body_size != body_size_check) {
  601. php_error_docref(NULL, E_WARNING, "Error reading font");
  602. efree(font);
  603. php_stream_close(stream);
  604. RETURN_FALSE;
  605. }
  606. font->data = emalloc(body_size);
  607. b = 0;
  608. while (b < body_size && (n = php_stream_read(stream, &font->data[b], body_size - b)) > 0) {
  609. b += n;
  610. }
  611. if (n <= 0) {
  612. efree(font->data);
  613. efree(font);
  614. if (php_stream_eof(stream)) {
  615. php_error_docref(NULL, E_WARNING, "End of file while reading body");
  616. } else {
  617. php_error_docref(NULL, E_WARNING, "Error while reading body");
  618. }
  619. php_stream_close(stream);
  620. RETURN_FALSE;
  621. }
  622. php_stream_close(stream);
  623. ind = zend_list_insert(font, le_gd_font);
  624. /* Adding 5 to the font index so we will never have font indices
  625. * that overlap with the old fonts (with indices 1-5). The first
  626. * list index given out is always 1.
  627. */
  628. RETURN_LONG(Z_RES_HANDLE_P(ind) + 5);
  629. }
  630. /* }}} */
  631. /* {{{ proto bool imagesetstyle(resource im, array styles)
  632. Set the line drawing styles for use with imageline and IMG_COLOR_STYLED. */
  633. PHP_FUNCTION(imagesetstyle)
  634. {
  635. zval *IM, *styles, *item;
  636. gdImagePtr im;
  637. int *stylearr;
  638. int index = 0;
  639. uint32_t num_styles;
  640. if (zend_parse_parameters(ZEND_NUM_ARGS(), "Oa", &IM, gd_image_ce, &styles) == FAILURE) {
  641. RETURN_THROWS();
  642. }
  643. im = php_gd_libgdimageptr_from_zval_p(IM);
  644. num_styles = zend_hash_num_elements(Z_ARRVAL_P(styles));
  645. if (num_styles == 0) {
  646. zend_argument_value_error(2, "cannot be empty");
  647. RETURN_THROWS();
  648. }
  649. /* copy the style values in the stylearr */
  650. stylearr = safe_emalloc(sizeof(int), num_styles, 0);
  651. ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(styles), item) {
  652. stylearr[index++] = zval_get_long(item);
  653. } ZEND_HASH_FOREACH_END();
  654. gdImageSetStyle(im, stylearr, index);
  655. efree(stylearr);
  656. RETURN_TRUE;
  657. }
  658. /* }}} */
  659. /* {{{ proto resource imagecreatetruecolor(int x_size, int y_size)
  660. Create a new true color image */
  661. PHP_FUNCTION(imagecreatetruecolor)
  662. {
  663. zend_long x_size, y_size;
  664. gdImagePtr im;
  665. if (zend_parse_parameters(ZEND_NUM_ARGS(), "ll", &x_size, &y_size) == FAILURE) {
  666. RETURN_THROWS();
  667. }
  668. if (x_size <= 0 || x_size >= INT_MAX) {
  669. zend_argument_value_error(1, "must be greater than 0");
  670. RETURN_THROWS();
  671. }
  672. if (y_size <= 0 || y_size >= INT_MAX) {
  673. zend_argument_value_error(2, "must be greater than 0");
  674. RETURN_THROWS();
  675. }
  676. im = gdImageCreateTrueColor(x_size, y_size);
  677. if (!im) {
  678. RETURN_FALSE;
  679. }
  680. php_gd_assign_libgdimageptr_as_extgdimage(return_value, im);
  681. }
  682. /* }}} */
  683. /* {{{ proto bool imageistruecolor(resource im)
  684. return true if the image uses truecolor */
  685. PHP_FUNCTION(imageistruecolor)
  686. {
  687. zval *IM;
  688. gdImagePtr im;
  689. if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &IM, gd_image_ce) == FAILURE) {
  690. RETURN_THROWS();
  691. }
  692. im = php_gd_libgdimageptr_from_zval_p(IM);
  693. RETURN_BOOL(im->trueColor);
  694. }
  695. /* }}} */
  696. /* {{{ proto void imagetruecolortopalette(resource im, bool ditherFlag, int colorsWanted)
  697. Convert a true color image to a palette based image with a number of colors, optionally using dithering. */
  698. PHP_FUNCTION(imagetruecolortopalette)
  699. {
  700. zval *IM;
  701. zend_bool dither;
  702. zend_long ncolors;
  703. gdImagePtr im;
  704. if (zend_parse_parameters(ZEND_NUM_ARGS(), "Obl", &IM, gd_image_ce, &dither, &ncolors) == FAILURE) {
  705. RETURN_THROWS();
  706. }
  707. im = php_gd_libgdimageptr_from_zval_p(IM);
  708. if (ncolors <= 0 || ZEND_LONG_INT_OVFL(ncolors)) {
  709. zend_argument_value_error(3, "must be greater than 0 and less than %d", INT_MAX);
  710. RETURN_THROWS();
  711. }
  712. if (gdImageTrueColorToPalette(im, dither, (int)ncolors)) {
  713. RETURN_TRUE;
  714. } else {
  715. php_error_docref(NULL, E_WARNING, "Couldn't convert to palette");
  716. RETURN_FALSE;
  717. }
  718. }
  719. /* }}} */
  720. /* {{{ proto void imagepalettetotruecolor(resource im)
  721. Convert a palette based image to a true color image. */
  722. PHP_FUNCTION(imagepalettetotruecolor)
  723. {
  724. zval *IM;
  725. gdImagePtr im;
  726. if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &IM, gd_image_ce) == FAILURE) {
  727. RETURN_THROWS();
  728. }
  729. im = php_gd_libgdimageptr_from_zval_p(IM);
  730. if (gdImagePaletteToTrueColor(im) == 0) {
  731. RETURN_FALSE;
  732. }
  733. RETURN_TRUE;
  734. }
  735. /* }}} */
  736. /* {{{ proto bool imagecolormatch(resource im1, resource im2)
  737. Makes the colors of the palette version of an image more closely match the true color version */
  738. PHP_FUNCTION(imagecolormatch)
  739. {
  740. zval *IM1, *IM2;
  741. gdImagePtr im1, im2;
  742. int result;
  743. if (zend_parse_parameters(ZEND_NUM_ARGS(), "OO", &IM1, gd_image_ce, &IM2, gd_image_ce) == FAILURE) {
  744. RETURN_THROWS();
  745. }
  746. im1 = php_gd_libgdimageptr_from_zval_p(IM1);
  747. im2 = php_gd_libgdimageptr_from_zval_p(IM2);
  748. result = gdImageColorMatch(im1, im2);
  749. switch (result) {
  750. case -1:
  751. php_error_docref(NULL, E_WARNING, "Image1 must be TrueColor" );
  752. RETURN_FALSE;
  753. break;
  754. case -2:
  755. php_error_docref(NULL, E_WARNING, "Image2 must be Palette" );
  756. RETURN_FALSE;
  757. break;
  758. case -3:
  759. php_error_docref(NULL, E_WARNING, "Image1 and Image2 must be the same size" );
  760. RETURN_FALSE;
  761. break;
  762. case -4:
  763. php_error_docref(NULL, E_WARNING, "Image2 must have at least one color" );
  764. RETURN_FALSE;
  765. break;
  766. }
  767. RETURN_TRUE;
  768. }
  769. /* }}} */
  770. /* {{{ proto bool imagesetthickness(resource im, int thickness)
  771. Set line thickness for drawing lines, ellipses, rectangles, polygons etc. */
  772. PHP_FUNCTION(imagesetthickness)
  773. {
  774. zval *IM;
  775. zend_long thick;
  776. gdImagePtr im;
  777. if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ol", &IM, gd_image_ce, &thick) == FAILURE) {
  778. RETURN_THROWS();
  779. }
  780. im = php_gd_libgdimageptr_from_zval_p(IM);
  781. gdImageSetThickness(im, thick);
  782. RETURN_TRUE;
  783. }
  784. /* }}} */
  785. /* {{{ proto bool imagefilledellipse(resource im, int cx, int cy, int w, int h, int color)
  786. Draw an ellipse */
  787. PHP_FUNCTION(imagefilledellipse)
  788. {
  789. zval *IM;
  790. zend_long cx, cy, w, h, color;
  791. gdImagePtr im;
  792. if (zend_parse_parameters(ZEND_NUM_ARGS(), "Olllll", &IM, gd_image_ce, &cx, &cy, &w, &h, &color) == FAILURE) {
  793. RETURN_THROWS();
  794. }
  795. im = php_gd_libgdimageptr_from_zval_p(IM);
  796. gdImageFilledEllipse(im, cx, cy, w, h, color);
  797. RETURN_TRUE;
  798. }
  799. /* }}} */
  800. /* {{{ proto bool imagefilledarc(resource im, int cx, int cy, int w, int h, int s, int e, int col, int style)
  801. Draw a filled partial ellipse */
  802. PHP_FUNCTION(imagefilledarc)
  803. {
  804. zval *IM;
  805. zend_long cx, cy, w, h, ST, E, col, style;
  806. gdImagePtr im;
  807. int e, st;
  808. if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ollllllll", &IM, gd_image_ce, &cx, &cy, &w, &h, &ST, &E, &col, &style) == FAILURE) {
  809. RETURN_THROWS();
  810. }
  811. im = php_gd_libgdimageptr_from_zval_p(IM);
  812. e = E;
  813. if (e < 0) {
  814. e %= 360;
  815. }
  816. st = ST;
  817. if (st < 0) {
  818. st %= 360;
  819. }
  820. gdImageFilledArc(im, cx, cy, w, h, st, e, col, style);
  821. RETURN_TRUE;
  822. }
  823. /* }}} */
  824. /* {{{ proto bool imagealphablending(resource im, bool on)
  825. Turn alpha blending mode on or off for the given image */
  826. PHP_FUNCTION(imagealphablending)
  827. {
  828. zval *IM;
  829. zend_bool blend;
  830. gdImagePtr im;
  831. if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ob", &IM, gd_image_ce, &blend) == FAILURE) {
  832. RETURN_THROWS();
  833. }
  834. im = php_gd_libgdimageptr_from_zval_p(IM);
  835. gdImageAlphaBlending(im, blend);
  836. RETURN_TRUE;
  837. }
  838. /* }}} */
  839. /* {{{ proto bool imagesavealpha(resource im, bool on)
  840. Include alpha channel to a saved image */
  841. PHP_FUNCTION(imagesavealpha)
  842. {
  843. zval *IM;
  844. zend_bool save;
  845. gdImagePtr im;
  846. if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ob", &IM, gd_image_ce, &save) == FAILURE) {
  847. RETURN_THROWS();
  848. }
  849. im = php_gd_libgdimageptr_from_zval_p(IM);
  850. gdImageSaveAlpha(im, save);
  851. RETURN_TRUE;
  852. }
  853. /* }}} */
  854. /* {{{ proto bool imagelayereffect(resource im, int effect)
  855. Set the alpha blending flag to use the bundled libgd layering effects */
  856. PHP_FUNCTION(imagelayereffect)
  857. {
  858. zval *IM;
  859. zend_long effect;
  860. gdImagePtr im;
  861. if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ol", &IM, gd_image_ce, &effect) == FAILURE) {
  862. RETURN_THROWS();
  863. }
  864. im = php_gd_libgdimageptr_from_zval_p(IM);
  865. gdImageAlphaBlending(im, effect);
  866. RETURN_TRUE;
  867. }
  868. /* }}} */
  869. #define CHECK_RGBA_RANGE(component, name, argument_number) \
  870. if (component < 0 || component > gd##name##Max) { \
  871. zend_argument_value_error(argument_number, "must be between 0 and %d (inclusive)", gd##name##Max); \
  872. RETURN_THROWS(); \
  873. }
  874. /* {{{ proto int imagecolorallocatealpha(resource im, int red, int green, int blue, int alpha)
  875. Allocate a color with an alpha level. Works for true color and palette based images */
  876. PHP_FUNCTION(imagecolorallocatealpha)
  877. {
  878. zval *IM;
  879. zend_long red, green, blue, alpha;
  880. gdImagePtr im;
  881. int ct = (-1);
  882. if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ollll", &IM, gd_image_ce, &red, &green, &blue, &alpha) == FAILURE) {
  883. RETURN_THROWS();
  884. }
  885. im = php_gd_libgdimageptr_from_zval_p(IM);
  886. CHECK_RGBA_RANGE(red, Red, 2);
  887. CHECK_RGBA_RANGE(green, Green, 3);
  888. CHECK_RGBA_RANGE(blue, Blue, 4);
  889. CHECK_RGBA_RANGE(alpha, Alpha, 5);
  890. ct = gdImageColorAllocateAlpha(im, red, green, blue, alpha);
  891. if (ct < 0) {
  892. RETURN_FALSE;
  893. }
  894. RETURN_LONG((zend_long)ct);
  895. }
  896. /* }}} */
  897. /* {{{ proto int imagecolorresolvealpha(resource im, int red, int green, int blue, int alpha)
  898. Resolve/Allocate a colour with an alpha level. Works for true colour and palette based images */
  899. PHP_FUNCTION(imagecolorresolvealpha)
  900. {
  901. zval *IM;
  902. zend_long red, green, blue, alpha;
  903. gdImagePtr im;
  904. if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ollll", &IM, gd_image_ce, &red, &green, &blue, &alpha) == FAILURE) {
  905. RETURN_THROWS();
  906. }
  907. im = php_gd_libgdimageptr_from_zval_p(IM);
  908. CHECK_RGBA_RANGE(red, Red, 2);
  909. CHECK_RGBA_RANGE(green, Green, 3);
  910. CHECK_RGBA_RANGE(blue, Blue, 4);
  911. CHECK_RGBA_RANGE(alpha, Alpha, 5);
  912. RETURN_LONG(gdImageColorResolveAlpha(im, red, green, blue, alpha));
  913. }
  914. /* }}} */
  915. /* {{{ proto int imagecolorclosestalpha(resource im, int red, int green, int blue, int alpha)
  916. Find the closest matching colour with alpha transparency */
  917. PHP_FUNCTION(imagecolorclosestalpha)
  918. {
  919. zval *IM;
  920. zend_long red, green, blue, alpha;
  921. gdImagePtr im;
  922. if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ollll", &IM, gd_image_ce, &red, &green, &blue, &alpha) == FAILURE) {
  923. RETURN_THROWS();
  924. }
  925. im = php_gd_libgdimageptr_from_zval_p(IM);
  926. CHECK_RGBA_RANGE(red, Red, 2);
  927. CHECK_RGBA_RANGE(green, Green, 3);
  928. CHECK_RGBA_RANGE(blue, Blue, 4);
  929. CHECK_RGBA_RANGE(alpha, Alpha, 5);
  930. RETURN_LONG(gdImageColorClosestAlpha(im, red, green, blue, alpha));
  931. }
  932. /* }}} */
  933. /* {{{ proto int imagecolorexactalpha(resource im, int red, int green, int blue, int alpha)
  934. Find exact match for colour with transparency */
  935. PHP_FUNCTION(imagecolorexactalpha)
  936. {
  937. zval *IM;
  938. zend_long red, green, blue, alpha;
  939. gdImagePtr im;
  940. if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ollll", &IM, gd_image_ce, &red, &green, &blue, &alpha) == FAILURE) {
  941. RETURN_THROWS();
  942. }
  943. im = php_gd_libgdimageptr_from_zval_p(IM);
  944. CHECK_RGBA_RANGE(red, Red, 2);
  945. CHECK_RGBA_RANGE(green, Green, 3);
  946. CHECK_RGBA_RANGE(blue, Blue, 4);
  947. CHECK_RGBA_RANGE(alpha, Alpha, 5);
  948. RETURN_LONG(gdImageColorExactAlpha(im, red, green, blue, alpha));
  949. }
  950. /* }}} */
  951. /* {{{ proto bool imagecopyresampled(resource dst_im, resource src_im, int dst_x, int dst_y, int src_x, int src_y, int dst_w, int dst_h, int src_w, int src_h)
  952. Copy and resize part of an image using resampling to help ensure clarity */
  953. PHP_FUNCTION(imagecopyresampled)
  954. {
  955. zval *SIM, *DIM;
  956. zend_long SX, SY, SW, SH, DX, DY, DW, DH;
  957. gdImagePtr im_dst, im_src;
  958. int srcH, srcW, dstH, dstW, srcY, srcX, dstY, dstX;
  959. if (zend_parse_parameters(ZEND_NUM_ARGS(), "OOllllllll", &DIM, gd_image_ce, &SIM, gd_image_ce, &DX, &DY, &SX, &SY, &DW, &DH, &SW, &SH) == FAILURE) {
  960. RETURN_THROWS();
  961. }
  962. im_src = php_gd_libgdimageptr_from_zval_p(SIM);
  963. im_dst = php_gd_libgdimageptr_from_zval_p(DIM);
  964. srcX = SX;
  965. srcY = SY;
  966. srcH = SH;
  967. srcW = SW;
  968. dstX = DX;
  969. dstY = DY;
  970. dstH = DH;
  971. dstW = DW;
  972. gdImageCopyResampled(im_dst, im_src, dstX, dstY, srcX, srcY, dstW, dstH, srcW, srcH);
  973. RETURN_TRUE;
  974. }
  975. /* }}} */
  976. #ifdef PHP_WIN32
  977. /* {{{ proto resource imagegrabwindow(int window_handle [, int client_area])
  978. Grab a window or its client area using a windows handle (HWND property in COM instance) */
  979. PHP_FUNCTION(imagegrabwindow)
  980. {
  981. HWND window;
  982. zend_long client_area = 0;
  983. RECT rc = {0};
  984. int Width, Height;
  985. HDC hdc;
  986. HDC memDC;
  987. HBITMAP memBM;
  988. HBITMAP hOld;
  989. zend_long lwindow_handle;
  990. gdImagePtr im = NULL;
  991. if (zend_parse_parameters(ZEND_NUM_ARGS(), "l|l", &lwindow_handle, &client_area) == FAILURE) {
  992. RETURN_THROWS();
  993. }
  994. window = (HWND) lwindow_handle;
  995. if (!IsWindow(window)) {
  996. php_error_docref(NULL, E_NOTICE, "Invalid window handle");
  997. RETURN_FALSE;
  998. }
  999. hdc = GetDC(0);
  1000. if (client_area) {
  1001. GetClientRect(window, &rc);
  1002. Width = rc.right;
  1003. Height = rc.bottom;
  1004. } else {
  1005. GetWindowRect(window, &rc);
  1006. Width = rc.right - rc.left;
  1007. Height = rc.bottom - rc.top;
  1008. }
  1009. Width = (Width/4)*4;
  1010. memDC = CreateCompatibleDC(hdc);
  1011. memBM = CreateCompatibleBitmap(hdc, Width, Height);
  1012. hOld = (HBITMAP) SelectObject (memDC, memBM);
  1013. PrintWindow(window, memDC, (UINT) client_area);
  1014. im = gdImageCreateTrueColor(Width, Height);
  1015. if (im) {
  1016. int x,y;
  1017. for (y=0; y <= Height; y++) {
  1018. for (x=0; x <= Width; x++) {
  1019. int c = GetPixel(memDC, x,y);
  1020. gdImageSetPixel(im, x, y, gdTrueColor(GetRValue(c), GetGValue(c), GetBValue(c)));
  1021. }
  1022. }
  1023. }
  1024. SelectObject(memDC,hOld);
  1025. DeleteObject(memBM);
  1026. DeleteDC(memDC);
  1027. ReleaseDC( 0, hdc );
  1028. if (!im) {
  1029. RETURN_FALSE;
  1030. }
  1031. php_gd_assign_libgdimageptr_as_extgdimage(return_value, im);
  1032. }
  1033. /* }}} */
  1034. /* {{{ proto resource imagegrabscreen()
  1035. Grab a screenshot */
  1036. PHP_FUNCTION(imagegrabscreen)
  1037. {
  1038. HWND window = GetDesktopWindow();
  1039. RECT rc = {0};
  1040. int Width, Height;
  1041. HDC hdc;
  1042. HDC memDC;
  1043. HBITMAP memBM;
  1044. HBITMAP hOld;
  1045. gdImagePtr im;
  1046. hdc = GetDC(0);
  1047. if (zend_parse_parameters_none() == FAILURE) {
  1048. RETURN_THROWS();
  1049. }
  1050. if (!hdc) {
  1051. RETURN_FALSE;
  1052. }
  1053. GetWindowRect(window, &rc);
  1054. Width = rc.right - rc.left;
  1055. Height = rc.bottom - rc.top;
  1056. Width = (Width/4)*4;
  1057. memDC = CreateCompatibleDC(hdc);
  1058. memBM = CreateCompatibleBitmap(hdc, Width, Height);
  1059. hOld = (HBITMAP) SelectObject (memDC, memBM);
  1060. BitBlt( memDC, 0, 0, Width, Height , hdc, rc.left, rc.top , SRCCOPY );
  1061. im = gdImageCreateTrueColor(Width, Height);
  1062. if (im) {
  1063. int x,y;
  1064. for (y=0; y <= Height; y++) {
  1065. for (x=0; x <= Width; x++) {
  1066. int c = GetPixel(memDC, x,y);
  1067. gdImageSetPixel(im, x, y, gdTrueColor(GetRValue(c), GetGValue(c), GetBValue(c)));
  1068. }
  1069. }
  1070. }
  1071. SelectObject(memDC,hOld);
  1072. DeleteObject(memBM);
  1073. DeleteDC(memDC);
  1074. ReleaseDC( 0, hdc );
  1075. if (!im) {
  1076. RETURN_FALSE;
  1077. }
  1078. php_gd_assign_libgdimageptr_as_extgdimage(return_value, im);
  1079. }
  1080. /* }}} */
  1081. #endif /* PHP_WIN32 */
  1082. /* {{{ proto resource imagerotate(resource src_im, float angle, int bgdcolor [, int ignoretransparent])
  1083. Rotate an image using a custom angle */
  1084. PHP_FUNCTION(imagerotate)
  1085. {
  1086. zval *SIM;
  1087. gdImagePtr im_dst, im_src;
  1088. double degrees;
  1089. zend_long color;
  1090. zend_long ignoretransparent = 0;
  1091. if (zend_parse_parameters(ZEND_NUM_ARGS(), "Odl|l", &SIM, gd_image_ce, &degrees, &color, &ignoretransparent) == FAILURE) {
  1092. RETURN_THROWS();
  1093. }
  1094. im_src = php_gd_libgdimageptr_from_zval_p(SIM);
  1095. im_dst = gdImageRotateInterpolated(im_src, (const float)degrees, color);
  1096. if (im_dst == NULL) {
  1097. RETURN_FALSE;
  1098. }
  1099. php_gd_assign_libgdimageptr_as_extgdimage(return_value, im_dst);
  1100. }
  1101. /* }}} */
  1102. /* {{{ proto bool imagesettile(resource image, resource tile)
  1103. Set the tile image to $tile when filling $image with the "IMG_COLOR_TILED" color */
  1104. PHP_FUNCTION(imagesettile)
  1105. {
  1106. zval *IM, *TILE;
  1107. gdImagePtr im, tile;
  1108. if (zend_parse_parameters(ZEND_NUM_ARGS(), "OO", &IM, gd_image_ce, &TILE, gd_image_ce) == FAILURE) {
  1109. RETURN_THROWS();
  1110. }
  1111. im = php_gd_libgdimageptr_from_zval_p(IM);
  1112. tile = php_gd_libgdimageptr_from_zval_p(TILE);
  1113. gdImageSetTile(im, tile);
  1114. RETURN_TRUE;
  1115. }
  1116. /* }}} */
  1117. /* {{{ proto bool imagesetbrush(resource image, resource brush)
  1118. Set the brush image to $brush when filling $image with the "IMG_COLOR_BRUSHED" color */
  1119. PHP_FUNCTION(imagesetbrush)
  1120. {
  1121. zval *IM, *TILE;
  1122. gdImagePtr im, tile;
  1123. if (zend_parse_parameters(ZEND_NUM_ARGS(), "OO", &IM, gd_image_ce, &TILE, gd_image_ce) == FAILURE) {
  1124. RETURN_THROWS();
  1125. }
  1126. im = php_gd_libgdimageptr_from_zval_p(IM);
  1127. tile = php_gd_libgdimageptr_from_zval_p(TILE);
  1128. gdImageSetBrush(im, tile);
  1129. RETURN_TRUE;
  1130. }
  1131. /* }}} */
  1132. /* {{{ proto resource imagecreate(int x_size, int y_size)
  1133. Create a new image */
  1134. PHP_FUNCTION(imagecreate)
  1135. {
  1136. zend_long x_size, y_size;
  1137. gdImagePtr im;
  1138. if (zend_parse_parameters(ZEND_NUM_ARGS(), "ll", &x_size, &y_size) == FAILURE) {
  1139. RETURN_THROWS();
  1140. }
  1141. if (x_size <= 0 || x_size >= INT_MAX) {
  1142. zend_argument_value_error(1, "must be greater than 0");
  1143. RETURN_THROWS();
  1144. }
  1145. if (y_size <= 0 || y_size >= INT_MAX) {
  1146. zend_argument_value_error(2, "must be greater than 0");
  1147. RETURN_THROWS();
  1148. }
  1149. im = gdImageCreate(x_size, y_size);
  1150. if (!im) {
  1151. RETURN_FALSE;
  1152. }
  1153. php_gd_assign_libgdimageptr_as_extgdimage(return_value, im);
  1154. }
  1155. /* }}} */
  1156. /* {{{ proto int imagetypes(void)
  1157. Return the types of images supported in a bitfield - 1=GIF, 2=JPEG, 4=PNG, 8=WBMP, 16=XPM */
  1158. PHP_FUNCTION(imagetypes)
  1159. {
  1160. int ret = 0;
  1161. ret = PHP_IMG_GIF;
  1162. #ifdef HAVE_GD_JPG
  1163. ret |= PHP_IMG_JPG;
  1164. #endif
  1165. #ifdef HAVE_GD_PNG
  1166. ret |= PHP_IMG_PNG;
  1167. #endif
  1168. ret |= PHP_IMG_WBMP;
  1169. #if defined(HAVE_GD_XPM)
  1170. ret |= PHP_IMG_XPM;
  1171. #endif
  1172. #ifdef HAVE_GD_WEBP
  1173. ret |= PHP_IMG_WEBP;
  1174. #endif
  1175. #ifdef HAVE_GD_BMP
  1176. ret |= PHP_IMG_BMP;
  1177. #endif
  1178. #ifdef HAVE_GD_TGA
  1179. ret |= PHP_IMG_TGA;
  1180. #endif
  1181. if (zend_parse_parameters_none() == FAILURE) {
  1182. RETURN_THROWS();
  1183. }
  1184. RETURN_LONG(ret);
  1185. }
  1186. /* }}} */
  1187. /* {{{ _php_ctx_getmbi
  1188. */
  1189. static int _php_ctx_getmbi(gdIOCtx *ctx)
  1190. {
  1191. int i, mbi = 0;
  1192. do {
  1193. i = (ctx->getC)(ctx);
  1194. if (i < 0) {
  1195. return -1;
  1196. }
  1197. mbi = (mbi << 7) | (i & 0x7f);
  1198. } while (i & 0x80);
  1199. return mbi;
  1200. }
  1201. /* }}} */
  1202. /* {{{ _php_image_type
  1203. */
  1204. static const char php_sig_gd2[3] = {'g', 'd', '2'};
  1205. static int _php_image_type (char data[12])
  1206. {
  1207. /* Based on ext/standard/image.c */
  1208. if (data == NULL) {
  1209. return -1;
  1210. }
  1211. if (!memcmp(data, php_sig_gd2, sizeof(php_sig_gd2))) {
  1212. return PHP_GDIMG_TYPE_GD2;
  1213. } else if (!memcmp(data, php_sig_jpg, sizeof(php_sig_jpg))) {
  1214. return PHP_GDIMG_TYPE_JPG;
  1215. } else if (!memcmp(data, php_sig_png, sizeof(php_sig_png))) {
  1216. return PHP_GDIMG_TYPE_PNG;
  1217. } else if (!memcmp(data, php_sig_gif, sizeof(php_sig_gif))) {
  1218. return PHP_GDIMG_TYPE_GIF;
  1219. } else if (!memcmp(data, php_sig_bmp, sizeof(php_sig_bmp))) {
  1220. return PHP_GDIMG_TYPE_BMP;
  1221. } else if(!memcmp(data, php_sig_riff, sizeof(php_sig_riff)) && !memcmp(data + sizeof(php_sig_riff) + sizeof(uint32_t), php_sig_webp, sizeof(php_sig_webp))) {
  1222. return PHP_GDIMG_TYPE_WEBP;
  1223. }
  1224. else {
  1225. gdIOCtx *io_ctx;
  1226. io_ctx = gdNewDynamicCtxEx(8, data, 0);
  1227. if (io_ctx) {
  1228. if (_php_ctx_getmbi(io_ctx) == 0 && _php_ctx_getmbi(io_ctx) >= 0) {
  1229. io_ctx->gd_free(io_ctx);
  1230. return PHP_GDIMG_TYPE_WBM;
  1231. } else {
  1232. io_ctx->gd_free(io_ctx);
  1233. }
  1234. }
  1235. }
  1236. return -1;
  1237. }
  1238. /* }}} */
  1239. /* {{{ _php_image_create_from_string
  1240. */
  1241. gdImagePtr _php_image_create_from_string(zend_string *data, char *tn, gdImagePtr (*ioctx_func_p)())
  1242. {
  1243. gdImagePtr im;
  1244. gdIOCtx *io_ctx;
  1245. io_ctx = gdNewDynamicCtxEx(ZSTR_LEN(data), ZSTR_VAL(data), 0);
  1246. if (!io_ctx) {
  1247. return NULL;
  1248. }
  1249. im = (*ioctx_func_p)(io_ctx);
  1250. if (!im) {
  1251. php_error_docref(NULL, E_WARNING, "Passed data is not in '%s' format", tn);
  1252. io_ctx->gd_free(io_ctx);
  1253. return NULL;
  1254. }
  1255. io_ctx->gd_free(io_ctx);
  1256. return im;
  1257. }
  1258. /* }}} */
  1259. /* {{{ proto resource imagecreatefromstring(string image)
  1260. Create a new image from the image stream in the string */
  1261. PHP_FUNCTION(imagecreatefromstring)
  1262. {
  1263. zend_string *data;
  1264. gdImagePtr im;
  1265. int imtype;
  1266. char sig[12];
  1267. if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &data) == FAILURE) {
  1268. RETURN_THROWS();
  1269. }
  1270. if (ZSTR_LEN(data) < sizeof(sig)) {
  1271. php_error_docref(NULL, E_WARNING, "Empty string or invalid image");
  1272. RETURN_FALSE;
  1273. }
  1274. memcpy(sig, ZSTR_VAL(data), sizeof(sig));
  1275. imtype = _php_image_type(sig);
  1276. switch (imtype) {
  1277. case PHP_GDIMG_TYPE_JPG:
  1278. #ifdef HAVE_GD_JPG
  1279. im = _php_image_create_from_string(data, "JPEG", gdImageCreateFromJpegCtx);
  1280. #else
  1281. php_error_docref(NULL, E_WARNING, "No JPEG support in this PHP build");
  1282. RETURN_FALSE;
  1283. #endif
  1284. break;
  1285. case PHP_GDIMG_TYPE_PNG:
  1286. #ifdef HAVE_GD_PNG
  1287. im = _php_image_create_from_string(data, "PNG", gdImageCreateFromPngCtx);
  1288. #else
  1289. php_error_docref(NULL, E_WARNING, "No PNG support in this PHP build");
  1290. RETURN_FALSE;
  1291. #endif
  1292. break;
  1293. case PHP_GDIMG_TYPE_GIF:
  1294. im = _php_image_create_from_string(data, "GIF", gdImageCreateFromGifCtx);
  1295. break;
  1296. case PHP_GDIMG_TYPE_WBM:
  1297. im = _php_image_create_from_string(data, "WBMP", gdImageCreateFromWBMPCtx);
  1298. break;
  1299. case PHP_GDIMG_TYPE_GD2:
  1300. im = _php_image_create_from_string(data, "GD2", gdImageCreateFromGd2Ctx);
  1301. break;
  1302. case PHP_GDIMG_TYPE_BMP:
  1303. im = _php_image_create_from_string(data, "BMP", gdImageCreateFromBmpCtx);
  1304. break;
  1305. case PHP_GDIMG_TYPE_WEBP:
  1306. #ifdef HAVE_GD_WEBP
  1307. im = _php_image_create_from_string(data, "WEBP", gdImageCreateFromWebpCtx);
  1308. break;
  1309. #else
  1310. php_error_docref(NULL, E_WARNING, "No WEBP support in this PHP build");
  1311. RETURN_FALSE;
  1312. #endif
  1313. default:
  1314. php_error_docref(NULL, E_WARNING, "Data is not in a recognized format");
  1315. RETURN_FALSE;
  1316. }
  1317. if (!im) {
  1318. php_error_docref(NULL, E_WARNING, "Couldn't create GD Image Stream out of Data");
  1319. RETURN_FALSE;
  1320. }
  1321. php_gd_assign_libgdimageptr_as_extgdimage(return_value, im);
  1322. }
  1323. /* }}} */
  1324. /* {{{ _php_image_create_from
  1325. */
  1326. static void _php_image_create_from(INTERNAL_FUNCTION_PARAMETERS, int image_type, char *tn, gdImagePtr (*func_p)(), gdImagePtr (*ioctx_func_p)())
  1327. {
  1328. char *file;
  1329. size_t file_len;
  1330. zend_long srcx, srcy, width, height;
  1331. gdImagePtr im = NULL;
  1332. php_stream *stream;
  1333. FILE * fp = NULL;
  1334. #ifdef HAVE_GD_JPG
  1335. long ignore_warning;
  1336. #endif
  1337. if (image_type == PHP_GDIMG_TYPE_GD2PART) {
  1338. if (zend_parse_parameters(ZEND_NUM_ARGS(), "pllll", &file, &file_len, &srcx, &srcy, &width, &height) == FAILURE) {
  1339. RETURN_THROWS();
  1340. }
  1341. if (width < 1) {
  1342. zend_argument_value_error(4, "must be greater than or equal to 1");
  1343. RETURN_THROWS();
  1344. }
  1345. if (height < 1) {
  1346. zend_argument_value_error(5, "must be greater than or equal to 1");
  1347. RETURN_THROWS();
  1348. }
  1349. } else {
  1350. if (zend_parse_parameters(ZEND_NUM_ARGS(), "p", &file, &file_len) == FAILURE) {
  1351. RETURN_THROWS();
  1352. }
  1353. }
  1354. stream = php_stream_open_wrapper(file, "rb", REPORT_ERRORS|IGNORE_PATH|IGNORE_URL_WIN, NULL);
  1355. if (stream == NULL) {
  1356. RETURN_FALSE;
  1357. }
  1358. /* try and avoid allocating a FILE* if the stream is not naturally a FILE* */
  1359. if (php_stream_is(stream, PHP_STREAM_IS_STDIO)) {
  1360. if (FAILURE == php_stream_cast(stream, PHP_STREAM_AS_STDIO, (void**)&fp, REPORT_ERRORS)) {
  1361. goto out_err;
  1362. }
  1363. } else if (ioctx_func_p) {
  1364. /* we can create an io context */
  1365. gdIOCtx* io_ctx;
  1366. zend_string *buff;
  1367. char *pstr;
  1368. buff = php_stream_copy_to_mem(stream, PHP_STREAM_COPY_ALL, 0);
  1369. if (!buff) {
  1370. php_error_docref(NULL, E_WARNING,"Cannot read image data");
  1371. goto out_err;
  1372. }
  1373. /* needs to be malloc (persistent) - GD will free() it later */
  1374. pstr = pestrndup(ZSTR_VAL(buff), ZSTR_LEN(buff), 1);
  1375. io_ctx = gdNewDynamicCtxEx(ZSTR_LEN(buff), pstr, 0);
  1376. if (!io_ctx) {
  1377. pefree(pstr, 1);
  1378. zend_string_release_ex(buff, 0);
  1379. php_error_docref(NULL, E_WARNING,"Cannot allocate GD IO context");
  1380. goto out_err;
  1381. }
  1382. if (image_type == PHP_GDIMG_TYPE_GD2PART) {
  1383. im = (*ioctx_func_p)(io_ctx, srcx, srcy, width, height);
  1384. } else {
  1385. im = (*ioctx_func_p)(io_ctx);
  1386. }
  1387. io_ctx->gd_free(io_ctx);
  1388. pefree(pstr, 1);
  1389. zend_string_release_ex(buff, 0);
  1390. }
  1391. else if (php_stream_can_cast(stream, PHP_STREAM_AS_STDIO)) {
  1392. /* try and force the stream to be FILE* */
  1393. if (FAILURE == php_stream_cast(stream, PHP_STREAM_AS_STDIO | PHP_STREAM_CAST_TRY_HARD, (void **) &fp, REPORT_ERRORS)) {
  1394. goto out_err;
  1395. }
  1396. }
  1397. if (!im && fp) {
  1398. switch (image_type) {
  1399. case PHP_GDIMG_TYPE_GD2PART:
  1400. im = (*func_p)(fp, srcx, srcy, width, height);
  1401. break;
  1402. #if defined(HAVE_GD_XPM)
  1403. case PHP_GDIMG_TYPE_XPM:
  1404. im = gdImageCreateFromXpm(file);
  1405. break;
  1406. #endif
  1407. #ifdef HAVE_GD_JPG
  1408. case PHP_GDIMG_TYPE_JPG:
  1409. ignore_warning = INI_INT("gd.jpeg_ignore_warning");
  1410. im = gdImageCreateFromJpegEx(fp, ignore_warning);
  1411. break;
  1412. #endif
  1413. default:
  1414. im = (*func_p)(fp);
  1415. break;
  1416. }
  1417. fflush(fp);
  1418. }
  1419. /* register_im: */
  1420. if (im) {
  1421. php_stream_close(stream);
  1422. php_gd_assign_libgdimageptr_as_extgdimage(return_value, im);
  1423. return;
  1424. }
  1425. php_error_docref(NULL, E_WARNING, "'%s' is not a valid %s file", file, tn);
  1426. out_err:
  1427. php_stream_close(stream);
  1428. RETURN_FALSE;
  1429. }
  1430. /* }}} */
  1431. /* {{{ proto resource imagecreatefromgif(string filename)
  1432. Create a new image from GIF file or URL */
  1433. PHP_FUNCTION(imagecreatefromgif)
  1434. {
  1435. _php_image_create_from(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_GIF, "GIF", gdImageCreateFromGif, gdImageCreateFromGifCtx);
  1436. }
  1437. /* }}} */
  1438. #ifdef HAVE_GD_JPG
  1439. /* {{{ proto resource imagecreatefromjpeg(string filename)
  1440. Create a new image from JPEG file or URL */
  1441. PHP_FUNCTION(imagecreatefromjpeg)
  1442. {
  1443. _php_image_create_from(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_JPG, "JPEG", gdImageCreateFromJpeg, gdImageCreateFromJpegCtx);
  1444. }
  1445. /* }}} */
  1446. #endif /* HAVE_GD_JPG */
  1447. #ifdef HAVE_GD_PNG
  1448. /* {{{ proto resource imagecreatefrompng(string filename)
  1449. Create a new image from PNG file or URL */
  1450. PHP_FUNCTION(imagecreatefrompng)
  1451. {
  1452. _php_image_create_from(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_PNG, "PNG", gdImageCreateFromPng, gdImageCreateFromPngCtx);
  1453. }
  1454. /* }}} */
  1455. #endif /* HAVE_GD_PNG */
  1456. #ifdef HAVE_GD_WEBP
  1457. /* {{{ proto resource imagecreatefromwebp(string filename)
  1458. Create a new image from WEBP file or URL */
  1459. PHP_FUNCTION(imagecreatefromwebp)
  1460. {
  1461. _php_image_create_from(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_WEBP, "WEBP", gdImageCreateFromWebp, gdImageCreateFromWebpCtx);
  1462. }
  1463. /* }}} */
  1464. #endif /* HAVE_GD_WEBP */
  1465. /* {{{ proto resource imagecreatefromxbm(string filename)
  1466. Create a new image from XBM file or URL */
  1467. PHP_FUNCTION(imagecreatefromxbm)
  1468. {
  1469. _php_image_create_from(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_XBM, "XBM", gdImageCreateFromXbm, NULL);
  1470. }
  1471. /* }}} */
  1472. #if defined(HAVE_GD_XPM)
  1473. /* {{{ proto resource imagecreatefromxpm(string filename)
  1474. Create a new image from XPM file or URL */
  1475. PHP_FUNCTION(imagecreatefromxpm)
  1476. {
  1477. _php_image_create_from(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_XPM, "XPM", gdImageCreateFromXpm, NULL);
  1478. }
  1479. /* }}} */
  1480. #endif
  1481. /* {{{ proto resource imagecreatefromwbmp(string filename)
  1482. Create a new image from WBMP file or URL */
  1483. PHP_FUNCTION(imagecreatefromwbmp)
  1484. {
  1485. _php_image_create_from(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_WBM, "WBMP", gdImageCreateFromWBMP, gdImageCreateFromWBMPCtx);
  1486. }
  1487. /* }}} */
  1488. /* {{{ proto resource imagecreatefromgd(string filename)
  1489. Create a new image from GD file or URL */
  1490. PHP_FUNCTION(imagecreatefromgd)
  1491. {
  1492. _php_image_create_from(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_GD, "GD", gdImageCreateFromGd, gdImageCreateFromGdCtx);
  1493. }
  1494. /* }}} */
  1495. /* {{{ proto resource imagecreatefromgd2(string filename)
  1496. Create a new image from GD2 file or URL */
  1497. PHP_FUNCTION(imagecreatefromgd2)
  1498. {
  1499. _php_image_create_from(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_GD2, "GD2", gdImageCreateFromGd2, gdImageCreateFromGd2Ctx);
  1500. }
  1501. /* }}} */
  1502. /* {{{ proto resource imagecreatefromgd2part(string filename, int srcX, int srcY, int width, int height)
  1503. Create a new image from a given part of GD2 file or URL */
  1504. PHP_FUNCTION(imagecreatefromgd2part)
  1505. {
  1506. _php_image_create_from(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_GD2PART, "GD2", gdImageCreateFromGd2Part, gdImageCreateFromGd2PartCtx);
  1507. }
  1508. /* }}} */
  1509. #if defined(HAVE_GD_BMP)
  1510. /* {{{ proto resource imagecreatefrombmp(string filename)
  1511. Create a new image from BMP file or URL */
  1512. PHP_FUNCTION(imagecreatefrombmp)
  1513. {
  1514. _php_image_create_from(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_BMP, "BMP", gdImageCreateFromBmp, gdImageCreateFromBmpCtx);
  1515. }
  1516. /* }}} */
  1517. #endif
  1518. #if defined(HAVE_GD_TGA)
  1519. /* {{{ proto resource imagecreatefromtga(string filename)
  1520. Create a new image from TGA file or URL */
  1521. PHP_FUNCTION(imagecreatefromtga)
  1522. {
  1523. _php_image_create_from(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_TGA, "TGA", gdImageCreateFromTga, gdImageCreateFromTgaCtx);
  1524. }
  1525. /* }}} */
  1526. #endif
  1527. /* {{{ _php_image_output
  1528. */
  1529. static void _php_image_output(INTERNAL_FUNCTION_PARAMETERS, int image_type, char *tn, void (*func_p)())
  1530. {
  1531. zval *imgind;
  1532. char *file = NULL;
  1533. zend_long quality = 0, type = 0;
  1534. gdImagePtr im;
  1535. char *fn = NULL;
  1536. FILE *fp;
  1537. size_t file_len = 0;
  1538. int argc = ZEND_NUM_ARGS();
  1539. int q = -1, t = 1;
  1540. /* The quality parameter for gd2 stands for chunk size */
  1541. if (zend_parse_parameters(argc, "O|pll", &imgind, gd_image_ce, &file, &file_len, &quality, &type) == FAILURE) {
  1542. RETURN_THROWS();
  1543. }
  1544. im = php_gd_libgdimageptr_from_zval_p(imgind);
  1545. if (argc > 1) {
  1546. fn = file;
  1547. if (argc >= 3) {
  1548. q = quality;
  1549. if (argc == 4) {
  1550. t = type;
  1551. }
  1552. }
  1553. }
  1554. if (argc >= 2 && file_len) {
  1555. PHP_GD_CHECK_OPEN_BASEDIR(fn, "Invalid filename");
  1556. fp = VCWD_FOPEN(fn, "wb");
  1557. if (!fp) {
  1558. php_error_docref(NULL, E_WARNING, "Unable to open '%s' for writing", fn);
  1559. RETURN_FALSE;
  1560. }
  1561. switch (image_type) {
  1562. case PHP_GDIMG_TYPE_GD:
  1563. (*func_p)(im, fp);
  1564. break;
  1565. case PHP_GDIMG_TYPE_GD2:
  1566. if (q == -1) {
  1567. q = 128;
  1568. }
  1569. (*func_p)(im, fp, q, t);
  1570. break;
  1571. default:
  1572. ZEND_ASSERT(0);
  1573. }
  1574. fflush(fp);
  1575. fclose(fp);
  1576. } else {
  1577. int b;
  1578. FILE *tmp;
  1579. char buf[4096];
  1580. zend_string *path;
  1581. tmp = php_open_temporary_file(NULL, NULL, &path);
  1582. if (tmp == NULL) {
  1583. php_error_docref(NULL, E_WARNING, "Unable to open temporary file");
  1584. RETURN_FALSE;
  1585. }
  1586. switch (image_type) {
  1587. case PHP_GDIMG_TYPE_GD:
  1588. (*func_p)(im, tmp);
  1589. break;
  1590. case PHP_GDIMG_TYPE_GD2:
  1591. if (q == -1) {
  1592. q = 128;
  1593. }
  1594. (*func_p)(im, tmp, q, t);
  1595. break;
  1596. default:
  1597. ZEND_ASSERT(0);
  1598. }
  1599. fseek(tmp, 0, SEEK_SET);
  1600. while ((b = fread(buf, 1, sizeof(buf), tmp)) > 0) {
  1601. php_write(buf, b);
  1602. }
  1603. fclose(tmp);
  1604. VCWD_UNLINK((const char *)ZSTR_VAL(path)); /* make sure that the temporary file is removed */
  1605. zend_string_release_ex(path, 0);
  1606. }
  1607. RETURN_TRUE;
  1608. }
  1609. /* }}} */
  1610. /* {{{ proto int imagexbm(int im, string filename [, int foreground])
  1611. Output XBM image to browser or file */
  1612. PHP_FUNCTION(imagexbm)
  1613. {
  1614. _php_image_output_ctx(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_XBM, "XBM", gdImageXbmCtx);
  1615. }
  1616. /* }}} */
  1617. /* {{{ proto bool imagegif(resource im [, mixed to])
  1618. Output GIF image to browser or file */
  1619. PHP_FUNCTION(imagegif)
  1620. {
  1621. _php_image_output_ctx(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_GIF, "GIF", gdImageGifCtx);
  1622. }
  1623. /* }}} */
  1624. #ifdef HAVE_GD_PNG
  1625. /* {{{ proto bool imagepng(resource im [, mixed to])
  1626. Output PNG image to browser or file */
  1627. PHP_FUNCTION(imagepng)
  1628. {
  1629. _php_image_output_ctx(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_PNG, "PNG", gdImagePngCtxEx);
  1630. }
  1631. /* }}} */
  1632. #endif /* HAVE_GD_PNG */
  1633. #ifdef HAVE_GD_WEBP
  1634. /* {{{ proto bool imagewebp(resource im [, mixed to[, int quality]] )
  1635. Output WEBP image to browser or file */
  1636. PHP_FUNCTION(imagewebp)
  1637. {
  1638. _php_image_output_ctx(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_WEBP, "WEBP", gdImageWebpCtx);
  1639. }
  1640. /* }}} */
  1641. #endif /* HAVE_GD_WEBP */
  1642. #ifdef HAVE_GD_JPG
  1643. /* {{{ proto bool imagejpeg(resource im [, mixed to [, int quality]])
  1644. Output JPEG image to browser or file */
  1645. PHP_FUNCTION(imagejpeg)
  1646. {
  1647. _php_image_output_ctx(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_JPG, "JPEG", gdImageJpegCtx);
  1648. }
  1649. /* }}} */
  1650. #endif /* HAVE_GD_JPG */
  1651. /* {{{ proto bool imagewbmp(resource im [, mixed to [, int foreground]])
  1652. Output WBMP image to browser or file */
  1653. PHP_FUNCTION(imagewbmp)
  1654. {
  1655. _php_image_output_ctx(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_WBM, "WBMP", gdImageWBMPCtx);
  1656. }
  1657. /* }}} */
  1658. /* {{{ proto bool imagegd(resource im [, mixed to])
  1659. Output GD image to browser or file */
  1660. PHP_FUNCTION(imagegd)
  1661. {
  1662. _php_image_output(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_GD, "GD", gdImageGd);
  1663. }
  1664. /* }}} */
  1665. /* {{{ proto bool imagegd2(resource im [, mixed to [, int chunk_size [, int type]]])
  1666. Output GD2 image to browser or file */
  1667. PHP_FUNCTION(imagegd2)
  1668. {
  1669. _php_image_output(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_GD2, "GD2", gdImageGd2);
  1670. }
  1671. /* }}} */
  1672. #ifdef HAVE_GD_BMP
  1673. /* {{{ proto bool imagebmp(resource im [, mixed to [, bool compressed]])
  1674. Output BMP image to browser or file */
  1675. PHP_FUNCTION(imagebmp)
  1676. {
  1677. _php_image_output_ctx(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_BMP, "BMP", gdImageBmpCtx);
  1678. }
  1679. /* }}} */
  1680. #endif
  1681. /* {{{ proto bool imagedestroy(resource im)
  1682. Destroy an image - No effect as of PHP 8.0 */
  1683. PHP_FUNCTION(imagedestroy)
  1684. {
  1685. /* This function used to free the resource, as resources are no longer used, it does nothing */
  1686. zval *IM;
  1687. if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &IM, gd_image_ce) == FAILURE) {
  1688. RETURN_THROWS();
  1689. }
  1690. RETURN_TRUE;
  1691. }
  1692. /* }}} */
  1693. /* {{{ proto int imagecolorallocate(resource im, int red, int green, int blue)
  1694. Allocate a color for an image */
  1695. PHP_FUNCTION(imagecolorallocate)
  1696. {
  1697. zval *IM;
  1698. zend_long red, green, blue;
  1699. gdImagePtr im;
  1700. int ct = (-1);
  1701. if (zend_parse_parameters(ZEND_NUM_ARGS(), "Olll", &IM, gd_image_ce, &red, &green, &blue) == FAILURE) {
  1702. RETURN_THROWS();
  1703. }
  1704. im = php_gd_libgdimageptr_from_zval_p(IM);
  1705. CHECK_RGBA_RANGE(red, Red, 2);
  1706. CHECK_RGBA_RANGE(green, Green, 3);
  1707. CHECK_RGBA_RANGE(blue, Blue, 4);
  1708. ct = gdImageColorAllocate(im, red, green, blue);
  1709. if (ct < 0) {
  1710. RETURN_FALSE;
  1711. }
  1712. RETURN_LONG(ct);
  1713. }
  1714. /* }}} */
  1715. /* {{{ proto void imagepalettecopy(resource dst, resource src)
  1716. Copy the palette from the src image onto the dst image */
  1717. PHP_FUNCTION(imagepalettecopy)
  1718. {
  1719. zval *dstim, *srcim;
  1720. gdImagePtr dst, src;
  1721. if (zend_parse_parameters(ZEND_NUM_ARGS(), "OO", &dstim, gd_image_ce, &srcim, gd_image_ce) == FAILURE) {
  1722. RETURN_THROWS();
  1723. }
  1724. src = php_gd_libgdimageptr_from_zval_p(srcim);
  1725. dst = php_gd_libgdimageptr_from_zval_p(dstim);
  1726. gdImagePaletteCopy(dst, src);
  1727. }
  1728. /* }}} */
  1729. /* {{{ proto int imagecolorat(resource im, int x, int y)
  1730. Get the index of the color of a pixel */
  1731. PHP_FUNCTION(imagecolorat)
  1732. {
  1733. zval *IM;
  1734. zend_long x, y;
  1735. gdImagePtr im;
  1736. ZEND_PARSE_PARAMETERS_START(3, 3)
  1737. Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
  1738. Z_PARAM_LONG(x)
  1739. Z_PARAM_LONG(y)
  1740. ZEND_PARSE_PARAMETERS_END();
  1741. im = php_gd_libgdimageptr_from_zval_p(IM);
  1742. if (gdImageTrueColor(im)) {
  1743. if (im->tpixels && gdImageBoundsSafe(im, x, y)) {
  1744. RETURN_LONG(gdImageTrueColorPixel(im, x, y));
  1745. } else {
  1746. php_error_docref(NULL, E_NOTICE, "" ZEND_LONG_FMT "," ZEND_LONG_FMT " is out of bounds", x, y);
  1747. RETURN_FALSE;
  1748. }
  1749. } else {
  1750. if (im->pixels && gdImageBoundsSafe(im, x, y)) {
  1751. RETURN_LONG(im->pixels[y][x]);
  1752. } else {
  1753. php_error_docref(NULL, E_NOTICE, "" ZEND_LONG_FMT "," ZEND_LONG_FMT " is out of bounds", x, y);
  1754. RETURN_FALSE;
  1755. }
  1756. }
  1757. }
  1758. /* }}} */
  1759. /* {{{ proto int imagecolorclosest(resource im, int red, int green, int blue)
  1760. Get the index of the closest color to the specified color */
  1761. PHP_FUNCTION(imagecolorclosest)
  1762. {
  1763. zval *IM;
  1764. zend_long red, green, blue;
  1765. gdImagePtr im;
  1766. if (zend_parse_parameters(ZEND_NUM_ARGS(), "Olll", &IM, gd_image_ce, &red, &green, &blue) == FAILURE) {
  1767. RETURN_THROWS();
  1768. }
  1769. im = php_gd_libgdimageptr_from_zval_p(IM);
  1770. CHECK_RGBA_RANGE(red, Red, 2);
  1771. CHECK_RGBA_RANGE(green, Green, 3);
  1772. CHECK_RGBA_RANGE(blue, Blue, 4);
  1773. RETURN_LONG(gdImageColorClosest(im, red, green, blue));
  1774. }
  1775. /* }}} */
  1776. /* {{{ proto int imagecolorclosesthwb(resource im, int red, int green, int blue)
  1777. Get the index of the color which has the hue, white and blackness nearest to the given color */
  1778. PHP_FUNCTION(imagecolorclosesthwb)
  1779. {
  1780. zval *IM;
  1781. zend_long red, green, blue;
  1782. gdImagePtr im;
  1783. if (zend_parse_parameters(ZEND_NUM_ARGS(), "Olll", &IM, gd_image_ce, &red, &green, &blue) == FAILURE) {
  1784. RETURN_THROWS();
  1785. }
  1786. im = php_gd_libgdimageptr_from_zval_p(IM);
  1787. CHECK_RGBA_RANGE(red, Red, 2);
  1788. CHECK_RGBA_RANGE(green, Green, 3);
  1789. CHECK_RGBA_RANGE(blue, Blue, 4);
  1790. RETURN_LONG(gdImageColorClosestHWB(im, red, green, blue));
  1791. }
  1792. /* }}} */
  1793. /* {{{ proto bool imagecolordeallocate(resource im, int index)
  1794. De-allocate a color for an image */
  1795. PHP_FUNCTION(imagecolordeallocate)
  1796. {
  1797. zval *IM;
  1798. zend_long index;
  1799. int col;
  1800. gdImagePtr im;
  1801. if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ol", &IM, gd_image_ce, &index) == FAILURE) {
  1802. RETURN_THROWS();
  1803. }
  1804. im = php_gd_libgdimageptr_from_zval_p(IM);
  1805. /* We can return right away for a truecolor image as deallocating colours is meaningless here */
  1806. if (gdImageTrueColor(im)) {
  1807. RETURN_TRUE;
  1808. }
  1809. col = index;
  1810. if (col >= 0 && col < gdImageColorsTotal(im)) {
  1811. gdImageColorDeallocate(im, col);
  1812. RETURN_TRUE;
  1813. } else {
  1814. zend_argument_value_error(2, "must be between 0 and %d", gdImageColorsTotal(im));
  1815. RETURN_THROWS();
  1816. }
  1817. }
  1818. /* }}} */
  1819. /* {{{ proto int imagecolorresolve(resource im, int red, int green, int blue)
  1820. Get the index of the specified color or its closest possible alternative */
  1821. PHP_FUNCTION(imagecolorresolve)
  1822. {
  1823. zval *IM;
  1824. zend_long red, green, blue;
  1825. gdImagePtr im;
  1826. if (zend_parse_parameters(ZEND_NUM_ARGS(), "Olll", &IM, gd_image_ce, &red, &green, &blue) == FAILURE) {
  1827. RETURN_THROWS();
  1828. }
  1829. im = php_gd_libgdimageptr_from_zval_p(IM);
  1830. CHECK_RGBA_RANGE(red, Red, 2);
  1831. CHECK_RGBA_RANGE(green, Green, 3);
  1832. CHECK_RGBA_RANGE(blue, Blue, 4);
  1833. RETURN_LONG(gdImageColorResolve(im, red, green, blue));
  1834. }
  1835. /* }}} */
  1836. /* {{{ proto int imagecolorexact(resource im, int red, int green, int blue)
  1837. Get the index of the specified color */
  1838. PHP_FUNCTION(imagecolorexact)
  1839. {
  1840. zval *IM;
  1841. zend_long red, green, blue;
  1842. gdImagePtr im;
  1843. if (zend_parse_parameters(ZEND_NUM_ARGS(), "Olll", &IM, gd_image_ce, &red, &green, &blue) == FAILURE) {
  1844. RETURN_THROWS();
  1845. }
  1846. im = php_gd_libgdimageptr_from_zval_p(IM);
  1847. CHECK_RGBA_RANGE(red, Red, 2);
  1848. CHECK_RGBA_RANGE(green, Green, 3);
  1849. CHECK_RGBA_RANGE(blue, Blue, 4);
  1850. RETURN_LONG(gdImageColorExact(im, red, green, blue));
  1851. }
  1852. /* }}} */
  1853. /* {{{ proto bool imagecolorset(resource im, int col, int red, int green, int blue)
  1854. Set the color for the specified palette index */
  1855. PHP_FUNCTION(imagecolorset)
  1856. {
  1857. zval *IM;
  1858. zend_long color, red, green, blue, alpha = 0;
  1859. int col;
  1860. gdImagePtr im;
  1861. if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ollll|l", &IM, gd_image_ce, &color, &red, &green, &blue, &alpha) == FAILURE) {
  1862. RETURN_THROWS();
  1863. }
  1864. im = php_gd_libgdimageptr_from_zval_p(IM);
  1865. CHECK_RGBA_RANGE(red, Red, 2);
  1866. CHECK_RGBA_RANGE(green, Green, 3);
  1867. CHECK_RGBA_RANGE(blue, Blue, 4);
  1868. col = color;
  1869. if (col >= 0 && col < gdImageColorsTotal(im)) {
  1870. im->red[col] = red;
  1871. im->green[col] = green;
  1872. im->blue[col] = blue;
  1873. im->alpha[col] = alpha;
  1874. } else {
  1875. RETURN_FALSE;
  1876. }
  1877. }
  1878. /* }}} */
  1879. /* {{{ proto array imagecolorsforindex(resource im, int col)
  1880. Get the colors for an index */
  1881. PHP_FUNCTION(imagecolorsforindex)
  1882. {
  1883. zval *IM;
  1884. zend_long index;
  1885. int col;
  1886. gdImagePtr im;
  1887. if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ol", &IM, gd_image_ce, &index) == FAILURE) {
  1888. RETURN_THROWS();
  1889. }
  1890. im = php_gd_libgdimageptr_from_zval_p(IM);
  1891. col = index;
  1892. if ((col >= 0 && gdImageTrueColor(im)) || (!gdImageTrueColor(im) && col >= 0 && col < gdImageColorsTotal(im))) {
  1893. array_init(return_value);
  1894. add_assoc_long(return_value,"red", gdImageRed(im,col));
  1895. add_assoc_long(return_value,"green", gdImageGreen(im,col));
  1896. add_assoc_long(return_value,"blue", gdImageBlue(im,col));
  1897. add_assoc_long(return_value,"alpha", gdImageAlpha(im,col));
  1898. } else {
  1899. php_error_docref(NULL, E_WARNING, "Color index %d out of range", col);
  1900. RETURN_FALSE;
  1901. }
  1902. }
  1903. /* }}} */
  1904. /* {{{ proto bool imagegammacorrect(resource im, float inputgamma, float outputgamma)
  1905. Apply a gamma correction to a GD image */
  1906. PHP_FUNCTION(imagegammacorrect)
  1907. {
  1908. zval *IM;
  1909. gdImagePtr im;
  1910. int i;
  1911. double input, output, gamma;
  1912. if (zend_parse_parameters(ZEND_NUM_ARGS(), "Odd", &IM, gd_image_ce, &input, &output) == FAILURE) {
  1913. RETURN_THROWS();
  1914. }
  1915. if (input <= 0.0) {
  1916. zend_argument_value_error(2, "must be greater than 0");
  1917. RETURN_THROWS();
  1918. }
  1919. if (output <= 0.0) {
  1920. zend_argument_value_error(3, "must be greater than 0");
  1921. RETURN_THROWS();
  1922. }
  1923. gamma = input / output;
  1924. im = php_gd_libgdimageptr_from_zval_p(IM);
  1925. if (gdImageTrueColor(im)) {
  1926. int x, y, c;
  1927. for (y = 0; y < gdImageSY(im); y++) {
  1928. for (x = 0; x < gdImageSX(im); x++) {
  1929. c = gdImageGetPixel(im, x, y);
  1930. gdImageSetPixel(im, x, y,
  1931. gdTrueColorAlpha(
  1932. (int) ((pow((gdTrueColorGetRed(c) / 255.0), gamma) * 255) + .5),
  1933. (int) ((pow((gdTrueColorGetGreen(c) / 255.0), gamma) * 255) + .5),
  1934. (int) ((pow((gdTrueColorGetBlue(c) / 255.0), gamma) * 255) + .5),
  1935. gdTrueColorGetAlpha(c)
  1936. )
  1937. );
  1938. }
  1939. }
  1940. RETURN_TRUE;
  1941. }
  1942. for (i = 0; i < gdImageColorsTotal(im); i++) {
  1943. im->red[i] = (int)((pow((im->red[i] / 255.0), gamma) * 255) + .5);
  1944. im->green[i] = (int)((pow((im->green[i] / 255.0), gamma) * 255) + .5);
  1945. im->blue[i] = (int)((pow((im->blue[i] / 255.0), gamma) * 255) + .5);
  1946. }
  1947. RETURN_TRUE;
  1948. }
  1949. /* }}} */
  1950. /* {{{ proto bool imagesetpixel(resource im, int x, int y, int col)
  1951. Set a single pixel */
  1952. PHP_FUNCTION(imagesetpixel)
  1953. {
  1954. zval *IM;
  1955. zend_long x, y, col;
  1956. gdImagePtr im;
  1957. ZEND_PARSE_PARAMETERS_START(4, 4)
  1958. Z_PARAM_OBJECT_OF_CLASS(IM, gd_image_ce)
  1959. Z_PARAM_LONG(x)
  1960. Z_PARAM_LONG(y)
  1961. Z_PARAM_LONG(col)
  1962. ZEND_PARSE_PARAMETERS_END();
  1963. im = php_gd_libgdimageptr_from_zval_p(IM);
  1964. gdImageSetPixel(im, x, y, col);
  1965. RETURN_TRUE;
  1966. }
  1967. /* }}} */
  1968. /* {{{ proto bool imageline(resource im, int x1, int y1, int x2, int y2, int col)
  1969. Draw a line */
  1970. PHP_FUNCTION(imageline)
  1971. {
  1972. zval *IM;
  1973. zend_long x1, y1, x2, y2, col;
  1974. gdImagePtr im;
  1975. if (zend_parse_parameters(ZEND_NUM_ARGS(), "Olllll", &IM, gd_image_ce, &x1, &y1, &x2, &y2, &col) == FAILURE) {
  1976. RETURN_THROWS();
  1977. }
  1978. im = php_gd_libgdimageptr_from_zval_p(IM);
  1979. if (im->AA) {
  1980. gdImageSetAntiAliased(im, col);
  1981. col = gdAntiAliased;
  1982. }
  1983. gdImageLine(im, x1, y1, x2, y2, col);
  1984. RETURN_TRUE;
  1985. }
  1986. /* }}} */
  1987. /* {{{ proto bool imagedashedline(resource im, int x1, int y1, int x2, int y2, int col)
  1988. Draw a dashed line */
  1989. PHP_FUNCTION(imagedashedline)
  1990. {
  1991. zval *IM;
  1992. zend_long x1, y1, x2, y2, col;
  1993. gdImagePtr im;
  1994. if (zend_parse_parameters(ZEND_NUM_ARGS(), "Olllll", &IM, gd_image_ce, &x1, &y1, &x2, &y2, &col) == FAILURE) {
  1995. RETURN_THROWS();
  1996. }
  1997. im = php_gd_libgdimageptr_from_zval_p(IM);
  1998. gdImageDashedLine(im, x1, y1, x2, y2, col);
  1999. RETURN_TRUE;
  2000. }
  2001. /* }}} */
  2002. /* {{{ proto bool imagerectangle(resource im, int x1, int y1, int x2, int y2, int col)
  2003. Draw a rectangle */
  2004. PHP_FUNCTION(imagerectangle)
  2005. {
  2006. zval *IM;
  2007. zend_long x1, y1, x2, y2, col;
  2008. gdImagePtr im;
  2009. if (zend_parse_parameters(ZEND_NUM_ARGS(), "Olllll", &IM, gd_image_ce, &x1, &y1, &x2, &y2, &col) == FAILURE) {
  2010. RETURN_THROWS();
  2011. }
  2012. im = php_gd_libgdimageptr_from_zval_p(IM);
  2013. gdImageRectangle(im, x1, y1, x2, y2, col);
  2014. RETURN_TRUE;
  2015. }
  2016. /* }}} */
  2017. /* {{{ proto bool imagefilledrectangle(resource im, int x1, int y1, int x2, int y2, int col)
  2018. Draw a filled rectangle */
  2019. PHP_FUNCTION(imagefilledrectangle)
  2020. {
  2021. zval *IM;
  2022. zend_long x1, y1, x2, y2, col;
  2023. gdImagePtr im;
  2024. if (zend_parse_parameters(ZEND_NUM_ARGS(), "Olllll", &IM, gd_image_ce, &x1, &y1, &x2, &y2, &col) == FAILURE) {
  2025. RETURN_THROWS();
  2026. }
  2027. im = php_gd_libgdimageptr_from_zval_p(IM);
  2028. gdImageFilledRectangle(im, x1, y1, x2, y2, col);
  2029. RETURN_TRUE;
  2030. }
  2031. /* }}} */
  2032. /* {{{ proto bool imagearc(resource im, int cx, int cy, int w, int h, int s, int e, int col)
  2033. Draw a partial ellipse */
  2034. PHP_FUNCTION(imagearc)
  2035. {
  2036. zval *IM;
  2037. zend_long cx, cy, w, h, ST, E, col;
  2038. gdImagePtr im;
  2039. int e, st;
  2040. if (zend_parse_parameters(ZEND_NUM_ARGS(), "Olllllll", &IM, gd_image_ce, &cx, &cy, &w, &h, &ST, &E, &col) == FAILURE) {
  2041. RETURN_THROWS();
  2042. }
  2043. im = php_gd_libgdimageptr_from_zval_p(IM);
  2044. e = E;
  2045. if (e < 0) {
  2046. e %= 360;
  2047. }
  2048. st = ST;
  2049. if (st < 0) {
  2050. st %= 360;
  2051. }
  2052. gdImageArc(im, cx, cy, w, h, st, e, col);
  2053. RETURN_TRUE;
  2054. }
  2055. /* }}} */
  2056. /* {{{ proto bool imageellipse(resource im, int cx, int cy, int w, int h, int color)
  2057. Draw an ellipse */
  2058. PHP_FUNCTION(imageellipse)
  2059. {
  2060. zval *IM;
  2061. zend_long cx, cy, w, h, color;
  2062. gdImagePtr im;
  2063. if (zend_parse_parameters(ZEND_NUM_ARGS(), "Olllll", &IM, gd_image_ce, &cx, &cy, &w, &h, &color) == FAILURE) {
  2064. RETURN_THROWS();
  2065. }
  2066. im = php_gd_libgdimageptr_from_zval_p(IM);
  2067. gdImageEllipse(im, cx, cy, w, h, color);
  2068. RETURN_TRUE;
  2069. }
  2070. /* }}} */
  2071. /* {{{ proto bool imagefilltoborder(resource im, int x, int y, int border, int col)
  2072. Flood fill to specific color */
  2073. PHP_FUNCTION(imagefilltoborder)
  2074. {
  2075. zval *IM;
  2076. zend_long x, y, border, col;
  2077. gdImagePtr im;
  2078. if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ollll", &IM, gd_image_ce, &x, &y, &border, &col) == FAILURE) {
  2079. RETURN_THROWS();
  2080. }
  2081. im = php_gd_libgdimageptr_from_zval_p(IM);
  2082. gdImageFillToBorder(im, x, y, border, col);
  2083. RETURN_TRUE;
  2084. }
  2085. /* }}} */
  2086. /* {{{ proto bool imagefill(resource im, int x, int y, int col)
  2087. Flood fill */
  2088. PHP_FUNCTION(imagefill)
  2089. {
  2090. zval *IM;
  2091. zend_long x, y, col;
  2092. gdImagePtr im;
  2093. if (zend_parse_parameters(ZEND_NUM_ARGS(), "Olll", &IM, gd_image_ce, &x, &y, &col) == FAILURE) {
  2094. RETURN_THROWS();
  2095. }
  2096. im = php_gd_libgdimageptr_from_zval_p(IM);
  2097. gdImageFill(im, x, y, col);
  2098. RETURN_TRUE;
  2099. }
  2100. /* }}} */
  2101. /* {{{ proto int imagecolorstotal(resource im)
  2102. Find out the number of colors in an image's palette */
  2103. PHP_FUNCTION(imagecolorstotal)
  2104. {
  2105. zval *IM;
  2106. gdImagePtr im;
  2107. if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &IM, gd_image_ce) == FAILURE) {
  2108. RETURN_THROWS();
  2109. }
  2110. im = php_gd_libgdimageptr_from_zval_p(IM);
  2111. RETURN_LONG(gdImageColorsTotal(im));
  2112. }
  2113. /* }}} */
  2114. /* {{{ proto int imagecolortransparent(resource im [, int col])
  2115. Define a color as transparent */
  2116. PHP_FUNCTION(imagecolortransparent)
  2117. {
  2118. zval *IM;
  2119. zend_long COL = 0;
  2120. gdImagePtr im;
  2121. int argc = ZEND_NUM_ARGS();
  2122. if (zend_parse_parameters(argc, "O|l", &IM, gd_image_ce, &COL) == FAILURE) {
  2123. RETURN_THROWS();
  2124. }
  2125. im = php_gd_libgdimageptr_from_zval_p(IM);
  2126. if (argc > 1) {
  2127. gdImageColorTransparent(im, COL);
  2128. }
  2129. RETURN_LONG(gdImageGetTransparent(im));
  2130. }
  2131. /* }}} */
  2132. /* {{{ proto int imageinterlace(resource im [, int interlace])
  2133. Enable or disable interlace */
  2134. PHP_FUNCTION(imageinterlace)
  2135. {
  2136. zval *IM;
  2137. int argc = ZEND_NUM_ARGS();
  2138. zend_long INT = 0;
  2139. gdImagePtr im;
  2140. if (zend_parse_parameters(argc, "O|l", &IM, gd_image_ce, &INT) == FAILURE) {
  2141. RETURN_THROWS();
  2142. }
  2143. im = php_gd_libgdimageptr_from_zval_p(IM);
  2144. if (argc > 1) {
  2145. gdImageInterlace(im, INT);
  2146. }
  2147. RETURN_LONG(gdImageGetInterlaced(im));
  2148. }
  2149. /* }}} */
  2150. /* {{{ php_imagepolygon
  2151. arg = -1 open polygon
  2152. arg = 0 normal polygon
  2153. arg = 1 filled polygon */
  2154. /* im, points, num_points, col */
  2155. static void php_imagepolygon(INTERNAL_FUNCTION_PARAMETERS, int filled)
  2156. {
  2157. zval *IM, *POINTS;
  2158. zend_long NPOINTS, COL;
  2159. zval *var = NULL;
  2160. gdImagePtr im;
  2161. gdPointPtr points;
  2162. int npoints, col, nelem, i;
  2163. if (zend_parse_parameters(ZEND_NUM_ARGS(), "Oal|l", &IM, gd_image_ce, &POINTS, &NPOINTS, &COL) == FAILURE) {
  2164. RETURN_THROWS();
  2165. }
  2166. if (ZEND_NUM_ARGS() == 3) {
  2167. COL = NPOINTS;
  2168. NPOINTS = zend_hash_num_elements(Z_ARRVAL_P(POINTS));
  2169. if (NPOINTS % 2 != 0) {
  2170. zend_argument_value_error(2, "must have an even number of elements");
  2171. RETURN_THROWS();
  2172. }
  2173. NPOINTS /= 2;
  2174. }
  2175. im = php_gd_libgdimageptr_from_zval_p(IM);
  2176. npoints = NPOINTS;
  2177. col = COL;
  2178. nelem = zend_hash_num_elements(Z_ARRVAL_P(POINTS));
  2179. if (npoints < 3) {
  2180. zend_argument_value_error(3, "must be greater than or equal to 3");
  2181. RETURN_THROWS();
  2182. }
  2183. if (nelem < npoints * 2) {
  2184. zend_value_error("Trying to use %d points in array with only %d points", npoints, nelem/2);
  2185. RETURN_THROWS();
  2186. }
  2187. points = (gdPointPtr) safe_emalloc(npoints, sizeof(gdPoint), 0);
  2188. for (i = 0; i < npoints; i++) {
  2189. if ((var = zend_hash_index_find(Z_ARRVAL_P(POINTS), (i * 2))) != NULL) {
  2190. points[i].x = zval_get_long(var);
  2191. }
  2192. if ((var = zend_hash_index_find(Z_ARRVAL_P(POINTS), (i * 2) + 1)) != NULL) {
  2193. points[i].y = zval_get_long(var);
  2194. }
  2195. }
  2196. if (im->AA) {
  2197. gdImageSetAntiAliased(im, col);
  2198. col = gdAntiAliased;
  2199. }
  2200. switch (filled) {
  2201. case -1:
  2202. gdImageOpenPolygon(im, points, npoints, col);
  2203. break;
  2204. case 0:
  2205. gdImagePolygon(im, points, npoints, col);
  2206. break;
  2207. case 1:
  2208. gdImageFilledPolygon(im, points, npoints, col);
  2209. break;
  2210. }
  2211. efree(points);
  2212. RETURN_TRUE;
  2213. }
  2214. /* }}} */
  2215. /* {{{ proto bool imagepolygon(resource im, array point, int num_points, int col)
  2216. Draw a polygon */
  2217. PHP_FUNCTION(imagepolygon)
  2218. {
  2219. php_imagepolygon(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
  2220. }
  2221. /* }}} */
  2222. /* {{{ proto bool imageopenpolygon(resource im, array point, int num_points, int col)
  2223. Draw a polygon */
  2224. PHP_FUNCTION(imageopenpolygon)
  2225. {
  2226. php_imagepolygon(INTERNAL_FUNCTION_PARAM_PASSTHRU, -1);
  2227. }
  2228. /* }}} */
  2229. /* {{{ proto bool imagefilledpolygon(resource im, array point, int num_points, int col)
  2230. Draw a filled polygon */
  2231. PHP_FUNCTION(imagefilledpolygon)
  2232. {
  2233. php_imagepolygon(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
  2234. }
  2235. /* }}} */
  2236. /* {{{ php_find_gd_font
  2237. */
  2238. static gdFontPtr php_find_gd_font(int size)
  2239. {
  2240. gdFontPtr font;
  2241. switch (size) {
  2242. case 1:
  2243. font = gdFontTiny;
  2244. break;
  2245. case 2:
  2246. font = gdFontSmall;
  2247. break;
  2248. case 3:
  2249. font = gdFontMediumBold;
  2250. break;
  2251. case 4:
  2252. font = gdFontLarge;
  2253. break;
  2254. case 5:
  2255. font = gdFontGiant;
  2256. break;
  2257. default: {
  2258. zval *zv = zend_hash_index_find(&EG(regular_list), size - 5);
  2259. if (!zv || (Z_RES_P(zv))->type != le_gd_font) {
  2260. if (size < 1) {
  2261. font = gdFontTiny;
  2262. } else {
  2263. font = gdFontGiant;
  2264. }
  2265. } else {
  2266. font = (gdFontPtr)Z_RES_P(zv)->ptr;
  2267. }
  2268. }
  2269. break;
  2270. }
  2271. return font;
  2272. }
  2273. /* }}} */
  2274. /* {{{ php_imagefontsize
  2275. * arg = 0 ImageFontWidth
  2276. * arg = 1 ImageFontHeight
  2277. */
  2278. static void php_imagefontsize(INTERNAL_FUNCTION_PARAMETERS, int arg)
  2279. {
  2280. zend_long SIZE;
  2281. gdFontPtr font;
  2282. if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &SIZE) == FAILURE) {
  2283. RETURN_THROWS();
  2284. }
  2285. font = php_find_gd_font(SIZE);
  2286. RETURN_LONG(arg ? font->h : font->w);
  2287. }
  2288. /* }}} */
  2289. /* {{{ proto int imagefontwidth(int font)
  2290. Get font width */
  2291. PHP_FUNCTION(imagefontwidth)
  2292. {
  2293. php_imagefontsize(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
  2294. }
  2295. /* }}} */
  2296. /* {{{ proto int imagefontheight(int font)
  2297. Get font height */
  2298. PHP_FUNCTION(imagefontheight)
  2299. {
  2300. php_imagefontsize(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
  2301. }
  2302. /* }}} */
  2303. /* {{{ php_gdimagecharup
  2304. * workaround for a bug in gd 1.2 */
  2305. static void php_gdimagecharup(gdImagePtr im, gdFontPtr f, int x, int y, int c, int color)
  2306. {
  2307. int cx, cy, px, py, fline;
  2308. cx = 0;
  2309. cy = 0;
  2310. if ((c < f->offset) || (c >= (f->offset + f->nchars))) {
  2311. return;
  2312. }
  2313. fline = (c - f->offset) * f->h * f->w;
  2314. for (py = y; (py > (y - f->w)); py--) {
  2315. for (px = x; (px < (x + f->h)); px++) {
  2316. if (f->data[fline + cy * f->w + cx]) {
  2317. gdImageSetPixel(im, px, py, color);
  2318. }
  2319. cy++;
  2320. }
  2321. cy = 0;
  2322. cx++;
  2323. }
  2324. }
  2325. /* }}} */
  2326. /* {{{ php_imagechar
  2327. * arg = 0 ImageChar
  2328. * arg = 1 ImageCharUp
  2329. * arg = 2 ImageString
  2330. * arg = 3 ImageStringUp
  2331. */
  2332. static void php_imagechar(INTERNAL_FUNCTION_PARAMETERS, int mode)
  2333. {
  2334. zval *IM;
  2335. zend_long SIZE, X, Y, COL;
  2336. char *C;
  2337. size_t C_len;
  2338. gdImagePtr im;
  2339. int ch = 0, col, x, y, size, i, l = 0;
  2340. unsigned char *str = NULL;
  2341. gdFontPtr font;
  2342. if (zend_parse_parameters(ZEND_NUM_ARGS(), "Olllsl", &IM, gd_image_ce, &SIZE, &X, &Y, &C, &C_len, &COL) == FAILURE) {
  2343. RETURN_THROWS();
  2344. }
  2345. im = php_gd_libgdimageptr_from_zval_p(IM);
  2346. col = COL;
  2347. if (mode < 2) {
  2348. ch = (int)((unsigned char)*C);
  2349. } else {
  2350. str = (unsigned char *) estrndup(C, C_len);
  2351. l = strlen((char *)str);
  2352. }
  2353. y = Y;
  2354. x = X;
  2355. size = SIZE;
  2356. font = php_find_gd_font(size);
  2357. switch (mode) {
  2358. case 0:
  2359. gdImageChar(im, font, x, y, ch, col);
  2360. break;
  2361. case 1:
  2362. php_gdimagecharup(im, font, x, y, ch, col);
  2363. break;
  2364. case 2:
  2365. for (i = 0; (i < l); i++) {
  2366. gdImageChar(im, font, x, y, (int) ((unsigned char) str[i]), col);
  2367. x += font->w;
  2368. }
  2369. break;
  2370. case 3: {
  2371. for (i = 0; (i < l); i++) {
  2372. /* php_gdimagecharup(im, font, x, y, (int) str[i], col); */
  2373. gdImageCharUp(im, font, x, y, (int) str[i], col);
  2374. y -= font->w;
  2375. }
  2376. break;
  2377. }
  2378. }
  2379. if (str) {
  2380. efree(str);
  2381. }
  2382. RETURN_TRUE;
  2383. }
  2384. /* }}} */
  2385. /* {{{ proto bool imagechar(resource im, int font, int x, int y, string c, int col)
  2386. Draw a character */
  2387. PHP_FUNCTION(imagechar)
  2388. {
  2389. php_imagechar(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
  2390. }
  2391. /* }}} */
  2392. /* {{{ proto bool imagecharup(resource im, int font, int x, int y, string c, int col)
  2393. Draw a character rotated 90 degrees counter-clockwise */
  2394. PHP_FUNCTION(imagecharup)
  2395. {
  2396. php_imagechar(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
  2397. }
  2398. /* }}} */
  2399. /* {{{ proto bool imagestring(resource im, int font, int x, int y, string str, int col)
  2400. Draw a string horizontally */
  2401. PHP_FUNCTION(imagestring)
  2402. {
  2403. php_imagechar(INTERNAL_FUNCTION_PARAM_PASSTHRU, 2);
  2404. }
  2405. /* }}} */
  2406. /* {{{ proto bool imagestringup(resource im, int font, int x, int y, string str, int col)
  2407. Draw a string vertically - rotated 90 degrees counter-clockwise */
  2408. PHP_FUNCTION(imagestringup)
  2409. {
  2410. php_imagechar(INTERNAL_FUNCTION_PARAM_PASSTHRU, 3);
  2411. }
  2412. /* }}} */
  2413. /* {{{ proto bool imagecopy(resource dst_im, resource src_im, int dst_x, int dst_y, int src_x, int src_y, int src_w, int src_h)
  2414. Copy part of an image */
  2415. PHP_FUNCTION(imagecopy)
  2416. {
  2417. zval *SIM, *DIM;
  2418. zend_long SX, SY, SW, SH, DX, DY;
  2419. gdImagePtr im_dst, im_src;
  2420. int srcH, srcW, srcY, srcX, dstY, dstX;
  2421. if (zend_parse_parameters(ZEND_NUM_ARGS(), "OOllllll", &DIM, gd_image_ce, &SIM, gd_image_ce, &DX, &DY, &SX, &SY, &SW, &SH) == FAILURE) {
  2422. RETURN_THROWS();
  2423. }
  2424. im_dst = php_gd_libgdimageptr_from_zval_p(DIM);
  2425. im_src = php_gd_libgdimageptr_from_zval_p(SIM);
  2426. srcX = SX;
  2427. srcY = SY;
  2428. srcH = SH;
  2429. srcW = SW;
  2430. dstX = DX;
  2431. dstY = DY;
  2432. gdImageCopy(im_dst, im_src, dstX, dstY, srcX, srcY, srcW, srcH);
  2433. RETURN_TRUE;
  2434. }
  2435. /* }}} */
  2436. /* {{{ proto bool imagecopymerge(resource dst_im, resource src_im, int dst_x, int dst_y, int src_x, int src_y, int src_w, int src_h, int pct)
  2437. Merge one part of an image with another */
  2438. PHP_FUNCTION(imagecopymerge)
  2439. {
  2440. zval *SIM, *DIM;
  2441. zend_long SX, SY, SW, SH, DX, DY, PCT;
  2442. gdImagePtr im_dst, im_src;
  2443. int srcH, srcW, srcY, srcX, dstY, dstX, pct;
  2444. if (zend_parse_parameters(ZEND_NUM_ARGS(), "OOlllllll", &DIM, gd_image_ce, &SIM, gd_image_ce, &DX, &DY, &SX, &SY, &SW, &SH, &PCT) == FAILURE) {
  2445. RETURN_THROWS();
  2446. }
  2447. im_src = php_gd_libgdimageptr_from_zval_p(SIM);
  2448. im_dst = php_gd_libgdimageptr_from_zval_p(DIM);
  2449. srcX = SX;
  2450. srcY = SY;
  2451. srcH = SH;
  2452. srcW = SW;
  2453. dstX = DX;
  2454. dstY = DY;
  2455. pct = PCT;
  2456. gdImageCopyMerge(im_dst, im_src, dstX, dstY, srcX, srcY, srcW, srcH, pct);
  2457. RETURN_TRUE;
  2458. }
  2459. /* }}} */
  2460. /* {{{ proto bool imagecopymergegray(resource dst_im, resource src_im, int dst_x, int dst_y, int src_x, int src_y, int src_w, int src_h, int pct)
  2461. Merge one part of an image with another */
  2462. PHP_FUNCTION(imagecopymergegray)
  2463. {
  2464. zval *SIM, *DIM;
  2465. zend_long SX, SY, SW, SH, DX, DY, PCT;
  2466. gdImagePtr im_dst, im_src;
  2467. int srcH, srcW, srcY, srcX, dstY, dstX, pct;
  2468. if (zend_parse_parameters(ZEND_NUM_ARGS(), "OOlllllll", &DIM, gd_image_ce, &SIM, gd_image_ce, &DX, &DY, &SX, &SY, &SW, &SH, &PCT) == FAILURE) {
  2469. RETURN_THROWS();
  2470. }
  2471. im_src = php_gd_libgdimageptr_from_zval_p(SIM);
  2472. im_dst = php_gd_libgdimageptr_from_zval_p(DIM);
  2473. srcX = SX;
  2474. srcY = SY;
  2475. srcH = SH;
  2476. srcW = SW;
  2477. dstX = DX;
  2478. dstY = DY;
  2479. pct = PCT;
  2480. gdImageCopyMergeGray(im_dst, im_src, dstX, dstY, srcX, srcY, srcW, srcH, pct);
  2481. RETURN_TRUE;
  2482. }
  2483. /* }}} */
  2484. /* {{{ proto bool imagecopyresized(resource dst_im, resource src_im, int dst_x, int dst_y, int src_x, int src_y, int dst_w, int dst_h, int src_w, int src_h)
  2485. Copy and resize part of an image */
  2486. PHP_FUNCTION(imagecopyresized)
  2487. {
  2488. zval *SIM, *DIM;
  2489. zend_long SX, SY, SW, SH, DX, DY, DW, DH;
  2490. gdImagePtr im_dst, im_src;
  2491. int srcH, srcW, dstH, dstW, srcY, srcX, dstY, dstX;
  2492. if (zend_parse_parameters(ZEND_NUM_ARGS(), "OOllllllll", &DIM, gd_image_ce, &SIM, gd_image_ce, &DX, &DY, &SX, &SY, &DW, &DH, &SW, &SH) == FAILURE) {
  2493. RETURN_THROWS();
  2494. }
  2495. im_src = php_gd_libgdimageptr_from_zval_p(SIM);
  2496. im_dst = php_gd_libgdimageptr_from_zval_p(DIM);
  2497. srcX = SX;
  2498. srcY = SY;
  2499. srcH = SH;
  2500. srcW = SW;
  2501. dstX = DX;
  2502. dstY = DY;
  2503. dstH = DH;
  2504. dstW = DW;
  2505. if (dstW <= 0) {
  2506. zend_argument_value_error(3, "must be greater than 0");
  2507. RETURN_THROWS();
  2508. }
  2509. if (dstH <= 0) {
  2510. zend_argument_value_error(4, "must be greater than 0");
  2511. RETURN_THROWS();
  2512. }
  2513. if (srcW <= 0) {
  2514. zend_argument_value_error(5, "must be greater than 0");
  2515. RETURN_THROWS();
  2516. }
  2517. if (srcH <= 0) {
  2518. zend_argument_value_error(6, "must be greater than 0");
  2519. RETURN_THROWS();
  2520. }
  2521. gdImageCopyResized(im_dst, im_src, dstX, dstY, srcX, srcY, dstW, dstH, srcW, srcH);
  2522. RETURN_TRUE;
  2523. }
  2524. /* }}} */
  2525. /* {{{ proto int imagesx(resource im)
  2526. Get image width */
  2527. PHP_FUNCTION(imagesx)
  2528. {
  2529. zval *IM;
  2530. gdImagePtr im;
  2531. if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &IM, gd_image_ce) == FAILURE) {
  2532. RETURN_THROWS();
  2533. }
  2534. im = php_gd_libgdimageptr_from_zval_p(IM);
  2535. RETURN_LONG(gdImageSX(im));
  2536. }
  2537. /* }}} */
  2538. /* {{{ proto int imagesy(resource im)
  2539. Get image height */
  2540. PHP_FUNCTION(imagesy)
  2541. {
  2542. zval *IM;
  2543. gdImagePtr im;
  2544. if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &IM, gd_image_ce) == FAILURE) {
  2545. RETURN_THROWS();
  2546. }
  2547. im = php_gd_libgdimageptr_from_zval_p(IM);
  2548. RETURN_LONG(gdImageSY(im));
  2549. }
  2550. /* }}} */
  2551. /* {{{ proto bool imagesetclip(resource im, int x1, int y1, int x2, int y2)
  2552. Set the clipping rectangle. */
  2553. PHP_FUNCTION(imagesetclip)
  2554. {
  2555. zval *im_zval;
  2556. gdImagePtr im;
  2557. zend_long x1, y1, x2, y2;
  2558. if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ollll", &im_zval, gd_image_ce, &x1, &y1, &x2, &y2) == FAILURE) {
  2559. RETURN_THROWS();
  2560. }
  2561. im = php_gd_libgdimageptr_from_zval_p(im_zval);
  2562. gdImageSetClip(im, x1, y1, x2, y2);
  2563. RETURN_TRUE;
  2564. }
  2565. /* }}} */
  2566. /* {{{ proto array imagegetclip(resource im)
  2567. Get the clipping rectangle. */
  2568. PHP_FUNCTION(imagegetclip)
  2569. {
  2570. zval *im_zval;
  2571. gdImagePtr im;
  2572. int x1, y1, x2, y2;
  2573. if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &im_zval, gd_image_ce) == FAILURE) {
  2574. RETURN_THROWS();
  2575. }
  2576. im = php_gd_libgdimageptr_from_zval_p(im_zval);
  2577. gdImageGetClip(im, &x1, &y1, &x2, &y2);
  2578. array_init(return_value);
  2579. add_next_index_long(return_value, x1);
  2580. add_next_index_long(return_value, y1);
  2581. add_next_index_long(return_value, x2);
  2582. add_next_index_long(return_value, y2);
  2583. }
  2584. /* }}} */
  2585. #define TTFTEXT_DRAW 0
  2586. #define TTFTEXT_BBOX 1
  2587. #ifdef HAVE_GD_FREETYPE
  2588. /* {{{ proto array imageftbbox(float size, float angle, string font_file, string text [, array extrainfo])
  2589. Give the bounding box of a text using fonts via freetype2 */
  2590. PHP_FUNCTION(imageftbbox)
  2591. {
  2592. php_imagettftext_common(INTERNAL_FUNCTION_PARAM_PASSTHRU, TTFTEXT_BBOX, 1);
  2593. }
  2594. /* }}} */
  2595. /* {{{ proto array imagefttext(resource im, float size, float angle, int x, int y, int col, string font_file, string text [, array extrainfo])
  2596. Write text to the image using fonts via freetype2 */
  2597. PHP_FUNCTION(imagefttext)
  2598. {
  2599. php_imagettftext_common(INTERNAL_FUNCTION_PARAM_PASSTHRU, TTFTEXT_DRAW, 1);
  2600. }
  2601. /* }}} */
  2602. /* {{{ proto array imagettfbbox(float size, float angle, string font_file, string text)
  2603. Give the bounding box of a text using TrueType fonts */
  2604. PHP_FUNCTION(imagettfbbox)
  2605. {
  2606. php_imagettftext_common(INTERNAL_FUNCTION_PARAM_PASSTHRU, TTFTEXT_BBOX, 0);
  2607. }
  2608. /* }}} */
  2609. /* {{{ proto array imagettftext(resource im, float size, float angle, int x, int y, int col, string font_file, string text)
  2610. Write text to the image using a TrueType font */
  2611. PHP_FUNCTION(imagettftext)
  2612. {
  2613. php_imagettftext_common(INTERNAL_FUNCTION_PARAM_PASSTHRU, TTFTEXT_DRAW, 0);
  2614. }
  2615. /* }}} */
  2616. /* {{{ php_imagettftext_common
  2617. */
  2618. static void php_imagettftext_common(INTERNAL_FUNCTION_PARAMETERS, int mode, int extended)
  2619. {
  2620. zval *IM, *EXT = NULL;
  2621. gdImagePtr im=NULL;
  2622. zend_long col = -1, x = 0, y = 0;
  2623. size_t str_len, fontname_len;
  2624. int i, brect[8];
  2625. double ptsize, angle;
  2626. char *str = NULL, *fontname = NULL;
  2627. char *error = NULL;
  2628. int argc = ZEND_NUM_ARGS();
  2629. gdFTStringExtra strex = {0};
  2630. if (mode == TTFTEXT_BBOX) {
  2631. if (argc < 4 || argc > ((extended) ? 5 : 4)) {
  2632. ZEND_WRONG_PARAM_COUNT();
  2633. } else if (zend_parse_parameters(argc, "ddss|a", &ptsize, &angle, &fontname, &fontname_len, &str, &str_len, &EXT) == FAILURE) {
  2634. RETURN_THROWS();
  2635. }
  2636. } else {
  2637. if (argc < 8 || argc > ((extended) ? 9 : 8)) {
  2638. ZEND_WRONG_PARAM_COUNT();
  2639. } else if (zend_parse_parameters(argc, "Oddlllss|a", &IM, gd_image_ce, &ptsize, &angle, &x, &y, &col, &fontname, &fontname_len, &str, &str_len, &EXT) == FAILURE) {
  2640. RETURN_THROWS();
  2641. }
  2642. im = php_gd_libgdimageptr_from_zval_p(IM);
  2643. }
  2644. /* convert angle to radians */
  2645. angle = angle * (M_PI/180);
  2646. if (extended && EXT) { /* parse extended info */
  2647. zval *item;
  2648. zend_string *key;
  2649. /* walk the assoc array */
  2650. ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(EXT), key, item) {
  2651. if (key == NULL) {
  2652. continue;
  2653. }
  2654. if (strcmp("linespacing", ZSTR_VAL(key)) == 0) {
  2655. strex.flags |= gdFTEX_LINESPACE;
  2656. strex.linespacing = zval_get_double(item);
  2657. }
  2658. } ZEND_HASH_FOREACH_END();
  2659. }
  2660. #ifdef VIRTUAL_DIR
  2661. {
  2662. char tmp_font_path[MAXPATHLEN];
  2663. if (!VCWD_REALPATH(fontname, tmp_font_path)) {
  2664. fontname = NULL;
  2665. }
  2666. }
  2667. #endif /* VIRTUAL_DIR */
  2668. PHP_GD_CHECK_OPEN_BASEDIR(fontname, "Invalid font filename");
  2669. if (extended) {
  2670. error = gdImageStringFTEx(im, brect, col, fontname, ptsize, angle, x, y, str, &strex);
  2671. } else {
  2672. error = gdImageStringFT(im, brect, col, fontname, ptsize, angle, x, y, str);
  2673. }
  2674. if (error) {
  2675. php_error_docref(NULL, E_WARNING, "%s", error);
  2676. RETURN_FALSE;
  2677. }
  2678. array_init(return_value);
  2679. /* return array with the text's bounding box */
  2680. for (i = 0; i < 8; i++) {
  2681. add_next_index_long(return_value, brect[i]);
  2682. }
  2683. }
  2684. /* }}} */
  2685. #endif /* HAVE_GD_FREETYPE */
  2686. /* Section Filters */
  2687. #define PHP_GD_SINGLE_RES \
  2688. zval *SIM; \
  2689. gdImagePtr im_src; \
  2690. if (zend_parse_parameters(1, "O", &SIM, gd_image_ce) == FAILURE) { \
  2691. RETURN_THROWS(); \
  2692. } \
  2693. im_src = php_gd_libgdimageptr_from_zval_p(SIM);
  2694. static void php_image_filter_negate(INTERNAL_FUNCTION_PARAMETERS)
  2695. {
  2696. PHP_GD_SINGLE_RES
  2697. if (gdImageNegate(im_src) == 1) {
  2698. RETURN_TRUE;
  2699. }
  2700. RETURN_FALSE;
  2701. }
  2702. static void php_image_filter_grayscale(INTERNAL_FUNCTION_PARAMETERS)
  2703. {
  2704. PHP_GD_SINGLE_RES
  2705. if (gdImageGrayScale(im_src) == 1) {
  2706. RETURN_TRUE;
  2707. }
  2708. RETURN_FALSE;
  2709. }
  2710. static void php_image_filter_brightness(INTERNAL_FUNCTION_PARAMETERS)
  2711. {
  2712. zval *SIM;
  2713. gdImagePtr im_src;
  2714. zend_long brightness, tmp;
  2715. if (zend_parse_parameters(ZEND_NUM_ARGS(), "Oll", &SIM, gd_image_ce, &tmp, &brightness) == FAILURE) {
  2716. RETURN_THROWS();
  2717. }
  2718. im_src = php_gd_libgdimageptr_from_zval_p(SIM);
  2719. if (gdImageBrightness(im_src, (int)brightness) == 1) {
  2720. RETURN_TRUE;
  2721. }
  2722. RETURN_FALSE;
  2723. }
  2724. static void php_image_filter_contrast(INTERNAL_FUNCTION_PARAMETERS)
  2725. {
  2726. zval *SIM;
  2727. gdImagePtr im_src;
  2728. zend_long contrast, tmp;
  2729. if (zend_parse_parameters(ZEND_NUM_ARGS(), "Oll", &SIM, gd_image_ce, &tmp, &contrast) == FAILURE) {
  2730. RETURN_THROWS();
  2731. }
  2732. im_src = php_gd_libgdimageptr_from_zval_p(SIM);
  2733. if (gdImageContrast(im_src, (int)contrast) == 1) {
  2734. RETURN_TRUE;
  2735. }
  2736. RETURN_FALSE;
  2737. }
  2738. static void php_image_filter_colorize(INTERNAL_FUNCTION_PARAMETERS)
  2739. {
  2740. zval *SIM;
  2741. gdImagePtr im_src;
  2742. zend_long r,g,b,tmp;
  2743. zend_long a = 0;
  2744. if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ollll|l", &SIM, gd_image_ce, &tmp, &r, &g, &b, &a) == FAILURE) {
  2745. RETURN_THROWS();
  2746. }
  2747. im_src = php_gd_libgdimageptr_from_zval_p(SIM);
  2748. if (gdImageColor(im_src, (int) r, (int) g, (int) b, (int) a) == 1) {
  2749. RETURN_TRUE;
  2750. }
  2751. RETURN_FALSE;
  2752. }
  2753. static void php_image_filter_edgedetect(INTERNAL_FUNCTION_PARAMETERS)
  2754. {
  2755. PHP_GD_SINGLE_RES
  2756. if (gdImageEdgeDetectQuick(im_src) == 1) {
  2757. RETURN_TRUE;
  2758. }
  2759. RETURN_FALSE;
  2760. }
  2761. static void php_image_filter_emboss(INTERNAL_FUNCTION_PARAMETERS)
  2762. {
  2763. PHP_GD_SINGLE_RES
  2764. if (gdImageEmboss(im_src) == 1) {
  2765. RETURN_TRUE;
  2766. }
  2767. RETURN_FALSE;
  2768. }
  2769. static void php_image_filter_gaussian_blur(INTERNAL_FUNCTION_PARAMETERS)
  2770. {
  2771. PHP_GD_SINGLE_RES
  2772. if (gdImageGaussianBlur(im_src) == 1) {
  2773. RETURN_TRUE;
  2774. }
  2775. RETURN_FALSE;
  2776. }
  2777. static void php_image_filter_selective_blur(INTERNAL_FUNCTION_PARAMETERS)
  2778. {
  2779. PHP_GD_SINGLE_RES
  2780. if (gdImageSelectiveBlur(im_src) == 1) {
  2781. RETURN_TRUE;
  2782. }
  2783. RETURN_FALSE;
  2784. }
  2785. static void php_image_filter_mean_removal(INTERNAL_FUNCTION_PARAMETERS)
  2786. {
  2787. PHP_GD_SINGLE_RES
  2788. if (gdImageMeanRemoval(im_src) == 1) {
  2789. RETURN_TRUE;
  2790. }
  2791. RETURN_FALSE;
  2792. }
  2793. static void php_image_filter_smooth(INTERNAL_FUNCTION_PARAMETERS)
  2794. {
  2795. zval *SIM;
  2796. zend_long tmp;
  2797. gdImagePtr im_src;
  2798. double weight;
  2799. if (zend_parse_parameters(ZEND_NUM_ARGS(), "Old", &SIM, gd_image_ce, &tmp, &weight) == FAILURE) {
  2800. RETURN_THROWS();
  2801. }
  2802. im_src = php_gd_libgdimageptr_from_zval_p(SIM);
  2803. if (gdImageSmooth(im_src, (float)weight)==1) {
  2804. RETURN_TRUE;
  2805. }
  2806. RETURN_FALSE;
  2807. }
  2808. static void php_image_filter_pixelate(INTERNAL_FUNCTION_PARAMETERS)
  2809. {
  2810. zval *IM;
  2811. gdImagePtr im;
  2812. zend_long tmp, blocksize;
  2813. zend_bool mode = 0;
  2814. if (zend_parse_parameters(ZEND_NUM_ARGS(), "Oll|b", &IM, gd_image_ce, &tmp, &blocksize, &mode) == FAILURE) {
  2815. RETURN_THROWS();
  2816. }
  2817. im = php_gd_libgdimageptr_from_zval_p(IM);
  2818. if (gdImagePixelate(im, (int) blocksize, (const unsigned int) mode)) {
  2819. RETURN_TRUE;
  2820. }
  2821. RETURN_FALSE;
  2822. }
  2823. static void php_image_filter_scatter(INTERNAL_FUNCTION_PARAMETERS)
  2824. {
  2825. zval *IM;
  2826. zval *hash_colors = NULL;
  2827. gdImagePtr im;
  2828. zend_long tmp;
  2829. zend_long scatter_sub, scatter_plus;
  2830. if (zend_parse_parameters(ZEND_NUM_ARGS(), "Olll|a", &IM, gd_image_ce, &tmp, &scatter_sub, &scatter_plus, &hash_colors) == FAILURE) {
  2831. RETURN_THROWS();
  2832. }
  2833. im = php_gd_libgdimageptr_from_zval_p(IM);
  2834. if (hash_colors) {
  2835. uint32_t i = 0;
  2836. uint32_t num_colors = zend_hash_num_elements(Z_ARRVAL_P(hash_colors));
  2837. zval *color;
  2838. int *colors;
  2839. if (num_colors == 0) {
  2840. RETURN_BOOL(gdImageScatter(im, (int)scatter_sub, (int)scatter_plus));
  2841. }
  2842. colors = emalloc(num_colors * sizeof(int));
  2843. ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(hash_colors), color) {
  2844. *(colors + i++) = (int) zval_get_long(color);
  2845. } ZEND_HASH_FOREACH_END();
  2846. RETVAL_BOOL(gdImageScatterColor(im, (int)scatter_sub, (int)scatter_plus, colors, num_colors));
  2847. efree(colors);
  2848. } else {
  2849. RETURN_BOOL(gdImageScatter(im, (int) scatter_sub, (int) scatter_plus));
  2850. }
  2851. }
  2852. /* {{{ proto bool imagefilter(resource src_im, int filtertype[, int arg1 [, int arg2 [, int arg3 [, int arg4 ]]]] )
  2853. Applies Filter an image using a custom angle */
  2854. PHP_FUNCTION(imagefilter)
  2855. {
  2856. zval *tmp;
  2857. typedef void (*image_filter)(INTERNAL_FUNCTION_PARAMETERS);
  2858. zend_long filtertype;
  2859. image_filter filters[] =
  2860. {
  2861. php_image_filter_negate ,
  2862. php_image_filter_grayscale,
  2863. php_image_filter_brightness,
  2864. php_image_filter_contrast,
  2865. php_image_filter_colorize,
  2866. php_image_filter_edgedetect,
  2867. php_image_filter_emboss,
  2868. php_image_filter_gaussian_blur,
  2869. php_image_filter_selective_blur,
  2870. php_image_filter_mean_removal,
  2871. php_image_filter_smooth,
  2872. php_image_filter_pixelate,
  2873. php_image_filter_scatter
  2874. };
  2875. if (ZEND_NUM_ARGS() < 2 || ZEND_NUM_ARGS() > IMAGE_FILTER_MAX_ARGS) {
  2876. WRONG_PARAM_COUNT;
  2877. } else if (zend_parse_parameters(2, "Ol", &tmp, gd_image_ce, &filtertype) == FAILURE) {
  2878. RETURN_THROWS();
  2879. }
  2880. if (filtertype >= 0 && filtertype <= IMAGE_FILTER_MAX) {
  2881. filters[filtertype](INTERNAL_FUNCTION_PARAM_PASSTHRU);
  2882. }
  2883. }
  2884. /* }}} */
  2885. /* {{{ proto resource imageconvolution(resource src_im, array matrix3x3, double div, double offset)
  2886. Apply a 3x3 convolution matrix, using coefficient div and offset */
  2887. PHP_FUNCTION(imageconvolution)
  2888. {
  2889. zval *SIM, *hash_matrix;
  2890. zval *var = NULL, *var2 = NULL;
  2891. gdImagePtr im_src = NULL;
  2892. double div, offset;
  2893. int nelem, i, j, res;
  2894. float matrix[3][3] = {{0,0,0}, {0,0,0}, {0,0,0}};
  2895. if (zend_parse_parameters(ZEND_NUM_ARGS(), "Oadd", &SIM, gd_image_ce, &hash_matrix, &div, &offset) == FAILURE) {
  2896. RETURN_THROWS();
  2897. }
  2898. im_src = php_gd_libgdimageptr_from_zval_p(SIM);
  2899. nelem = zend_hash_num_elements(Z_ARRVAL_P(hash_matrix));
  2900. if (nelem != 3) {
  2901. zend_argument_value_error(2, "must be a 3x3 array");
  2902. RETURN_THROWS();
  2903. }
  2904. for (i=0; i<3; i++) {
  2905. if ((var = zend_hash_index_find(Z_ARRVAL_P(hash_matrix), (i))) != NULL && Z_TYPE_P(var) == IS_ARRAY) {
  2906. if (zend_hash_num_elements(Z_ARRVAL_P(var)) != 3 ) {
  2907. 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)));
  2908. RETURN_THROWS();
  2909. }
  2910. for (j=0; j<3; j++) {
  2911. if ((var2 = zend_hash_index_find(Z_ARRVAL_P(var), j)) != NULL) {
  2912. matrix[i][j] = (float) zval_get_double(var2);
  2913. } else {
  2914. zend_argument_value_error(2, "must be a 3x3 array, matrix[%d][%d] cannot be found (missing integer key)", i, j);
  2915. RETURN_THROWS();
  2916. }
  2917. }
  2918. }
  2919. }
  2920. res = gdImageConvolution(im_src, matrix, (float)div, (float)offset);
  2921. if (res) {
  2922. RETURN_TRUE;
  2923. } else {
  2924. RETURN_FALSE;
  2925. }
  2926. }
  2927. /* }}} */
  2928. /* End section: Filters */
  2929. /* {{{ proto bool imageflip(resource im, int mode)
  2930. Flip an image (in place) horizontally, vertically or both directions. */
  2931. PHP_FUNCTION(imageflip)
  2932. {
  2933. zval *IM;
  2934. zend_long mode;
  2935. gdImagePtr im;
  2936. if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ol", &IM, gd_image_ce, &mode) == FAILURE) {
  2937. RETURN_THROWS();
  2938. }
  2939. im = php_gd_libgdimageptr_from_zval_p(IM);
  2940. switch (mode) {
  2941. case GD_FLIP_VERTICAL:
  2942. gdImageFlipVertical(im);
  2943. break;
  2944. case GD_FLIP_HORIZONTAL:
  2945. gdImageFlipHorizontal(im);
  2946. break;
  2947. case GD_FLIP_BOTH:
  2948. gdImageFlipBoth(im);
  2949. break;
  2950. default:
  2951. zend_argument_value_error(2, "must be either IMG_FLIP_VERTICAL, IMG_FLIP_HORIZONTAL, or IMG_FLIP_BOTH");
  2952. RETURN_THROWS();
  2953. }
  2954. RETURN_TRUE;
  2955. }
  2956. /* }}} */
  2957. /* {{{ proto bool imageantialias(resource im, bool on)
  2958. Should antialiased functions used or not*/
  2959. PHP_FUNCTION(imageantialias)
  2960. {
  2961. zval *IM;
  2962. zend_bool alias;
  2963. gdImagePtr im;
  2964. if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ob", &IM, gd_image_ce, &alias) == FAILURE) {
  2965. RETURN_THROWS();
  2966. }
  2967. im = php_gd_libgdimageptr_from_zval_p(IM);
  2968. if (im->trueColor) {
  2969. im->AA = alias;
  2970. }
  2971. RETURN_TRUE;
  2972. }
  2973. /* }}} */
  2974. /* {{{ proto resource imagecrop(resource im, array rect)
  2975. Crop an image using the given coordinates and size, x, y, width and height. */
  2976. PHP_FUNCTION(imagecrop)
  2977. {
  2978. zval *IM;
  2979. gdImagePtr im;
  2980. gdImagePtr im_crop;
  2981. gdRect rect;
  2982. zval *z_rect;
  2983. zval *tmp;
  2984. if (zend_parse_parameters(ZEND_NUM_ARGS(), "Oa", &IM, gd_image_ce, &z_rect) == FAILURE) {
  2985. RETURN_THROWS();
  2986. }
  2987. im = php_gd_libgdimageptr_from_zval_p(IM);
  2988. if ((tmp = zend_hash_str_find(Z_ARRVAL_P(z_rect), "x", sizeof("x") -1)) != NULL) {
  2989. rect.x = zval_get_long(tmp);
  2990. } else {
  2991. zend_argument_value_error(2, "must have an 'x' key");
  2992. RETURN_THROWS();
  2993. }
  2994. if ((tmp = zend_hash_str_find(Z_ARRVAL_P(z_rect), "y", sizeof("y") - 1)) != NULL) {
  2995. rect.y = zval_get_long(tmp);
  2996. } else {
  2997. zend_argument_value_error(2, "must have a 'y' key");
  2998. RETURN_THROWS();
  2999. }
  3000. if ((tmp = zend_hash_str_find(Z_ARRVAL_P(z_rect), "width", sizeof("width") - 1)) != NULL) {
  3001. rect.width = zval_get_long(tmp);
  3002. } else {
  3003. zend_argument_value_error(2, "must have a 'width' key");
  3004. RETURN_THROWS();
  3005. }
  3006. if ((tmp = zend_hash_str_find(Z_ARRVAL_P(z_rect), "height", sizeof("height") - 1)) != NULL) {
  3007. rect.height = zval_get_long(tmp);
  3008. } else {
  3009. zend_argument_value_error(2, "must have a 'height' key");
  3010. RETURN_THROWS();
  3011. }
  3012. im_crop = gdImageCrop(im, &rect);
  3013. if (im_crop == NULL) {
  3014. RETURN_FALSE;
  3015. }
  3016. php_gd_assign_libgdimageptr_as_extgdimage(return_value, im_crop);
  3017. }
  3018. /* }}} */
  3019. /* {{{ proto resource imagecropauto(resource im [, int mode = GD_CROP_DEFAULT [, float threshold [, int color]]])
  3020. Crop an image automatically using one of the available modes. */
  3021. PHP_FUNCTION(imagecropauto)
  3022. {
  3023. zval *IM;
  3024. zend_long mode = GD_CROP_DEFAULT;
  3025. zend_long color = -1;
  3026. double threshold = 0.5f;
  3027. gdImagePtr im;
  3028. gdImagePtr im_crop;
  3029. if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|ldl", &IM, gd_image_ce, &mode, &threshold, &color) == FAILURE) {
  3030. RETURN_THROWS();
  3031. }
  3032. im = php_gd_libgdimageptr_from_zval_p(IM);
  3033. switch (mode) {
  3034. case GD_CROP_DEFAULT:
  3035. case GD_CROP_TRANSPARENT:
  3036. case GD_CROP_BLACK:
  3037. case GD_CROP_WHITE:
  3038. case GD_CROP_SIDES:
  3039. im_crop = gdImageCropAuto(im, mode);
  3040. break;
  3041. case GD_CROP_THRESHOLD:
  3042. if (color < 0 || (!gdImageTrueColor(im) && color >= gdImageColorsTotal(im))) {
  3043. zend_argument_value_error(4, "must be greater than or equal to 0 when using the threshold mode");
  3044. RETURN_THROWS();
  3045. }
  3046. im_crop = gdImageCropThreshold(im, color, (float) threshold);
  3047. break;
  3048. default:
  3049. zend_argument_value_error(2, "must be a valid mode");
  3050. RETURN_THROWS();
  3051. }
  3052. if (im_crop == NULL) {
  3053. RETURN_FALSE;
  3054. }
  3055. php_gd_assign_libgdimageptr_as_extgdimage(return_value, im_crop);
  3056. }
  3057. /* }}} */
  3058. /* {{{ proto resource imagescale(resource im, int new_width[, int new_height[, int method]])
  3059. Scale an image using the given new width and height. */
  3060. PHP_FUNCTION(imagescale)
  3061. {
  3062. zval *IM;
  3063. gdImagePtr im;
  3064. gdImagePtr im_scaled = NULL;
  3065. int new_width, new_height;
  3066. zend_long tmp_w, tmp_h=-1, tmp_m = GD_BILINEAR_FIXED;
  3067. gdInterpolationMethod method, old_method;
  3068. if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ol|ll", &IM, gd_image_ce, &tmp_w, &tmp_h, &tmp_m) == FAILURE) {
  3069. RETURN_THROWS();
  3070. }
  3071. method = tmp_m;
  3072. im = php_gd_libgdimageptr_from_zval_p(IM);
  3073. if (tmp_h < 0 || tmp_w < 0) {
  3074. /* preserve ratio */
  3075. long src_x, src_y;
  3076. src_x = gdImageSX(im);
  3077. src_y = gdImageSY(im);
  3078. if (src_x && tmp_h < 0) {
  3079. tmp_h = tmp_w * src_y / src_x;
  3080. }
  3081. if (src_y && tmp_w < 0) {
  3082. tmp_w = tmp_h * src_x / src_y;
  3083. }
  3084. }
  3085. if (tmp_h <= 0 || tmp_h > INT_MAX || tmp_w <= 0 || tmp_w > INT_MAX) {
  3086. RETURN_FALSE;
  3087. }
  3088. new_width = tmp_w;
  3089. new_height = tmp_h;
  3090. /* gdImageGetInterpolationMethod() is only available as of GD 2.1.1 */
  3091. old_method = im->interpolation_id;
  3092. if (gdImageSetInterpolationMethod(im, method)) {
  3093. im_scaled = gdImageScale(im, new_width, new_height);
  3094. }
  3095. gdImageSetInterpolationMethod(im, old_method);
  3096. if (im_scaled == NULL) {
  3097. RETURN_FALSE;
  3098. }
  3099. php_gd_assign_libgdimageptr_as_extgdimage(return_value, im_scaled);
  3100. }
  3101. /* }}} */
  3102. /* {{{ proto resource imageaffine(resource src, array affine[, array clip])
  3103. Return an image containing the affine tramsformed src image, using an optional clipping area */
  3104. PHP_FUNCTION(imageaffine)
  3105. {
  3106. zval *IM;
  3107. gdImagePtr src;
  3108. gdImagePtr dst;
  3109. gdRect rect;
  3110. gdRectPtr pRect = NULL;
  3111. zval *z_rect = NULL;
  3112. zval *z_affine;
  3113. zval *tmp;
  3114. double affine[6];
  3115. int i, nelems;
  3116. zval *zval_affine_elem = NULL;
  3117. if (zend_parse_parameters(ZEND_NUM_ARGS(), "Oa|a", &IM, gd_image_ce, &z_affine, &z_rect) == FAILURE) {
  3118. RETURN_THROWS();
  3119. }
  3120. src = php_gd_libgdimageptr_from_zval_p(IM);
  3121. if ((nelems = zend_hash_num_elements(Z_ARRVAL_P(z_affine))) != 6) {
  3122. zend_argument_value_error(2, "must have 6 elements");
  3123. RETURN_THROWS();
  3124. }
  3125. for (i = 0; i < nelems; i++) {
  3126. if ((zval_affine_elem = zend_hash_index_find(Z_ARRVAL_P(z_affine), i)) != NULL) {
  3127. switch (Z_TYPE_P(zval_affine_elem)) {
  3128. case IS_LONG:
  3129. affine[i] = Z_LVAL_P(zval_affine_elem);
  3130. break;
  3131. case IS_DOUBLE:
  3132. affine[i] = Z_DVAL_P(zval_affine_elem);
  3133. break;
  3134. case IS_STRING:
  3135. affine[i] = zval_get_double(zval_affine_elem);
  3136. break;
  3137. default:
  3138. zend_argument_type_error(3, "contains invalid type for element %i", i);
  3139. RETURN_THROWS();
  3140. }
  3141. }
  3142. }
  3143. if (z_rect != NULL) {
  3144. if ((tmp = zend_hash_str_find(Z_ARRVAL_P(z_rect), "x", sizeof("x") - 1)) != NULL) {
  3145. rect.x = zval_get_long(tmp);
  3146. } else {
  3147. zend_argument_value_error(3, "must have an 'x' key");
  3148. RETURN_THROWS();
  3149. }
  3150. if ((tmp = zend_hash_str_find(Z_ARRVAL_P(z_rect), "y", sizeof("y") - 1)) != NULL) {
  3151. rect.y = zval_get_long(tmp);
  3152. } else {
  3153. zend_argument_value_error(3, "must have a 'y' key");
  3154. RETURN_THROWS();
  3155. }
  3156. if ((tmp = zend_hash_str_find(Z_ARRVAL_P(z_rect), "width", sizeof("width") - 1)) != NULL) {
  3157. rect.width = zval_get_long(tmp);
  3158. } else {
  3159. zend_argument_value_error(3, "must have a 'width' key");
  3160. RETURN_THROWS();
  3161. }
  3162. if ((tmp = zend_hash_str_find(Z_ARRVAL_P(z_rect), "height", sizeof("height") - 1)) != NULL) {
  3163. rect.height = zval_get_long(tmp);
  3164. } else {
  3165. zend_argument_value_error(3, "must have a 'height' key");
  3166. RETURN_THROWS();
  3167. }
  3168. pRect = &rect;
  3169. }
  3170. if (gdTransformAffineGetImage(&dst, src, pRect, affine) != GD_TRUE) {
  3171. RETURN_FALSE;
  3172. }
  3173. if (dst == NULL) {
  3174. RETURN_FALSE;
  3175. }
  3176. php_gd_assign_libgdimageptr_as_extgdimage(return_value, dst);
  3177. }
  3178. /* }}} */
  3179. /* {{{ proto array imageaffinematrixget(int type[, array options])
  3180. Return an image containing the affine tramsformed src image, using an optional clipping area */
  3181. PHP_FUNCTION(imageaffinematrixget)
  3182. {
  3183. double affine[6];
  3184. zend_long type;
  3185. zval *options = NULL;
  3186. zval *tmp;
  3187. int res = GD_FALSE, i;
  3188. if (zend_parse_parameters(ZEND_NUM_ARGS(), "l|z", &type, &options) == FAILURE) {
  3189. RETURN_THROWS();
  3190. }
  3191. switch((gdAffineStandardMatrix)type) {
  3192. case GD_AFFINE_TRANSLATE:
  3193. case GD_AFFINE_SCALE: {
  3194. double x, y;
  3195. if (!options || Z_TYPE_P(options) != IS_ARRAY) {
  3196. zend_argument_type_error(1, "must be of type array when using translate or scale");
  3197. RETURN_THROWS();
  3198. }
  3199. if ((tmp = zend_hash_str_find(Z_ARRVAL_P(options), "x", sizeof("x") - 1)) != NULL) {
  3200. x = zval_get_double(tmp);
  3201. } else {
  3202. zend_argument_value_error(2, "must have an 'x' key");
  3203. RETURN_THROWS();
  3204. }
  3205. if ((tmp = zend_hash_str_find(Z_ARRVAL_P(options), "y", sizeof("y") - 1)) != NULL) {
  3206. y = zval_get_double(tmp);
  3207. } else {
  3208. zend_argument_value_error(2, "must have a 'y' key");
  3209. RETURN_THROWS();
  3210. }
  3211. if (type == GD_AFFINE_TRANSLATE) {
  3212. res = gdAffineTranslate(affine, x, y);
  3213. } else {
  3214. res = gdAffineScale(affine, x, y);
  3215. }
  3216. break;
  3217. }
  3218. case GD_AFFINE_ROTATE:
  3219. case GD_AFFINE_SHEAR_HORIZONTAL:
  3220. case GD_AFFINE_SHEAR_VERTICAL: {
  3221. double angle;
  3222. if (!options) {
  3223. zend_argument_type_error(2, "must be of type int|double when using rotate or shear");
  3224. RETURN_THROWS();
  3225. }
  3226. angle = zval_get_double(options);
  3227. if (type == GD_AFFINE_SHEAR_HORIZONTAL) {
  3228. res = gdAffineShearHorizontal(affine, angle);
  3229. } else if (type == GD_AFFINE_SHEAR_VERTICAL) {
  3230. res = gdAffineShearVertical(affine, angle);
  3231. } else {
  3232. res = gdAffineRotate(affine, angle);
  3233. }
  3234. break;
  3235. }
  3236. default:
  3237. zend_argument_value_error(1, "must be a valid element type");
  3238. RETURN_THROWS();
  3239. }
  3240. if (res == GD_FALSE) {
  3241. RETURN_FALSE;
  3242. } else {
  3243. array_init(return_value);
  3244. for (i = 0; i < 6; i++) {
  3245. add_index_double(return_value, i, affine[i]);
  3246. }
  3247. }
  3248. } /* }}} */
  3249. /* {{{ proto array imageaffineconcat(array m1, array m2)
  3250. Concat two matrices (as in doing many ops in one go) */
  3251. PHP_FUNCTION(imageaffinematrixconcat)
  3252. {
  3253. double m1[6];
  3254. double m2[6];
  3255. double mr[6];
  3256. zval *tmp;
  3257. zval *z_m1;
  3258. zval *z_m2;
  3259. int i;
  3260. if (zend_parse_parameters(ZEND_NUM_ARGS(), "aa", &z_m1, &z_m2) == FAILURE) {
  3261. RETURN_THROWS();
  3262. }
  3263. if (zend_hash_num_elements(Z_ARRVAL_P(z_m1)) != 6) {
  3264. zend_argument_value_error(1, "must have 6 elements");
  3265. RETURN_THROWS();
  3266. }
  3267. if (zend_hash_num_elements(Z_ARRVAL_P(z_m2)) != 6) {
  3268. zend_argument_value_error(1, "must have 6 elements");
  3269. RETURN_THROWS();
  3270. }
  3271. for (i = 0; i < 6; i++) {
  3272. if ((tmp = zend_hash_index_find(Z_ARRVAL_P(z_m1), i)) != NULL) {
  3273. switch (Z_TYPE_P(tmp)) {
  3274. case IS_LONG:
  3275. m1[i] = Z_LVAL_P(tmp);
  3276. break;
  3277. case IS_DOUBLE:
  3278. m1[i] = Z_DVAL_P(tmp);
  3279. break;
  3280. case IS_STRING:
  3281. m1[i] = zval_get_double(tmp);
  3282. break;
  3283. default:
  3284. zend_argument_type_error(1, "contains invalid type for element %i", i);
  3285. RETURN_THROWS();
  3286. }
  3287. }
  3288. if ((tmp = zend_hash_index_find(Z_ARRVAL_P(z_m2), i)) != NULL) {
  3289. switch (Z_TYPE_P(tmp)) {
  3290. case IS_LONG:
  3291. m2[i] = Z_LVAL_P(tmp);
  3292. break;
  3293. case IS_DOUBLE:
  3294. m2[i] = Z_DVAL_P(tmp);
  3295. break;
  3296. case IS_STRING:
  3297. m2[i] = zval_get_double(tmp);
  3298. break;
  3299. default:
  3300. zend_argument_type_error(2, "contains invalid type for element %i", i);
  3301. RETURN_THROWS();
  3302. }
  3303. }
  3304. }
  3305. if (gdAffineConcat (mr, m1, m2) != GD_TRUE) {
  3306. RETURN_FALSE;
  3307. }
  3308. array_init(return_value);
  3309. for (i = 0; i < 6; i++) {
  3310. add_index_double(return_value, i, mr[i]);
  3311. }
  3312. } /* }}} */
  3313. /* {{{ proto resource imagegetinterpolation(resource im)
  3314. Get the default interpolation method. */
  3315. PHP_FUNCTION(imagegetinterpolation)
  3316. {
  3317. zval *IM;
  3318. gdImagePtr im;
  3319. if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &IM, gd_image_ce) == FAILURE) {
  3320. RETURN_THROWS();
  3321. }
  3322. im = php_gd_libgdimageptr_from_zval_p(IM);
  3323. #ifdef HAVE_GD_GET_INTERPOLATION
  3324. RETURN_LONG(gdImageGetInterpolationMethod(im));
  3325. #else
  3326. RETURN_LONG(im->interpolation_id);
  3327. #endif
  3328. }
  3329. /* }}} */
  3330. /* {{{ proto resource imagesetinterpolation(resource im [, int method]])
  3331. Set the default interpolation method, passing -1 or 0 sets it to the libgd default (bilinear). */
  3332. PHP_FUNCTION(imagesetinterpolation)
  3333. {
  3334. zval *IM;
  3335. gdImagePtr im;
  3336. zend_long method = GD_BILINEAR_FIXED;
  3337. if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|l", &IM, gd_image_ce, &method) == FAILURE) {
  3338. RETURN_THROWS();
  3339. }
  3340. im = php_gd_libgdimageptr_from_zval_p(IM);
  3341. if (method == -1) {
  3342. method = GD_BILINEAR_FIXED;
  3343. }
  3344. RETURN_BOOL(gdImageSetInterpolationMethod(im, (gdInterpolationMethod) method));
  3345. }
  3346. /* }}} */
  3347. /* {{{ proto array imageresolution(resource im [, res_x, [res_y]])
  3348. Get or set the resolution of the image in DPI. */
  3349. PHP_FUNCTION(imageresolution)
  3350. {
  3351. zval *IM;
  3352. gdImagePtr im;
  3353. zend_long res_x = GD_RESOLUTION, res_y = GD_RESOLUTION;
  3354. if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|ll", &IM, gd_image_ce, &res_x, &res_y) == FAILURE) {
  3355. RETURN_THROWS();
  3356. }
  3357. im = php_gd_libgdimageptr_from_zval_p(IM);
  3358. switch (ZEND_NUM_ARGS()) {
  3359. case 3:
  3360. gdImageSetResolution(im, res_x, res_y);
  3361. RETURN_TRUE;
  3362. case 2:
  3363. gdImageSetResolution(im, res_x, res_x);
  3364. RETURN_TRUE;
  3365. default:
  3366. array_init(return_value);
  3367. add_next_index_long(return_value, gdImageResolutionX(im));
  3368. add_next_index_long(return_value, gdImageResolutionY(im));
  3369. }
  3370. }
  3371. /* }}} */
  3372. /*********************************************************
  3373. *
  3374. * Stream Handling
  3375. * Formerly contained within ext/gd/gd_ctx.c and included
  3376. * at the the top of this file
  3377. *
  3378. ********************************************************/
  3379. #define CTX_PUTC(c,ctx) ctx->putC(ctx, c)
  3380. static void _php_image_output_putc(struct gdIOCtx *ctx, int c) /* {{{ */
  3381. {
  3382. /* without the following downcast, the write will fail
  3383. * (i.e., will write a zero byte) for all
  3384. * big endian architectures:
  3385. */
  3386. unsigned char ch = (unsigned char) c;
  3387. php_write(&ch, 1);
  3388. } /* }}} */
  3389. static int _php_image_output_putbuf(struct gdIOCtx *ctx, const void* buf, int l) /* {{{ */
  3390. {
  3391. return php_write((void *)buf, l);
  3392. } /* }}} */
  3393. static void _php_image_output_ctxfree(struct gdIOCtx *ctx) /* {{{ */
  3394. {
  3395. if(ctx) {
  3396. efree(ctx);
  3397. }
  3398. } /* }}} */
  3399. static void _php_image_stream_putc(struct gdIOCtx *ctx, int c) /* {{{ */ {
  3400. char ch = (char) c;
  3401. php_stream * stream = (php_stream *)ctx->data;
  3402. php_stream_write(stream, &ch, 1);
  3403. } /* }}} */
  3404. static int _php_image_stream_putbuf(struct gdIOCtx *ctx, const void* buf, int l) /* {{{ */
  3405. {
  3406. php_stream * stream = (php_stream *)ctx->data;
  3407. return php_stream_write(stream, (void *)buf, l);
  3408. } /* }}} */
  3409. static void _php_image_stream_ctxfree(struct gdIOCtx *ctx) /* {{{ */
  3410. {
  3411. if(ctx->data) {
  3412. ctx->data = NULL;
  3413. }
  3414. if(ctx) {
  3415. efree(ctx);
  3416. }
  3417. } /* }}} */
  3418. static void _php_image_stream_ctxfreeandclose(struct gdIOCtx *ctx) /* {{{ */
  3419. {
  3420. if(ctx->data) {
  3421. php_stream_close((php_stream *) ctx->data);
  3422. ctx->data = NULL;
  3423. }
  3424. if(ctx) {
  3425. efree(ctx);
  3426. }
  3427. } /* }}} */
  3428. /* {{{ _php_image_output_ctx */
  3429. static void _php_image_output_ctx(INTERNAL_FUNCTION_PARAMETERS, int image_type, char *tn, void (*func_p)())
  3430. {
  3431. zval *imgind;
  3432. char *file = NULL;
  3433. size_t file_len = 0;
  3434. zend_long quality, basefilter;
  3435. zend_bool compressed = 1;
  3436. gdImagePtr im;
  3437. int argc = ZEND_NUM_ARGS();
  3438. int q = -1, i;
  3439. int f = -1;
  3440. gdIOCtx *ctx = NULL;
  3441. zval *to_zval = NULL;
  3442. php_stream *stream;
  3443. int close_stream = 1;
  3444. /* The third (quality) parameter for Wbmp and Xbm stands for the foreground color index when called
  3445. * from imagey<type>().
  3446. */
  3447. switch (image_type) {
  3448. case PHP_GDIMG_TYPE_XBM:
  3449. if (zend_parse_parameters(argc, "Op!|ll", &imgind, gd_image_ce, &file, &file_len, &quality, &basefilter) == FAILURE) {
  3450. RETURN_THROWS();
  3451. }
  3452. break;
  3453. case PHP_GDIMG_TYPE_BMP:
  3454. if (zend_parse_parameters(argc, "O|z!b", &imgind, gd_image_ce, &to_zval, &compressed) == FAILURE) {
  3455. RETURN_THROWS();
  3456. }
  3457. break;
  3458. default:
  3459. /* PHP_GDIMG_TYPE_GIF
  3460. * PHP_GDIMG_TYPE_PNG
  3461. * PHP_GDIMG_TYPE_JPG
  3462. * PHP_GDIMG_TYPE_WBM
  3463. * PHP_GDIMG_TYPE_WEBP
  3464. * */
  3465. if (zend_parse_parameters(argc, "O|z!ll", &imgind, gd_image_ce, &to_zval, &quality, &basefilter) == FAILURE) {
  3466. RETURN_THROWS();
  3467. }
  3468. }
  3469. im = php_gd_libgdimageptr_from_zval_p(imgind);
  3470. if (image_type != PHP_GDIMG_TYPE_BMP && argc >= 3) {
  3471. q = quality; /* or colorindex for foreground of BW images (defaults to black) */
  3472. if (argc == 4) {
  3473. f = basefilter;
  3474. }
  3475. }
  3476. if (argc > 1 && to_zval != NULL) {
  3477. if (Z_TYPE_P(to_zval) == IS_RESOURCE) {
  3478. php_stream_from_zval_no_verify(stream, to_zval);
  3479. if (stream == NULL) {
  3480. RETURN_FALSE;
  3481. }
  3482. close_stream = 0;
  3483. } else if (Z_TYPE_P(to_zval) == IS_STRING) {
  3484. if (CHECK_ZVAL_NULL_PATH(to_zval)) {
  3485. zend_argument_type_error(2, "must not contain null bytes");
  3486. RETURN_THROWS();
  3487. }
  3488. stream = php_stream_open_wrapper(Z_STRVAL_P(to_zval), "wb", REPORT_ERRORS|IGNORE_PATH|IGNORE_URL_WIN, NULL);
  3489. if (stream == NULL) {
  3490. RETURN_FALSE;
  3491. }
  3492. } else {
  3493. php_error_docref(NULL, E_WARNING, "Invalid 2nd parameter, it must a filename or a stream");
  3494. RETURN_FALSE;
  3495. }
  3496. } else if (argc > 1 && file != NULL) {
  3497. stream = php_stream_open_wrapper(file, "wb", REPORT_ERRORS|IGNORE_PATH|IGNORE_URL_WIN, NULL);
  3498. if (stream == NULL) {
  3499. RETURN_FALSE;
  3500. }
  3501. } else {
  3502. ctx = ecalloc(1, sizeof(gdIOCtx));
  3503. ctx->putC = _php_image_output_putc;
  3504. ctx->putBuf = _php_image_output_putbuf;
  3505. ctx->gd_free = _php_image_output_ctxfree;
  3506. }
  3507. if (!ctx) {
  3508. ctx = ecalloc(1, sizeof(gdIOCtx));
  3509. ctx->putC = _php_image_stream_putc;
  3510. ctx->putBuf = _php_image_stream_putbuf;
  3511. if (close_stream) {
  3512. ctx->gd_free = _php_image_stream_ctxfreeandclose;
  3513. } else {
  3514. ctx->gd_free = _php_image_stream_ctxfree;
  3515. }
  3516. ctx->data = (void *)stream;
  3517. }
  3518. switch(image_type) {
  3519. case PHP_GDIMG_TYPE_JPG:
  3520. (*func_p)(im, ctx, q);
  3521. break;
  3522. case PHP_GDIMG_TYPE_WEBP:
  3523. if (q == -1) {
  3524. q = 80;
  3525. }
  3526. (*func_p)(im, ctx, q);
  3527. break;
  3528. case PHP_GDIMG_TYPE_PNG:
  3529. (*func_p)(im, ctx, q, f);
  3530. break;
  3531. case PHP_GDIMG_TYPE_XBM:
  3532. case PHP_GDIMG_TYPE_WBM:
  3533. if (argc < 3) {
  3534. for(i=0; i < gdImageColorsTotal(im); i++) {
  3535. if(!gdImageRed(im, i) && !gdImageGreen(im, i) && !gdImageBlue(im, i)) break;
  3536. }
  3537. q = i;
  3538. }
  3539. if (image_type == PHP_GDIMG_TYPE_XBM) {
  3540. (*func_p)(im, file ? file : "", q, ctx);
  3541. } else {
  3542. (*func_p)(im, q, ctx);
  3543. }
  3544. break;
  3545. case PHP_GDIMG_TYPE_BMP:
  3546. (*func_p)(im, ctx, (int) compressed);
  3547. break;
  3548. default:
  3549. (*func_p)(im, ctx);
  3550. break;
  3551. }
  3552. ctx->gd_free(ctx);
  3553. RETURN_TRUE;
  3554. }
  3555. /* }}} */