/****************************************************************************** Warp 0.01 -- image filter plug-in for The Gimp program Copyright (C) 1996 John P. Beale Mostly copied from LIC:Line Integral Convolution, Copyright (C) 1996 Tom Bech =============================================================================== John's E-mail: beale@best.com Tom's E-mail: tomb@ii.uib.no You can contact the original The Gimp authors at gimp@xcf.berkeley.edu =============================================================================== This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. =============================================================================== This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. =============================================================================== You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. =============================================================================== In other words, you can't sue me for whatever happens while using this ;) ******************************************************************************* Changes (post 0.01): ******************************************************************************* This plug-in implements image warping ******************************************************************************/ /* @(GIMP) = @(GIMP_DEP) = @(GIMP_OBJ) = @(GIMP_LIB) = @(GIMP_AUTHOR) = @(GIMP_EMAIL) = @(GIMP_DESC) = @(GIMP_VERSION) = <0.01> @(GIMP_URL) = */ #include #include #include #include "gimp.h" /************/ /* Typedefs */ /************/ #ifndef M_PI #define M_PI 3.14159265358979323846 #endif #define D double #define CHECKBOUNDS(x,y) (x>=0 && y>=0 && xr=a->r+b->r; a->g=a->g+b->g; a->b=a->b+b->b; } /* RGBMul(a,b): a = a*b where b is a scalar value */ void RGBMul(RGBPixel *a,double b) { a->r=a->r*b; a->g=a->g*b; a->b=a->b*b; } /* force R,G,B to be in interval [0..1] */ void RGBClamp(RGBPixel *a) { if (a->r>1.0) a->r=1.0; if (a->g>1.0) a->g=1.0; if (a->b>1.0) a->b=1.0; if (a->r<0.0) a->r=0.0; if (a->g<0.0) a->g=0.0; if (a->b<0.0) a->b=0.0; } void SetColor(RGBPixel *a,double r,double g,double b) { a->r=r; a->g=g; a->b=b; } long int XYToIndex(int x,int y) { return((long int)x*(long int)channels+(long int)y*(long int)modulo); } int CheckBounds(int x,int y) { if (x<0 || y<0 || x>width-1 || y>height-1) return(1); else return(0); } unsigned char PeekMap(unsigned char *DispMap,int x,int y) { long int index; index=(long int)x+(long int)width*(long int)y; return(DispMap[index]); } void PokeMap(unsigned char *DispMap,int x,int y,unsigned char value) { long int index; index=(long int)x+(long int)width*(long int)y; DispMap[index]=value; } RGBPixel Peek(unsigned char *data,int x,int y) { long int index=XYToIndex(x,y); RGBPixel color; color.r=((double)data[index])/255.0; color.g=((double)data[index+1])/255.0; color.b=((double)data[index+2])/255.0; return(color); } void Poke(unsigned char *data,int x,int y,RGBPixel *color) { long int index=XYToIndex(x,y); data[index]=(unsigned char)(255.0*color->r); data[index+1]=(unsigned char)(255.0*color->g); data[index+2]=(unsigned char)(255.0*color->b); } /*************/ /* Main part */ /*************/ /***************************************************/ /* Compute the derivative in the x and y direction */ /* We use these convolution kernels: */ /* |1 0 -1| | 1 2 1| */ /* DX: |2 0 -2| DY: | 0 0 0| */ /* |1 0 -1| | -1 -2 -1| */ /* (It's a varation of the Sobel kernels, really) */ /***************************************************/ double gradx(unsigned char *image,int x,int y) { double val=0; if (CHECKBOUNDS(x-1,y-1)) val=val+(D)PeekMap(image,x-1,y-1); if (CHECKBOUNDS(x+1,y-1)) val=val-(D)PeekMap(image,x+1,y-1); if (CHECKBOUNDS(x-1,y)) val=val+2*(D)PeekMap(image,x-1,y); if (CHECKBOUNDS(x+1,y)) val=val-2*(D)PeekMap(image,x+1,y); if (CHECKBOUNDS(x-1,y+1)) val=val+(D)PeekMap(image,x-1,y+1); if (CHECKBOUNDS(x+1,y+1)) val=val-(D)PeekMap(image,x+1,y+1); return(val); } double grady(unsigned char *image,int x,int y) { double val=0; if (CHECKBOUNDS(x-1,y-1)) val=val+(D)PeekMap(image,x-1,y-1); if (CHECKBOUNDS(x,y-1)) val=val+2*(D)PeekMap(image,x,y-1); if (CHECKBOUNDS(x+1,y-1)) val=val+(D)PeekMap(image,x+1,y-1); if (CHECKBOUNDS(x-1,y+1)) val=val-(D)PeekMap(image,x-1,y+1); if (CHECKBOUNDS(x,y+1)) val=val-2*(D)PeekMap(image,x,y+1); if (CHECKBOUNDS(x+1,y+1)) val=val-(D)PeekMap(image,x+1,y+1); return(val); } /************************************/ /* A nice 2nd order cubic spline :) */ /************************************/ double cubic(double t) { double at=fabs(t); if (at<1.0) return 2.0*at*at*at-3.0*at*at+1.0; else return 0.0; } double omega(double u,double v,int i,int j) { while (i<0) i+=NUMX; while (j<0) j+=NUMY; i%=NUMX; j%=NUMY; return cubic(u)*cubic(v)*(G[i][j][0]*u+G[i][j][1]*v); } /*************************************************************/ /* The noise function (2D variant of Perlins noise function) */ /*************************************************************/ double noise(double x,double y) { int i,sti=(int)floor(x/dx); int j,stj=(int)floor(y/dy); double sum=0.0; /* Calculate the double sum */ /* ======================== */ for (i=sti; i<=sti+1; i++) { for (j=stj; j<=stj+1; j++) sum+=omega((x-(double)i*dx)/dx,(y-(double)j*dy)/dy,i,j); } return(sum); } /*************************************************/ /* Generates pseudo-random vectors with length 1 */ /*************************************************/ void generatevectors(void) { double alpha; int i,j; for (i=0; imax) max=b; if (c>max) max=c; return(max); } double Minimum(double a,double b,double c) { double min=a; if (br,col->g,col->b); min=Minimum(col->r,col->g,col->b); if (max==min) *hue=-1.0; else { delta=max-min; if (col->r==max) { *hue=(col->g-col->b)/delta; } else if (col->g==max) { *hue=2.0+(col->b-col->r)/delta; } else if (col->b==max) { *hue=4.0+(col->r-col->g)/delta; } *hue=*hue*60.0; if (*hue<0.0) *hue=*hue+360.0; } } void RGB_To_Saturation(RGBPixel *col,double *sat) { double max,min,l; max=Maximum(col->r,col->g,col->b); min=Minimum(col->r,col->g,col->b); if (max==min) *sat=0.0; else { l=(max+min)/2.0; if (l<=0.5) *sat=(max-min)/(max+min); else *sat=(max-min)/(2.0-max-min); } } void RGB_To_Brightness(RGBPixel *col,double *bri) { double max,min; max=Maximum(col->r,col->g,col->b); min=Minimum(col->r,col->g,col->b); *bri=(max+min)/2.0; } void RGBToHue(Image image,unsigned char **map) { unsigned char *data,dval,*themap; int w,h; RGBPixel color; double val; long int maxc,cnt,index; data=gimp_image_data(image); w=gimp_image_width(image); h=gimp_image_height(image); maxc=(long int)w*(long int)h; themap=(unsigned char *)malloc((size_t)maxc*sizeof(unsigned char)); for (cnt=0;cnt