Last commit for php_imlib.c: a2f603174ce34359dde60b6227d138b5bf330503

Revert "Quick and dirty PHP7 port."

Piotr Pawłow [2016-09-14 15:21:01]
Revert "Quick and dirty PHP7 port."

This reverts commit 87380c76cb1eb3644da7291d842281caaae63f2d.
There are much more differences between PHP5 and 7 than I anticipated.
The code doesn't work right.
/*
   +----------------------------------------------------------------------+
   | PHP version 4.0                                                      |
   +----------------------------------------------------------------------+
   | Copyright (c) 1997, 1998, 1999, 2000 The PHP Group                   |
   +----------------------------------------------------------------------+
   | 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.               |
   +----------------------------------------------------------------------+
   | Authors: Matt McClanahan <cardinal@dodds.net>                        |
   +----------------------------------------------------------------------+
 */

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

/* #define IMLIB_DEBUG */

#ifdef IMLIB_DEBUG
#define ID_PRINTF(format, args...) \
fprintf(stderr, "php-imlib: " format "\n" , ## args); fflush(stdout)
#endif

#if HAVE_IMLIB
#ifdef ZTS
int gd_imlib_id;
#else
zend_imlib_globals imlib_globals;
#endif

static unsigned char third_arg_force_ref[] = { 3, BYREF_NONE, BYREF_NONE, BYREF_FORCE };
static unsigned char third_and_fourth_arg_force_ref[] = { 4, BYREF_NONE, BYREF_NONE, BYREF_FORCE, BYREF_FORCE };
static unsigned char second_through_fifth_arg_force_ref[] = { 5, BYREF_NONE, BYREF_FORCE, BYREF_FORCE, BYREF_FORCE, BYREF_FORCE };
static unsigned char third_through_sixth_arg_force_ref[] = { 6, BYREF_NONE, BYREF_NONE, BYREF_FORCE, BYREF_FORCE, BYREF_FORCE, BYREF_FORCE };
static int le_imlib_cr;
static int le_imlib_font;
static int le_imlib_img;
static int le_imlib_poly;
static int le_imlib_filter;
static int le_imlib_cm;
#if HAVE_LIBT1
static int le_ps_font, le_ps_enc;
#endif

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_color_modifier,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_color_modifier,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_get_text_advance,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_orientate,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)
	PHP_FE(imlib_create_filter,NULL)
	PHP_FE(imlib_free_filter,NULL)
	PHP_FE(imlib_image_filter,NULL)
	PHP_FE(imlib_filter_set,NULL)
	PHP_FE(imlib_filter_set_alpha,NULL)
	PHP_FE(imlib_filter_set_red,NULL)
	PHP_FE(imlib_filter_set_green,NULL)
	PHP_FE(imlib_filter_set_blue,NULL)
	PHP_FE(imlib_filter_constants,NULL)
	PHP_FE(imlib_filter_divisors,NULL)
	PHP_FE(imlib_apply_filter,NULL)
	PHP_FE(imlib_modify_color_modifier_gamma,NULL)
	PHP_FE(imlib_modify_color_modifier_brightness,NULL)
	PHP_FE(imlib_modify_color_modifier_contrast,NULL)
	PHP_FE(imlib_reset_color_modifier,NULL)
	PHP_FE(imlib_apply_color_modifier,NULL)
	PHP_FE(imlib_set_color_modifier,NULL)
	PHP_FE(imlib_get_color_modifier,third_through_sixth_arg_force_ref)
        PHP_FE(imlib_psloadfont,NULL)
        PHP_FE(imlib_psfreefont,NULL)
        PHP_FE(imlib_psencodefont,NULL)
        PHP_FE(imlib_psextendfont,NULL)
        PHP_FE(imlib_psslantfont,NULL)
	PHP_FE(imlib_pstext,NULL)
        PHP_FE(imlib_psbbox,NULL)

	{NULL, NULL, NULL}
};

ZEND_DECLARE_MODULE_GLOBALS(imlib)

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,OnUpdateInt,min_cache_size,zend_imlib_globals,imlib_globals)
STD_PHP_INI_ENTRY("imlib.max_cache_size","4194304",PHP_INI_SYSTEM,OnUpdateInt,max_cache_size,zend_imlib_globals,imlib_globals)
STD_PHP_INI_ENTRY("imlib.cache_size","0",PHP_INI_SYSTEM|PHP_INI_PERDIR,OnUpdateInt,cache_size,zend_imlib_globals,imlib_globals)
PHP_INI_ENTRY("imlib.font_cache_size","524288",PHP_INI_SYSTEM,OnUpdateFontCacheSize)
STD_PHP_INI_ENTRY("imlib.filter_path",PHP_IMLIB_FILTER_PATH,PHP_INI_SYSTEM,OnUpdateString,filter_path,zend_imlib_globals,imlib_globals)
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_cm(PHP_Imlib_Color_Modifier mod)
{
   imlib_context_set_color_modifier(mod->cm);
   imlib_free_color_modifier();
   efree(mod);
}

static void _php_imlib_free_filter(Imlib_Filter fil)
{
   imlib_context_set_filter(fil);
   imlib_free_filter();
}

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(PHP_Imlib_Font fn)
{
   imlib_context_set_font(fn->font);
   imlib_free_font();
   efree(fn);
}

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);
}

void _php_imlib_set_cache_size(int size)
{
   IMLIBLS_FETCH();
   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);
}

struct php_imlib_filter* _php_imlib_load_filter(char* file)
{
	struct php_imlib_filter* ptr=NULL;
	struct php_imlib_filter_info* info=NULL;
	char* path;
	int initrv=FAILURE;
#ifdef IMLIB_DEBUG
	ID_PRINTF("Loading library %s...",file);
#endif
	ptr=calloc(1,sizeof(struct php_imlib_filter));
	if (ptr==NULL) goto error;
	ptr->filename=strdup(file);
	ptr->handle=lt_dlopenext(file);
	if (!ptr->handle) goto error;
#ifdef IMLIB_DEBUG
	ID_PRINTF("Library loaded, handle=%p. Looking for entry points...",ptr->handle);
#endif
	ptr->init=lt_dlsym(ptr->handle,"php_filter_init");
	ptr->deinit=lt_dlsym(ptr->handle,"php_filter_deinit");
	ptr->exec=lt_dlsym(ptr->handle,"php_filter_exec");
	ptr->getfiltercount=lt_dlsym(ptr->handle,"php_filter_getfiltercount");
	ptr->getfilternames=lt_dlsym(ptr->handle,"php_filter_getfilternames");
        ptr->getextinfo=lt_dlsym(ptr->handle,"php_filter_getextinfo");
        ptr->getparams=lt_dlsym(ptr->handle,"php_filter_getparams");

#ifdef IMLIB_DEBUG
	ID_PRINTF("Function pointers: init=%p, deinit=%p, exec=%p, count=%p, names=%p",ptr->init,ptr->deinit,ptr->exec,ptr->getfiltercount,ptr->getfilternames);
#endif
	if (!ptr->getfiltercount || !ptr->getfilternames || !ptr->exec) goto error;
#ifdef IMLIB_DEBUG
	ID_PRINTF("Getting filter info...");
#endif
	if (ptr->init)
	{
		initrv=ptr->init();
		if (initrv==FAILURE) goto error;
	}
	ptr->filters=ptr->getfiltercount();
	ptr->names=malloc(ptr->filters*sizeof(char*));
	if (!ptr->names) goto error;
	ptr->getfilternames(ptr->names);
	ptr->next=NULL;
	return ptr;
error:
#ifdef IMLIB_DEBUG
	ID_PRINTF("Error loading library!");
#endif
	if (ptr)
	{
		if (ptr->handle)
		{
			if (ptr->deinit)
			{
				if (initrv==SUCCESS) ptr->deinit();
			}
			lt_dlclose(ptr->handle);
		}
		if (ptr->names) free(ptr->names);
		if (ptr->filename) free(ptr->filename);
		free(ptr);
	}
	return NULL;
}

void _php_imlib_unload_filter(struct php_imlib_filter* ptr)
{
	if (ptr==NULL) return;
	if (ptr->deinit) ptr->deinit();
	if (ptr->names) free(ptr->names);
	if (ptr->filename) free(ptr->filename);
	lt_dlclose(ptr->handle);
	free(ptr);
}

void _php_imlib_unload_filters()
{
	struct php_imlib_filter* f_ptr;

	IMLIBLS_FETCH();
	f_ptr=IMLIBG(filters);
	while (f_ptr!=NULL)
	{
		struct php_imlib_filter* f_ptr_next;
		f_ptr_next=f_ptr->next;
		_php_imlib_unload_filter(f_ptr);
		f_ptr=f_ptr_next;
	}
	IMLIBG(filters)=NULL;

	lt_dlexit();
}

void _php_imlib_load_filters()
{
	struct php_imlib_filter* f_ptr;
	char* path;
	DIR* dirp=NULL;
	struct dirent *dp;
	char** names=NULL;
	int names_size,names_index,i;
	int ltinitrv=0;

	IMLIBLS_FETCH();
	f_ptr=IMLIBG(filters);
	if (f_ptr!=NULL) return;
#ifdef IMLIB_DEBUG
	ID_PRINTF("Initializing libltdl...");
#endif
	if ((ltinitrv=lt_dlinit())>0) goto error;

#ifdef IMLIB_DEBUG
	ID_PRINTF("Loading filters...");
#endif
	path=IMLIBG(filter_path);
	lt_dladdsearchdir(path);
#ifdef IMLIB_DEBUG
	ID_PRINTF("Opening directory %s...",path);
#endif
	if ((dirp=opendir(path))==NULL) goto error;

	names_size=20;
	names_index=0;
	if ((names=malloc(names_size*sizeof(char*)))==NULL) goto error;

#ifdef IMLIB_DEBUG
	ID_PRINTF("Scanning directory...");
#endif
	errno=0;
	while ((dp=readdir(dirp))!=NULL)
	{
		char* name;

		if ((name=strdup(dp->d_name))==NULL) goto error;
		if ((strcmp(name, ".")) && (strcmp(name, "..")))
		{
			char* ext;

			ext=strchr(name,'.');
			if (ext)
			{
				*ext='\0';
				for (i=0;i<names_index;i++)
				{
					if (strcmp(names[i],name)==0)
						break;
				}
				if (i==names_index)
				{
					if (names_index==names_size)
					{
						char** names_new;

						names_size*=2;
						names_new=realloc(names,names_size*sizeof(char*));
						if (names_new==NULL)
						{
							free(name);
							goto error;
						}
						names=names_new;
					}
#ifdef IMLIB_DEBUG
	ID_PRINTF("Found library %s",name);
#endif
					names[names_index++]=name;
				}
			}
		}
	}
	if (errno!=0) goto error;
	if (names_index>0)
	{
		IMLIBG(filters)=f_ptr=malloc(sizeof(struct php_imlib_filter));

		for (i=0;i<names_index;i++)
		{
			if ((f_ptr->next=_php_imlib_load_filter(names[i]))!=NULL)
				f_ptr=f_ptr->next;
		}
		IMLIBG(filters)=IMLIBG(filters)->next;
	}
	goto cleanup;

error:
#ifdef IMLIB_DEBUG
	ID_PRINTF("Error loading filters!");
#endif
	_php_imlib_unload_filters();
cleanup:
	if (names!=NULL)
	{
		for (i=0;i<names_index;i++)
		{
			free(names[i]);
		}
		free(names);
	}
	if (dirp!=NULL) closedir(dirp);
}

struct php_imlib_filter* _php_imlib_find_filter(char *filter_name)
{
	struct php_imlib_filter* f_ptr;
	int i;

	_php_imlib_load_filters();
	IMLIBLS_FETCH();
	f_ptr=IMLIBG(filters);
	while (f_ptr!=NULL)
	{
		for (i=0;i<f_ptr->filters;i++)
		{
			if (strcmp(f_ptr->names[i],filter_name)==0)
			{
				return f_ptr;
			}
		}
		f_ptr=f_ptr->next;
	}
	return NULL;
}

Imlib_Image _php_imlib_get_image(zval** im_resource)
{
	Imlib_Image im;
	TSRMLS_FETCH();
	MY_ZEND_FETCH_RESOURCE(im, Imlib_Image, im_resource, -1, "Imlib Image", le_imlib_img);
	return im;
}

Imlib_Filter _php_imlib_get_filter(zval** fil_resource)
{
	Imlib_Filter fil;
	TSRMLS_FETCH();
	MY_ZEND_FETCH_RESOURCE(fil, Imlib_Filter, fil_resource, -1, "Imlib Filter", le_imlib_filter);
	return fil;
}

void _php_imlib_color_modifier_synch(PHP_Imlib_Color_Modifier cm)
{
	if ((cm->modified)&&(!cm->valid))
	{
	    fprintf(stderr,"Panic!! Color Modifier in invalid state!");
	    return;
	}
	imlib_context_set_color_modifier(cm->cm);
        if (cm->modified)
	{
	    imlib_set_color_modifier_tables(cm->channels[0],cm->channels[1],cm->channels[2],cm->channels[3]);
	    cm->modified=0;
	}
	if (!cm->valid)
	{
	    imlib_get_color_modifier_tables(cm->channels[0],cm->channels[1],cm->channels[2],cm->channels[3]);
	    cm->valid=1;
	}
	imlib_context_set_color_modifier(NULL);
}

Imlib_Color_Modifier _php_imlib_get_cm(zval** cm_resource)
{
	PHP_Imlib_Color_Modifier cm;
	TSRMLS_FETCH();
	MY_ZEND_FETCH_RESOURCE(cm, Imlib_Color_Modifier, cm_resource, -1, "Imlib Color Modifier", le_imlib_cm);
	if (cm->modified) _php_imlib_color_modifier_synch(cm);
	cm->valid=0;
	return cm->cm;
}

Imlib_Font _php_imlib_get_font(zval** font_resource)
{
	PHP_Imlib_Font php_font;
	TSRMLS_FETCH();
	MY_ZEND_FETCH_RESOURCE(php_font, PHP_Imlib_Font, font_resource, -1, "Imlib Font", le_imlib_font);
	return php_font->font;
}

Imlib_TTF_Encoding _php_imlib_get_encoding(zval** font_resource)
{
	PHP_Imlib_Font php_font;
	TSRMLS_FETCH();
	MY_ZEND_FETCH_RESOURCE(php_font, PHP_Imlib_Font, font_resource, -1, "Imlib Font", le_imlib_font);
	return php_font->enc;
}

Imlib_Color_Range _php_imlib_get_cr(zval** cr_resource)
{
	Imlib_Color_Range cr;
	TSRMLS_FETCH();
	MY_ZEND_FETCH_RESOURCE(cr, Imlib_Color_Range, cr_resource, -1, "Imlib Color Range", le_imlib_cr);
	return cr;
}

ImlibPolygon _php_imlib_get_poly(zval** poly_resource)
{
	ImlibPolygon poly;
	TSRMLS_FETCH();
	MY_ZEND_FETCH_RESOURCE(poly, ImlibPolygon, poly_resource, -1, "Imlib Polygon", le_imlib_poly);
	return poly;
}

#if HAVE_LIBT1

/* {{{ _php_imlib_free_ps_font
 */
void _php_imlib_free_ps_font(zend_rsrc_list_entry *rsrc TSRMLS_DC)
{
        int *font = (int *)rsrc->ptr;

        T1_DeleteFont(*font);
        efree(font);
}
/* }}} */

/* {{{ _php_imlib_free_ps_enc
 */
void _php_imlib_free_ps_enc(zend_rsrc_list_entry *rsrc TSRMLS_DC)
{
        char **enc = (char **)rsrc->ptr;

        T1_DeleteEncoding(enc);
}
/* }}} */

#endif


#ifdef COMPILE_DL_IMLIB
ZEND_GET_MODULE(imlib)
#endif

PHP_MINIT_FUNCTION(imlib)
{
	IMLIBLS_FETCH();
	IMLIBG(filters)=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);
	le_imlib_filter = register_list_destructors(_php_imlib_free_filter,NULL);
	le_imlib_cm = register_list_destructors(_php_imlib_free_cm,NULL);
#if HAVE_LIBT1
        T1_SetBitmapPad(8);
        T1_InitLib(NO_LOGFILE|IGNORE_CONFIGFILE|IGNORE_FONTDATABASE);
        T1_SetLogLevel(T1LOG_DEBUG);
        le_ps_font = zend_register_list_destructors_ex(_php_imlib_free_ps_font, NULL, "imlib PS font", module_number);
        le_ps_enc = zend_register_list_destructors_ex(_php_imlib_free_ps_enc, NULL, "imlib PS encoding", module_number);
#endif

	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_TTF_ENCODING_ISO_8859_1", IMLIB_TTF_ENCODING_ISO_8859_1, CONST_CS|CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("IMLIB_TTF_ENCODING_ISO_8859_2", IMLIB_TTF_ENCODING_ISO_8859_2, CONST_CS|CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("IMLIB_TTF_ENCODING_ISO_8859_3", IMLIB_TTF_ENCODING_ISO_8859_3, CONST_CS|CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("IMLIB_TTF_ENCODING_ISO_8859_4", IMLIB_TTF_ENCODING_ISO_8859_4, CONST_CS|CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("IMLIB_TTF_ENCODING_ISO_8859_5", IMLIB_TTF_ENCODING_ISO_8859_5, CONST_CS|CONST_PERSISTENT);

	REGISTER_LONG_CONSTANT("IMLIB_CHANNEL_RED", 1, CONST_CS|CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("IMLIB_CHANNEL_GREEN", 2, CONST_CS|CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("IMLIB_CHANNEL_BLUE", 4, CONST_CS|CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("IMLIB_CHANNEL_ALPHA", 8, 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)
{
	_php_imlib_unload_filters();

	UNREGISTER_INI_ENTRIES();

	return SUCCESS;
}

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

	/* Set default cache size */
        _php_imlib_set_cache_size(IMLIBG(cache_size));
	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;
	IMLIBLS_FETCH();

	/* Restore cache size */
        _php_imlib_set_cache_size(0);
	/* 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)
{
        struct php_imlib_filter* f_ptr;
        int i;

        _php_imlib_load_filters();
        IMLIBLS_FETCH();
        f_ptr=IMLIBG(filters);

	DISPLAY_INI_ENTRIES();

#ifdef HAVE_LIBT1
        php_info_print_table_start();
        php_info_print_table_row(2, "T1Lib Support", "enabled");
        php_info_print_table_end();
#endif

        while (f_ptr!=NULL)
        {
		char* extinfo[3] = {NULL, NULL, NULL};
		php_info_print_table_start();
		if (f_ptr->getextinfo) f_ptr->getextinfo(extinfo);
		if (extinfo[0])
		{
			char* infostr;
			f_ptr->getextinfo(extinfo);
			infostr=emalloc((strlen(extinfo[0])+strlen(f_ptr->filename)+4)*sizeof(char));
			strcpy(infostr,extinfo[0]);
			strcat(infostr," (");
			strcat(infostr,f_ptr->filename);
			strcat(infostr,")");
			php_info_print_table_row(2, "Filter name", infostr);
			efree(infostr);
		}
		else
		{
			php_info_print_table_row(2, "Filter name", f_ptr->filename);
		}
		if (extinfo[1]) php_info_print_table_row(2,"Description",extinfo[1]);
		if (extinfo[2]) php_info_print_table_row(2,"Author",extinfo[2]);

		{
			char* filters;
			filters=estrdup("");
			for (i=0;i<f_ptr->filters;i++)
			{
				int newlen;
				char* params=NULL;
				if (f_ptr->getparams) params=f_ptr->getparams(f_ptr->names[i]);
				newlen=strlen(filters)+strlen(f_ptr->names[i])+2;
				if (params) newlen+=strlen(params)+3;
				filters=erealloc(filters,newlen*sizeof(char));
				if (filters)
				{
					strcat(filters,f_ptr->names[i]);
					if (params)
					{
						strcat(filters," (");
						strcat(filters,params);
						strcat(filters,")");
					}
					strcat(filters,"\n");
				}
			}
			php_info_print_table_row(2,"Filters",filters);
			efree(filters);
		}
		f_ptr=f_ptr->next;
		php_info_print_table_end();
	}
}

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;
   IMLIBLS_FETCH();

   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;
   IMLIBLS_FETCH();

   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;
   IMLIBLS_FETCH();

   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;
   IMLIBLS_FETCH();

   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;
   IMLIBLS_FETCH();

   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();

   if (dst) 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;
   IMLIBLS_FETCH();

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

   cr = imlib_create_color_range();

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


/* {{{ proto int imlib_create_color_modifier(void)
   Create a new color modifier */
PHP_FUNCTION(imlib_create_color_modifier)
{
   PHP_Imlib_Color_Modifier cm;
   IMLIBLS_FETCH();

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

   cm=(PHP_Imlib_Color_Modifier)emalloc(sizeof(PHP_Imlib_Color_Modifier_struct));
   if (!cm) RETURN_FALSE;

   cm->cm = imlib_create_color_modifier();
   cm->modified=0;
   cm->valid=0;

   if (cm->cm) ZEND_REGISTER_RESOURCE(return_value, cm, le_imlib_cm);
}
/* }}} */

/* {{{ 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;
   IMLIBLS_FETCH();

   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);

   if (dst) 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;
   IMLIBLS_FETCH();

   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);

   if (dst) 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;
   IMLIBLS_FETCH();

   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);

   if (im) {
      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;
   IMLIBLS_FETCH();

   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);

   if (dst) 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;
   IMLIBLS_FETCH();

   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);

   if (dst) 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;
   IMLIBLS_FETCH();

   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;
   IMLIBLS_FETCH();

   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_color_modifier(int cm)
   Free a color modifier */
PHP_FUNCTION(imlib_free_color_modifier)
{
   zval **fcm;
   PHP_Imlib_Color_Modifier cm;
   IMLIBLS_FETCH();

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

   ZEND_FETCH_RESOURCE(cm, PHP_Imlib_Color_Modifier, fcm, -1, "Imlib Color Modifier", le_imlib_cm);
   zend_list_delete(Z_LVAL_PP(fcm));
}
/* }}} */

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

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

   ZEND_FETCH_RESOURCE(fn, PHP_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;
   IMLIBLS_FETCH();

   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_advance(int font, string str, int &horiz_adv, int &vert_adv, int direction)
   Determines the horizontal and vertical advance of a string if drawn with a given font in the specified direction*/
PHP_FUNCTION(imlib_get_text_advance)
{
   zval **font, **textstr, **thoriz_adv, **tvert_adv, **tdir;
   PHP_Imlib_Font fn;
   const char *text = NULL;
   int horiz_adv, vert_adv, dir;
   Imlib_TTF_Encoding old_enc;
   IMLIBLS_FETCH();

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

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

   zval_dtor(*thoriz_adv);
   zval_dtor(*tvert_adv);

   convert_to_string_ex(textstr);
   convert_to_long_ex(thoriz_adv);
   convert_to_long_ex(tvert_adv);
   convert_to_long_ex(tdir);
   text = Z_STRVAL_PP(textstr);
   horiz_adv = Z_LVAL_PP(thoriz_adv);
   vert_adv = Z_LVAL_PP(tvert_adv);
   dir = Z_LVAL_PP(tdir);

   imlib_context_set_font(fn->font);
   old_enc=imlib_context_get_TTF_encoding();
   imlib_context_set_TTF_encoding(fn->enc);
   imlib_context_set_direction(dir);
   imlib_get_text_advance(text, &horiz_adv, &vert_adv);
   imlib_context_set_TTF_encoding(old_enc);

   ZVAL_LONG(*thoriz_adv,horiz_adv);
   ZVAL_LONG(*tvert_adv,vert_adv);
}
/* }}} */


/* {{{ 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;
   PHP_Imlib_Font fn;
   const char *text = NULL;
   int w,h,dir;
   Imlib_TTF_Encoding old_enc;
   IMLIBLS_FETCH();

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

   ZEND_FETCH_RESOURCE(fn, PHP_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->font);
   old_enc=imlib_context_get_TTF_encoding();
   imlib_context_set_TTF_encoding(fn->enc);
   imlib_context_set_direction(dir);
   imlib_get_text_size(text, &w, &h);
   imlib_context_set_TTF_encoding(old_enc);

   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;
   IMLIBLS_FETCH();

   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;
   IMLIBLS_FETCH();

   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;
   IMLIBLS_FETCH();

   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;
   IMLIBLS_FETCH();

   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_rectange(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 void imlib_image_orientate(int img, int stepping)
   Orientate an image 90 x steps */
PHP_FUNCTION(imlib_image_orientate)
{
   zval **img, **stepping;
   int r;
   Imlib_Image im;
   IMLIBLS_FETCH();

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

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

   imlib_context_set_image(im);
   r = Z_LVAL_PP(stepping);
   imlib_image_orientate(r);
}
/* }}} */


/* {{{ 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;
   IMLIBLS_FETCH();

   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;
   IMLIBLS_FETCH();

   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;
   IMLIBLS_FETCH();

   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;
   IMLIBLS_FETCH();

   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;
   IMLIBLS_FETCH();

   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;
   IMLIBLS_FETCH();

   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[, string encoding])
   Load a font */
PHP_FUNCTION(imlib_load_font)
{
   zval **fontname, **encoding;
   PHP_Imlib_Font fn;
   int argc;

   IMLIBLS_FETCH();

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

   if ((Z_LVAL_PP(encoding)<IMLIB_TTF_ENCODING_ISO_8859_1)||(Z_LVAL_PP(encoding)>IMLIB_TTF_ENCODING_ISO_8859_5))
   {
      php_error(E_NOTICE, "Invalid font encoding ignored");
      argc=1;
   }

   fn=(PHP_Imlib_Font)emalloc(sizeof(PHP_Imlib_Font_struct));
   if (!fn) RETURN_FALSE;

   if (argc==2)
   {
      convert_to_long_ex(encoding);
      fn->enc=(Imlib_TTF_Encoding)Z_LVAL_PP(encoding);
      imlib_context_set_TTF_encoding(fn->enc);
   }

   convert_to_string_ex(fontname);
   fn->font = imlib_load_font(Z_STRVAL_PP(fontname));

   if (!fn->font)
   {
      efree(fn);
      php_error(E_WARNING, "%s - Could not load font.", Z_STRVAL_PP(fontname));
      RETURN_FALSE;
   }
   if (argc==1)
   {
      fn->enc=imlib_context_get_TTF_encoding();
   }

   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;
   IMLIBLS_FETCH();

   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;
   IMLIBLS_FETCH();

   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;
   IMLIBLS_FETCH();

   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;
   IMLIBLS_FETCH();

   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;
   IMLIBLS_FETCH();

   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;
   IMLIBLS_FETCH();

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

   poly = imlib_polygon_new();
   if (poly) 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;
   IMLIBLS_FETCH();

   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;
   PHP_Imlib_Font fn;
   char *text;
   int x,y,dir,r,g,b,a;
   Imlib_TTF_Encoding old_enc;
   IMLIBLS_FETCH();

   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, PHP_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->font);
   imlib_context_set_direction(dir);
   old_enc=imlib_context_get_TTF_encoding();
   imlib_context_set_TTF_encoding(fn->enc);
   imlib_text_draw(x, y, text);
   imlib_context_set_TTF_encoding(old_enc);

   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);
   RETURN_TRUE;
}
/* }}} */

/* {{{ proto void imlib_apply_filter(int img, string filter, array params)
   Apply external filter to an image */
PHP_FUNCTION(imlib_apply_filter)
{
   zval **img, **tfilter_name, **tparams;
   Imlib_Image im;
   struct php_imlib_filter* filter;
   char* filter_name;
   HashTable* arg_ht;
   if (ZEND_NUM_ARGS() < 2 || ZEND_NUM_ARGS() > 3 || zend_get_parameters_ex(3, &img, &tfilter_name, &tparams) == FAILURE) {
      WRONG_PARAM_COUNT;
   }

   ZEND_FETCH_RESOURCE(im, Imlib_Image, img, -1, "Imlib Image", le_imlib_img);
   convert_to_string_ex(tfilter_name);
   filter_name = Z_STRVAL_PP(tfilter_name);

   filter = _php_imlib_find_filter(filter_name);

   if (!filter) {
      php_error(E_WARNING, "%s - Filter not found.", filter_name);
      RETURN_FALSE;
   }

   convert_to_array_ex(tparams);
   arg_ht=HASH_OF(*tparams);

/* ID_PRINTF("Image before: %p",im); */
   if (filter->exec(im, filter_name, arg_ht)==FAILURE)
   {
      php_error(E_WARNING, "Error executing filter %s.", filter_name);
      RETURN_FALSE;
   }
/* ID_PRINTF("Image after: %p",imlib_context_get_image()); */

   RETURN_TRUE;
}
/* }}} */

/* {{{ proto int imlib_create_filter(void)
   Create a new filter */
PHP_FUNCTION(imlib_create_filter)
{
   Imlib_Filter fil;

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

   fil = imlib_create_filter(0);

   if (fil) ZEND_REGISTER_RESOURCE(return_value, fil, le_imlib_filter);
}
/* }}} */


/* {{{ proto void imlib_free_filter(int filter)
   Free a filter */
PHP_FUNCTION(imlib_free_filter)
{
   zval **filter;
   Imlib_Filter fil;

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

   ZEND_FETCH_RESOURCE(fil, Imlib_Filter, filter, -1, "Imlib Filter", le_imlib_filter);
   zend_list_delete(Z_LVAL_PP(filter));
}
/* }}} */

/* {{{ proto void imlib_image_filter(int img, int filter)
   Apply filter to an image */
PHP_FUNCTION(imlib_image_filter)
{
   zval **filter, **img;
   Imlib_Filter fil;
   Imlib_Image im;

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

   ZEND_FETCH_RESOURCE(im, Imlib_Image, img, -1, "Imlib Image", le_imlib_img);
   ZEND_FETCH_RESOURCE(fil, Imlib_Filter, filter, -1, "Imlib Filter", le_imlib_filter);

   imlib_context_set_image(im);
   imlib_context_set_filter(fil);
   imlib_image_filter();
}
/* }}} */

static void _php_imlib_filter_set(INTERNAL_FUNCTION_PARAMETERS, int type)
{
    zval **filter, **txoff, **tyoff, **ta, **tr, **tg, **tb;
    int argc,xoff,yoff,a,r,g,b;
    Imlib_Filter fil;

    argc=ZEND_NUM_ARGS();
    if (argc!=7 || zend_get_parameters_ex(argc, &filter, &txoff, &tyoff, &ta, &tr, &tg, &tb) == FAILURE) {
       WRONG_PARAM_COUNT;
    }

    ZEND_FETCH_RESOURCE(fil, Imlib_Filter, filter, -1, "Imlib Filter", le_imlib_filter);

    convert_to_long_ex(txoff);
    convert_to_long_ex(tyoff);
    convert_to_long_ex(ta);
    convert_to_long_ex(tr);
    convert_to_long_ex(tg);
    convert_to_long_ex(tb);

    r=Z_LVAL_PP(tr);
    g=Z_LVAL_PP(tg);
    b=Z_LVAL_PP(tb);
    a=Z_LVAL_PP(ta);
    xoff=Z_LVAL_PP(txoff);
    yoff=Z_LVAL_PP(tyoff);

    imlib_context_set_filter(fil);

    if (type==0) imlib_filter_set(xoff,yoff,a,r,g,b);
    if (type==1) imlib_filter_set_red(xoff,yoff,a,r,g,b);
    if (type==2) imlib_filter_set_green(xoff,yoff,a,r,g,b);
    if (type==3) imlib_filter_set_blue(xoff,yoff,a,r,g,b);
    if (type==4) imlib_filter_set_alpha(xoff,yoff,a,r,g,b);
}

/* {{{ proto void imlib_filter_set(int filter, int xoff, int yoff, int a, int r, int g, int b)
   Set weights for source pixel at (xoff,yoff). Each channel will be processed separately, which means that
   value of "a" will be user for alpha channel only, "r" for red channel etc
   */
PHP_FUNCTION(imlib_filter_set)
{
    _php_imlib_filter_set(INTERNAL_FUNCTION_PARAM_PASSTHRU,0);
}
/* }}} */

/* {{{ proto void imlib_filter_set_red(int filter, int xoff, int yoff, int a, int r, int g, int b)
   Set weights for source pixel at (xoff,yoff). Only red component of the destination pixel will be affected.*/
PHP_FUNCTION(imlib_filter_set_red)
{
    _php_imlib_filter_set(INTERNAL_FUNCTION_PARAM_PASSTHRU,1);
}
/* }}} */

/* {{{ proto void imlib_filter_set_green(int filter, int xoff, int yoff, int a, int r, int g, int b)
   Set weights for source pixel at (xoff,yoff). Only green component of the destination pixel will be affected.*/
PHP_FUNCTION(imlib_filter_set_green)
{
    _php_imlib_filter_set(INTERNAL_FUNCTION_PARAM_PASSTHRU,2);
}
/* }}} */

/* {{{ proto void imlib_filter_set_blue(int filter, int xoff, int yoff, int a, int r, int g, int b)
   Set weights for source pixel at (xoff,yoff). Only blue component of the destination pixel will be affected.*/
PHP_FUNCTION(imlib_filter_set_blue)
{
    _php_imlib_filter_set(INTERNAL_FUNCTION_PARAM_PASSTHRU,3);
}
/* }}} */

/* {{{ proto void imlib_filter_set_alpha(int filter, int xoff, int yoff, int a, int r, int g, int b)
   Set weights for source pixel at (xoff,yoff). Only alpha component of the destination pixel will be affected.*/
PHP_FUNCTION(imlib_filter_set_alpha)
{
    _php_imlib_filter_set(INTERNAL_FUNCTION_PARAM_PASSTHRU,4);
}
/* }}} */

/* {{{ proto void imlib_filter_constants(int filter, int a, int r, int g, int b)
   Set filter constants */
PHP_FUNCTION(imlib_filter_constants)
{
	zval **filter, **a, **r, **g, **b;
	Imlib_Filter fil;

	if (ZEND_NUM_ARGS()!=5 || zend_get_parameters_ex(5, &filter, &a, &r, &g, &b) == FAILURE) {
	   WRONG_PARAM_COUNT;
	}

        ZEND_FETCH_RESOURCE(fil, Imlib_Filter, filter, -1, "Imlib Filter", le_imlib_filter);

	convert_to_long_ex(a);
	convert_to_long_ex(r);
	convert_to_long_ex(g);
	convert_to_long_ex(b);

	imlib_context_set_filter(fil);
	imlib_filter_constants(Z_LVAL_PP(a),Z_LVAL_PP(r),Z_LVAL_PP(g),Z_LVAL_PP(b));
}
/* }}} */

/* {{{ proto void imlib_filter_divisors(int filter, int a, int r, int g, int b)
   Set filter divisors */
PHP_FUNCTION(imlib_filter_divisors)
{
	zval **filter, **a, **r, **g, **b;
	Imlib_Filter fil;

	if (ZEND_NUM_ARGS()!=5 || zend_get_parameters_ex(5, &filter, &a, &r, &g, &b) == FAILURE) {
	   WRONG_PARAM_COUNT;
	}

        ZEND_FETCH_RESOURCE(fil, Imlib_Filter, filter, -1, "Imlib Filter", le_imlib_filter);

	convert_to_long_ex(a);
	convert_to_long_ex(r);
	convert_to_long_ex(g);
	convert_to_long_ex(b);

	imlib_context_set_filter(fil);
	imlib_filter_divisors(Z_LVAL_PP(a),Z_LVAL_PP(r),Z_LVAL_PP(g),Z_LVAL_PP(b));
}
/* }}} */


/* {{{ proto void imlib_modify_color_modifier_gamma(int cm, double gamma_value)
   Adjust color modifier gamma */
PHP_FUNCTION(imlib_modify_color_modifier_gamma)
{
    zval **gamma, **color_modifier;
    PHP_Imlib_Color_Modifier cm;

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

    ZEND_FETCH_RESOURCE(cm, PHP_Imlib_Color_Modifier, color_modifier, -1, "Imlib Color Modifier", le_imlib_cm);
    if (cm->modified) _php_imlib_color_modifier_synch(cm);
    convert_to_double_ex(gamma);
    imlib_context_set_color_modifier(cm->cm);
    imlib_modify_color_modifier_gamma(Z_DVAL_PP(gamma));
    imlib_context_set_color_modifier(NULL);
    cm->valid=0;
}
/* }}} */


/* {{{ proto void imlib_modify_color_modifier_brightness(int cm, double brightness_value)
   Adjust color modifier brightness */
PHP_FUNCTION(imlib_modify_color_modifier_brightness)
{
    zval **brightness, **color_modifier;
    PHP_Imlib_Color_Modifier cm;

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

    ZEND_FETCH_RESOURCE(cm, Imlib_Color_Modifier, color_modifier, -1, "Imlib Color Modifier", le_imlib_cm);
    if (cm->modified) _php_imlib_color_modifier_synch(cm);
    convert_to_double_ex(brightness);
    imlib_context_set_color_modifier(cm->cm);
    imlib_modify_color_modifier_brightness(Z_DVAL_PP(brightness));
    imlib_context_set_color_modifier(NULL);
    cm->valid=0;
}
/* }}} */


/* {{{ proto void imlib_modify_color_modifier_contrast(int cm, double contrast_value)
   Adjust color modifier contrast */
PHP_FUNCTION(imlib_modify_color_modifier_contrast)
{
    zval **contrast, **color_modifier;
    PHP_Imlib_Color_Modifier cm;

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

    ZEND_FETCH_RESOURCE(cm, PHP_Imlib_Color_Modifier, color_modifier, -1, "Imlib Color Modifier", le_imlib_cm);
    if (cm->modified) _php_imlib_color_modifier_synch(cm);
    convert_to_double_ex(contrast);
    imlib_context_set_color_modifier(cm->cm);
    imlib_modify_color_modifier_contrast(Z_DVAL_PP(contrast));
    imlib_context_set_color_modifier(NULL);
    cm->valid=0;
}
/* }}} */


/* {{{ proto void imlib_reset_color_modifier(int cm)
   Reset color modifier to default (one-to-one) mapping */
PHP_FUNCTION(imlib_reset_color_modifier)
{
    zval **color_modifier;
    PHP_Imlib_Color_Modifier cm;

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

    ZEND_FETCH_RESOURCE(cm, PHP_Imlib_Color_Modifier, color_modifier, -1, "Imlib Color Modifier", le_imlib_cm);
    imlib_context_set_color_modifier(cm->cm);
    imlib_reset_color_modifier();
    imlib_context_set_color_modifier(NULL);
    cm->valid=0;
}
/* }}} */


/* {{{ proto void imlib_apply_color_modifier(int img, int cm[, int x, int y, int width, int height])
   Apply color modifier to an image or its part */
PHP_FUNCTION(imlib_apply_color_modifier)
{
    zval **color_modifier, **image, **x, **y, **width, **height;
    PHP_Imlib_Color_Modifier cm;
    Imlib_Image img;
    int argc;

    argc=ZEND_NUM_ARGS();
    if ((argc!=2 && argc!=6) || zend_get_parameters_ex(argc, &image, &color_modifier, &x, &y, &width, &height) == FAILURE) {
       WRONG_PARAM_COUNT;
    }

    ZEND_FETCH_RESOURCE(cm, PHP_Imlib_Color_Modifier, color_modifier, -1, "Imlib Color Modifier", le_imlib_cm);
    ZEND_FETCH_RESOURCE(img, Imlib_Image, image, -1, "Imlib Image", le_imlib_img);
    if (cm->modified) _php_imlib_color_modifier_synch(cm);
    imlib_context_set_image(img);

    imlib_context_set_color_modifier(cm->cm);
    if (argc==2) {
        imlib_apply_color_modifier();
    } else {
	convert_to_long_ex(x);
	convert_to_long_ex(y);
	convert_to_long_ex(width);
	convert_to_long_ex(height);
	imlib_apply_color_modifier_to_rectangle(Z_LVAL_PP(x),Z_LVAL_PP(y),Z_LVAL_PP(width),Z_LVAL_PP(height));
    }
    imlib_context_set_color_modifier(NULL);
}
/* }}} */

/* {{{ proto void imlib_set_color_modifier(int cm, int index, int value[, int channels])
   Set color modifier value at given index for given channels (or all if not specified) */

PHP_FUNCTION(imlib_set_color_modifier)
{
    zval **color_modifier, **tindex, **tvalue, **tchannels;
    unsigned char index, value, channels;
    PHP_Imlib_Color_Modifier cm;
    int argc,i=0;

    argc=ZEND_NUM_ARGS();
    if (argc < 3 || argc > 4 || zend_get_parameters_ex(argc, &color_modifier, &tindex, &tvalue, &tchannels) == FAILURE) {
	WRONG_PARAM_COUNT;
    }
    ZEND_FETCH_RESOURCE(cm, PHP_Imlib_Color_Modifier, color_modifier, -1, "Imlib Color Modifier", le_imlib_cm);
    convert_to_long_ex(tindex);
    convert_to_long_ex(tvalue);
    index=(unsigned char)Z_LVAL_PP(tindex);
    value=(unsigned char)Z_LVAL_PP(tvalue);
    if (argc==4) {
	convert_to_long_ex(tchannels);
	channels=(unsigned char)Z_LVAL_PP(tchannels);
    } else {
	channels=15;
    };
    if (!cm->valid) _php_imlib_color_modifier_synch(cm);
    while (i<4) {
	if (channels&1)	{
	    cm->channels[i][index]=value;
	    cm->modified=1;
	}
	i++;
	channels>>=1;
    }
}
/* }}} */


/* {{{ proto void imlib_get_color_modifier(int cm, int index, int &red, int &green, int &blue, int &alpha)
   Get color modifier values at given index */

PHP_FUNCTION(imlib_get_color_modifier)
{
    zval **color_modifier, **tindex, **tred, **tgreen, **tblue, **talpha;
    unsigned char index;
    PHP_Imlib_Color_Modifier cm;

    if (ZEND_NUM_ARGS() != 6 || zend_get_parameters_ex(6, &color_modifier, &tindex, &tred, &tgreen, &tblue, &talpha) == FAILURE) {
	WRONG_PARAM_COUNT;
    }
    ZEND_FETCH_RESOURCE(cm, PHP_Imlib_Color_Modifier, color_modifier, -1, "Imlib Color Modifier", le_imlib_cm);
    convert_to_long_ex(tindex);
    index=(unsigned char)Z_LVAL_PP(tindex);
    if (!cm->valid) _php_imlib_color_modifier_synch(cm);

    zval_dtor(*tred);
    zval_dtor(*tgreen);
    zval_dtor(*tblue);
    zval_dtor(*talpha);

    ZVAL_LONG(*tred,cm->channels[0][index]);
    ZVAL_LONG(*tgreen,cm->channels[1][index]);
    ZVAL_LONG(*tblue,cm->channels[2][index]);
    ZVAL_LONG(*talpha,cm->channels[3][index]);
}
/* }}} */


/* Type1 font support taken from GD module, originally written by Jouni Ahto <jah@mork.net>,
   modified for imlib by Piotr Pawlow <pp@siedziba.pl> */

/* {{{ proto array imlib_pstext(int img, string text, int font, int size, int x, int y, int r, int g, int b, int a [, int space[, int tightness[, double angle[, int antialias]]]])
   Rasterize a string over an image */
PHP_FUNCTION(imlib_pstext)
{
#if HAVE_LIBT1

	zval **img, **str, **fnt, **sz, **fg, **px, **py, **tr, **tg, **tb, **ta, **aas, **wd, **ang, **sp;
	int i, j, x, y, argc;
	unsigned long r, g, b, a;
	unsigned long color;
	int space;
	int *f_ind;
	int h_lines, v_lines, c_ind;
	int aa[16], aa_steps;
	int width, amount_kern, add_width;
	double angle, extend;
	unsigned long aa_greys[17];
	Imlib_Image bg_img;
	GLYPH *str_img;
	T1_OUTLINE *char_path, *str_path;
	T1_TMATRIX *transform = NULL;
	char *_str;

	argc=ZEND_NUM_ARGS();

	if (argc<10 || argc>14 || zend_get_parameters_ex(argc, &img, &str, &fnt, &sz, &px, &py, &tr, &tg, &tb, &ta, &sp, &wd, &ang, &aas) == FAILURE) {
		WRONG_PARAM_COUNT;
	}

	space = 0;
	aa_steps = 4;
	width = 0;
	angle = 0;

	switch (argc) {
	    case 14:
		convert_to_long_ex(aas);
		aa_steps = Z_LVAL_PP(aas);
	    case 13:
		convert_to_double_ex(ang);
		angle = Z_DVAL_PP(ang);
	    case 12:
		convert_to_long_ex(wd);
		width = Z_LVAL_PP(wd);
	    case 11:
		convert_to_long_ex(sp);
		space = Z_LVAL_PP(sp);
	    case 10:
		convert_to_string_ex(str);
		convert_to_long_ex(sz);
		convert_to_long_ex(px);
		convert_to_long_ex(py);
		convert_to_long_ex(tr);
		convert_to_long_ex(tg);
		convert_to_long_ex(tb);
		convert_to_long_ex(ta);
		x = Z_LVAL_PP(px);
		y = Z_LVAL_PP(py);
		r = Z_LVAL_PP(tr);
		g = Z_LVAL_PP(tg);
		b = Z_LVAL_PP(tb);
		a = Z_LVAL_PP(ta);
		color=(r<<16)|(g<<8)|b;
	}

	ZEND_FETCH_RESOURCE(bg_img, Imlib_Image, img, -1, "Imlib Image", le_imlib_img);
        ZEND_FETCH_RESOURCE(f_ind, int *, fnt, -1, "Type 1 font", le_ps_font);

	T1_AASetBitsPerPixel(32);

	switch (aa_steps) {
	case 4:
		T1_AASetGrayValues(0, ((a>>2)<<24)|color, ((a>>1)<<24)|color, (((a>>2)+(a>>1))<<24)|color, (a<<24)|color);
		T1_AASetLevel(T1_AA_LOW);
		break;
	case 16:
		aa_greys[0]=0;
		{
		    int i;
	    	    for (i=1;i<=16;i++) {
			aa_greys[i]=((a*i/16)<<24)|color;
		    }
		}
		T1_AAHSetGrayValues(aa_greys);
		T1_AASetLevel(T1_AA_HIGH);
		break;
	default:
		php_error(E_WARNING, "Invalid value %d as number of steps for antialiasing", aa_steps);
		RETURN_FALSE;
	}

	if (angle) {
		transform = T1_RotateMatrix(NULL, angle);
	}

        _str = Z_STRVAL_PP(str);

        if (width) {
                extend = T1_GetExtend(*f_ind);
                str_path = T1_GetCharOutline(*f_ind, _str[0], Z_LVAL_PP(sz), transform);

                for (i = 1; i < Z_STRLEN_PP(str); i++) {
                        amount_kern = (int) T1_GetKerning(*f_ind, _str[i-1], _str[i]);
                        amount_kern += _str[i-1] == ' ' ? space : 0;
                        add_width = (int) (amount_kern+width)/extend;

                        char_path = T1_GetMoveOutline(*f_ind, add_width, 0, 0, Z_LVAL_PP(sz), transform);
                        str_path = T1_ConcatOutlines(str_path, char_path);

                        char_path = T1_GetCharOutline(*f_ind, _str[i], Z_LVAL_PP(sz), transform);
                        str_path = T1_ConcatOutlines(str_path, char_path);
                }
                str_img = T1_AAFillOutline(str_path, 0);
        } else {
                str_img = T1_AASetString(*f_ind, _str,  Z_STRLEN_PP(str), space, T1_KERNING, Z_LVAL_PP(sz), transform);
        }

        if (T1_errno) {
                php_error(E_WARNING, "libt1 returned error %d", T1_errno);
                RETURN_FALSE;
        }

	h_lines = str_img->metrics.ascent -  str_img->metrics.descent;
	v_lines = str_img->metrics.rightSideBearing - str_img->metrics.leftSideBearing;

	if (str_img->bits)
	{
	    Imlib_Image textimg;

	    textimg=imlib_create_image_using_data(v_lines,h_lines,(DATA32*)(str_img->bits));
	    if (textimg) {
		imlib_context_set_image(textimg);
		imlib_image_set_has_alpha(1);
		imlib_context_set_image(bg_img);
		imlib_context_set_blend(1);
		imlib_blend_image_onto_image(textimg,1,0,0,v_lines,h_lines,x+str_img->metrics.leftSideBearing,y-str_img->metrics.ascent,v_lines,h_lines);
		imlib_context_set_image(textimg);
		imlib_free_image();
	    } else RETURN_FALSE;
	}

	if (array_init(return_value) == FAILURE) {
		RETURN_FALSE;
	}

        if (array_init(return_value) == FAILURE) {
                php_error(E_WARNING, "Couldn't initialize array for returning bounding box");
                RETURN_FALSE;
        }

        add_next_index_long(return_value, str_img->metrics.leftSideBearing);
        add_next_index_long(return_value, str_img->metrics.descent);
        add_next_index_long(return_value, str_img->metrics.rightSideBearing);
        add_next_index_long(return_value, str_img->metrics.ascent);
#else
        php_error(E_WARNING, "imlib_pstext: No T1lib support in this PHP build");
        RETURN_FALSE;
#endif  /* HAVE_LIBT1 */
}
/* }}} */


/* {{{ proto int imlib_psloadfont(string pathname)
   Load a new font from specified file */
PHP_FUNCTION(imlib_psloadfont)
{
#if HAVE_LIBT1
        zval **file;
        int f_ind, *font;

        if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &file) == FAILURE) {
                ZEND_WRONG_PARAM_COUNT();
        }

        convert_to_string_ex(file);

        f_ind = T1_AddFont(Z_STRVAL_PP(file));

        if (f_ind < 0) {
                switch (f_ind) {
                case -1:
                        php_error(E_WARNING, "Couldn't find the font file");
                        RETURN_FALSE;
                        break;
                case -2:
                case -3:
                        php_error(E_WARNING, "Memory allocation fault in t1lib");
                        RETURN_FALSE;
                        break;
                default:
                        php_error(E_WARNING, "An unknown error occurred in t1lib");
                        RETURN_FALSE;
                        break;
                }
        }

        if (T1_LoadFont(f_ind)) {
                php_error(E_WARNING, "Couldn't load the font");
                RETURN_FALSE;
        }
        font = (int *) emalloc(sizeof(int));
        *font = f_ind;
        ZEND_REGISTER_RESOURCE(return_value, font, le_ps_font);
#else
        php_error(E_WARNING, "imlib_psloadfont: No T1lib support in this PHP build");
        RETURN_FALSE;
#endif
}
/* }}} */

/* {{{ proto bool imlib_psfreefont(int font_index)
   Free memory used by a font */
PHP_FUNCTION(imlib_psfreefont)
{
#if HAVE_LIBT1
        zval **fnt;
        int *f_ind;

        if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &fnt) == FAILURE) {
                ZEND_WRONG_PARAM_COUNT();
        }

        ZEND_FETCH_RESOURCE(f_ind, int *, fnt, -1, "Type 1 font", le_ps_font);

        zend_list_delete(Z_LVAL_PP(fnt));
        RETURN_TRUE;
#else
        php_error(E_WARNING, "imlib_psfreefont: No T1lib support in this PHP build");
        RETURN_FALSE;
#endif
}
/* }}} */

/* {{{ proto bool imlib_psencodefont(int font_index, string filename)
   To change a fonts character encoding vector */
PHP_FUNCTION(imlib_psencodefont)
{
#if HAVE_LIBT1
        zval **fnt, **enc;
        char **enc_vector;
        int *f_ind;

        if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &fnt, &enc) == FAILURE) {
                ZEND_WRONG_PARAM_COUNT();
        }

        convert_to_string_ex(enc);

        ZEND_FETCH_RESOURCE(f_ind, int *, fnt, -1, "Type 1 font", le_ps_font);

        if ((enc_vector = T1_LoadEncoding(Z_STRVAL_PP(enc))) == NULL) {
                php_error(E_WARNING, "Couldn't load encoding vector from %s", Z_STRVAL_PP(enc));
                RETURN_FALSE;
        }

        T1_DeleteAllSizes(*f_ind);
        if (T1_ReencodeFont(*f_ind, enc_vector)) {
                T1_DeleteEncoding(enc_vector);
                php_error(E_WARNING, "Couldn't reencode font");
                RETURN_FALSE;
        }
        zend_list_insert(enc_vector, le_ps_enc);
        RETURN_TRUE;
#else
        php_error(E_WARNING, "imlib_psencodefont: No T1lib support in this PHP build");
        RETURN_FALSE;
#endif
}
/* }}} */

/* {{{ proto bool imlib_psextendfont(int font_index, double extend)
   Extend or or condense (if extend < 1) a font */
PHP_FUNCTION(imlib_psextendfont)
{
#if HAVE_LIBT1
        zval **fnt, **ext;
        int *f_ind;

        if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &fnt, &ext) == FAILURE) {
                ZEND_WRONG_PARAM_COUNT();
        }

        convert_to_double_ex(ext);

        ZEND_FETCH_RESOURCE(f_ind, int *, fnt, -1, "Type 1 font", le_ps_font);

        if (T1_ExtendFont(*f_ind, Z_DVAL_PP(ext)) != 0) RETURN_FALSE;

        RETURN_TRUE;
#else
        php_error(E_WARNING, "imlib_psextendfont: No T1lib support in this PHP build");
        RETURN_FALSE;
#endif
}
/* }}} */

/* {{{ proto bool imlib_psslantfont(int font_index, double slant)
   Slant a font */
PHP_FUNCTION(imlib_psslantfont)
{
#if HAVE_LIBT1
        zval **fnt, **slt;
        int *f_ind;

        if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &fnt, &slt) == FAILURE) {
                ZEND_WRONG_PARAM_COUNT();
        }

        convert_to_double_ex(slt);

        ZEND_FETCH_RESOURCE(f_ind, int *, fnt, -1, "Type 1 font", le_ps_font);

        if (T1_SlantFont(*f_ind, Z_DVAL_PP(slt)) != 0) RETURN_FALSE;
        RETURN_TRUE;
#else
        php_error(E_WARNING, "imlib_psslantfont: No T1lib support in this PHP build");
        RETURN_FALSE;
#endif
}
/* }}} */

/* {{{ proto array imlib_psbbox(string text, int font, int size [, int space, int tightness, int angle])
   Return the bounding box needed by a string if rasterized */
PHP_FUNCTION(imlib_psbbox)
{
#if HAVE_LIBT1
	zval **str, **fnt, **sz, **sp, **wd, **ang;
	int i, space, add_width = 0, char_width, amount_kern;
	int cur_x, cur_y, dx, dy;
	int x1, y1, x2, y2, x3, y3, x4, y4;
	int *f_ind;
	int per_char = 0;
	double angle, sin_a = 0, cos_a = 0;
	BBox char_bbox, str_bbox = {0, 0, 0, 0};

	switch(ZEND_NUM_ARGS()) {
	case 3:
		if (zend_get_parameters_ex(3, &str, &fnt, &sz) == FAILURE) {
			RETURN_FALSE;
		}
		space = 0;
		break;
	case 6:
		if (zend_get_parameters_ex(6, &str, &fnt, &sz, &sp, &wd, &ang) == FAILURE) {
			RETURN_FALSE;
		}
		convert_to_long_ex(sp);
		convert_to_long_ex(wd);
		convert_to_double_ex(ang);
		space = Z_LVAL_PP(sp);
		add_width = Z_LVAL_PP(wd);
		angle = Z_DVAL_PP(ang) * M_PI / 180;
		sin_a = sin(angle);
		cos_a = cos(angle);
		per_char =  add_width || angle ? 1 : 0;
		break;
	default:
		ZEND_WRONG_PARAM_COUNT();
	}

	ZEND_FETCH_RESOURCE(f_ind, int *, fnt, -1, "Type 1 font", le_ps_font);

	convert_to_string_ex(str);
	convert_to_long_ex(sz);

#define max(a, b) (a > b ? a : b)
#define min(a, b) (a < b ? a : b)
#define new_x(a, b) (int) ((a) * cos_a - (b) * sin_a)
#define new_y(a, b) (int) ((a) * sin_a + (b) * cos_a)

	if (per_char) {
		space += T1_GetCharWidth(*f_ind, ' ');
		cur_x = cur_y = 0;

		for (i = 0; i < (*str)->value.str.len; i++) {
			if ((*str)->value.str.val[i] == ' ') {
				char_bbox.llx = char_bbox.lly = char_bbox.ury = 0;
				char_bbox.urx = char_width = space;
			} else {
				char_bbox = T1_GetCharBBox(*f_ind, (*str)->value.str.val[i]);
				char_width = T1_GetCharWidth(*f_ind, (*str)->value.str.val[i]);
			}
			amount_kern = i ? T1_GetKerning(*f_ind, (*str)->value.str.val[i-1], (*str)->value.str.val[i]) : 0;

			/* Transfer character bounding box to right place */
			x1 = new_x(char_bbox.llx, char_bbox.lly) + cur_x;
			y1 = new_y(char_bbox.llx, char_bbox.lly) + cur_y;
			x2 = new_x(char_bbox.llx, char_bbox.ury) + cur_x;
			y2 = new_y(char_bbox.llx, char_bbox.ury) + cur_y;
			x3 = new_x(char_bbox.urx, char_bbox.ury) + cur_x;
			y3 = new_y(char_bbox.urx, char_bbox.ury) + cur_y;
			x4 = new_x(char_bbox.urx, char_bbox.lly) + cur_x;
			y4 = new_y(char_bbox.urx, char_bbox.lly) + cur_y;

			/* Find min & max values and compare them with current bounding box */
			str_bbox.llx = min(str_bbox.llx, min(x1, min(x2, min(x3, x4))));
			str_bbox.lly = min(str_bbox.lly, min(y1, min(y2, min(y3, y4))));
			str_bbox.urx = max(str_bbox.urx, max(x1, max(x2, max(x3, x4))));
			str_bbox.ury = max(str_bbox.ury, max(y1, max(y2, max(y3, y4))));

			/* Move to the next base point */
			dx = new_x(char_width + add_width + amount_kern, 0);
			dy = new_y(char_width + add_width + amount_kern, 0);
			cur_x += dx;
			cur_y += dy;
			/*
			printf("%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\n", x1, y1, x2, y2, x3, y3, x4, y4, char_bbox.llx, char_bbox.lly, char_bbox.urx, char_bbox.ury, char_width, amount_kern, cur_x, cur_y, dx, dy);
			*/
		}

	} else {
		str_bbox = T1_GetStringBBox(*f_ind, (*str)->value.str.val, (*str)->value.str.len, space, T1_KERNING);
	}
	if (T1_errno) RETURN_FALSE;

	if (array_init(return_value) == FAILURE) {
		RETURN_FALSE;
	}
	/*
	printf("%d %d %d %d\n", str_bbox.llx, str_bbox.lly, str_bbox.urx, str_bbox.ury);
	*/
	add_next_index_long(return_value, (int) ceil(((double) str_bbox.llx)*(*sz)->value.lval/1000));
	add_next_index_long(return_value, (int) ceil(((double) str_bbox.lly)*(*sz)->value.lval/1000));
	add_next_index_long(return_value, (int) ceil(((double) str_bbox.urx)*(*sz)->value.lval/1000));
	add_next_index_long(return_value, (int) ceil(((double) str_bbox.ury)*(*sz)->value.lval/1000));
#else
	php_error(E_WARNING, "imlib_psbbox: No T1lib support in this PHP build");
	RETURN_FALSE;
#endif
}
/* }}} */

#endif	/* HAVE_IMLIB */


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