/*
   +----------------------------------------------------------------------+
   | PHP version 4.0                                                      |
   +----------------------------------------------------------------------+
   | Copyright (c) 2000, 2001 Matt McClanahan                             |
   | Copyright (c) 2000, 2001, 2005 Steve Langasek                        |
   +----------------------------------------------------------------------+
   | This source file is subject to version 2.02 of the PHP license,      |
   | that is bundled with this package in the file LICENSE, and is        |
   | available at through the world-wide-web at                           |
   | http://www.php.net/license/2_02.txt.                                 |
   | If you did not receive a copy of the PHP license and are unable to   |
   | obtain it through the world-wide-web, please send a note to          |
   | license@php.net so we can mail you a copy immediately.               |
   |                                                                      |
   | Alternatively, you may distribute and/or modify this code under the  |
   | terms of version 2 of the GNU Library General Public License as      |
   | published by the Free Software Foundation.                           |
   |                                                                      |
   | This software is distributed in the hope that it will be useful,     |
   | but WITHOUT ANY WARRANTY; without even the implied warranty of       |
   | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU    |
   | Library General Public License for more details.                     |
   |                                                                      |
   | You should have received a copy of the GNU Library General Public    |
   | License in the file COPYING accompanying this software; if not,      |
   | write to the Free Software Foundation, Inc.,                         |
   | 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA              |
   |                                                                      |
   +----------------------------------------------------------------------+
   | Authors: Matt McClanahan <cardinal@dodds.net>                        |
   |          Steve Langasek <vorlon@dodds.net>                           |
   +----------------------------------------------------------------------+
 */

#include "php.h"
#include "php_config.h"
#include "php_ini.h"
#include "php_imlib.h"

#if HAVE_IMLIB

ZEND_DECLARE_MODULE_GLOBALS(imlib);

static
	ZEND_BEGIN_ARG_INFO(third_and_fourth_arg_force_ref, 0)
		ZEND_ARG_PASS_INFO(0)
		ZEND_ARG_PASS_INFO(0)
		ZEND_ARG_PASS_INFO(1)
		ZEND_ARG_PASS_INFO(1)
	ZEND_END_ARG_INFO();

static
	ZEND_BEGIN_ARG_INFO(second_through_fifth_arg_force_ref, 0)
		ZEND_ARG_PASS_INFO(0)
		ZEND_ARG_PASS_INFO(1)
		ZEND_ARG_PASS_INFO(1)
		ZEND_ARG_PASS_INFO(1)
		ZEND_ARG_PASS_INFO(1)
	ZEND_END_ARG_INFO();

static int le_imlib_cr;
static int le_imlib_font;
static int le_imlib_img;
static int le_imlib_poly;

function_entry imlib_functions[] = {
	PHP_FE(imlib_add_color_to_color_range,NULL)
	PHP_FE(imlib_blend_image_onto_image,NULL)
	PHP_FE(imlib_clone_image,NULL)
	PHP_FE(imlib_create_color_range,NULL)
	PHP_FE(imlib_create_cropped_image,NULL)
	PHP_FE(imlib_create_cropped_scaled_image,NULL)
	PHP_FE(imlib_create_image,NULL)
	PHP_FE(imlib_create_rotated_image,NULL)
	PHP_FE(imlib_create_scaled_image,NULL)
	PHP_FE(imlib_dump_image,second_arg_force_ref)
	PHP_FE(imlib_free_color_range,NULL)
	PHP_FE(imlib_free_font,NULL)
	PHP_FE(imlib_free_image,NULL)
	PHP_FE(imlib_get_text_size,third_and_fourth_arg_force_ref)
	PHP_FE(imlib_image_blur,NULL)
	PHP_FE(imlib_image_draw_ellipse,NULL)
	PHP_FE(imlib_image_draw_line,NULL)
	PHP_FE(imlib_image_draw_polygon,NULL)
	PHP_FE(imlib_image_draw_rectangle,NULL)
	PHP_FE(imlib_image_fill_color_range_rectangle,NULL)
	PHP_FE(imlib_image_fill_ellipse,NULL)
	PHP_FE(imlib_image_fill_polygon,NULL)
	PHP_FE(imlib_image_fill_rectangle,NULL)
	PHP_FE(imlib_image_flip_horizontal,NULL)
	PHP_FE(imlib_image_flip_vertical,NULL)
	PHP_FE(imlib_image_flip_diagonal,NULL)
	PHP_FE(imlib_image_format,NULL)
	PHP_FE(imlib_image_get_filename,NULL)
	PHP_FE(imlib_image_get_height,NULL)
	PHP_FE(imlib_image_get_width,NULL)
	PHP_FE(imlib_image_has_alpha,NULL)
	PHP_FE(imlib_image_modify_alpha,NULL)
	PHP_FE(imlib_image_sharpen,NULL)
	PHP_FE(imlib_image_set_format,NULL)
	PHP_FE(imlib_image_tile_horizontal,NULL)
	PHP_FE(imlib_image_tile_vertical,NULL)
	PHP_FE(imlib_image_tile,NULL)
	PHP_FE(imlib_list_fonts,NULL)
	PHP_FE(imlib_load_font,NULL)
	PHP_FE(imlib_load_image,second_arg_force_ref)
	PHP_FALIAS(imlib_load_image_with_error_return,imlib_load_image,second_arg_force_ref)
	PHP_FE(imlib_polygon_add_point,NULL)
	PHP_FE(imlib_polygon_contains_point,NULL)
	PHP_FE(imlib_polygon_free,NULL)
	PHP_FE(imlib_polygon_get_bounds,second_through_fifth_arg_force_ref)
	PHP_FE(imlib_polygon_new,NULL)
	PHP_FE(imlib_save_image,third_arg_force_ref)
	PHP_FALIAS(imlib_save_image_with_error_return,imlib_save_image,third_arg_force_ref)
	PHP_FE(imlib_text_draw,NULL)
	PHP_FE(imlib_get_cache_size,NULL)
	PHP_FE(imlib_set_cache_size,NULL)
	{NULL, NULL, NULL}
};

PHP_INI_BEGIN()
STD_PHP_INI_ENTRY("imlib.font_path",
		  "/usr/local/share/fonts",
		  PHP_INI_SYSTEM|PHP_INI_PERDIR,
		  OnUpdateString,
		  font_path,
		  zend_imlib_globals,
		  imlib_globals)
STD_PHP_INI_ENTRY("imlib.min_cache_size","0",PHP_INI_SYSTEM,
                  OnUpdateLong,min_cache_size,
                  zend_imlib_globals,imlib_globals)
STD_PHP_INI_ENTRY("imlib.max_cache_size","4194304",PHP_INI_SYSTEM,
                  OnUpdateLong,max_cache_size,
                  zend_imlib_globals,imlib_globals)
STD_PHP_INI_ENTRY("imlib.cache_size","0",PHP_INI_SYSTEM|PHP_INI_PERDIR,
                  OnUpdateLong,cache_size,
                  zend_imlib_globals,imlib_globals)
PHP_INI_ENTRY("imlib.font_cache_size","524288",PHP_INI_SYSTEM,
              OnUpdateFontCacheSize)
PHP_INI_END()

zend_module_entry imlib_module_entry = {
	STANDARD_MODULE_HEADER,
	"imlib",
	imlib_functions,
	PHP_MINIT(imlib),
	PHP_MSHUTDOWN(imlib),
	PHP_RINIT(imlib),
	PHP_RSHUTDOWN(imlib),
	PHP_MINFO(imlib),
	NO_VERSION_YET,
	STANDARD_MODULE_PROPERTIES
};

PHP_INI_MH(OnUpdateFontCacheSize)
{
   int size;
   if (sscanf(new_value,"%d",&size)==1)
   {
      imlib_set_font_cache_size(size);
      return SUCCESS;
   }
   else
   {
      return FAILURE;
   }
}

static void _php_imlib_free_cr(Imlib_Color_Range cr)
{
   imlib_context_set_color_range(cr);
   imlib_free_color_range();
}

static void _php_imlib_free_font(Imlib_Font fn)
{
   imlib_context_set_font(fn);
   imlib_free_font();
}

static void _php_imlib_free_img(Imlib_Image im)
{
   imlib_context_set_image(im);
   imlib_free_image();
}

static void _php_imlib_free_poly(ImlibPolygon poly)
{
   imlib_polygon_free(poly);
}

static void _php_imlib_set_cache_size(int size TSRMLS_DC)
{
   if (size>IMLIBG(max_cache_size)) {
      size=IMLIBG(max_cache_size);
   }
   if (size<IMLIBG(min_cache_size)) {
      size=IMLIBG(min_cache_size);
   }
   imlib_set_cache_size(size);
}

static void php_imlib_init_globals(zend_imlib_globals *imlib_globals)
{
	imlib_globals->font_path = NULL;
	imlib_globals->saved_path = NULL;
}

#ifdef COMPILE_DL_IMLIB
ZEND_GET_MODULE(imlib)
#endif

PHP_MINIT_FUNCTION(imlib)
{
	ZEND_INIT_MODULE_GLOBALS(imlib, php_imlib_init_globals, NULL);
	le_imlib_cr = register_list_destructors(_php_imlib_free_cr,NULL);
	le_imlib_font = register_list_destructors(_php_imlib_free_font,NULL);
	le_imlib_img = register_list_destructors(_php_imlib_free_img,NULL);
	le_imlib_poly = register_list_destructors(_php_imlib_free_poly,NULL);

	REGISTER_LONG_CONSTANT("IMLIB_TEXT_TO_RIGHT", IMLIB_TEXT_TO_RIGHT, CONST_CS|CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("IMLIB_TEXT_TO_LEFT", IMLIB_TEXT_TO_LEFT, CONST_CS|CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("IMLIB_TEXT_TO_DOWN", IMLIB_TEXT_TO_DOWN, CONST_CS|CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("IMLIB_TEXT_TO_UP", IMLIB_TEXT_TO_UP, CONST_CS|CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("IMLIB_TEXT_TO_ANGLE", IMLIB_TEXT_TO_ANGLE, CONST_CS|CONST_PERSISTENT);

	REGISTER_LONG_CONSTANT("IMLIB_LOAD_ERROR_NONE", IMLIB_LOAD_ERROR_NONE,
	                       CONST_CS|CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("IMLIB_LOAD_ERROR_FILE_DOES_NOT_EXIST",
	                       IMLIB_LOAD_ERROR_FILE_DOES_NOT_EXIST,
	                       CONST_CS|CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("IMLIB_LOAD_ERROR_FILE_IS_DIRECTORY",
	                       IMLIB_LOAD_ERROR_FILE_IS_DIRECTORY,
	                       CONST_CS|CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("IMLIB_LOAD_ERROR_PERMISSION_DENIED_TO_READ",
	                       IMLIB_LOAD_ERROR_PERMISSION_DENIED_TO_READ,
	                       CONST_CS|CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("IMLIB_LOAD_ERROR_NO_LOADER_FOR_FILE_FORMAT",
	                       IMLIB_LOAD_ERROR_NO_LOADER_FOR_FILE_FORMAT,
	                       CONST_CS|CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("IMLIB_LOAD_ERROR_PATH_TOO_LONG",
	                       IMLIB_LOAD_ERROR_PATH_TOO_LONG,
	                       CONST_CS|CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("IMLIB_LOAD_ERROR_PATH_COMPONENT_NON_EXISTANT",
	                       IMLIB_LOAD_ERROR_PATH_COMPONENT_NON_EXISTANT,
	                       CONST_CS|CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("IMLIB_LOAD_ERROR_PATH_COMPONENT_NOT_DIRECTORY",
	                       IMLIB_LOAD_ERROR_PATH_COMPONENT_NOT_DIRECTORY,
	                       CONST_CS|CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("IMLIB_LOAD_ERROR_PATH_POINTS_OUTSIDE_ADDRESS_SPACE",
	                       IMLIB_LOAD_ERROR_PATH_POINTS_OUTSIDE_ADDRESS_SPACE,
	                       CONST_CS|CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("IMLIB_LOAD_ERROR_TOO_MANY_SYMBOLIC_LINKS",
	                       IMLIB_LOAD_ERROR_TOO_MANY_SYMBOLIC_LINKS,
	                       CONST_CS|CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("IMLIB_LOAD_ERROR_OUT_OF_MEMORY",
	                       IMLIB_LOAD_ERROR_OUT_OF_MEMORY,
	                       CONST_CS|CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("IMLIB_LOAD_ERROR_OUT_OF_FILE_DESCRIPTORS",
	                       IMLIB_LOAD_ERROR_OUT_OF_FILE_DESCRIPTORS,
	                       CONST_CS|CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("IMLIB_LOAD_ERROR_PERMISSION_DENIED_TO_WRITE",
	                       IMLIB_LOAD_ERROR_PERMISSION_DENIED_TO_WRITE,
	                       CONST_CS|CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("IMLIB_LOAD_ERROR_OUT_OF_DISK_SPACE",
	                       IMLIB_LOAD_ERROR_OUT_OF_DISK_SPACE,
	                       CONST_CS|CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("IMLIB_LOAD_ERROR_UNKNOWN", IMLIB_LOAD_ERROR_UNKNOWN,
	                       CONST_CS|CONST_PERSISTENT);

	REGISTER_INI_ENTRIES();

	return SUCCESS;
}

PHP_MSHUTDOWN_FUNCTION(imlib)
{
	UNREGISTER_INI_ENTRIES();

	return SUCCESS;
}

PHP_RINIT_FUNCTION(imlib)
{
	char **font_list;
	char *pathbuf, *ptr, *end;
	int i, font_count;

	/* Set default cache size */
	_php_imlib_set_cache_size(IMLIBG(cache_size) TSRMLS_CC);
	font_list = imlib_list_font_path(&font_count);
	if (!font_count) {
		IMLIBG(saved_path) = NULL;
	} else {
		/* Save the current path where we can retrieve it later. */
		IMLIBG(saved_path) = (char **) emalloc(sizeof(char *) * (font_count + 1));
		for (i = 0; i < font_count; i++) {
			IMLIBG(saved_path)[i] = estrdup(font_list[i]);
		}
		IMLIBG(saved_path)[i] = NULL;

		/* Now clear the imlib path... */
		for (i = 0; i < font_count; i++) {
			imlib_remove_path_from_font_path(IMLIBG(saved_path)[i]);
		}
	}

	if (!IMLIBG(font_path)) {
		return SUCCESS;
	}

	/* And repopulate it with the ini-specified default. */
	ptr = pathbuf = estrdup(IMLIBG(font_path));

	while (ptr && *ptr) {
		end = strchr(ptr, ':');

		if (end != NULL) {
			*end = '\0';
			end++;
		}
		imlib_add_path_to_font_path(ptr);
		ptr = end;
	}
	efree(pathbuf);

	return SUCCESS;
}

PHP_RSHUTDOWN_FUNCTION(imlib)
{
	char **font_list;
	int i, font_count;

	/* Restore cache size */
	_php_imlib_set_cache_size(0 TSRMLS_CC);
	/* Retrieve the current path and clear it out. */
	font_list = imlib_list_font_path(&font_count);
	for (i = 0; i < font_count; i++) {
		imlib_remove_path_from_font_path(font_list[i]);
	}

	/* Restore the saved font path. */
	if (!IMLIBG(saved_path)) {
		return SUCCESS;
	}
	for (i = 0; IMLIBG(saved_path)[i] != NULL; i++) {
		imlib_add_path_to_font_path(IMLIBG(saved_path)[i]);
		efree(IMLIBG(saved_path)[i]);
	}

	efree(IMLIBG(saved_path));
	return SUCCESS;
}

PHP_MINFO_FUNCTION(imlib)
{
	DISPLAY_INI_ENTRIES();
}

static void _php_convert_four_longs(zval **zone, zval **ztwo, zval **zthree,
                                    zval **zfour, int *one, int *two,
                                    int *three, int *four)
{
   convert_to_long_ex(zone);
   convert_to_long_ex(ztwo);
   convert_to_long_ex(zthree);
   convert_to_long_ex(zfour);
   *one = Z_LVAL_PP(zone);
   *two = Z_LVAL_PP(ztwo);
   *three = Z_LVAL_PP(zthree);
   *four = Z_LVAL_PP(zfour);
}

static int _php_handle_cliprect_array(zval **dbox, char *func_name,
                                      int *x, int *y, int *w, int *h)
{
   zval **element, ***box_coords;
   int i,arrcount;
   HashTable *box;

   box = HASH_OF(*dbox);
   if (!box) {
      php_error(E_WARNING, "Wrong datatype in call to %s, need array",func_name);
      return 0;
   }

   arrcount = zend_hash_num_elements(box);
   if (arrcount != 4) {
      php_error(E_WARNING, "Wrong number of array elements in call to %s, need four (x,y,w,h)",
                func_name);
      return 0;
   }

   box_coords = (zval ***)emalloc(arrcount * sizeof(zval **));

   for (i = 0; i < arrcount; i++)
   { 
      if (zend_hash_index_find(box, i, (void **)&element) == SUCCESS)
      {
         convert_to_long_ex(element);
         box_coords[i] = element;
      }
   }
   *x = Z_LVAL_PP(box_coords[0]);
   *y = Z_LVAL_PP(box_coords[1]);
   *w = Z_LVAL_PP(box_coords[2]);
   *h = Z_LVAL_PP(box_coords[3]);

   efree(box_coords);
   return 1;
}

static int _php_handle_imlib_error(INTERNAL_FUNCTION_PARAMETERS,
                                    Imlib_Load_Error err, const char *img)
{
   int errnum;

   switch (err)
   {
      case IMLIB_LOAD_ERROR_NONE:
         errnum = 0;
         break;
      case IMLIB_LOAD_ERROR_FILE_DOES_NOT_EXIST:
         php_error(E_WARNING, "%s - File does not exist", img);
         errnum = 1;
         break;
      case IMLIB_LOAD_ERROR_FILE_IS_DIRECTORY:
         php_error(E_WARNING, "%s - Directory specified for image filename", img);
         errnum = 2;
         break;
      case IMLIB_LOAD_ERROR_PERMISSION_DENIED_TO_READ:
         php_error(E_WARNING, "%s - No read access to directory", img);
         errnum = 3;
         break;
      case IMLIB_LOAD_ERROR_NO_LOADER_FOR_FILE_FORMAT:
         php_error(E_WARNING, "%s - No Imlib2 loader for that file format", img);
         errnum = 4;
         break;
      case IMLIB_LOAD_ERROR_PATH_TOO_LONG:
         php_error(E_WARNING, "%s - Path specified is too long", img);
         errnum = 5;
         break;
      case IMLIB_LOAD_ERROR_PATH_COMPONENT_NON_EXISTANT:
         php_error(E_WARNING, "%s - Path component does not exist", img);
         errnum = 6;
         break;
      case IMLIB_LOAD_ERROR_PATH_COMPONENT_NOT_DIRECTORY:
         php_error(E_WARNING, "%s - Path component is not a directory", img);
         errnum = 7;
         break;
      case IMLIB_LOAD_ERROR_PATH_POINTS_OUTSIDE_ADDRESS_SPACE:
         php_error(E_WARNING, "%s - Path points outside address space", img);
         errnum = 8;
         break;
      case IMLIB_LOAD_ERROR_TOO_MANY_SYMBOLIC_LINKS:
         php_error(E_WARNING, "%s - Too many levels of symbolic links", img);
         errnum = 9;
         break;
      case IMLIB_LOAD_ERROR_OUT_OF_MEMORY:
         php_error(E_WARNING, "While loading %s - Out of memory", img);
         errnum = 10;
         break;
      case IMLIB_LOAD_ERROR_OUT_OF_FILE_DESCRIPTORS:
         php_error(E_WARNING, "While loading %s - Out of file descriptors", img);
         errnum = 11;
         break;
      case IMLIB_LOAD_ERROR_PERMISSION_DENIED_TO_WRITE:
         php_error(E_WARNING, "%s - Cannot write to directory", img);
         errnum = 12;
         break;
      case IMLIB_LOAD_ERROR_OUT_OF_DISK_SPACE:
         php_error(E_WARNING, "%s - Cannot write - out of disk space", img);
         errnum = 13;
         break;
      case IMLIB_LOAD_ERROR_UNKNOWN:
      default:
         php_error(E_WARNING, "While loading %s - Unknown error.", img);
         errnum = 14;
   }
   return errnum;
}

static void _php_imlib_draw_something(INTERNAL_FUNCTION_PARAMETERS, void (*func)(), char *func_name)
{
   zval **img, **d1, **d2, **d3, **d4, **dr, **dg, **db, **da, **dbox;
   int x,y,w,h,r,g,b,a,cx,cy,cw,ch,argc;
   Imlib_Image im;

   argc = ZEND_NUM_ARGS();
   if (argc < 9 || argc > 10 || zend_get_parameters_ex(argc, &img, &d1, &d2, &d3, &d4, &dr, &dg, &db, &da, &dbox) == FAILURE) {
      WRONG_PARAM_COUNT;
   }

   ZEND_FETCH_RESOURCE(im, Imlib_Image, img, -1, "Imlib Image", le_imlib_img);

   _php_convert_four_longs(d1,d2,d3,d4,&x,&y,&w,&h);
   _php_convert_four_longs(dr,dg,db,da,&r,&g,&b,&a);

   imlib_context_set_image(im);
   imlib_context_set_color(r,g,b,a);

   /* FIXME: This should take an optional antialias option, with on as default */
   imlib_context_set_anti_alias(0);

   if (argc > 9)
   {
      if (!_php_handle_cliprect_array(dbox, func_name, &cx,&cy,&cw,&ch))
         RETURN_FALSE;
      imlib_context_set_cliprect(cx,cy,cw,ch);
   }

   (*func)(x,y,w,h);
   imlib_context_set_cliprect(0,0,0,0);
   RETURN_TRUE;
}

static void _php_imlib_single_arg(INTERNAL_FUNCTION_PARAMETERS, void (*func)())
{
   zval **img;
   Imlib_Image im;

   if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &img) == FAILURE) {
      WRONG_PARAM_COUNT;
   }

   ZEND_FETCH_RESOURCE(im, Imlib_Image, img, -1, "Imlib Image", le_imlib_img);

   imlib_context_set_image(im);
   (*func)();
}

/* We wrap imlib_image_draw_line, because it doesn't return a void like all
   the other drawing functions do.  So, since we don't care about
   Imlib_Updates, we're going to return our own void.  Nyeh. */
static void _php_wrap_draw_line(int x1, int y1, int x2, int y2)
{
   imlib_image_draw_line(x1,y1,x2,y2,0);
}


/* {{{ proto void imlib_add_color_to_color_range(int cr, int x, int r, int g, int b, int a)
   Add a color to a color range at a specified distance from the previous color in the range.  A distance of 0 centers it */
PHP_FUNCTION(imlib_add_color_to_color_range)
{
   zval **crange, **cx, **cr, **cg, **cb, **ca;
   int x,r,g,b,a;
   Imlib_Color_Range range;

   if (ZEND_NUM_ARGS() != 6 || zend_get_parameters_ex(6, &crange, &cx, &cr, &cg, &cb, &ca) == FAILURE) {
      WRONG_PARAM_COUNT;
   }

   ZEND_FETCH_RESOURCE(range, Imlib_Color_Range, crange, -1, "Imlib Color Range", le_imlib_cr);

   convert_to_long_ex(cx);
   x = Z_LVAL_PP(cx);
   _php_convert_four_longs(cr,cg,cb,ca,&r,&g,&b,&a);

   imlib_context_set_color_range(range);
   imlib_context_set_color(r,g,b,a);
   imlib_add_color_to_color_range(x);
}
/* }}} */


/* {{{ proto void imlib_blend_image_onto_image(int dstimg, int srcimg, int malpha, int srcx, int srcy, int srcw, int srch, int dstx, int dsty, int dstw, int dsth, char dither, char blend, char alias)
   Blend a rectangular area from an image onto an area of another image, scaling as necessary */
PHP_FUNCTION(imlib_blend_image_onto_image)
{
   zval **dstimg, **srcimg, **malpha, **srcx, **srcy, **srcw, **srch, **dstx, **dsty, **dstw, **dsth, **dither, **blend, **alias;
   Imlib_Image dst,src;
   int sx,sy,sw,sh,dx,dy,dw,dh;
   int calias, calpha, cblend, cdither;

   if (ZEND_NUM_ARGS() != 14 || zend_get_parameters_ex(14, &dstimg, &srcimg, &malpha, &srcx, &srcy, &srcw, &srch, &dstx, &dsty, &dstw, &dsth, &dither, &blend, &alias) == FAILURE) {
      WRONG_PARAM_COUNT;
   }

   ZEND_FETCH_RESOURCE(src, Imlib_Image, srcimg, -1, "Imlib Image", le_imlib_img);
   ZEND_FETCH_RESOURCE(dst, Imlib_Image, dstimg, -1, "Imlib Image", le_imlib_img);

   _php_convert_four_longs(srcx,srcy,srcw,srch,&sx,&sy,&sw,&sh);
   _php_convert_four_longs(dstx,dsty,dstw,dsth,&dx,&dy,&dw,&dh);

   convert_to_long_ex(malpha);
   convert_to_long_ex(dither);
   convert_to_long_ex(blend);
   convert_to_long_ex(alias);
   calpha = Z_LVAL_PP(malpha);
   cdither = Z_LVAL_PP(dither);
   cblend = Z_LVAL_PP(blend);
   calias = Z_LVAL_PP(alias);

   imlib_context_set_image(dst);
   imlib_context_set_anti_alias(calias);
   imlib_context_set_dither(cdither);
   imlib_context_set_blend(cblend);
   imlib_context_set_angle(0);
   imlib_blend_image_onto_image(src,calpha,sx,sy,sw,sh,dx,dy,dw,dh);
}
/* }}} */


/* {{{ proto int imlib_clone_image(int img)
   Duplicate an image */
PHP_FUNCTION(imlib_clone_image)
{
   zval **img;
   Imlib_Image src,dst;

   if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &img) == FAILURE) {
      WRONG_PARAM_COUNT;
   }

   ZEND_FETCH_RESOURCE(src, Imlib_Image, img, -1, "Imlib Image", le_imlib_img);

   imlib_context_set_image(src);
   dst = imlib_clone_image();

   ZEND_REGISTER_RESOURCE(return_value, dst, le_imlib_img);
}
/* }}} */


/* {{{ proto int imlib_create_color_range()
   Create a new color range */
PHP_FUNCTION(imlib_create_color_range)
{
   Imlib_Color_Range cr;

   if (ZEND_NUM_ARGS() != 0) {
      WRONG_PARAM_COUNT;
   }

   cr = imlib_create_color_range();

   ZEND_REGISTER_RESOURCE(return_value, cr, le_imlib_cr);
}
/* }}} */


/* {{{ proto int imlib_create_cropped_image(int img, int srcx, int srcy, int srcw, int srch)
   Create an image from a cropped region of another image */
PHP_FUNCTION(imlib_create_cropped_image)
{
   zval **img, **srcx, **srcy, **srcw, **srch;
   int sx,sy,sw,sh;
   Imlib_Image src,dst;

   if (ZEND_NUM_ARGS() != 5 || zend_get_parameters_ex(5, &img, &srcx, &srcy, &srcw, &srch) == FAILURE) {
      WRONG_PARAM_COUNT;
   }

   ZEND_FETCH_RESOURCE(src, Imlib_Image, img, -1, "Imlib Image", le_imlib_img);

   _php_convert_four_longs(srcx,srcy,srcw,srch,&sx,&sy,&sw,&sh);

   imlib_context_set_image(src);
   dst = imlib_create_cropped_image(sx,sy,sw,sh);

   ZEND_REGISTER_RESOURCE(return_value, dst, le_imlib_img);
}
/* }}} */

                     
/* {{{ proto int imlib_create_cropped_scaled_image(int img, int srcx, int srcy, int srcw, int srch, int dstw, int dsth)
   Create a scaled image from a cropped region of another image */
PHP_FUNCTION(imlib_create_cropped_scaled_image)
{
   zval **img, **srcx, **srcy, **srcw, **srch, **dstw, **dsth;
   int sx,sy,sw,sh,dw,dh;
   Imlib_Image src,dst;

   if (ZEND_NUM_ARGS() != 7 || zend_get_parameters_ex(7, &img, &srcx, &srcy, &srcw,
                                                      &srch, &dstw, &dsth) == FAILURE) {
      WRONG_PARAM_COUNT;
   }

   ZEND_FETCH_RESOURCE(src, Imlib_Image, img, -1, "Imlib Image", le_imlib_img);

   _php_convert_four_longs(srcx,srcy,srcw,srch,&sx,&sy,&sw,&sh);
   convert_to_long_ex(dstw);
   convert_to_long_ex(dsth);
   dw = Z_LVAL_PP(dstw);
   dh = Z_LVAL_PP(dsth);

   imlib_context_set_image(src);
   dst = imlib_create_cropped_scaled_image(sx,sy, sw,sh, dw,dh);

   ZEND_REGISTER_RESOURCE(return_value, dst, le_imlib_img);
}
/* }}} */


/* {{{ proto int imlib_create_image(int w, int h)
   Create a new image with the specified dimensions */
PHP_FUNCTION(imlib_create_image)
{
   zval **nx, **ny;
   Imlib_Image im;
   int x,y;

   if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &nx, &ny) == FAILURE) {
      WRONG_PARAM_COUNT;
   }

   convert_to_long_ex(nx);
   convert_to_long_ex(ny);
   x = Z_LVAL_PP(nx);
   y = Z_LVAL_PP(ny);

   im = imlib_create_image(x,y);

   imlib_context_set_image(im);
   memset(imlib_image_get_data(), '\0', x * y * sizeof(DATA32));

   ZEND_REGISTER_RESOURCE(return_value, im, le_imlib_img);
}
/* }}} */


/* {{{ proto int imlib_create_rotated_image(int srcimg, int degrees[, int radians])
   Create a rotated copy of an image.  If radians is specified, degrees will be ignored. */
PHP_FUNCTION(imlib_create_rotated_image)
{
   zval **srcimg, **cangle, **crads;
   double angle, radians, pi = 3.141592654;
   int argc;
   Imlib_Image src, dst;

   argc = ZEND_NUM_ARGS();
   if (argc < 2 || argc > 3 || zend_get_parameters_ex(argc, &srcimg, &cangle, &crads) == FAILURE) {
      WRONG_PARAM_COUNT;
   }

   ZEND_FETCH_RESOURCE(src, Imlib_Image, srcimg, -1, "Imlib Image", le_imlib_img);

   if (argc > 2)
   {
      convert_to_double_ex(crads);
      radians = Z_DVAL_PP(crads);
   }
   else
   {
      convert_to_double_ex(cangle);
      angle = Z_DVAL_PP(cangle);
      radians = angle * pi/180;
   }

   imlib_context_set_image(src);
   dst = imlib_create_rotated_image(radians);

   ZEND_REGISTER_RESOURCE(return_value, dst, le_imlib_img);
}
/* }}} */


/* {{{ proto int imlib_create_scaled_image(int img, int dstw, int dsth)
   Create a scaled copy of an image.  If dstw or dsth is left blank, the aspect ratio of the source image will be preserved. */
PHP_FUNCTION(imlib_create_scaled_image)
{
   zval **img, **dstw, **dsth;
   int sw,sh,dw,dh;
   Imlib_Image src,dst;

   if (ZEND_NUM_ARGS() != 3 || zend_get_parameters_ex(3, &img, &dstw, &dsth) == FAILURE) {
      WRONG_PARAM_COUNT;
   }

   ZEND_FETCH_RESOURCE(src, Imlib_Image, img, -1, "Imlib Image", le_imlib_img);

   convert_to_long_ex(dstw);
   convert_to_long_ex(dsth);
   dw = Z_LVAL_PP(dstw);
   dh = Z_LVAL_PP(dsth);

   if (!dw && !dh) {
      RETURN_FALSE;
   }

   imlib_context_set_image(src);
   sw = imlib_image_get_width();
   sh = imlib_image_get_height();
   if (!dw) {
      dw = (int) (((double)dh * sw) / sh);
   }
   if (!dh) {
      dh = (int) (((double) dw * sh) / sw);
   }

   dst = imlib_create_cropped_scaled_image(0,0, sw,sh, dw,dh);

   ZEND_REGISTER_RESOURCE(return_value, dst, le_imlib_img);
}
/* }}} */


/* {{{ proto bool imlib_dump_image(int img[, int &err[, int quality]])
   Output an image at an optional quality setting */
PHP_FUNCTION(imlib_dump_image)
{
   int argc, q, fd, retval, output;
   char *tmpfile;
   zval **img, **quality, **err;
   Imlib_Image im;
   Imlib_Load_Error im_err;

   argc = ZEND_NUM_ARGS();
   if (argc < 1 || argc > 3 || zend_get_parameters_ex(argc, &img, &err, &quality) == FAILURE) {
      WRONG_PARAM_COUNT;
   }

   if (argc > 1) {
      zval_dtor(*err);
      ZVAL_LONG(*err,0);
   }

   ZEND_FETCH_RESOURCE(im, Imlib_Image, img, -1, "Imlib Image", le_imlib_img);

   tmpfile = estrdup("/tmp/phpimlib.XXXXXX");

   if ((fd = mkstemp(tmpfile)) < 0) {
      php_error(E_WARNING, "%s: unable to open temporary file", get_active_function_name(TSRMLS_C));
      efree(tmpfile);
      RETURN_FALSE;
   }

   /* TODO: notify in case of errors? */
   retval = fchmod(fd, S_IRUSR|S_IWUSR);
   if (retval != 0) {
      php_error(E_WARNING, "%s: could not change permissions on temporary file", get_active_function_name(TSRMLS_C));
      close(fd);
      efree(tmpfile);
      RETURN_FALSE;
   }

   imlib_context_set_image(im);
   if(!imlib_image_format()) {
      imlib_image_set_format("png");
   }

   if (argc > 2)
   {
      convert_to_long_ex(quality);
      q = Z_LVAL_PP(quality);
      imlib_image_attach_data_value("quality",NULL,q,NULL);
   }

   imlib_save_image_with_error_return(tmpfile,&im_err);

   if (im_err)
   {
      close(fd);
      unlink(tmpfile);
      efree(tmpfile);
      if (argc > 1)
      {
         ZVAL_LONG(*err,im_err);
      }
      _php_handle_imlib_error(INTERNAL_FUNCTION_PARAM_PASSTHRU,
                              im_err,tmpfile);
      RETURN_FALSE;
   }

   /* fseek or something, then read the file and dump it out. */
   lseek(fd, 0, SEEK_SET);

   output = php_header();
   if (output) {
      char buf[4096];

#if APACHE && defined(CHARSET_EBCDIC)
      SLS_FETCH();
      /* This is a binary file already: avoid EBCDIC->ASCII conversion */
      ap_bsetflag(php3_rqst->connection->client, B_EBCDIC2ASCII, 0);
#endif
      while ((retval = read(fd, buf, sizeof(buf))) > 0) {
         php_write(buf, retval TSRMLS_CC);
      }
   }

   close(fd);
   unlink(tmpfile);
   efree(tmpfile);

   if (output) {
      RETURN_TRUE;
   } else {
      RETURN_FALSE;
   }
}
/* }}} */


/* {{{ proto void imlib_free_color_range(int cr)
   Free a color range */
PHP_FUNCTION(imlib_free_color_range)
{
   zval **fcr;
   Imlib_Color_Range cr;

   if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &fcr) == FAILURE) {
      WRONG_PARAM_COUNT;
   }

   ZEND_FETCH_RESOURCE(cr, Imlib_Color_Range, fcr, -1, "Imlib Color Range", le_imlib_cr);
   zend_list_delete(Z_LVAL_PP(fcr));
}
/* }}} */


/* {{{ proto void imlib_free_font(int font)
   Free a font */
PHP_FUNCTION(imlib_free_font)
{
   zval **font;
   Imlib_Font fn;

   if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &font) == FAILURE) {
      WRONG_PARAM_COUNT;
   }

   ZEND_FETCH_RESOURCE(fn, Imlib_Font, font, -1, "Imlib Font", le_imlib_font);
   zend_list_delete(Z_LVAL_PP(font));
}
/* }}} */


/* {{{ proto void imlib_free_image(int img)
   Free an image */
PHP_FUNCTION(imlib_free_image)
{
   zval **img;
   Imlib_Image im;

   if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &img) == FAILURE) {
      WRONG_PARAM_COUNT;
   }

   ZEND_FETCH_RESOURCE(im, Imlib_Image, img, -1, "Imlib Image", le_imlib_img);
   zend_list_delete(Z_LVAL_PP(img));
}
/* }}} */


/* {{{ proto void imlib_get_text_size(int font, string str, int &w, int &h, int direction)
   Determines the width and height of a string if drawn with a given font in the specified direction */
PHP_FUNCTION(imlib_get_text_size)
{
   zval **font, **textstr, **tw, **th, **tdir;
   Imlib_Font fn;
   const char *text = NULL;
   int w,h,dir;

   if (ZEND_NUM_ARGS() != 5 || zend_get_parameters_ex(5, &font, &textstr, &tw, &th, &tdir) == FAILURE) {
      WRONG_PARAM_COUNT;
   }

   ZEND_FETCH_RESOURCE(fn, Imlib_Font, font, -1, "Imlib Font", le_imlib_font);

   zval_dtor(*tw);
   zval_dtor(*th);

   convert_to_string_ex(textstr);
   convert_to_long_ex(tw);
   convert_to_long_ex(th);
   convert_to_long_ex(tdir);
   text = Z_STRVAL_PP(textstr);
   w = Z_LVAL_PP(tw);
   h = Z_LVAL_PP(th);
   dir = Z_LVAL_PP(tdir);

   imlib_context_set_font(fn);
   imlib_context_set_direction(dir);
   imlib_get_text_size(text, &w, &h);

   ZVAL_LONG(*tw,w);
   ZVAL_LONG(*th,h);
}
/* }}} */


/* {{{ proto void imlib_image_blur(int img, int radius)
   Blur an image with a given blur radius */
PHP_FUNCTION(imlib_image_blur)
{
   zval **img, **radius;
   int r;
   Imlib_Image im;

   if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &img, &radius) == FAILURE) {
      WRONG_PARAM_COUNT;
   }

   ZEND_FETCH_RESOURCE(im, Imlib_Image, img, -1, "Imlib Image", le_imlib_img);

   convert_to_long_ex(radius);
   r = Z_LVAL_PP(radius);

   imlib_context_set_image(im);
   imlib_image_blur(r);
}
/* }}} */


/* {{{ proto bool imlib_image_draw_ellipse(int img, int xc, int yc, int w, int h, int r, int g, int b, int a[, array cliprect])
   Draw an ellipse of the specified size and color on an image */
PHP_FUNCTION(imlib_image_draw_ellipse)
{
   _php_imlib_draw_something(INTERNAL_FUNCTION_PARAM_PASSTHRU,imlib_image_draw_ellipse,
                             "imlib_image_draw_ellipse");
}
/* }}} */


/* {{{ proto bool imlib_image_draw_line(int img, int x1, int y1, int x2, int y2, int r, int g, int b, int a[, array cliprect])
   Draw a line of the specified size and color on an image */
PHP_FUNCTION(imlib_image_draw_line)
{
   _php_imlib_draw_something(INTERNAL_FUNCTION_PARAM_PASSTHRU,_php_wrap_draw_line,
                             "imlib_image_draw_ellipse");
}
/* }}} */


/* {{{ proto bool imlib_image_draw_polygon(int img, int polygon, bool closed, int r, int g, int b, int a[, array cliprect])
   Draw the defined polygon on an image */
PHP_FUNCTION(imlib_image_draw_polygon)
{
   zval **img, **polygon, **pclosed, **pr, **pg, **pb, **pa, **dbox;
   int r,g,b,a,cx,cy,cw,ch,argc;
   Imlib_Image im;
   ImlibPolygon poly;
   int closed;

   argc = ZEND_NUM_ARGS();
   if (argc < 7 || argc > 8 || zend_get_parameters_ex(argc, &img, &polygon, &pclosed, &pr, &pg, &pb, &pa, &dbox) == FAILURE) {
      WRONG_PARAM_COUNT;
   }

   ZEND_FETCH_RESOURCE(im, Imlib_Image, img, -1, "Imlib Image", le_imlib_img);
   ZEND_FETCH_RESOURCE(poly, ImlibPolygon, polygon, -1, "Imlib Polygon", le_imlib_poly);

   _php_convert_four_longs(pr,pg,pb,pa,&r,&g,&b,&a);

   convert_to_long_ex(pclosed);
   closed = Z_LVAL_PP(pclosed);

   imlib_context_set_image(im);
   imlib_context_set_color(r,g,b,a);

   if (argc > 7)
   {
      if (!_php_handle_cliprect_array(dbox, "imlib_image_draw_polygon", &cx, &cy, &cw, &ch))
         RETURN_FALSE;
      imlib_context_set_cliprect(cx,cy,cw,ch);
   }

   imlib_image_draw_polygon(poly,closed);
   imlib_context_set_cliprect(0,0,0,0);
}
/* }}} */


/* {{{ proto bool imlib_image_draw_rectangle(int img, int x, int y, int w, int h, int r, int g, int b, int a[, array cliprect])
   Draw a rectangle of the specified size and color on an image */
PHP_FUNCTION(imlib_image_draw_rectangle)
{
   _php_imlib_draw_something(INTERNAL_FUNCTION_PARAM_PASSTHRU,imlib_image_draw_rectangle,
                             "imlib_image_draw_rectangle");
}
/* }}} */


/* {{{ proto bool imlib_image_fill_color_range_rectangle(int im, int cr, int x, int y, int width, int height, int angle)
   Fill a rectangle with a color range at a given angle on an image */
PHP_FUNCTION(imlib_image_fill_color_range_rectangle)
{
   zval **fim, **fcr, **fx, **fy, **fwidth, **fheight, **fangle, **fbox;
   int x,y,width,height,argc,cx,cy,cw,ch;
   double angle;
   Imlib_Image im;
   Imlib_Color_Range cr;

   argc = ZEND_NUM_ARGS();
   if (argc < 7 || argc > 8 || zend_get_parameters_ex(argc, &fim, &fcr, &fx, &fy, &fwidth, &fheight, &fangle, &fbox) == FAILURE) {
      WRONG_PARAM_COUNT;
   }

   _php_convert_four_longs(fx,fy,fwidth,fheight,&x,&y,&width,&height);
   convert_to_double_ex(fangle);
   angle = Z_DVAL_PP(fangle);

   ZEND_FETCH_RESOURCE(cr, Imlib_Color_Range, fcr, -1, "Imlib Color Range", le_imlib_cr);
   ZEND_FETCH_RESOURCE(im, Imlib_Image, fim, -1, "Imlib Image", le_imlib_img);

   imlib_context_set_color_range(cr);
   imlib_context_set_image(im);

   if (argc > 7)
   {
      if (!_php_handle_cliprect_array(fbox, "imlib_image_fill_color_range_rectangle", &cx,&cy,&cw,&ch))
         RETURN_FALSE;
      imlib_context_set_cliprect(cx,cy,cw,ch);
   }

   imlib_image_fill_color_range_rectangle(x,y,width,height, angle);
   imlib_context_set_cliprect(0,0,0,0);
   RETURN_TRUE;
}
/* }}} */


/* {{{ proto void imlib_image_fill_ellipse(int img, int xc, int yc, int w, int h, int r, int g, int b, int a[, array cliprect])
   Fill an ellipse of the specified size and color on an image */
PHP_FUNCTION(imlib_image_fill_ellipse)
{
   _php_imlib_draw_something(INTERNAL_FUNCTION_PARAM_PASSTHRU,imlib_image_fill_ellipse,
                             "imlib_image_fill_ellipse");
}
/* }}} */


/* {{{ proto bool imlib_image_fill_polygon(int img, int polygon, int r, int g, int b, int a[, array cliprect])
   Draw and fill the defined polygon on an image */
PHP_FUNCTION(imlib_image_fill_polygon)
{
   zval **img, **polygon, **pr, **pg, **pb, **pa, **dbox;
   int r,g,b,a,cx,cy,cw,ch,argc;
   Imlib_Image im;
   ImlibPolygon poly;

   argc = ZEND_NUM_ARGS();
   if (argc < 6 || argc > 7 || zend_get_parameters_ex(argc, &img, &polygon, &pr, &pg, &pb, &pa, &dbox) == FAILURE) {
      WRONG_PARAM_COUNT;
   }

   ZEND_FETCH_RESOURCE(im, Imlib_Image, img, -1, "Imlib Image", le_imlib_img);
   ZEND_FETCH_RESOURCE(poly, ImlibPolygon, polygon, -1, "Imlib Polygon", le_imlib_poly);

   _php_convert_four_longs(pr,pg,pb,pa,&r,&g,&b,&a);

   imlib_context_set_image(im);
   imlib_context_set_color(r,g,b,a);

   if (argc > 6)
   {
      if (!_php_handle_cliprect_array(dbox, "imlib_image_fill_polygon", &cx, &cy, &cw, &ch))
         RETURN_FALSE;
      imlib_context_set_cliprect(cx,cy,cw,ch);
   }

   imlib_image_fill_polygon(poly);
   imlib_context_set_cliprect(0,0,0,0);
   RETURN_TRUE;
}
/* }}} */


/* {{{ proto void imlib_image_fill_rectangle(int img, int x, int y, int w, int h, int r, int g, int b, int a[, array cliprect])
   Fill a rectangle of the specified size and color on an image */
PHP_FUNCTION(imlib_image_fill_rectangle)
{
   _php_imlib_draw_something(INTERNAL_FUNCTION_PARAM_PASSTHRU,imlib_image_fill_rectangle,
                             "imlib_image_fill_rectangle");
}
/* }}} */


/* {{{ proto void imlib_image_flip_horizontal(int img)
   Flip an image horizontally */
PHP_FUNCTION(imlib_image_flip_horizontal)
{
   _php_imlib_single_arg(INTERNAL_FUNCTION_PARAM_PASSTHRU,imlib_image_flip_horizontal);
}
/* }}} */


/* {{{ proto void imlib_image_flip_vertical(int img)
   Flip an Imlib_Image vertically */
PHP_FUNCTION(imlib_image_flip_vertical)
{
   _php_imlib_single_arg(INTERNAL_FUNCTION_PARAM_PASSTHRU,imlib_image_flip_vertical);
}
/* }}} */


/* {{{ proto void imlib_image_flip_diagonal(int img)
   Flip an image diagonally */
PHP_FUNCTION(imlib_image_flip_diagonal)
{
   _php_imlib_single_arg(INTERNAL_FUNCTION_PARAM_PASSTHRU,imlib_image_flip_diagonal);
}
/* }}} */


/* {{{ proto string imlib_image_format(int img)
   Returns the image format of an image */
PHP_FUNCTION(imlib_image_format)
{
   zval **img;
   Imlib_Image im;
   char *name;

   if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &img) == FAILURE) {
      WRONG_PARAM_COUNT;
   }

   ZEND_FETCH_RESOURCE(im, Imlib_Image, img, -1, "Imlib Image", le_imlib_img);

   imlib_context_set_image(im);
   name = imlib_image_format();
   if (!name)
      RETURN_FALSE;

   RETURN_STRING(name,strlen(name));
}
/* }}} */


/* {{{ proto string imlib_image_get_filename(int img)
   Returns the filename of an image */
PHP_FUNCTION(imlib_image_get_filename)
{
   zval **img;
   Imlib_Image im;
   const char *name = NULL;

   if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &img) == FAILURE) {
      WRONG_PARAM_COUNT;
   }

   ZEND_FETCH_RESOURCE(im, Imlib_Image, img, -1, "Imlib Image", le_imlib_img);

   imlib_context_set_image(im);
   name = imlib_image_get_filename();
   if (!name)
      RETURN_FALSE;

   RETURN_STRING((char*)name,strlen(name));
}
/* }}} */


/* {{{ proto int imlib_image_get_height(int img)
   Returns the height of an image */
PHP_FUNCTION(imlib_image_get_height)
{
   zval **img;
   Imlib_Image im;
   int height;

   if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &img) == FAILURE) {
      WRONG_PARAM_COUNT;
   }

   ZEND_FETCH_RESOURCE(im, Imlib_Image, img, -1, "Imlib Image", le_imlib_img);

   imlib_context_set_image(im);
   height = imlib_image_get_height();

   RETURN_LONG((long)height);
}
/* }}} */


/* {{{ proto int imlib_image_get_width(int img)
   Returns the width of an image */
PHP_FUNCTION(imlib_image_get_width)
{
   zval **img;
   Imlib_Image im;
   int width;

   if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &img) == FAILURE) {
      WRONG_PARAM_COUNT;
   }

   ZEND_FETCH_RESOURCE(im, Imlib_Image, img, -1, "Imlib Image", le_imlib_img);

   imlib_context_set_image(im);
   width = imlib_image_get_width();

   RETURN_LONG((long)width);
}
/* }}} */


/* {{{ proto bool imlib_image_has_alpha(int img)
   Return a boolean for whether or not an image has an alpha channel */
PHP_FUNCTION(imlib_image_has_alpha)
{
   zval **img;
   Imlib_Image im;

   if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &img) == FAILURE) {
      WRONG_PARAM_COUNT;
   }

   ZEND_FETCH_RESOURCE(im, Imlib_Image, img, -1, "Imlib Image", le_imlib_img);

   imlib_context_set_image(im);
   if (imlib_image_has_alpha())
   {
      RETURN_TRUE;
   }
   else
   {
      RETURN_FALSE;
   }
}
/* }}} */


/* {{{ proto void imlib_image_modify_alpha(int img, int alpha)
   Set the alpha channel of an image, or modify it if one was already present */
PHP_FUNCTION(imlib_image_modify_alpha)
{
   zval **img, **alpha;
   Imlib_Image im;
   DATA8 map[256];
   Imlib_Color_Modifier *cmod;
   int malpha, i;
   double ratio;

   if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &img, &alpha) == FAILURE) {
      WRONG_PARAM_COUNT;
   }

   ZEND_FETCH_RESOURCE(im, Imlib_Image, img, -1, "Imlib Image", le_imlib_img);

   convert_to_long_ex(alpha);
   malpha = Z_LVAL_PP(alpha);
   ratio = ((double)malpha) / 255;

   imlib_context_set_image(im);
   if (imlib_image_has_alpha())
   {
      for (i = 0; i < 256; i++)
         map[i] = (DATA8) (i * ratio);
   }
   else
   {
      for (i = 0; i < 256; i++)
         map[i] = malpha;
      imlib_image_set_has_alpha(1);
   }

   cmod = imlib_create_color_modifier();
   imlib_context_set_color_modifier(cmod);
   imlib_set_color_modifier_tables(NULL, NULL, NULL, map);
   imlib_apply_color_modifier();
   imlib_free_color_modifier();
}
/* }}} */


/* {{{ proto void imlib_image_set_format(int img, string format)
   Sets the image format of an image. */
PHP_FUNCTION(imlib_image_set_format)
{
   zval **img, **zformat;
   Imlib_Image im;
   char *format;

   if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &img, &zformat) == FAILURE) {
      WRONG_PARAM_COUNT;
   }

   ZEND_FETCH_RESOURCE(im, Imlib_Image, img, -1, "Imlib Image", le_imlib_img);

   convert_to_string_ex(zformat);
   format = Z_STRVAL_PP(zformat);
   if (!format) {
      RETURN_FALSE;    
   }

   imlib_context_set_image(im);
   imlib_image_set_format(format);

   RETURN_TRUE;
}
/* }}} */


/* {{{ proto void imlib_image_sharpen(int img, int radius)
   Sharpen an image with a given sharpen radius */
PHP_FUNCTION(imlib_image_sharpen)
{
   zval **img, **radius;
   int r;
   Imlib_Image im;

   if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &img, &radius) == FAILURE) {
      WRONG_PARAM_COUNT;
   }

   ZEND_FETCH_RESOURCE(im, Imlib_Image, img, -1, "Imlib Image", le_imlib_img);

   convert_to_long_ex(radius);
   r = Z_LVAL_PP(radius);

   imlib_context_set_image(im);
   imlib_image_sharpen(r);
}
/* }}} */


/* {{{ proto void imlib_image_tile_horizontal(int img)
   Tile an image horizontally */
PHP_FUNCTION(imlib_image_tile_horizontal)
{
   _php_imlib_single_arg(INTERNAL_FUNCTION_PARAM_PASSTHRU,imlib_image_tile_horizontal);
}
/* }}} */


/* {{{ proto void imlib_image_tile_vertical(int img)
   Tile an image vertically */
PHP_FUNCTION(imlib_image_tile_vertical)
{
   _php_imlib_single_arg(INTERNAL_FUNCTION_PARAM_PASSTHRU,imlib_image_tile_vertical);
}
/* }}} */


/* {{{ proto void imlib_image_tile(int img)
   Tile an image horizontally and diagonally */
PHP_FUNCTION(imlib_image_tile)
{
   _php_imlib_single_arg(INTERNAL_FUNCTION_PARAM_PASSTHRU,imlib_image_tile);
}
/* }}} */


/* {{{ proto array imlib_list_fonts()
   Return an array of all the fonts available in the font path */
PHP_FUNCTION(imlib_list_fonts)
{
   int fcount, i;
   char **flist = imlib_list_fonts(&fcount);

   if (array_init(return_value) == FAILURE) {
      php_error(E_WARNING, "Cannot initialize return value");
      RETURN_FALSE;
   }

   if (!fcount)
      RETURN_FALSE;

   for (i = 0; i < fcount; i++)
   {
      /* FIXME: Is 1 the right parameter here? */
      add_next_index_string(return_value, flist[i], 1);
   }

   imlib_free_font_list(flist,fcount);
}
/* }}} */


/* {{{ proto int imlib_load_font(string fontname)
   Load a font */
PHP_FUNCTION(imlib_load_font)
{
   zval **fontname;
   Imlib_Font fn;

   if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &fontname) == FAILURE) {
      WRONG_PARAM_COUNT;
   }

   convert_to_string_ex(fontname);
   fn = imlib_load_font(Z_STRVAL_PP(fontname));
   if (!fn)
   {
      php_error(E_WARNING, "%s - Could not load font.", Z_STRVAL_PP(fontname));
      RETURN_FALSE;
   }
   ZEND_REGISTER_RESOURCE(return_value, fn, le_imlib_font);
}
/* }}} */


/* {{{ proto int imlib_load_image(string img[, int &err])
   Load a file into an image, optionally fetch an error parameter */
PHP_FUNCTION(imlib_load_image)
{
   zval **img, **err;
   int argc;
   Imlib_Image im;
   Imlib_Load_Error im_err;

   argc = ZEND_NUM_ARGS();
   if (argc < 1 || argc > 2 || zend_get_parameters_ex(argc, &img, &err) == FAILURE) {
      WRONG_PARAM_COUNT;
   }

   convert_to_string_ex(img);
   if (argc == 2) {
      zval_dtor(*err);
      ZVAL_LONG(*err,0);
   }

   im = imlib_load_image_with_error_return(Z_STRVAL_PP(img),&im_err);

   if ((im_err) || (!im))
   {
      if (argc == 2) {
         ZVAL_LONG(*err,im_err);
      }
      _php_handle_imlib_error(INTERNAL_FUNCTION_PARAM_PASSTHRU,
                              im_err,Z_STRVAL_PP(img));
      RETURN_FALSE;
   }
   else
   {
      ZEND_REGISTER_RESOURCE(return_value, im, le_imlib_img);
   }
}
/* }}} */


/* {{{ proto void imlib_polygon_add_point(int polygon, int x, int y)
   Add a point to a given polygon */
PHP_FUNCTION(imlib_polygon_add_point)
{
   zval **polygon, **px, **py;
   int x,y;
   ImlibPolygon poly;

   if (ZEND_NUM_ARGS() != 3 || zend_get_parameters_ex(3, &polygon, &px, &py) == FAILURE) {
      WRONG_PARAM_COUNT;
   }

   ZEND_FETCH_RESOURCE(poly, ImlibPolygon, polygon, -1, "Imlib Polygon", le_imlib_poly);

   convert_to_long_ex(px);
   convert_to_long_ex(py);
   x = Z_LVAL_PP(px);
   y = Z_LVAL_PP(py);

   imlib_polygon_add_point(poly,x,y);
}
/* }}} */


/* {{{ proto bool imlib_polygon_contains_point(int polygon, int x, int y)
   Check if a give point is inside a polygon */
PHP_FUNCTION(imlib_polygon_contains_point)
{
   zval **polygon, **px, **py;
   int x,y,ret;
   ImlibPolygon poly;

   if (ZEND_NUM_ARGS() != 3 || zend_get_parameters_ex(3, &polygon, &px, &py) == FAILURE) {
      WRONG_PARAM_COUNT;
   }

   ZEND_FETCH_RESOURCE(poly, ImlibPolygon, polygon, -1, "Imlib Polygon", le_imlib_poly);

   convert_to_long_ex(px);
   convert_to_long_ex(py);
   x = Z_LVAL_PP(px);
   y = Z_LVAL_PP(py);

   ret = imlib_polygon_contains_point(poly,x,y);

   if (ret)
   {
      RETURN_TRUE;
   }
   else
   {
      RETURN_FALSE;
   }
}
/* }}} */


/* {{{ proto void imlib_polygon_free(int polygon)
   Free a polygon */
PHP_FUNCTION(imlib_polygon_free)
{
   zval **polygon;
   ImlibPolygon poly;

   if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &polygon) == FAILURE) {
      WRONG_PARAM_COUNT;
   }

   ZEND_FETCH_RESOURCE(poly, ImlibPolygon, polygon, -1, "Imlib Polygon", le_imlib_poly);
   zend_list_delete(Z_LVAL_PP(polygon));
}
/* }}} */


/* {{{ proto void imlib_polygon_get_bounds(int polygon, int &x1, int &y1, int &x2, int &y2)
   Get the bounding coords of a polygon */
PHP_FUNCTION(imlib_polygon_get_bounds)
{
   zval **polygon, **px1, **py1, **px2, **py2;
   int x1,y1,x2,y2;
   ImlibPolygon poly;

   if (ZEND_NUM_ARGS() != 5 || zend_get_parameters_ex(5, &polygon, &px1, &py1, &px2, &py2) == FAILURE) {
      WRONG_PARAM_COUNT;
   }

   ZEND_FETCH_RESOURCE(poly, ImlibPolygon, polygon, -1, "Imlib Polygon", le_imlib_poly);

   zval_dtor(*px1);
   zval_dtor(*py1);
   zval_dtor(*px2);
   zval_dtor(*py2);

   imlib_polygon_get_bounds(poly,&x1,&y1,&x2,&y2);

   ZVAL_LONG(*px1,x1);
   ZVAL_LONG(*py1,y1);
   ZVAL_LONG(*px2,x2);
   ZVAL_LONG(*py2,y2);
}
/* }}} */


/* {{{ proto int imlib_polygon_new()
   Create a new polygon */
PHP_FUNCTION(imlib_polygon_new)
{
   ImlibPolygon poly;

   if (ZEND_NUM_ARGS() != 0) {
      WRONG_PARAM_COUNT;
   }

   poly = imlib_polygon_new();
   ZEND_REGISTER_RESOURCE(return_value, poly, le_imlib_poly);
}
/* }}} */


/* {{{ proto bool imlib_save_image(int img, string name[, int &err[, int quality]])
   Save an image to a file, at an optional quality level (1-100) for jpegs.  For pngs, the value will be converted to a compression level (0-9) */
PHP_FUNCTION(imlib_save_image)
{
   zval **img, **name, **quality, **err;
   Imlib_Image im;
   Imlib_Load_Error im_err;
   int argc, q;

   argc = ZEND_NUM_ARGS();
   if (argc < 2 || argc > 4 || zend_get_parameters_ex(argc, &img, &name, &err, &quality) == FAILURE) {
      WRONG_PARAM_COUNT;
   }

   ZEND_FETCH_RESOURCE(im, Imlib_Image, img, -1, "Imlib Image", le_imlib_img);

   convert_to_string_ex(name);
   imlib_context_set_image(im);

   if (argc > 2) {
      zval_dtor(*err);
      ZVAL_LONG(*err,0);
   }

   if (argc > 3)
   {
      convert_to_long_ex(quality);
      q = Z_LVAL_PP(quality);
      imlib_image_attach_data_value("quality",NULL,q,NULL);
   }

   imlib_save_image_with_error_return(Z_STRVAL_PP(name),&im_err);

   if (im_err)
   {
      if (argc > 2)
      {
         ZVAL_LONG(*err,im_err);
      }
      _php_handle_imlib_error(INTERNAL_FUNCTION_PARAM_PASSTHRU,
                              im_err,Z_STRVAL_PP(name));
      RETURN_FALSE;
   }

   RETURN_TRUE;
}
/* }}} */


/* {{{ proto void imlib_text_draw(int img, int font, int x, int y, string str, int direction, int r, int g, int b, int a)
   Draw a text string using a font onto an image */
PHP_FUNCTION(imlib_text_draw)
{                               
   zval **img, **font, **tx, **ty, **textstr, **tdir, **tr, **tg, **tb, **ta;
   Imlib_Image im;
   Imlib_Font fn;
   char *text;
   int x,y,dir,r,g,b,a;

   if (ZEND_NUM_ARGS() != 10 || zend_get_parameters_ex(10, &img, &font, &tx, &ty, &textstr, &tdir, &tr, &tg, &tb, &ta) == FAILURE) {
      WRONG_PARAM_COUNT;
   }

   ZEND_FETCH_RESOURCE(im, Imlib_Image, img, -1, "Imlib Image", le_imlib_img);
   ZEND_FETCH_RESOURCE(fn, Imlib_Font, font, -1, "Imlib Font", le_imlib_font);

   convert_to_long_ex(tx);
   convert_to_long_ex(ty);
   convert_to_long_ex(tdir);
   convert_to_string_ex(textstr);
   x = Z_LVAL_PP(tx);
   y = Z_LVAL_PP(ty);
   dir = Z_LVAL_PP(tdir);
   text = Z_STRVAL_PP(textstr);
   _php_convert_four_longs(tr,tg,tb,ta,&r,&g,&b,&a);

   imlib_context_set_image(im);
   imlib_context_set_color(r,g,b,a);
   imlib_context_set_font(fn);
   imlib_context_set_direction(dir);
   imlib_text_draw(x, y, text);

   RETURN_TRUE;	/* TODO: Useful return value? */
}
/* }}} */
                        
/* {{{ proto int imlib_get_cache_size() 
   Get the size of image cache */
PHP_FUNCTION(imlib_get_cache_size)
{
   RETURN_LONG((long)imlib_get_cache_size());
}
/* }}} */

/* {{{ proto void imlib_set_cache_size(int bytes) 
   Set the size of image cache */
PHP_FUNCTION(imlib_set_cache_size)
{
   zval** tsize;
   int size;
   if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &tsize) == FAILURE) {
      WRONG_PARAM_COUNT;
   }
   convert_to_long_ex(tsize);
   size = Z_LVAL_PP(tsize);
   _php_imlib_set_cache_size(size TSRMLS_CC);
   RETURN_TRUE;
}
/* }}} */

#endif	/* HAVE_IMLIB */


/*
 * Local variables:
 * tab-width: 4
 * c-basic-offset: 4
 * End:
 */
