#include "php.h" #include "php_imlib.h" #define php_filter_init php_colormatrix_LTX_php_filter_init #define php_filter_deinit php_colormatrix_LTX_php_filter_deinit #define php_filter_exec php_colormatrix_LTX_php_filter_exec #define php_filter_getfiltercount php_colormatrix_LTX_php_filter_getfiltercount #define php_filter_getfilternames php_colormatrix_LTX_php_filter_getfilternames #define php_filter_getextinfo php_colormatrix_LTX_php_filter_getextinfo #define php_filter_getparams php_colormatrix_LTX_php_filter_getparams #define RLUM (0.3086) #define GLUM (0.6094) #define BLUM (0.0820) /* * identmat - * make an identity matrix */ static void _php_colormatrix_identmat(double *matrix) { *matrix++ = 1.0; /* row 1 */ *matrix++ = 0.0; *matrix++ = 0.0; *matrix++ = 0.0; *matrix++ = 0.0; /* row 2 */ *matrix++ = 1.0; *matrix++ = 0.0; *matrix++ = 0.0; *matrix++ = 0.0; /* row 3 */ *matrix++ = 0.0; *matrix++ = 1.0; *matrix++ = 0.0; *matrix++ = 0.0; /* row 4 */ *matrix++ = 0.0; *matrix++ = 0.0; *matrix++ = 1.0; } /* * matrixmult - * multiply two matricies */ static void _php_colormatrix_matrixmult(double a[16],double b[16],double c[16]) { int x, y; double tmp[16]; for(y=0; y<4 ; y++) { for(x=0 ; x<4 ; x++) { tmp[(y<<2)+x] = b[(y<<2)+0] * a[(0<<2)+x] + b[(y<<2)+1] * a[(1<<2)+x] + b[(y<<2)+2] * a[(2<<2)+x] + b[(y<<2)+3] * a[(3<<2)+x]; } } memcpy(c,tmp,sizeof(double)*16); } /* * xformpnt - * transform a 3D point using a matrix */ static void _php_colormatrix_xformpnt(double matrix[16],double x,double y,double z,double *tx,double *ty,double *tz) { *tx = x*matrix[0] + y*matrix[4] + z*matrix[8] + matrix[12]; *ty = x*matrix[1] + y*matrix[5] + z*matrix[9] + matrix[13]; *tz = x*matrix[2] + y*matrix[6] + z*matrix[10] + matrix[14]; } /* * xrotate - * rotate about the x (red) axis */ static void _php_colormatrix_xrotatemat(double mat[16],double rs,double rc) { double mmat[16]; mmat[0] = 1.0; mmat[1] = 0.0; mmat[2] = 0.0; mmat[3] = 0.0; mmat[4] = 0.0; mmat[5] = rc; mmat[6] = rs; mmat[7] = 0.0; mmat[8] = 0.0; mmat[9] = -rs; mmat[10] = rc; mmat[11] = 0.0; mmat[12] = 0.0; mmat[13] = 0.0; mmat[14] = 0.0; mmat[15] = 1.0; _php_colormatrix_matrixmult(mmat,mat,mat); } /* * yrotate - * rotate about the y (green) axis */ static void _php_colormatrix_yrotatemat(double mat[16],double rs,double rc) { double mmat[16]; mmat[0] = rc; mmat[1] = 0.0; mmat[2] = -rs; mmat[3] = 0.0; mmat[4] = 0.0; mmat[5] = 1.0; mmat[6] = 0.0; mmat[7] = 0.0; mmat[8] = rs; mmat[9] = 0.0; mmat[10] = rc; mmat[11] = 0.0; mmat[12] = 0.0; mmat[13] = 0.0; mmat[14] = 0.0; mmat[15] = 1.0; _php_colormatrix_matrixmult(mmat,mat,mat); } /* * zrotate - * rotate about the z (blue) axis */ static void _php_colormatrix_zrotatemat(double mat[16],double rs,double rc) { double mmat[16]; mmat[0] = rc; mmat[1] = rs; mmat[2] = 0.0; mmat[3] = 0.0; mmat[4] = -rs; mmat[5] = rc; mmat[6] = 0.0; mmat[7] = 0.0; mmat[8] = 0.0; mmat[9] = 0.0; mmat[10] = 1.0; mmat[11] = 0.0; mmat[12] = 0.0; mmat[13] = 0.0; mmat[14] = 0.0; mmat[15] = 1.0; _php_colormatrix_matrixmult(mmat,mat,mat); } /* * zshear - * shear z using x and y. */ static void _php_colormatrix_zshearmat(double mat[16],double dx,double dy) { double mmat[16]; mmat[0] = 1.0; mmat[1] = 0.0; mmat[2] = dx; mmat[3] = 0.0; mmat[4] = 0.0; mmat[5] = 1.0; mmat[6] = dy; mmat[7] = 0.0; mmat[8] = 0.0; mmat[9] = 0.0; mmat[10] = 1.0; mmat[11] = 0.0; mmat[12] = 0.0; mmat[13] = 0.0; mmat[14] = 0.0; mmat[15] = 1.0; _php_colormatrix_matrixmult(mmat,mat,mat); } /* * huerotatemat - * rotate the hue, while maintaining luminance. */ static void _php_colormatrix_huerotatemat(double mat[16],double rot) { double mmat[16]; double mag; double lx, ly, lz; double xrs, xrc; double yrs, yrc; double zrs, zrc; double zsx, zsy; _php_colormatrix_identmat(mmat); /* rotate the grey vector into positive Z */ mag = sqrt(2.0); xrs = 1.0/mag; xrc = 1.0/mag; _php_colormatrix_xrotatemat(mmat,xrs,xrc); mag = sqrt(3.0); yrs = -1.0/mag; yrc = sqrt(2.0)/mag; _php_colormatrix_yrotatemat(mmat,yrs,yrc); /* shear the space to make the luminance plane horizontal */ _php_colormatrix_xformpnt(mmat,RLUM,GLUM,BLUM,&lx,&ly,&lz); zsx = lx/lz; zsy = ly/lz; _php_colormatrix_zshearmat(mmat,zsx,zsy); /* rotate the hue */ zrs = sin(rot*M_PI/180.0); zrc = cos(rot*M_PI/180.0); _php_colormatrix_zrotatemat(mmat,zrs,zrc); /* unshear the space to put the luminance plane back */ _php_colormatrix_zshearmat(mmat,-zsx,-zsy); /* rotate the grey vector back into place */ _php_colormatrix_yrotatemat(mmat,-yrs,yrc); _php_colormatrix_xrotatemat(mmat,-xrs,xrc); _php_colormatrix_matrixmult(mmat,mat,mat); } /* * saturatemat - * make a saturation marix */ static void _php_colormatrix_saturatemat(double mat[16], double sat) { mat[0] = (1.0-sat)*RLUM + sat; mat[1] = (1.0-sat)*RLUM; mat[2] = (1.0-sat)*RLUM; mat[3] = 0.0; mat[4] = (1.0-sat)*GLUM; mat[5] = (1.0-sat)*GLUM + sat; mat[6] = (1.0-sat)*GLUM; mat[7] = 0.0; mat[8] = (1.0-sat)*BLUM; mat[9] = (1.0-sat)*BLUM; mat[10] = (1.0-sat)*BLUM + sat; mat[11] = 0.0; mat[12] = 0.0; mat[13] = 0.0; mat[14] = 0.0; mat[15] = 1.0; } static void _php_colormatrix_usermat(double mat[16], zval** data) { HashTable* mat_ht; HashPosition pos; convert_to_array_ex(data); mat_ht=HASH_OF(*data); zend_hash_internal_pointer_reset_ex(mat_ht,&pos); while (pos) { char *str_index; ulong num_index; int retval; zval **value; retval=zend_hash_get_current_key_ex(mat_ht,&str_index,NULL,&num_index,0,&pos); if (retval==HASH_KEY_IS_LONG) { if ((num_index>=0)&&(num_index<16)) { zend_hash_get_current_data_ex(mat_ht,&value,&pos); convert_to_double_ex(value); mat[num_index]=Z_DVAL_PP(value); } } zend_hash_move_forward_ex(mat_ht,&pos); } } static int _php_colormatrix_exec(Imlib_Image im, char* filter, HashTable* params) { HashPosition pos; double mat[16]; int x=0,y=0,w,h,imgw,imgh; _php_colormatrix_identmat(mat); imlib_context_set_image( im ); w = imgw = imlib_image_get_width(); h = imgh = imlib_image_get_height(); zend_hash_internal_pointer_reset_ex(params,&pos); while (pos) { char *str_index; ulong num_index; int retval; retval=zend_hash_get_current_key_ex(params,&str_index,NULL,&num_index,0,&pos); if (retval==HASH_KEY_IS_STRING) { zval **data; zend_hash_get_current_data_ex(params,&data,&pos); if (!strcmp(str_index,"x")) { convert_to_long_ex(data); x=Z_LVAL_PP(data); }; if (!strcmp(str_index,"y")) { convert_to_long_ex(data); y=Z_LVAL_PP(data); }; if (!strcmp(str_index,"w")) { convert_to_long_ex(data); w=Z_LVAL_PP(data); }; if (!strcmp(str_index,"h")) { convert_to_long_ex(data); h=Z_LVAL_PP(data); }; if (!strcmp(filter,"cm_user")) { if (!strcmp(str_index,"matrix")) _php_colormatrix_usermat(mat,data); } if (!strcmp(filter,"cm_saturation")) { if (!strcmp(str_index,"sat")) { convert_to_double_ex(data); _php_colormatrix_saturatemat(mat,Z_DVAL_PP(data)); }; } if (!strcmp(filter,"cm_huerot")) { if (!strcmp(str_index,"angle")) { convert_to_double_ex(data); _php_colormatrix_huerotatemat(mat,Z_DVAL_PP(data)); }; } } zend_hash_move_forward_ex(params,&pos); } if (x<0) x=0; if (y<0) y=0; if (w<0) w=0; if (h<0) h=0; if (x>=imgw) x=imgw-1; if (y>=imgh) y=imgh-1; if ((x+w)>imgw) w=imgw-x; if ((y+h)>imgh) h=imgh-y; { DATA32 *img_ptr,*old_ptr; int i,j; old_ptr = img_ptr = imlib_image_get_data(); img_ptr+=x+y*imgw; for (j=y;j<(y+h);j++) { for (i=x;i<(x+w);i++) { int r,g,b,nr,ng,nb; DATA32 argb; argb=*img_ptr; r=(argb&0x00ff0000)>>16; g=(argb&0x0000ff00)>>8; b=(argb&0x000000ff); nr = r*mat[0] + g*mat[4] + b*mat[8] + mat[12]; ng = r*mat[1] + g*mat[5] + b*mat[9] + mat[13]; nb = r*mat[2] + g*mat[6] + b*mat[10] + mat[14]; if (nr<0) nr=0; if (nr>255) nr=255; if (ng<0) ng=0; if (ng>255) ng=255; if (nb<0) nb=0; if (nb>255) nb=255; *img_ptr=(argb&0xff000000) | (nr<<16) | (ng<<8) | nb; img_ptr++; } img_ptr+=imgw-w; } imlib_image_put_back_data(old_ptr); } return SUCCESS; } int php_filter_init() { return SUCCESS; } void php_filter_deinit() { return; } int php_filter_exec(Imlib_Image im, char *filter, HashTable *params) { if (!strcmp(filter, "cm_user") || !strcmp(filter,"cm_saturation") || !strcmp(filter,"cm_huerot")) { return _php_colormatrix_exec(im,filter,params); } return FAILURE; } int php_filter_getfiltercount() { return 3; } void php_filter_getfilternames(char** filternames) { filternames[0]="cm_user"; filternames[1]="cm_saturation"; filternames[2]="cm_huerot"; } void php_filter_getextinfo(char** info) { info[0]="Color Matrix"; info[1]="Color processing using 4x4 matrices. Based on an article by Paul Haeberli.\n" "You can use built-in saturation and hue rotate filters (both filters maintain luminance), or supply your own matrix as a 16-element array. RGB values are computed as follows:\n" "r' = r*matrix[0] + g*matrix[4] + b*matrix[8] + matrix[12]\n" "g' = r*matrix[1] + g*matrix[5] + b*matrix[9] + matrix[13]\n" "b' = r*matrix[2] + g*matrix[6] + b*matrix[10] + matrix[14]"; info[2]="Piotr Pawlow (pp@siedziba.pl)"; } char* php_filter_getparams(char* filter) { if (!strcmp(filter, "cm_user")) return "int x=0, int y=0, int w=image_width, int h=image_height, array matrix=(1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1)"; if (!strcmp(filter, "cm_saturation")) return "int x=0, int y=0, int w=image_width, int h=image_height, double sat=1"; if (!strcmp(filter, "cm_huerot")) return "int x=0, int y=0, int w=image_width, int h=image_height, double angle=0"; return NULL; }