10 filters.c - implements filters that operate on images
17 i_unsharp_mask(im, 2.0, 1.0);
22 filters.c implements basic filters for Imager. These filters
23 should be accessible from the filter interface as defined in
26 =head1 FUNCTION REFERENCE
28 Some of these functions are internal.
41 Clamps the input value between 0 and 255. (internal)
51 if (in>255) { return 255; }
52 else if (in>0) return in;
59 =item i_contrast(im, intensity)
61 Scales the pixel values by the amount specified.
64 intensity - scalefactor
70 i_contrast(i_img *im, float intensity) {
73 unsigned int new_color;
76 mm_log((1,"i_contrast(im %p, intensity %f)\n", im, intensity));
78 if(intensity < 0) return;
80 for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
81 i_gpix(im, x, y, &rcolor);
83 for(ch = 0; ch < im->channels; ch++) {
84 new_color = (unsigned int) rcolor.channel[ch];
85 new_color *= intensity;
90 rcolor.channel[ch] = (unsigned char) new_color;
92 i_ppix(im, x, y, &rcolor);
98 =item i_hardinvert(im)
100 Inverts the pixel values of the input image.
108 i_hardinvert(i_img *im) {
114 mm_log((1,"i_hardinvert(im %p)\n", im));
116 for(y = 0; y < im->ysize; y++) {
117 for(x = 0; x < im->xsize; x++) {
118 i_gpix(im, x, y, &rcolor);
120 for(ch = 0; ch < im->channels; ch++) {
121 rcolor.channel[ch] = 255 - rcolor.channel[ch];
124 i_ppix(im, x, y, &rcolor);
132 =item i_noise(im, amount, type)
134 Inverts the pixel values by the amount specified.
137 amount - deviation in pixel values
138 type - noise individual for each channel if true
144 /* random() is non-ASCII, even if it is better than rand() */
145 #define random() rand()
149 i_noise(i_img *im, float amount, unsigned char type) {
153 float damount = amount * 2;
157 mm_log((1,"i_noise(im %p, intensity %.2f\n", im, amount));
159 if(amount < 0) return;
161 for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
162 i_gpix(im, x, y, &rcolor);
165 color_inc = (amount - (damount * ((float)random() / RAND_MAX)));
168 for(ch = 0; ch < im->channels; ch++) {
169 new_color = (int) rcolor.channel[ch];
172 new_color += (amount - (damount * ((float)random() / RAND_MAX)));
174 new_color += color_inc;
180 if(new_color > 255) {
184 rcolor.channel[ch] = (unsigned char) new_color;
187 i_ppix(im, x, y, &rcolor);
193 =item i_noise(im, amount, type)
195 Inverts the pixel values by the amount specified.
198 amount - deviation in pixel values
199 type - noise individual for each channel if true
206 =item i_applyimage(im, add_im, mode)
208 Apply's an image to another image
211 add_im - image that is applied to target
212 mode - what method is used in applying:
232 void i_applyimage(i_img *im, i_img *add_im, unsigned char mode) {
236 mm_log((1, "i_applyimage(im %p, add_im %p, mode %d", im, add_im, mode));
238 mx = (add_im->xsize <= im->xsize) ? add_im->xsize : add_im->xsize;
239 my = (add_im->ysize <= im->ysize) ? add_im->ysize : add_im->ysize;
241 for(x = 0; x < mx; x++) {
242 for(y = 0; y < my; y++) {
249 =item i_bumpmap(im, bump, channel, light_x, light_y, st)
251 Makes a bumpmap on image im using the bump image as the elevation map.
254 bump - image that contains the elevation info
255 channel - to take the elevation information from
256 light_x - x coordinate of light source
257 light_y - y coordinate of light source
258 st - length of shadow
264 i_bumpmap(i_img *im, i_img *bump, int channel, int light_x, int light_y, int st) {
267 i_color x1_color, y1_color, x2_color, y2_color, dst_color;
272 unsigned char px1, px2, py1, py2;
276 mm_log((1, "i_bumpmap(im %p, add_im %p, channel %d, light_x %d, light_y %d, st %d)\n",
277 im, bump, channel, light_x, light_y, st));
280 if(channel >= bump->channels) {
281 mm_log((1, "i_bumpmap: channel = %d while bump image only has %d channels\n", channel, bump->channels));
285 mx = (bump->xsize <= im->xsize) ? bump->xsize : im->xsize;
286 my = (bump->ysize <= im->ysize) ? bump->ysize : im->ysize;
288 i_img_empty_ch(&new_im, im->xsize, im->ysize, im->channels);
290 aX = (light_x > (mx >> 1)) ? light_x : mx - light_x;
291 aY = (light_y > (my >> 1)) ? light_y : my - light_y;
293 aL = sqrt((aX * aX) + (aY * aY));
295 for(y = 1; y < my - 1; y++) {
296 for(x = 1; x < mx - 1; x++) {
297 i_gpix(bump, x + st, y, &x1_color);
298 i_gpix(bump, x, y + st, &y1_color);
299 i_gpix(bump, x - st, y, &x2_color);
300 i_gpix(bump, x, y - st, &y2_color);
302 i_gpix(im, x, y, &dst_color);
304 px1 = x1_color.channel[channel];
305 py1 = y1_color.channel[channel];
306 px2 = x2_color.channel[channel];
307 py2 = y2_color.channel[channel];
315 fZ = (sqrt((nX * nX) + (nY * nY)) / aL);
317 tX = abs(x - light_x) / aL;
318 tY = abs(y - light_y) / aL;
320 tZ = 1 - (sqrt((tX * tX) + (tY * tY)) * fZ);
325 for(ch = 0; ch < im->channels; ch++)
326 dst_color.channel[ch] = (unsigned char) (float)(dst_color.channel[ch] * tZ);
328 i_ppix(&new_im, x, y, &dst_color);
332 i_copyto(im, &new_im, 0, 0, (int)im->xsize, (int)im->ysize, 0, 0);
334 i_img_exorcise(&new_im);
347 dotp(fvec *a, fvec *b) {
348 return a->x*b->x+a->y*b->y+a->z*b->z;
354 double d = sqrt(dotp(a,a));
368 I = Ia + Ip*( cd*Scol(N.L) + cs*(R.V)^n )
370 Here, the variables are:
372 * Ia - ambient colour
373 * Ip - intensity of the point light source
374 * cd - diffuse coefficient
375 * Scol - surface colour
376 * cs - specular coefficient
377 * n - objects shinyness
379 * L - lighting vector
380 * R - reflection vector
383 static void fvec_dump(fvec *x) {
384 printf("(%.2f %.2f %.2f)", x->x, x->y, x->z);
388 /* XXX: Should these return a code for success? */
394 =item i_bumpmap_complex(im, bump, channel, tx, ty, Lx, Ly, Lz, Ip, cd, cs, n, Ia, Il, Is)
396 Makes a bumpmap on image im using the bump image as the elevation map.
399 bump - image that contains the elevation info
400 channel - to take the elevation information from
401 tx - shift in x direction of where to start applying bumpmap
402 ty - shift in y direction of where to start applying bumpmap
403 Lx - x position/direction of light
404 Ly - y position/direction of light
405 Lz - z position/direction of light
407 cd - diffuse coefficient
408 cs - specular coefficient
409 n - surface shinyness
414 if z<0 then the L is taken to be the direction the light is shining in. Otherwise
415 the L is taken to be the position of the Light, Relative to the image.
422 i_bumpmap_complex(i_img *im,
442 float cdc[MAXCHANNELS];
443 float csc[MAXCHANNELS];
445 i_color x1_color, y1_color, x2_color, y2_color;
447 i_color Scol; /* Surface colour */
449 fvec L; /* Light vector */
450 fvec N; /* surface normal */
451 fvec R; /* Reflection vector */
452 fvec V; /* Vision vector */
454 mm_log((1, "i_bumpmap_complex(im %p, bump %p, channel %d, tx %d, ty %d, Lx %.2f, Ly %.2f, Lz %.2f, cd %.2f, cs %.2f, n %.2f, Ia %p, Il %p, Is %p)\n",
455 im, bump, channel, tx, ty, Lx, Ly, Lz, cd, cs, n, Ia, Il, Is));
457 if (channel >= bump->channels) {
458 mm_log((1, "i_bumpmap_complex: channel = %d while bump image only has %d channels\n", channel, bump->channels));
462 for(ch=0; ch<im->channels; ch++) {
463 cdc[ch] = (float)Il->channel[ch]*cd/255.f;
464 csc[ch] = (float)Is->channel[ch]*cs/255.f;
476 if (Lz < 0) { /* Light specifies a direction vector, reverse it to get the vector from surface to light */
481 } else { /* Light is the position of the light source */
489 i_img_empty_ch(&new_im, im->xsize, im->ysize, im->channels);
491 for(y = 0; y < im->ysize; y++) {
492 for(x = 0; x < im->xsize; x++) {
494 double dx = 0, dy = 0;
496 /* Calculate surface normal */
497 if (mx<x && x<Mx && my<y && y<My) {
498 i_gpix(bump, x + 1, y, &x1_color);
499 i_gpix(bump, x - 1, y, &x2_color);
500 i_gpix(bump, x, y + 1, &y1_color);
501 i_gpix(bump, x, y - 1, &y2_color);
502 dx = x2_color.channel[channel] - x1_color.channel[channel];
503 dy = y2_color.channel[channel] - y1_color.channel[channel];
513 /* Calculate Light vector if needed */
522 R.x = -L.x + 2*dp1*N.x;
523 R.y = -L.y + 2*dp1*N.y;
524 R.z = -L.z + 2*dp1*N.z;
528 dp1 = dp1<0 ?0 : dp1;
529 dp2 = pow(dp2<0 ?0 : dp2,n);
531 i_gpix(im, x, y, &Scol);
533 for(ch = 0; ch < im->channels; ch++)
535 saturate( Ia->channel[ch] + cdc[ch]*Scol.channel[ch]*dp1 + csc[ch]*dp2 );
537 i_ppix(&new_im, x, y, &Scol);
541 i_copyto(im, &new_im, 0, 0, (int)im->xsize, (int)im->ysize, 0, 0);
542 i_img_exorcise(&new_im);
547 =item i_postlevels(im, levels)
549 Quantizes Images to fewer levels.
552 levels - number of levels
558 i_postlevels(i_img *im, int levels) {
566 rv = (int) ((float)(256 / levels));
569 for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
570 i_gpix(im, x, y, &rcolor);
572 for(ch = 0; ch < im->channels; ch++) {
573 pv = (((float)rcolor.channel[ch] / 255)) * av;
574 pv = (int) ((int)pv * rv);
577 else if(pv > 255) pv = 255;
579 rcolor.channel[ch] = (unsigned char) pv;
581 i_ppix(im, x, y, &rcolor);
587 =item i_mosaic(im, size)
589 Makes an image looks like a mosaic with tilesize of size
598 i_mosaic(i_img *im, int size) {
606 sqrsize = size * size;
608 for(y = 0; y < im->ysize; y += size) for(x = 0; x < im->xsize; x += size) {
609 for(z = 0; z < 256; z++) col[z] = 0;
611 for(lx = 0; lx < size; lx++) {
612 for(ly = 0; ly < size; ly++) {
613 i_gpix(im, (x + lx), (y + ly), &rcolor);
615 for(ch = 0; ch < im->channels; ch++) {
616 col[ch] += rcolor.channel[ch];
621 for(ch = 0; ch < im->channels; ch++)
622 rcolor.channel[ch] = (int) ((float)col[ch] / sqrsize);
625 for(lx = 0; lx < size; lx++)
626 for(ly = 0; ly < size; ly++)
627 i_ppix(im, (x + lx), (y + ly), &rcolor);
634 =item i_watermark(im, wmark, tx, ty, pixdiff)
636 Applies a watermark to the target image
639 wmark - watermark image
640 tx - x coordinate of where watermark should be applied
641 ty - y coordinate of where watermark should be applied
642 pixdiff - the magnitude of the watermark, controls how visible it is
648 i_watermark(i_img *im, i_img *wmark, int tx, int ty, int pixdiff) {
652 for(vx=0;vx<128;vx++) for(vy=0;vy<110;vy++) {
654 i_gpix(im, tx+vx, ty+vy,&val );
655 i_gpix(wmark, vx, vy, &wval);
657 for(ch=0;ch<im->channels;ch++)
658 val.channel[ch] = saturate( val.channel[ch] + (pixdiff* (wval.channel[0]-128) )/128 );
660 i_ppix(im,tx+vx,ty+vy,&val);
666 =item i_autolevels(im, lsat, usat, skew)
668 Scales and translates each color such that it fills the range completely.
669 Skew is not implemented yet - purpose is to control the color skew that can
670 occur when changing the contrast.
673 lsat - fraction of pixels that will be truncated at the lower end of the spectrum
674 usat - fraction of pixels that will be truncated at the higher end of the spectrum
681 i_autolevels(i_img *im, float lsat, float usat, float skew) {
683 int i, x, y, rhist[256], ghist[256], bhist[256];
684 int rsum, rmin, rmax;
685 int gsum, gmin, gmax;
686 int bsum, bmin, bmax;
687 int rcl, rcu, gcl, gcu, bcl, bcu;
689 mm_log((1,"i_autolevels(im %p, lsat %f,usat %f,skew %f)\n", im, lsat,usat,skew));
692 for(i=0;i<256;i++) rhist[i]=ghist[i]=bhist[i] = 0;
693 /* create histogram for each channel */
694 for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
695 i_gpix(im, x, y, &val);
696 rhist[val.channel[0]]++;
697 ghist[val.channel[1]]++;
698 bhist[val.channel[2]]++;
707 rmin = gmin = bmin = 0;
708 rmax = gmax = bmax = 255;
710 rcu = rcl = gcu = gcl = bcu = bcl = 0;
712 for(i=0; i<256; i++) {
713 rcl += rhist[i]; if ( (rcl<rsum*lsat) ) rmin=i;
714 rcu += rhist[255-i]; if ( (rcu<rsum*usat) ) rmax=255-i;
716 gcl += ghist[i]; if ( (gcl<gsum*lsat) ) gmin=i;
717 gcu += ghist[255-i]; if ( (gcu<gsum*usat) ) gmax=255-i;
719 bcl += bhist[i]; if ( (bcl<bsum*lsat) ) bmin=i;
720 bcu += bhist[255-i]; if ( (bcu<bsum*usat) ) bmax=255-i;
723 for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
724 i_gpix(im, x, y, &val);
725 val.channel[0]=saturate((val.channel[0]-rmin)*255/(rmax-rmin));
726 val.channel[1]=saturate((val.channel[1]-gmin)*255/(gmax-gmin));
727 val.channel[2]=saturate((val.channel[2]-bmin)*255/(bmax-bmin));
728 i_ppix(im, x, y, &val);
735 Pseudo noise utility function used to generate perlin noise. (internal)
745 Noise(int x, int y) {
748 return ( 1.0 - ( (n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff) / 1073741824.0);
752 =item SmoothedNoise1(x,y)
754 Pseudo noise utility function used to generate perlin noise. (internal)
764 SmoothedNoise1(float x, float y) {
765 float corners = ( Noise(x-1, y-1)+Noise(x+1, y-1)+Noise(x-1, y+1)+Noise(x+1, y+1) ) / 16;
766 float sides = ( Noise(x-1, y) +Noise(x+1, y) +Noise(x, y-1) +Noise(x, y+1) ) / 8;
767 float center = Noise(x, y) / 4;
768 return corners + sides + center;
773 =item G_Interpolate(a, b, x)
775 Utility function used to generate perlin noise. (internal)
781 float C_Interpolate(float a, float b, float x) {
782 /* float ft = x * 3.1415927; */
784 float f = (1 - cos(ft)) * .5;
785 return a*(1-f) + b*f;
790 =item InterpolatedNoise(x, y)
792 Utility function used to generate perlin noise. (internal)
799 InterpolatedNoise(float x, float y) {
802 float fractional_X = x - integer_X;
804 float fractional_Y = y - integer_Y;
806 float v1 = SmoothedNoise1(integer_X, integer_Y);
807 float v2 = SmoothedNoise1(integer_X + 1, integer_Y);
808 float v3 = SmoothedNoise1(integer_X, integer_Y + 1);
809 float v4 = SmoothedNoise1(integer_X + 1, integer_Y + 1);
811 float i1 = C_Interpolate(v1 , v2 , fractional_X);
812 float i2 = C_Interpolate(v3 , v4 , fractional_X);
814 return C_Interpolate(i1 , i2 , fractional_Y);
820 =item PerlinNoise_2D(x, y)
822 Utility function used to generate perlin noise. (internal)
829 PerlinNoise_2D(float x, float y) {
833 int Number_Of_Octaves=6;
834 int n = Number_Of_Octaves - 1;
839 total = total + InterpolatedNoise(x * frequency, y * frequency) * amplitude;
847 =item i_radnoise(im, xo, yo, rscale, ascale)
849 Perlin-like radial noise.
852 xo - x coordinate of center
853 yo - y coordinate of center
854 rscale - radial scale
855 ascale - angular scale
861 i_radnoise(i_img *im, int xo, int yo, float rscale, float ascale) {
868 for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
869 xc = (float)x-xo+0.5;
870 yc = (float)y-yo+0.5;
871 r = rscale*sqrt(xc*xc+yc*yc)+1.2;
872 a = (PI+atan2(yc,xc))*ascale;
873 v = saturate(128+100*(PerlinNoise_2D(a,r)));
874 /* v=saturate(120+12*PerlinNoise_2D(xo+(float)x/scale,yo+(float)y/scale)); Good soft marble */
875 for(ch=0; ch<im->channels; ch++) val.channel[ch]=v;
876 i_ppix(im, x, y, &val);
882 =item i_turbnoise(im, xo, yo, scale)
884 Perlin-like 2d noise noise.
887 xo - x coordinate translation
888 yo - y coordinate translation
889 scale - scale of noise
895 i_turbnoise(i_img *im, float xo, float yo, float scale) {
900 for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
901 /* v=saturate(125*(1.0+PerlinNoise_2D(xo+(float)x/scale,yo+(float)y/scale))); */
902 v = saturate(120*(1.0+sin(xo+(float)x/scale+PerlinNoise_2D(xo+(float)x/scale,yo+(float)y/scale))));
903 for(ch=0; ch<im->channels; ch++) val.channel[ch] = v;
904 i_ppix(im, x, y, &val);
911 =item i_gradgen(im, num, xo, yo, ival, dmeasure)
913 Gradient generating function.
916 num - number of points given
917 xo - array of x coordinates
918 yo - array of y coordinates
919 ival - array of i_color objects
920 dmeasure - distance measure to be used.
922 1 = Euclidean squared
923 2 = Manhattan distance
930 i_gradgen(i_img *im, int num, int *xo, int *yo, i_color *ival, int dmeasure) {
934 int channels = im->channels;
935 int xsize = im->xsize;
936 int ysize = im->ysize;
940 mm_log((1,"i_gradgen(im %p, num %d, xo %p, yo %p, ival %p, dmeasure %d)\n", im, num, xo, yo, ival, dmeasure));
942 for(p = 0; p<num; p++) {
943 mm_log((1,"i_gradgen: (%d, %d)\n", xo[p], yo[p]));
947 fdist = mymalloc( sizeof(float) * num );
949 for(y = 0; y<ysize; y++) for(x = 0; x<xsize; x++) {
952 for(p = 0; p<num; p++) {
956 case 0: /* euclidean */
957 fdist[p] = sqrt(xd*xd + yd*yd); /* euclidean distance */
959 case 1: /* euclidean squared */
960 fdist[p] = xd*xd + yd*yd; /* euclidean distance */
962 case 2: /* euclidean squared */
963 fdist[p] = max(xd*xd, yd*yd); /* manhattan distance */
966 m_fatal(3,"i_gradgen: Unknown distance measure\n");
971 csd = 1/((num-1)*cs);
973 for(p = 0; p<num; p++) fdist[p] = (cs-fdist[p])*csd;
975 for(ch = 0; ch<channels; ch++) {
977 for(p = 0; p<num; p++) tres += ival[p].channel[ch] * fdist[p];
978 val.channel[ch] = saturate(tres);
980 i_ppix(im, x, y, &val);
986 i_nearest_color_foo(i_img *im, int num, int *xo, int *yo, i_color *ival, int dmeasure) {
989 int xsize = im->xsize;
990 int ysize = im->ysize;
992 mm_log((1,"i_gradgen(im %p, num %d, xo %p, yo %p, ival %p, dmeasure %d)\n", im, num, xo, yo, ival, dmeasure));
994 for(p = 0; p<num; p++) {
995 mm_log((1,"i_gradgen: (%d, %d)\n", xo[p], yo[p]));
999 for(y = 0; y<ysize; y++) for(x = 0; x<xsize; x++) {
1008 case 0: /* euclidean */
1009 mindist = sqrt(xd*xd + yd*yd); /* euclidean distance */
1011 case 1: /* euclidean squared */
1012 mindist = xd*xd + yd*yd; /* euclidean distance */
1014 case 2: /* euclidean squared */
1015 mindist = max(xd*xd, yd*yd); /* manhattan distance */
1018 m_fatal(3,"i_nearest_color: Unknown distance measure\n");
1021 for(p = 1; p<num; p++) {
1025 case 0: /* euclidean */
1026 curdist = sqrt(xd*xd + yd*yd); /* euclidean distance */
1028 case 1: /* euclidean squared */
1029 curdist = xd*xd + yd*yd; /* euclidean distance */
1031 case 2: /* euclidean squared */
1032 curdist = max(xd*xd, yd*yd); /* manhattan distance */
1035 m_fatal(3,"i_nearest_color: Unknown distance measure\n");
1037 if (curdist < mindist) {
1042 i_ppix(im, x, y, &ival[midx]);
1047 i_nearest_color(i_img *im, int num, int *xo, int *yo, i_color *oval, int dmeasure) {
1053 int xsize = im->xsize;
1054 int ysize = im->ysize;
1057 mm_log((1,"i_nearest_color(im %p, num %d, xo %p, yo %p, ival %p, dmeasure %d)\n", im, num, xo, yo, oval, dmeasure));
1059 tval = mymalloc( sizeof(float)*num*im->channels );
1060 ival = mymalloc( sizeof(i_color)*num );
1061 cmatch = mymalloc( sizeof(int)*num );
1063 for(p = 0; p<num; p++) {
1064 for(ch = 0; ch<im->channels; ch++) tval[ p * im->channels + ch] = 0;
1069 for(y = 0; y<ysize; y++) for(x = 0; x<xsize; x++) {
1078 case 0: /* euclidean */
1079 mindist = sqrt(xd*xd + yd*yd); /* euclidean distance */
1081 case 1: /* euclidean squared */
1082 mindist = xd*xd + yd*yd; /* euclidean distance */
1084 case 2: /* euclidean squared */
1085 mindist = max(xd*xd, yd*yd); /* manhattan distance */
1088 m_fatal(3,"i_nearest_color: Unknown distance measure\n");
1091 for(p = 1; p<num; p++) {
1095 case 0: /* euclidean */
1096 curdist = sqrt(xd*xd + yd*yd); /* euclidean distance */
1098 case 1: /* euclidean squared */
1099 curdist = xd*xd + yd*yd; /* euclidean distance */
1101 case 2: /* euclidean squared */
1102 curdist = max(xd*xd, yd*yd); /* manhattan distance */
1105 m_fatal(3,"i_nearest_color: Unknown distance measure\n");
1107 if (curdist < mindist) {
1114 i_gpix(im, x, y, &val);
1115 c2 = 1.0/(float)(cmatch[midx]);
1118 for(ch = 0; ch<im->channels; ch++)
1119 tval[midx*im->channels + ch] = c1*tval[midx*im->channels + ch] + c2 * (float) val.channel[ch];
1124 for(p = 0; p<num; p++) for(ch = 0; ch<im->channels; ch++) ival[p].channel[ch] = tval[p*im->channels + ch];
1126 i_nearest_color_foo(im, num, xo, yo, ival, dmeasure);
1130 =item i_unsharp_mask(im, stddev, scale)
1132 Perform an usharp mask, which is defined as subtracting the blurred
1133 image from double the original.
1137 void i_unsharp_mask(i_img *im, double stddev, double scale) {
1143 /* it really shouldn't ever be more than 1.0, but maybe ... */
1148 i_gaussian(©, stddev);
1149 if (im->bits == i_8_bits) {
1150 i_color *blur = mymalloc(im->xsize * sizeof(i_color) * 2);
1151 i_color *out = blur + im->xsize;
1153 for (y = 0; y < im->ysize; ++y) {
1154 i_glin(©, 0, copy.xsize, y, blur);
1155 i_glin(im, 0, im->xsize, y, out);
1156 for (x = 0; x < im->xsize; ++x) {
1157 for (ch = 0; ch < im->channels; ++ch) {
1158 /*int temp = out[x].channel[ch] +
1159 scale * (out[x].channel[ch] - blur[x].channel[ch]);*/
1160 int temp = out[x].channel[ch] * 2 - blur[x].channel[ch];
1163 else if (temp > 255)
1165 out[x].channel[ch] = temp;
1168 i_plin(im, 0, im->xsize, y, out);
1174 i_fcolor *blur = mymalloc(im->xsize * sizeof(i_fcolor) * 2);
1175 i_fcolor *out = blur + im->xsize;
1177 for (y = 0; y < im->ysize; ++y) {
1178 i_glinf(©, 0, copy.xsize, y, blur);
1179 i_glinf(im, 0, im->xsize, y, out);
1180 for (x = 0; x < im->xsize; ++x) {
1181 for (ch = 0; ch < im->channels; ++ch) {
1182 double temp = out[x].channel[ch] +
1183 scale * (out[x].channel[ch] - blur[x].channel[ch]);
1186 else if (temp > 1.0)
1188 out[x].channel[ch] = temp;
1191 i_plinf(im, 0, im->xsize, y, out);
1196 i_img_exorcise(©);
1200 static double linear_fount_f(double x, double y, struct fount_state *state);
1201 static double bilinear_fount_f(double x, double y, struct fount_state *state);
1202 static double radial_fount_f(double x, double y, struct fount_state *state);
1203 static double square_fount_f(double x, double y, struct fount_state *state);
1204 static double revolution_fount_f(double x, double y,
1205 struct fount_state *state);
1206 static double conical_fount_f(double x, double y, struct fount_state *state);
1208 typedef double (*fount_func)(double, double, struct fount_state *);
1209 static fount_func fount_funcs[] =
1219 static double linear_interp(double pos, i_fountain_seg *seg);
1220 static double sine_interp(double pos, i_fountain_seg *seg);
1221 static double sphereup_interp(double pos, i_fountain_seg *seg);
1222 static double spheredown_interp(double pos, i_fountain_seg *seg);
1223 typedef double (*fount_interp)(double pos, i_fountain_seg *seg);
1224 static fount_interp fount_interps[] =
1233 static void direct_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg);
1234 static void hue_up_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg);
1235 static void hue_down_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg);
1236 typedef void (*fount_cinterp)(i_fcolor *out, double pos, i_fountain_seg *seg);
1237 static fount_cinterp fount_cinterps[] =
1244 typedef double (*fount_repeat)(double v);
1245 static double fount_r_none(double v);
1246 static double fount_r_sawtooth(double v);
1247 static double fount_r_triangle(double v);
1248 static double fount_r_saw_both(double v);
1249 static double fount_r_tri_both(double v);
1250 static fount_repeat fount_repeats[] =
1259 static int simple_ssample(i_fcolor *out, double x, double y,
1260 struct fount_state *state);
1261 static int random_ssample(i_fcolor *out, double x, double y,
1262 struct fount_state *state);
1263 static int circle_ssample(i_fcolor *out, double x, double y,
1264 struct fount_state *state);
1265 typedef int (*fount_ssample)(i_fcolor *out, double x, double y,
1266 struct fount_state *state);
1267 static fount_ssample fount_ssamples[] =
1276 fount_getat(i_fcolor *out, double x, double y, struct fount_state *state);
1279 Keep state information used by each type of fountain fill
1281 struct fount_state {
1282 /* precalculated for the equation of the line perpendicular to the line AB */
1293 fount_repeat rpfunc;
1294 fount_ssample ssfunc;
1296 i_fountain_seg *segs;
1301 fount_init_state(struct fount_state *state, double xa, double ya,
1302 double xb, double yb, i_fountain_type type,
1303 i_fountain_repeat repeat, int combine, int super_sample,
1304 double ssample_param, int count, i_fountain_seg *segs);
1307 fount_finish_state(struct fount_state *state);
1309 #define EPSILON (1e-6)
1312 =item i_fountain(im, xa, ya, xb, yb, type, repeat, combine, super_sample, ssample_param, count, segs)
1314 Draws a fountain fill using A(xa, ya) and B(xb, yb) as reference points.
1316 I<type> controls how the reference points are used:
1322 linear, where A is 0 and B is 1.
1326 linear in both directions from A.
1330 circular, where A is the centre of the fill, and B is a point
1333 =item i_ft_radial_square
1335 where A is the centre of the fill and B is the centre of
1336 one side of the square.
1338 =item i_ft_revolution
1340 where A is the centre of the fill and B defines the 0/1.0
1345 similar to i_ft_revolution, except that the revolution goes in both
1350 I<repeat> can be one of:
1356 values < 0 are treated as zero, values > 1 are treated as 1.
1360 negative values are treated as 0, positive values are modulo 1.0
1364 negative values are treated as zero, if (int)value is odd then the value is treated as 1-(value
1365 mod 1.0), otherwise the same as for sawtooth.
1369 like i_fr_sawtooth, except that the sawtooth pattern repeats into
1374 Like i_fr_triangle, except that negative values are handled as their
1379 If combine is non-zero then non-opaque values are combined with the
1382 I<super_sample> controls super sampling, if any. At some point I'll
1383 probably add a adaptive super-sampler. Current possible values are:
1389 No super-sampling is done.
1393 A square grid of points withing the pixel are sampled.
1397 Random points within the pixel are sampled.
1401 Points on the radius of a circle are sampled. This produces fairly
1402 good results, but is fairly slow since sin() and cos() are evaluated
1407 I<ssample_param> is intended to be roughly the number of points
1408 sampled within the pixel.
1410 I<count> and I<segs> define the segments of the fill.
1417 i_fountain(i_img *im, double xa, double ya, double xb, double yb,
1418 i_fountain_type type, i_fountain_repeat repeat,
1419 int combine, int super_sample, double ssample_param,
1420 int count, i_fountain_seg *segs) {
1421 struct fount_state state;
1423 i_fcolor *line = mymalloc(sizeof(i_fcolor) * im->xsize);
1424 i_fcolor *work = NULL;
1426 i_fountain_seg *my_segs;
1427 i_fill_combine_f combine_func = NULL;
1428 i_fill_combinef_f combinef_func = NULL;
1430 i_get_combine(combine, &combine_func, &combinef_func);
1432 work = mymalloc(sizeof(i_fcolor) * im->xsize);
1434 fount_init_state(&state, xa, ya, xb, yb, type, repeat, combine,
1435 super_sample, ssample_param, count, segs);
1436 my_segs = state.segs;
1438 for (y = 0; y < im->ysize; ++y) {
1439 i_glinf(im, 0, im->xsize, y, line);
1440 for (x = 0; x < im->xsize; ++x) {
1443 if (super_sample == i_fts_none)
1444 got_one = fount_getat(&c, x, y, &state);
1446 got_one = state.ssfunc(&c, x, y, &state);
1455 combinef_func(line, work, im->channels, im->xsize);
1456 i_plinf(im, 0, im->xsize, y, line);
1458 fount_finish_state(&state);
1464 struct fount_state state;
1465 } i_fill_fountain_t;
1468 fill_fountf(i_fill_t *fill, int x, int y, int width, int channels,
1469 i_fcolor *data, i_fcolor *work);
1471 fount_fill_destroy(i_fill_t *fill);
1474 =item i_new_fount(xa, ya, xb, yb, type, repeat, combine, super_sample, ssample_param, count, segs)
1476 Creates a new general fill which fills with a fountain fill.
1482 i_new_fill_fount(double xa, double ya, double xb, double yb,
1483 i_fountain_type type, i_fountain_repeat repeat,
1484 int combine, int super_sample, double ssample_param,
1485 int count, i_fountain_seg *segs) {
1486 i_fill_fountain_t *fill = mymalloc(sizeof(i_fill_fountain_t));
1488 fill->base.fill_with_color = NULL;
1489 fill->base.fill_with_fcolor = fill_fountf;
1490 fill->base.destroy = fount_fill_destroy;
1492 i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
1494 fill->base.combine = NULL;
1495 fill->base.combinef = NULL;
1497 fount_init_state(&fill->state, xa, ya, xb, yb, type, repeat, combine,
1498 super_sample, ssample_param, count, segs);
1506 =head1 INTERNAL FUNCTIONS
1510 =item fount_init_state(...)
1512 Used by both the fountain fill filter and the fountain fill.
1518 fount_init_state(struct fount_state *state, double xa, double ya,
1519 double xb, double yb, i_fountain_type type,
1520 i_fountain_repeat repeat, int combine, int super_sample,
1521 double ssample_param, int count, i_fountain_seg *segs) {
1523 i_fountain_seg *my_segs = mymalloc(sizeof(i_fountain_seg) * count);
1524 /*int have_alpha = im->channels == 2 || im->channels == 4;*/
1526 memset(state, 0, sizeof(*state));
1527 /* we keep a local copy that we can adjust for speed */
1528 for (i = 0; i < count; ++i) {
1529 i_fountain_seg *seg = my_segs + i;
1532 if (seg->type < 0 || type >= i_ft_end)
1533 seg->type = i_ft_linear;
1534 if (seg->color < 0 || seg->color >= i_fc_end)
1535 seg->color = i_fc_direct;
1536 if (seg->color == i_fc_hue_up || seg->color == i_fc_hue_down) {
1537 /* so we don't have to translate to HSV on each request, do it here */
1538 for (j = 0; j < 2; ++j) {
1539 i_rgb_to_hsvf(seg->c+j);
1541 if (seg->color == i_fc_hue_up) {
1542 if (seg->c[1].channel[0] <= seg->c[0].channel[0])
1543 seg->c[1].channel[0] += 1.0;
1546 if (seg->c[0].channel[0] <= seg->c[0].channel[1])
1547 seg->c[0].channel[0] += 1.0;
1550 /*printf("start %g mid %g end %g c0(%g,%g,%g,%g) c1(%g,%g,%g,%g) type %d color %d\n",
1551 seg->start, seg->middle, seg->end, seg->c[0].channel[0],
1552 seg->c[0].channel[1], seg->c[0].channel[2], seg->c[0].channel[3],
1553 seg->c[1].channel[0], seg->c[1].channel[1], seg->c[1].channel[2],
1554 seg->c[1].channel[3], seg->type, seg->color);*/
1558 /* initialize each engine */
1559 /* these are so common ... */
1560 state->lA = xb - xa;
1561 state->lB = yb - ya;
1562 state->AB = sqrt(state->lA * state->lA + state->lB * state->lB);
1567 type = i_ft_linear; /* make the invalid value valid */
1570 state->lC = ya * ya - ya * yb + xa * xa - xa * xb;
1572 state->mult = 1/linear_fount_f(xb, yb, state);
1576 state->mult = 1.0 / sqrt((double)(xb-xa)*(xb-xa)
1577 + (double)(yb-ya)*(yb-ya));
1580 case i_ft_radial_square:
1581 state->cos = state->lA / state->AB;
1582 state->sin = state->lB / state->AB;
1583 state->mult = 1.0 / state->AB;
1586 case i_ft_revolution:
1587 state->theta = atan2(yb-ya, xb-xa);
1588 state->mult = 1.0 / (PI * 2);
1592 state->theta = atan2(yb-ya, xb-xa);
1593 state->mult = 1.0 / PI;
1596 state->ffunc = fount_funcs[type];
1597 if (super_sample < 0
1598 || super_sample >= (int)(sizeof(fount_ssamples)/sizeof(*fount_ssamples))) {
1601 state->ssample_data = NULL;
1602 switch (super_sample) {
1604 ssample_param = floor(0.5 + sqrt(ssample_param));
1605 state->ssample_data = mymalloc(sizeof(i_fcolor) * ssample_param * ssample_param);
1610 ssample_param = floor(0.5+ssample_param);
1611 state->ssample_data = mymalloc(sizeof(i_fcolor) * ssample_param);
1614 state->parm = ssample_param;
1615 state->ssfunc = fount_ssamples[super_sample];
1616 if (repeat < 0 || repeat >= (sizeof(fount_repeats)/sizeof(*fount_repeats)))
1618 state->rpfunc = fount_repeats[repeat];
1619 state->segs = my_segs;
1620 state->count = count;
1624 fount_finish_state(struct fount_state *state) {
1625 if (state->ssample_data)
1626 myfree(state->ssample_data);
1627 myfree(state->segs);
1632 =item fount_getat(out, x, y, ffunc, rpfunc, state, segs, count)
1634 Evaluates the fountain fill at the given point.
1636 This is called by both the non-super-sampling and super-sampling code.
1638 You might think that it would make sense to sample the fill parameter
1639 instead, and combine those, but this breaks badly.
1645 fount_getat(i_fcolor *out, double x, double y, struct fount_state *state) {
1646 double v = (state->rpfunc)((state->ffunc)(x, y, state));
1650 while (i < state->count
1651 && (v < state->segs[i].start || v > state->segs[i].end)) {
1654 if (i < state->count) {
1655 v = (fount_interps[state->segs[i].type])(v, state->segs+i);
1656 (fount_cinterps[state->segs[i].color])(out, v, state->segs+i);
1664 =item linear_fount_f(x, y, state)
1666 Calculate the fill parameter for a linear fountain fill.
1668 Uses the point to line distance function, with some precalculation
1669 done in i_fountain().
1674 linear_fount_f(double x, double y, struct fount_state *state) {
1675 return (state->lA * x + state->lB * y + state->lC) / state->AB * state->mult;
1679 =item bilinear_fount_f(x, y, state)
1681 Calculate the fill parameter for a bi-linear fountain fill.
1686 bilinear_fount_f(double x, double y, struct fount_state *state) {
1687 return fabs((state->lA * x + state->lB * y + state->lC) / state->AB * state->mult);
1691 =item radial_fount_f(x, y, state)
1693 Calculate the fill parameter for a radial fountain fill.
1695 Simply uses the distance function.
1700 radial_fount_f(double x, double y, struct fount_state *state) {
1701 return sqrt((double)(state->xa-x)*(state->xa-x)
1702 + (double)(state->ya-y)*(state->ya-y)) * state->mult;
1706 =item square_fount_f(x, y, state)
1708 Calculate the fill parameter for a square fountain fill.
1710 Works by rotating the reference co-ordinate around the centre of the
1716 square_fount_f(double x, double y, struct fount_state *state) {
1717 int xc, yc; /* centred on A */
1718 double xt, yt; /* rotated by theta */
1721 xt = fabs(xc * state->cos + yc * state->sin);
1722 yt = fabs(-xc * state->sin + yc * state->cos);
1723 return (xt > yt ? xt : yt) * state->mult;
1727 =item revolution_fount_f(x, y, state)
1729 Calculates the fill parameter for the revolution fountain fill.
1734 revolution_fount_f(double x, double y, struct fount_state *state) {
1735 double angle = atan2(y - state->ya, x - state->xa);
1737 angle -= state->theta;
1739 angle = fmod(angle+ PI * 4, PI*2);
1742 return angle * state->mult;
1746 =item conical_fount_f(x, y, state)
1748 Calculates the fill parameter for the conical fountain fill.
1753 conical_fount_f(double x, double y, struct fount_state *state) {
1754 double angle = atan2(y - state->ya, x - state->xa);
1756 angle -= state->theta;
1759 else if (angle > PI)
1762 return fabs(angle) * state->mult;
1766 =item linear_interp(pos, seg)
1768 Calculates linear interpolation on the fill parameter. Breaks the
1769 segment into 2 regions based in the I<middle> value.
1774 linear_interp(double pos, i_fountain_seg *seg) {
1775 if (pos < seg->middle) {
1776 double len = seg->middle - seg->start;
1780 return (pos - seg->start) / len / 2;
1783 double len = seg->end - seg->middle;
1787 return 0.5 + (pos - seg->middle) / len / 2;
1792 =item sine_interp(pos, seg)
1794 Calculates sine function interpolation on the fill parameter.
1799 sine_interp(double pos, i_fountain_seg *seg) {
1800 /* I wonder if there's a simple way to smooth the transition for this */
1801 double work = linear_interp(pos, seg);
1803 return (1-cos(work * PI))/2;
1807 =item sphereup_interp(pos, seg)
1809 Calculates spherical interpolation on the fill parameter, with the cusp
1815 sphereup_interp(double pos, i_fountain_seg *seg) {
1816 double work = linear_interp(pos, seg);
1818 return sqrt(1.0 - (1-work) * (1-work));
1822 =item spheredown_interp(pos, seg)
1824 Calculates spherical interpolation on the fill parameter, with the cusp
1830 spheredown_interp(double pos, i_fountain_seg *seg) {
1831 double work = linear_interp(pos, seg);
1833 return 1-sqrt(1.0 - work * work);
1837 =item direct_cinterp(out, pos, seg)
1839 Calculates the fountain color based on direct scaling of the channels
1840 of the color channels.
1845 direct_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg) {
1847 for (ch = 0; ch < MAXCHANNELS; ++ch) {
1848 out->channel[ch] = seg->c[0].channel[ch] * (1 - pos)
1849 + seg->c[1].channel[ch] * pos;
1854 =item hue_up_cinterp(put, pos, seg)
1856 Calculates the fountain color based on scaling a HSV value. The hue
1857 increases as the fill parameter increases.
1862 hue_up_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg) {
1864 for (ch = 0; ch < MAXCHANNELS; ++ch) {
1865 out->channel[ch] = seg->c[0].channel[ch] * (1 - pos)
1866 + seg->c[1].channel[ch] * pos;
1872 =item hue_down_cinterp(put, pos, seg)
1874 Calculates the fountain color based on scaling a HSV value. The hue
1875 decreases as the fill parameter increases.
1880 hue_down_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg) {
1882 for (ch = 0; ch < MAXCHANNELS; ++ch) {
1883 out->channel[ch] = seg->c[0].channel[ch] * (1 - pos)
1884 + seg->c[1].channel[ch] * pos;
1890 =item simple_ssample(out, parm, x, y, state, ffunc, rpfunc, segs, count)
1892 Simple grid-based super-sampling.
1897 simple_ssample(i_fcolor *out, double x, double y, struct fount_state *state) {
1898 i_fcolor *work = state->ssample_data;
1900 int grid = state->parm;
1901 double base = -0.5 + 0.5 / grid;
1902 double step = 1.0 / grid;
1906 for (dx = 0; dx < grid; ++dx) {
1907 for (dy = 0; dy < grid; ++dy) {
1908 if (fount_getat(work+samp_count, x + base + step * dx,
1909 y + base + step * dy, state)) {
1914 for (ch = 0; ch < MAXCHANNELS; ++ch) {
1915 out->channel[ch] = 0;
1916 for (i = 0; i < samp_count; ++i) {
1917 out->channel[ch] += work[i].channel[ch];
1919 /* we divide by 4 rather than samp_count since if there's only one valid
1920 sample it should be mostly transparent */
1921 out->channel[ch] /= grid * grid;
1927 =item random_ssample(out, parm, x, y, state, ffunc, rpfunc, segs, count)
1929 Random super-sampling.
1934 random_ssample(i_fcolor *out, double x, double y,
1935 struct fount_state *state) {
1936 i_fcolor *work = state->ssample_data;
1938 int maxsamples = state->parm;
1939 double rand_scale = 1.0 / RAND_MAX;
1941 for (i = 0; i < maxsamples; ++i) {
1942 if (fount_getat(work+samp_count, x - 0.5 + rand() * rand_scale,
1943 y - 0.5 + rand() * rand_scale, state)) {
1947 for (ch = 0; ch < MAXCHANNELS; ++ch) {
1948 out->channel[ch] = 0;
1949 for (i = 0; i < samp_count; ++i) {
1950 out->channel[ch] += work[i].channel[ch];
1952 /* we divide by maxsamples rather than samp_count since if there's
1953 only one valid sample it should be mostly transparent */
1954 out->channel[ch] /= maxsamples;
1960 =item circle_ssample(out, parm, x, y, state, ffunc, rpfunc, segs, count)
1962 Super-sampling around the circumference of a circle.
1964 I considered saving the sin()/cos() values and transforming step-size
1965 around the circle, but that's inaccurate, though it may not matter
1971 circle_ssample(i_fcolor *out, double x, double y,
1972 struct fount_state *state) {
1973 i_fcolor *work = state->ssample_data;
1975 int maxsamples = state->parm;
1976 double angle = 2 * PI / maxsamples;
1977 double radius = 0.3; /* semi-random */
1979 for (i = 0; i < maxsamples; ++i) {
1980 if (fount_getat(work+samp_count, x + radius * cos(angle * i),
1981 y + radius * sin(angle * i), state)) {
1985 for (ch = 0; ch < MAXCHANNELS; ++ch) {
1986 out->channel[ch] = 0;
1987 for (i = 0; i < samp_count; ++i) {
1988 out->channel[ch] += work[i].channel[ch];
1990 /* we divide by maxsamples rather than samp_count since if there's
1991 only one valid sample it should be mostly transparent */
1992 out->channel[ch] /= maxsamples;
1998 =item fount_r_none(v)
2000 Implements no repeats. Simply clamps the fill value.
2005 fount_r_none(double v) {
2006 return v < 0 ? 0 : v > 1 ? 1 : v;
2010 =item fount_r_sawtooth(v)
2012 Implements sawtooth repeats. Clamps negative values and uses fmod()
2018 fount_r_sawtooth(double v) {
2019 return v < 0 ? 0 : fmod(v, 1.0);
2023 =item fount_r_triangle(v)
2025 Implements triangle repeats. Clamps negative values, uses fmod to get
2026 a range 0 through 2 and then adjusts values > 1.
2031 fount_r_triangle(double v) {
2036 return v > 1.0 ? 2.0 - v : v;
2041 =item fount_r_saw_both(v)
2043 Implements sawtooth repeats in the both postive and negative directions.
2045 Adjusts the value to be postive and then just uses fmod().
2050 fount_r_saw_both(double v) {
2053 return fmod(v, 1.0);
2057 =item fount_r_tri_both(v)
2059 Implements triangle repeats in the both postive and negative directions.
2061 Uses fmod on the absolute value, and then adjusts values > 1.
2066 fount_r_tri_both(double v) {
2067 v = fmod(fabs(v), 2.0);
2068 return v > 1.0 ? 2.0 - v : v;
2072 =item fill_fountf(fill, x, y, width, channels, data)
2074 The fill function for fountain fills.
2079 fill_fountf(i_fill_t *fill, int x, int y, int width, int channels,
2080 i_fcolor *data, i_fcolor *work) {
2081 i_fill_fountain_t *f = (i_fill_fountain_t *)fill;
2083 if (fill->combinef) {
2084 i_fcolor *wstart = work;
2091 if (f->state.ssfunc)
2092 got_one = f->state.ssfunc(&c, x, y, &f->state);
2094 got_one = fount_getat(&c, x, y, &f->state);
2100 (fill->combinef)(data, wstart, channels, count);
2107 if (f->state.ssfunc)
2108 got_one = f->state.ssfunc(&c, x, y, &f->state);
2110 got_one = fount_getat(&c, x, y, &f->state);
2120 =item fount_fill_destroy(fill)
2125 fount_fill_destroy(i_fill_t *fill) {
2126 i_fill_fountain_t *f = (i_fill_fountain_t *)fill;
2127 fount_finish_state(&f->state);
2135 Arnar M. Hrafnkelsson <addi@umich.edu>
2137 Tony Cook <tony@develop-help.com> (i_fountain())