/*
 *  php-pipi      Php binding for Libpipi
 *  Copyright (c) 2008 Vion Nicolas <nico@picapo.net>
 *
 *
 *  This library is free software. It comes without any warranty, to
 *  the extent permitted by applicable law. You can redistribute it
 *  and/or modify it under the terms of the Do What The Fuck You Want
 *  To Public License, Version 2, as published by Sam Hocevar. See
 *  http://sam.zoy.org/wtfpl/COPYING for more details.
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "php.h"
#include "php_pipi.h"

static function_entry pipi_functions[] = {
	PHP_FE(pipi_get_color_from_string, NULL)    
	PHP_FE(pipi_get_version, NULL)
	PHP_FE(pipi_create_context, NULL)
	PHP_FE(pipi_get_command_list, NULL)
	PHP_FE(pipi_command, NULL)
	PHP_FE(pipi_load, NULL)
	PHP_FE(pipi_load_stock, NULL)
	PHP_FE(pipi_new, NULL)
	PHP_FE(pipi_copy, NULL)
	PHP_FE(pipi_save, NULL)
	PHP_FE(pipi_set_gamma, NULL)
	PHP_FE(pipi_get_pixels, NULL)
	PHP_FE(pipi_get_image_width, NULL)
	PHP_FE(pipi_get_image_height, NULL)
	PHP_FE(pipi_get_image_pitch, NULL)
	PHP_FE(pipi_get_image_last_modified, NULL)
	PHP_FE(pipi_get_format_name, NULL)
	PHP_FE(pipi_measure_msd, NULL)
	PHP_FE(pipi_measure_rmsd, NULL)
	PHP_FE(pipi_resize, NULL)
	PHP_FE(pipi_render_random, NULL)
	PHP_FE(pipi_render_bayer, NULL)
	PHP_FE(pipi_render_halftone, NULL)
	PHP_FE(pipi_rgb, NULL)
	PHP_FE(pipi_red, NULL)
	PHP_FE(pipi_green, NULL)
	PHP_FE(pipi_blue, NULL)
	PHP_FE(pipi_mean, NULL)
	PHP_FE(pipi_min, NULL)
	PHP_FE(pipi_max, NULL)
	PHP_FE(pipi_add, NULL)
	PHP_FE(pipi_sub, NULL)
	PHP_FE(pipi_difference, NULL)
	PHP_FE(pipi_multiply, NULL)
	PHP_FE(pipi_divide, NULL)
	PHP_FE(pipi_screen, NULL)
	PHP_FE(pipi_overlay, NULL)
	PHP_FE(pipi_convolution, NULL)
	PHP_FE(pipi_gaussian_blur, NULL)
	PHP_FE(pipi_gaussian_blur_ext, NULL)
	PHP_FE(pipi_box_blur, NULL)
	PHP_FE(pipi_box_blur_ext, NULL)
	PHP_FE(pipi_brightness, NULL)
	PHP_FE(pipi_contrast, NULL)
	PHP_FE(pipi_autocontrast, NULL)
	PHP_FE(pipi_invert, NULL)
	PHP_FE(pipi_threshold, NULL)
	PHP_FE(pipi_hflip, NULL)
	PHP_FE(pipi_vflip, NULL)
	PHP_FE(pipi_rotate90, NULL)
	PHP_FE(pipi_rotate180, NULL)
	PHP_FE(pipi_rotate270, NULL)
	PHP_FE(pipi_median, NULL)
	PHP_FE(pipi_median_ext, NULL)
	PHP_FE(pipi_dilate, NULL)
	PHP_FE(pipi_erode, NULL)
	PHP_FE(pipi_order, NULL)
	PHP_FE(pipi_tile, NULL)
	PHP_FE(pipi_flood_fill, NULL)
	PHP_FE(pipi_draw_line, NULL)
	PHP_FE(pipi_draw_rectangle, NULL)
	PHP_FE(pipi_draw_polyline, NULL)
	PHP_FE(pipi_draw_bezier4, NULL)
	PHP_FE(pipi_reduce, NULL)
	PHP_FE(pipi_dither_ediff, NULL)
	PHP_FE(pipi_dither_ordered, NULL)
	PHP_FE(pipi_dither_ordered_ext, NULL)
	PHP_FE(pipi_dither_halftone, NULL)
	PHP_FE(pipi_dither_random, NULL)
	PHP_FE(pipi_dither_ostromoukhov, NULL)
	PHP_FE(pipi_dither_dbs, NULL)
	PHP_FE(pipi_dither_24to16, NULL)
	PHP_FE(pipi_new_histogram, NULL)
	PHP_FE(pipi_get_image_histogram, NULL)
	PHP_FE(pipi_render_histogram, NULL)

	{NULL, NULL, NULL}
};

zend_module_entry pipi_module_entry = {
#if ZEND_MODULE_API_NO >= 20010901
	STANDARD_MODULE_HEADER,
#endif
	PHP_PIPI_EXTNAME,
	pipi_functions,
	PHP_MINIT(pipi),
	NULL,
	NULL,
	NULL,
	PHP_MINFO(pipi),
#if ZEND_MODULE_API_NO >= 20010901
	PHP_PIPI_VERSION,
#endif
	STANDARD_MODULE_PROPERTIES
};

#ifdef COMPILE_DL_PIPI
ZEND_GET_MODULE(pipi)
#endif

PHP_MINFO_FUNCTION(pipi) {
	php_info_print_table_start();
	php_info_print_table_row(2, "Pipi library version", pipi_get_version());
	php_info_print_table_end();
}


//--------PIPI'S RESSOURCES DESTRUCTORS---------//

static void php_pipi_image_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC) {
	pipi_free(rsrc->ptr);
}

static void php_pipi_context_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC) {
	pipi_destroy_context(rsrc->ptr);
}

static void php_pipi_histogram_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC) {
	pipi_free_histogram(rsrc->ptr);
}


//--------INITIALIZATION---------//

PHP_MINIT_FUNCTION(pipi) {
	le_pipi_image = zend_register_list_destructors_ex(php_pipi_image_dtor, NULL, PHP_PIPI_IMAGE_RES_NAME, module_number);
	le_pipi_context = zend_register_list_destructors_ex(php_pipi_context_dtor, NULL, PHP_PIPI_CONTEXT_RES_NAME, module_number);
	le_pipi_histogram = zend_register_list_destructors_ex(php_pipi_histogram_dtor, NULL, PHP_PIPI_HISTOGRAM_RES_NAME, module_number);

	REGISTER_LONG_CONSTANT("PIPI_SCAN_RASTER", PIPI_SCAN_RASTER, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("PIPI_SCAN_SERPENTINE", PIPI_SCAN_SERPENTINE, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("PIPI_PIXELS_UNINITIALISED", PIPI_PIXELS_UNINITIALISED, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("PIPI_PIXELS_RGBA_U8", PIPI_PIXELS_RGBA_U8, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("PIPI_PIXELS_BGR_U8", PIPI_PIXELS_BGR_U8, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("PIPI_PIXELS_RGBA_F32", PIPI_PIXELS_RGBA_F32, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("PIPI_PIXELS_Y_F32", PIPI_PIXELS_Y_F32, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("PIPI_PIXELS_MASK_U8", PIPI_PIXELS_MASK_U8, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("PIPI_PIXELS_MAX", PIPI_PIXELS_MAX, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("PIPI_COLOR_R", PIPI_COLOR_R, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("PIPI_COLOR_G", PIPI_COLOR_G, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("PIPI_COLOR_B", PIPI_COLOR_B, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("PIPI_COLOR_A", PIPI_COLOR_A, CONST_CS | CONST_PERSISTENT);
	REGISTER_LONG_CONSTANT("PIPI_COLOR_Y", PIPI_COLOR_Y, CONST_CS | CONST_PERSISTENT);

	return SUCCESS;
}

//----------SOME USEFULL MACROS---------------//

#define FETCH_STR(str) \
	int __len; \
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &__len) == FAILURE) { \
		RETURN_FALSE; \
	} 

#define FETCH_LONG(l) \
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &l) == FAILURE) { \
		RETURN_FALSE; \
	} 

#define FETCH_IMG(img) \
	zval *_zval; \
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &_zval) == FAILURE) { \
		RETURN_FALSE; \
	} \
	ZEND_FETCH_RESOURCE(img, pipi_image_t*, &_zval, -1, PHP_PIPI_IMAGE_RES_NAME, le_pipi_image); 

#define FETCH_IMG_IMG(img1, img2) \
	zval *_zval1, *_zval2; \
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rr", &_zval1, &_zval2) == FAILURE) { \
		RETURN_FALSE; \
	} \
	ZEND_FETCH_RESOURCE(img1, pipi_image_t*, &_zval1, -1, PHP_PIPI_IMAGE_RES_NAME, le_pipi_image); \
	ZEND_FETCH_RESOURCE(img2, pipi_image_t*, &_zval2, -1, PHP_PIPI_IMAGE_RES_NAME, le_pipi_image); 

#define RETURN_SUCCESS(i) \
	RETURN_BOOL((i) == 0);


//--------PIPI'S FUNCTIONS---------//

PHP_FUNCTION(pipi_get_color_from_string) {
}

PHP_FUNCTION(pipi_get_version) {
	if (ZEND_NUM_ARGS() != 0) {
		WRONG_PARAM_COUNT;
	}
	RETURN_STRING(estrdup(pipi_get_version()), 0);
}

PHP_FUNCTION(pipi_create_context) {
	pipi_context_t *context;
	context = pipi_create_context();
	ZEND_REGISTER_RESOURCE(return_value, context, le_pipi_context);
}

PHP_FUNCTION(pipi_get_command_list) {
	pipi_command_t const *list, *cmd;
	list = pipi_get_command_list();

	array_init(return_value);
        for (cmd = list; cmd->name; cmd++)
		add_assoc_long(return_value, (char*) cmd->name, cmd->argc);
}

PHP_FUNCTION(pipi_command) {
	zval *res;
	char *arg1, *arg2 = NULL;
	int arg1_len, arg2_len;
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs|s", &res, &arg1, &arg1_len, &arg2, &arg2_len) == FAILURE) {
		RETURN_FALSE;
	}

	pipi_context_t *ctxt;
	ZEND_FETCH_RESOURCE(ctxt, pipi_context_t*, &res, -1, PHP_PIPI_CONTEXT_RES_NAME, le_pipi_context); 

	if (arg2_len != 0) {
		RETURN_SUCCESS(pipi_command(ctxt, arg1, arg2));
	}
	RETURN_SUCCESS(pipi_command(ctxt, arg1));	
}

PHP_FUNCTION(pipi_load) {
	char *str;
	FETCH_STR(str);
	pipi_image_t *img;
	img = pipi_load(str);
	ZEND_REGISTER_RESOURCE(return_value, img, le_pipi_image);
}

PHP_FUNCTION(pipi_load_stock) {
	char *str;
	FETCH_STR(str);
	pipi_image_t *img;
	img = pipi_load_stock(str);
	ZEND_REGISTER_RESOURCE(return_value, img, le_pipi_image);
}

PHP_FUNCTION(pipi_new) {
	long width, height = 0;
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ll", &width, &height) == FAILURE) {
		RETURN_FALSE;
	}
	pipi_image_t *img;
	img = pipi_new(width, height);
	ZEND_REGISTER_RESOURCE(return_value, img, le_pipi_image);
}

PHP_FUNCTION(pipi_copy) {
	pipi_image_t *src, *result;
	FETCH_IMG(src);
	result = pipi_copy(src);
	ZEND_REGISTER_RESOURCE(return_value, result, le_pipi_image);
}

PHP_FUNCTION(pipi_save) {
	zval *res;
	char *str;
	int str_len;
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &res, &str, &str_len) == FAILURE) {
		RETURN_FALSE;
	}

	pipi_image_t *img;
	ZEND_FETCH_RESOURCE(img, pipi_image_t*, &res, -1, PHP_PIPI_IMAGE_RES_NAME, le_pipi_image); 

	RETURN_SUCCESS(pipi_save(img, str));	
}

PHP_FUNCTION(pipi_set_gamma) {
	long value;
	FETCH_LONG(value);
	pipi_set_gamma(value);
}

PHP_FUNCTION(pipi_get_pixels) {
}

PHP_FUNCTION(pipi_get_image_width) {
	pipi_image_t *img;
	FETCH_IMG(img);
	RETURN_LONG(pipi_get_image_width(img));
}

PHP_FUNCTION(pipi_get_image_height) {
	pipi_image_t *img;
	FETCH_IMG(img);
	RETURN_LONG(pipi_get_image_height(img));
}

PHP_FUNCTION(pipi_get_image_pitch) {
	pipi_image_t *img;
	FETCH_IMG(img);
	RETURN_LONG(pipi_get_image_pitch(img));
}

PHP_FUNCTION(pipi_get_image_last_modified) {
	pipi_image_t *img;
	FETCH_IMG(img);
	RETURN_LONG(pipi_get_image_last_midified(img));
}

PHP_FUNCTION(pipi_get_format_name) {
	long id;
	FETCH_LONG(id);
	RETURN_STRING(estrdup(pipi_get_format_name(id)), 0);
}

PHP_FUNCTION(pipi_measure_msd) {
	pipi_image_t *img1, *img2;
	FETCH_IMG_IMG(img1, img2);
	RETURN_LONG(pipi_measure_msd(img1, img2));
}

PHP_FUNCTION(pipi_measure_rmsd) {
	pipi_image_t *img1, *img2;
	FETCH_IMG_IMG(img1, img2);
	RETURN_LONG(pipi_measure_rmsd(img1, img2));
}

PHP_FUNCTION(pipi_resize) {
	zval *_zval;
	long width, height = 0;
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rll", &_zval, &width, &height) == FAILURE) {
		RETURN_FALSE;
	}
	pipi_image_t *src, *result;
	ZEND_FETCH_RESOURCE(src, pipi_image_t*, &_zval, -1, PHP_PIPI_IMAGE_RES_NAME, le_pipi_image);

	result = pipi_resize(src, width, height);
	ZEND_REGISTER_RESOURCE(return_value, result, le_pipi_image);
}

PHP_FUNCTION(pipi_render_random) {
	long width, height = 0;
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ll", &width, &height) == FAILURE) {
		RETURN_FALSE;
	}
	pipi_image_t *img;
	img = pipi_render_random(width, height);
	ZEND_REGISTER_RESOURCE(return_value, img, le_pipi_image);
}

PHP_FUNCTION(pipi_render_bayer) {
	long width, height = 0;
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ll", &width, &height) == FAILURE) {
		RETURN_FALSE;
	}
	pipi_image_t *img;
	img = pipi_render_bayer(width, height);
	ZEND_REGISTER_RESOURCE(return_value, img, le_pipi_image);
}

PHP_FUNCTION(pipi_render_halftone) {
	long width, height = 0;
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ll", &width, &height) == FAILURE) {
		RETURN_FALSE;
	}
	pipi_image_t *img;
	img = pipi_render_halftone(width, height);
	ZEND_REGISTER_RESOURCE(return_value, img, le_pipi_image);
}

PHP_FUNCTION(pipi_rgb) {
	zval *_zval1, *_zval2, *_zval3;
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rrr", &_zval1, &_zval2, &_zval3) == FAILURE) {
		RETURN_FALSE;
	}

	pipi_image_t *img_r, *img_g, *img_b, *result;
	ZEND_FETCH_RESOURCE(img_r, pipi_image_t*, &_zval1, -1, PHP_PIPI_IMAGE_RES_NAME, le_pipi_image);
	ZEND_FETCH_RESOURCE(img_g, pipi_image_t*, &_zval2, -1, PHP_PIPI_IMAGE_RES_NAME, le_pipi_image); 
	ZEND_FETCH_RESOURCE(img_b, pipi_image_t*, &_zval3, -1, PHP_PIPI_IMAGE_RES_NAME, le_pipi_image); 

	result = pipi_rgb(img_r, img_g, img_b);
	ZEND_REGISTER_RESOURCE(return_value, result, le_pipi_image);
}

PHP_FUNCTION(pipi_red) {
	pipi_image_t *src, *result;
	FETCH_IMG(src);
	result = pipi_red(src);
	ZEND_REGISTER_RESOURCE(return_value, result, le_pipi_image);
}

PHP_FUNCTION(pipi_green) {
	pipi_image_t *src, *result;
	FETCH_IMG(src);
	result = pipi_green(src);
	ZEND_REGISTER_RESOURCE(return_value, result, le_pipi_image);
}

PHP_FUNCTION(pipi_blue) {
	pipi_image_t *src, *result;
	FETCH_IMG(src);
	result = pipi_blue(src);
	ZEND_REGISTER_RESOURCE(return_value, result, le_pipi_image);
}

PHP_FUNCTION(pipi_mean) {
	pipi_image_t *img1, *img2, *result;
	FETCH_IMG_IMG(img1, img2);
	result = pipi_mean(img1, img2);
	ZEND_REGISTER_RESOURCE(return_value, result, le_pipi_image);
}

PHP_FUNCTION(pipi_min) {
	pipi_image_t *img1, *img2, *result;
	FETCH_IMG_IMG(img1, img2);
	result = pipi_min(img1, img2);
	ZEND_REGISTER_RESOURCE(return_value, result, le_pipi_image);
}

PHP_FUNCTION(pipi_max) {
	pipi_image_t *img1, *img2, *result;
	FETCH_IMG_IMG(img1, img2);
	result = pipi_max(img1, img2);
	ZEND_REGISTER_RESOURCE(return_value, result, le_pipi_image);
}

PHP_FUNCTION(pipi_add) {
	pipi_image_t *img1, *img2, *result;
	FETCH_IMG_IMG(img1, img2);
	result = pipi_add(img1, img2);
	ZEND_REGISTER_RESOURCE(return_value, result, le_pipi_image);
}

PHP_FUNCTION(pipi_sub) {
	pipi_image_t *img1, *img2, *result;
	FETCH_IMG_IMG(img1, img2);
	result = pipi_sub(img1, img2);
	ZEND_REGISTER_RESOURCE(return_value, result, le_pipi_image);
}

PHP_FUNCTION(pipi_difference) {
	pipi_image_t *img1, *img2, *result;
	FETCH_IMG_IMG(img1, img2);
	result = pipi_difference(img1, img2);
	ZEND_REGISTER_RESOURCE(return_value, result, le_pipi_image);
}

PHP_FUNCTION(pipi_multiply) {
	pipi_image_t *img1, *img2, *result;
	FETCH_IMG_IMG(img1, img2);
	result = pipi_multiply(img1, img2);
	ZEND_REGISTER_RESOURCE(return_value, result, le_pipi_image);
}

PHP_FUNCTION(pipi_divide) {
	pipi_image_t *img1, *img2, *result;
	FETCH_IMG_IMG(img1, img2);
	result = pipi_divide(img1, img2);
	ZEND_REGISTER_RESOURCE(return_value, result, le_pipi_image);
}

PHP_FUNCTION(pipi_screen) {
	pipi_image_t *img1, *img2, *result;
	FETCH_IMG_IMG(img1, img2);
	result = pipi_screen(img1, img2);
	ZEND_REGISTER_RESOURCE(return_value, result, le_pipi_image);
}

PHP_FUNCTION(pipi_overlay) {
	pipi_image_t *img1, *img2, *result;
	FETCH_IMG_IMG(img1, img2);
	result = pipi_overlay(img1, img2);
	ZEND_REGISTER_RESOURCE(return_value, result, le_pipi_image);
}

PHP_FUNCTION(pipi_convolution) {
}

PHP_FUNCTION(pipi_gaussian_blur) {
	zval *_zval;
	double value = 0;
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rd", &_zval, &value) == FAILURE) {
		RETURN_FALSE;
	}
	pipi_image_t *src, *result;
	ZEND_FETCH_RESOURCE(src, pipi_image_t*, &_zval, -1, PHP_PIPI_IMAGE_RES_NAME, le_pipi_image);

	result = pipi_gaussian_blur(src, value);
	ZEND_REGISTER_RESOURCE(return_value, result, le_pipi_image);
}

PHP_FUNCTION(pipi_gaussian_blur_ext) {
	zval *_zval;
	double v1, v2, v3, v4, v5 = 0;
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rddddd", &_zval, &v1, &v2, &v3, &v4, &v5) == FAILURE) {
		RETURN_FALSE;
	}
	pipi_image_t *src, *result;
	ZEND_FETCH_RESOURCE(src, pipi_image_t*, &_zval, -1, PHP_PIPI_IMAGE_RES_NAME, le_pipi_image);

	result = pipi_gaussian_blur_ext(src, v1, v2, v3, v4, v5);
	ZEND_REGISTER_RESOURCE(return_value, result, le_pipi_image);
}

PHP_FUNCTION(pipi_box_blur) {
	zval *_zval;
	long value = 0;
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &_zval, &value) == FAILURE) {
		RETURN_FALSE;
	}
	pipi_image_t *src, *result;
	ZEND_FETCH_RESOURCE(src, pipi_image_t*, &_zval, -1, PHP_PIPI_IMAGE_RES_NAME, le_pipi_image);

	result = pipi_box_blur(src, value);
	ZEND_REGISTER_RESOURCE(return_value, result, le_pipi_image);
}

PHP_FUNCTION(pipi_box_blur_ext) {
	zval *_zval;
	long m, n = 0;
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rll", &_zval, &m, &n) == FAILURE) {
		RETURN_FALSE;
	}
	pipi_image_t *src, *result;
	ZEND_FETCH_RESOURCE(src, pipi_image_t*, &_zval, -1, PHP_PIPI_IMAGE_RES_NAME, le_pipi_image);

	result = pipi_box_blur_ext(src, m, n);
	ZEND_REGISTER_RESOURCE(return_value, result, le_pipi_image);
}

PHP_FUNCTION(pipi_brightness) {
	zval *_zval;
	double value = 0;
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rd", &_zval, &value) == FAILURE) {
		RETURN_FALSE;
	}
	pipi_image_t *src, *result;
	ZEND_FETCH_RESOURCE(src, pipi_image_t*, &_zval, -1, PHP_PIPI_IMAGE_RES_NAME, le_pipi_image);

	result = pipi_brightness(src, value);
	ZEND_REGISTER_RESOURCE(return_value, result, le_pipi_image);
}

PHP_FUNCTION(pipi_contrast) {
	zval *_zval;
	double value = 0;
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rd", &_zval, &value) == FAILURE) {
		RETURN_FALSE;
	}
	pipi_image_t *src, *result;
	ZEND_FETCH_RESOURCE(src, pipi_image_t*, &_zval, -1, PHP_PIPI_IMAGE_RES_NAME, le_pipi_image);

	result = pipi_contrast(src, value);
	ZEND_REGISTER_RESOURCE(return_value, result, le_pipi_image);
}

PHP_FUNCTION(pipi_autocontrast) {
	pipi_image_t *src, *result;
	FETCH_IMG(src);
	result = pipi_autocontrast(src);
	ZEND_REGISTER_RESOURCE(return_value, result, le_pipi_image);
}

PHP_FUNCTION(pipi_invert) {
	pipi_image_t *src, *result;
	FETCH_IMG(src);
	result = pipi_invert(src);
	ZEND_REGISTER_RESOURCE(return_value, result, le_pipi_image);
}

PHP_FUNCTION(pipi_threshold) {
	zval *_zval;
	double value = 0;
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rd", &_zval, &value) == FAILURE) {
		RETURN_FALSE;
	}
	pipi_image_t *src, *result;
	ZEND_FETCH_RESOURCE(src, pipi_image_t*, &_zval, -1, PHP_PIPI_IMAGE_RES_NAME, le_pipi_image);

	result = pipi_threshold(src, value);
	ZEND_REGISTER_RESOURCE(return_value, result, le_pipi_image);
}

PHP_FUNCTION(pipi_hflip) {
	pipi_image_t *src, *result;
	FETCH_IMG(src);
	result = pipi_hflip(src);
	ZEND_REGISTER_RESOURCE(return_value, result, le_pipi_image);
}

PHP_FUNCTION(pipi_vflip) {
	pipi_image_t *src, *result;
	FETCH_IMG(src);
	result = pipi_vflip(src);
	ZEND_REGISTER_RESOURCE(return_value, result, le_pipi_image);
}

PHP_FUNCTION(pipi_rotate90) {
	pipi_image_t *src, *result;
	FETCH_IMG(src);
	result = pipi_rotate90(src);
	ZEND_REGISTER_RESOURCE(return_value, result, le_pipi_image);
}

PHP_FUNCTION(pipi_rotate180) {
	pipi_image_t *src, *result;
	FETCH_IMG(src);
	result = pipi_rotate180(src);
	ZEND_REGISTER_RESOURCE(return_value, result, le_pipi_image);
}

PHP_FUNCTION(pipi_rotate270) {
	pipi_image_t *src, *result;
	FETCH_IMG(src);
	result = pipi_rotate270(src);
	ZEND_REGISTER_RESOURCE(return_value, result, le_pipi_image);
}

PHP_FUNCTION(pipi_median) {
	zval *_zval;
	long value = 0;
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &_zval, &value) == FAILURE) {
		RETURN_FALSE;
	}
	pipi_image_t *src, *result;
	ZEND_FETCH_RESOURCE(src, pipi_image_t*, &_zval, -1, PHP_PIPI_IMAGE_RES_NAME, le_pipi_image);

	result = pipi_median(src, value);
	ZEND_REGISTER_RESOURCE(return_value, result, le_pipi_image);
}

PHP_FUNCTION(pipi_median_ext) {
	zval *_zval;
	long rx, ry = 0;
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rll", &_zval, &rx, &ry) == FAILURE) {
		RETURN_FALSE;
	}
	pipi_image_t *src, *result;
	ZEND_FETCH_RESOURCE(src, pipi_image_t*, &_zval, -1, PHP_PIPI_IMAGE_RES_NAME, le_pipi_image);

	result = pipi_median_ext(src, rx, ry);
	ZEND_REGISTER_RESOURCE(return_value, result, le_pipi_image);
}

PHP_FUNCTION(pipi_dilate) {
	pipi_image_t *src, *result;
	FETCH_IMG(src);
	result = pipi_dilate(src);
	ZEND_REGISTER_RESOURCE(return_value, result, le_pipi_image);
}

PHP_FUNCTION(pipi_erode) {
	pipi_image_t *src, *result;
	FETCH_IMG(src);
	result = pipi_erode(src);
	ZEND_REGISTER_RESOURCE(return_value, result, le_pipi_image);
}

PHP_FUNCTION(pipi_order) {
	pipi_image_t *src, *result;
	FETCH_IMG(src);
	result = pipi_order(src);
	ZEND_REGISTER_RESOURCE(return_value, result, le_pipi_image);
}

PHP_FUNCTION(pipi_tile) {
	zval *_zval;
	long width, height = 0;
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rll", &_zval, &width, &height) == FAILURE) {
		RETURN_FALSE;
	}
	pipi_image_t *src, *result;
	ZEND_FETCH_RESOURCE(src, pipi_image_t*, &_zval, -1, PHP_PIPI_IMAGE_RES_NAME, le_pipi_image);

	result = pipi_tile(src, width, height);
	ZEND_REGISTER_RESOURCE(return_value, result, le_pipi_image);
}

PHP_FUNCTION(pipi_flood_fill) {
}

PHP_FUNCTION(pipi_draw_line) {
	zval *_zval;
	long x1, y1, x2, y2, color, style = 0;
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rlllll|l", &_zval, &x1, &y1, &x2, &y2, &color, &style) == FAILURE) {
		RETURN_FALSE;
	}
	pipi_image_t *img;
	ZEND_FETCH_RESOURCE(img, pipi_image_t*, &_zval, -1, PHP_PIPI_IMAGE_RES_NAME, le_pipi_image);
	RETURN_SUCCESS(pipi_draw_line(img, x1, y1, x2, y2, color, style));
}

PHP_FUNCTION(pipi_draw_rectangle) {
}

PHP_FUNCTION(pipi_draw_polyline) {
}

PHP_FUNCTION(pipi_draw_bezier4) {
}

PHP_FUNCTION(pipi_reduce) {
}

PHP_FUNCTION(pipi_dither_ediff) {
}

PHP_FUNCTION(pipi_dither_ordered) {
	pipi_image_t *img1, *img2, *result;
	FETCH_IMG_IMG(img1, img2);
	result = pipi_dither_ordered(img1, img2);
	ZEND_REGISTER_RESOURCE(return_value, result, le_pipi_image);
}

PHP_FUNCTION(pipi_dither_ordered_ext) {
	zval *_zval1;
	zval *_zval2;
	double precision, angle = 0;
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rrdd", &_zval1, &_zval2, &precision, &angle) == FAILURE) {
		RETURN_FALSE;
	}
	pipi_image_t *img1, *img2, *result;
	ZEND_FETCH_RESOURCE(img1, pipi_image_t*, &_zval1, -1, PHP_PIPI_IMAGE_RES_NAME, le_pipi_image);
	ZEND_FETCH_RESOURCE(img2, pipi_image_t*, &_zval2, -1, PHP_PIPI_IMAGE_RES_NAME, le_pipi_image);

	result = pipi_dither_ordered_ext(img1, img2, precision, angle);
	ZEND_REGISTER_RESOURCE(return_value, result, le_pipi_image);
}

PHP_FUNCTION(pipi_dither_halftone) {
	zval *_zval;
	double r, angle = 0;
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rdd", &_zval, &r, &angle) == FAILURE) {
		RETURN_FALSE;
	}
	pipi_image_t *src, *result;
	ZEND_FETCH_RESOURCE(src, pipi_image_t*, &_zval, -1, PHP_PIPI_IMAGE_RES_NAME, le_pipi_image);

	result = pipi_dither_halftone(src, r, angle);
	ZEND_REGISTER_RESOURCE(return_value, result, le_pipi_image);
}

PHP_FUNCTION(pipi_dither_random) {
	pipi_image_t *src, *result;
	FETCH_IMG(src);
	result = pipi_dither_random(src);
	ZEND_REGISTER_RESOURCE(return_value, result, le_pipi_image);
}

PHP_FUNCTION(pipi_dither_ostromoukhov) {
}

PHP_FUNCTION(pipi_dither_dbs) {
	pipi_image_t *src, *result;
	FETCH_IMG(src);
	result = pipi_dither_dbs(src);
	ZEND_REGISTER_RESOURCE(return_value, result, le_pipi_image);
}

PHP_FUNCTION(pipi_dither_24to16) {
	pipi_image_t *img;
	FETCH_IMG(img);
	pipi_dither_24to16(img);
}

PHP_FUNCTION(pipi_new_histogram) {
	if (ZEND_NUM_ARGS() != 0) {
		WRONG_PARAM_COUNT;
	}
	pipi_histogram_t *histogram;
	histogram = pipi_new_histogram();
	ZEND_REGISTER_RESOURCE(return_value, histogram, le_pipi_histogram);
}

PHP_FUNCTION(pipi_get_image_histogram) {
	zval *_zval_img, *_zval_hst;
	long flags = 0;
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rrl", &_zval_img, &_zval_hst, &flags) == FAILURE) {
		RETURN_FALSE;
	}
	pipi_image_t *image;
	pipi_histogram_t *histogram;
	ZEND_FETCH_RESOURCE(image, pipi_image_t*, &_zval_img, -1, PHP_PIPI_IMAGE_RES_NAME, le_pipi_image);
	ZEND_FETCH_RESOURCE(histogram, pipi_histogram_t*, &_zval_hst, -1, PHP_PIPI_HISTOGRAM_RES_NAME, le_pipi_histogram);

	RETURN_SUCCESS(pipi_get_image_histogram(image, histogram, flags));
}

PHP_FUNCTION(pipi_render_histogram) {
	zval *_zval_img, *_zval_hst;
	long flags = 0;
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rrl", &_zval_img, &_zval_hst, &flags) == FAILURE) {
		RETURN_FALSE;
	}
	pipi_image_t *image;
	pipi_histogram_t *histogram;
	ZEND_FETCH_RESOURCE(image, pipi_image_t*, &_zval_img, -1, PHP_PIPI_IMAGE_RES_NAME, le_pipi_image);
	ZEND_FETCH_RESOURCE(histogram, pipi_histogram_t*, &_zval_hst, -1, PHP_PIPI_HISTOGRAM_RES_NAME, le_pipi_histogram);

	RETURN_SUCCESS(pipi_render_histogram(image, histogram, flags));
}