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);
987 i_nearest_color_foo(i_img *im, int num, int *xo, int *yo, i_color *ival, int dmeasure) {
990 int xsize = im->xsize;
991 int ysize = im->ysize;
993 mm_log((1,"i_gradgen(im %p, num %d, xo %p, yo %p, ival %p, dmeasure %d)\n", im, num, xo, yo, ival, dmeasure));
995 for(p = 0; p<num; p++) {
996 mm_log((1,"i_gradgen: (%d, %d)\n", xo[p], yo[p]));
1000 for(y = 0; y<ysize; y++) for(x = 0; x<xsize; x++) {
1009 case 0: /* euclidean */
1010 mindist = sqrt(xd*xd + yd*yd); /* euclidean distance */
1012 case 1: /* euclidean squared */
1013 mindist = xd*xd + yd*yd; /* euclidean distance */
1015 case 2: /* euclidean squared */
1016 mindist = max(xd*xd, yd*yd); /* manhattan distance */
1019 m_fatal(3,"i_nearest_color: Unknown distance measure\n");
1022 for(p = 1; p<num; p++) {
1026 case 0: /* euclidean */
1027 curdist = sqrt(xd*xd + yd*yd); /* euclidean distance */
1029 case 1: /* euclidean squared */
1030 curdist = xd*xd + yd*yd; /* euclidean distance */
1032 case 2: /* euclidean squared */
1033 curdist = max(xd*xd, yd*yd); /* manhattan distance */
1036 m_fatal(3,"i_nearest_color: Unknown distance measure\n");
1038 if (curdist < mindist) {
1043 i_ppix(im, x, y, &ival[midx]);
1048 i_nearest_color(i_img *im, int num, int *xo, int *yo, i_color *oval, int dmeasure) {
1054 int xsize = im->xsize;
1055 int ysize = im->ysize;
1058 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));
1060 tval = mymalloc( sizeof(float)*num*im->channels );
1061 ival = mymalloc( sizeof(i_color)*num );
1062 cmatch = mymalloc( sizeof(int)*num );
1064 for(p = 0; p<num; p++) {
1065 for(ch = 0; ch<im->channels; ch++) tval[ p * im->channels + ch] = 0;
1070 for(y = 0; y<ysize; y++) for(x = 0; x<xsize; x++) {
1079 case 0: /* euclidean */
1080 mindist = sqrt(xd*xd + yd*yd); /* euclidean distance */
1082 case 1: /* euclidean squared */
1083 mindist = xd*xd + yd*yd; /* euclidean distance */
1085 case 2: /* euclidean squared */
1086 mindist = max(xd*xd, yd*yd); /* manhattan distance */
1089 m_fatal(3,"i_nearest_color: Unknown distance measure\n");
1092 for(p = 1; p<num; p++) {
1096 case 0: /* euclidean */
1097 curdist = sqrt(xd*xd + yd*yd); /* euclidean distance */
1099 case 1: /* euclidean squared */
1100 curdist = xd*xd + yd*yd; /* euclidean distance */
1102 case 2: /* euclidean squared */
1103 curdist = max(xd*xd, yd*yd); /* manhattan distance */
1106 m_fatal(3,"i_nearest_color: Unknown distance measure\n");
1108 if (curdist < mindist) {
1115 i_gpix(im, x, y, &val);
1116 c2 = 1.0/(float)(cmatch[midx]);
1119 for(ch = 0; ch<im->channels; ch++)
1120 tval[midx*im->channels + ch] = c1*tval[midx*im->channels + ch] + c2 * (float) val.channel[ch];
1125 for(p = 0; p<num; p++) for(ch = 0; ch<im->channels; ch++) ival[p].channel[ch] = tval[p*im->channels + ch];
1127 i_nearest_color_foo(im, num, xo, yo, ival, dmeasure);
1131 =item i_unsharp_mask(im, stddev, scale)
1133 Perform an usharp mask, which is defined as subtracting the blurred
1134 image from double the original.
1138 void i_unsharp_mask(i_img *im, double stddev, double scale) {
1144 /* it really shouldn't ever be more than 1.0, but maybe ... */
1149 i_gaussian(©, stddev);
1150 if (im->bits == i_8_bits) {
1151 i_color *blur = mymalloc(im->xsize * sizeof(i_color) * 2);
1152 i_color *out = blur + im->xsize;
1154 for (y = 0; y < im->ysize; ++y) {
1155 i_glin(©, 0, copy.xsize, y, blur);
1156 i_glin(im, 0, im->xsize, y, out);
1157 for (x = 0; x < im->xsize; ++x) {
1158 for (ch = 0; ch < im->channels; ++ch) {
1159 /*int temp = out[x].channel[ch] +
1160 scale * (out[x].channel[ch] - blur[x].channel[ch]);*/
1161 int temp = out[x].channel[ch] * 2 - blur[x].channel[ch];
1164 else if (temp > 255)
1166 out[x].channel[ch] = temp;
1169 i_plin(im, 0, im->xsize, y, out);
1175 i_fcolor *blur = mymalloc(im->xsize * sizeof(i_fcolor) * 2);
1176 i_fcolor *out = blur + im->xsize;
1178 for (y = 0; y < im->ysize; ++y) {
1179 i_glinf(©, 0, copy.xsize, y, blur);
1180 i_glinf(im, 0, im->xsize, y, out);
1181 for (x = 0; x < im->xsize; ++x) {
1182 for (ch = 0; ch < im->channels; ++ch) {
1183 double temp = out[x].channel[ch] +
1184 scale * (out[x].channel[ch] - blur[x].channel[ch]);
1187 else if (temp > 1.0)
1189 out[x].channel[ch] = temp;
1192 i_plinf(im, 0, im->xsize, y, out);
1197 i_img_exorcise(©);
1201 static double linear_fount_f(double x, double y, struct fount_state *state);
1202 static double bilinear_fount_f(double x, double y, struct fount_state *state);
1203 static double radial_fount_f(double x, double y, struct fount_state *state);
1204 static double square_fount_f(double x, double y, struct fount_state *state);
1205 static double revolution_fount_f(double x, double y,
1206 struct fount_state *state);
1207 static double conical_fount_f(double x, double y, struct fount_state *state);
1209 typedef double (*fount_func)(double, double, struct fount_state *);
1210 static fount_func fount_funcs[] =
1220 static double linear_interp(double pos, i_fountain_seg *seg);
1221 static double sine_interp(double pos, i_fountain_seg *seg);
1222 static double sphereup_interp(double pos, i_fountain_seg *seg);
1223 static double spheredown_interp(double pos, i_fountain_seg *seg);
1224 typedef double (*fount_interp)(double pos, i_fountain_seg *seg);
1225 static fount_interp fount_interps[] =
1234 static void direct_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg);
1235 static void hue_up_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg);
1236 static void hue_down_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg);
1237 typedef void (*fount_cinterp)(i_fcolor *out, double pos, i_fountain_seg *seg);
1238 static fount_cinterp fount_cinterps[] =
1245 typedef double (*fount_repeat)(double v);
1246 static double fount_r_none(double v);
1247 static double fount_r_sawtooth(double v);
1248 static double fount_r_triangle(double v);
1249 static double fount_r_saw_both(double v);
1250 static double fount_r_tri_both(double v);
1251 static fount_repeat fount_repeats[] =
1260 static int simple_ssample(i_fcolor *out, double x, double y,
1261 struct fount_state *state);
1262 static int random_ssample(i_fcolor *out, double x, double y,
1263 struct fount_state *state);
1264 static int circle_ssample(i_fcolor *out, double x, double y,
1265 struct fount_state *state);
1266 typedef int (*fount_ssample)(i_fcolor *out, double x, double y,
1267 struct fount_state *state);
1268 static fount_ssample fount_ssamples[] =
1277 fount_getat(i_fcolor *out, double x, double y, struct fount_state *state);
1280 Keep state information used by each type of fountain fill
1282 struct fount_state {
1283 /* precalculated for the equation of the line perpendicular to the line AB */
1294 fount_repeat rpfunc;
1295 fount_ssample ssfunc;
1297 i_fountain_seg *segs;
1302 fount_init_state(struct fount_state *state, double xa, double ya,
1303 double xb, double yb, i_fountain_type type,
1304 i_fountain_repeat repeat, int combine, int super_sample,
1305 double ssample_param, int count, i_fountain_seg *segs);
1308 fount_finish_state(struct fount_state *state);
1310 #define EPSILON (1e-6)
1313 =item i_fountain(im, xa, ya, xb, yb, type, repeat, combine, super_sample, ssample_param, count, segs)
1315 Draws a fountain fill using A(xa, ya) and B(xb, yb) as reference points.
1317 I<type> controls how the reference points are used:
1323 linear, where A is 0 and B is 1.
1327 linear in both directions from A.
1331 circular, where A is the centre of the fill, and B is a point
1334 =item i_ft_radial_square
1336 where A is the centre of the fill and B is the centre of
1337 one side of the square.
1339 =item i_ft_revolution
1341 where A is the centre of the fill and B defines the 0/1.0
1346 similar to i_ft_revolution, except that the revolution goes in both
1351 I<repeat> can be one of:
1357 values < 0 are treated as zero, values > 1 are treated as 1.
1361 negative values are treated as 0, positive values are modulo 1.0
1365 negative values are treated as zero, if (int)value is odd then the value is treated as 1-(value
1366 mod 1.0), otherwise the same as for sawtooth.
1370 like i_fr_sawtooth, except that the sawtooth pattern repeats into
1375 Like i_fr_triangle, except that negative values are handled as their
1380 If combine is non-zero then non-opaque values are combined with the
1383 I<super_sample> controls super sampling, if any. At some point I'll
1384 probably add a adaptive super-sampler. Current possible values are:
1390 No super-sampling is done.
1394 A square grid of points withing the pixel are sampled.
1398 Random points within the pixel are sampled.
1402 Points on the radius of a circle are sampled. This produces fairly
1403 good results, but is fairly slow since sin() and cos() are evaluated
1408 I<ssample_param> is intended to be roughly the number of points
1409 sampled within the pixel.
1411 I<count> and I<segs> define the segments of the fill.
1418 i_fountain(i_img *im, double xa, double ya, double xb, double yb,
1419 i_fountain_type type, i_fountain_repeat repeat,
1420 int combine, int super_sample, double ssample_param,
1421 int count, i_fountain_seg *segs) {
1422 struct fount_state state;
1424 i_fcolor *line = mymalloc(sizeof(i_fcolor) * im->xsize);
1425 i_fcolor *work = NULL;
1427 i_fountain_seg *my_segs;
1428 i_fill_combine_f combine_func = NULL;
1429 i_fill_combinef_f combinef_func = NULL;
1431 i_get_combine(combine, &combine_func, &combinef_func);
1433 work = mymalloc(sizeof(i_fcolor) * im->xsize);
1435 fount_init_state(&state, xa, ya, xb, yb, type, repeat, combine,
1436 super_sample, ssample_param, count, segs);
1437 my_segs = state.segs;
1439 for (y = 0; y < im->ysize; ++y) {
1440 i_glinf(im, 0, im->xsize, y, line);
1441 for (x = 0; x < im->xsize; ++x) {
1444 if (super_sample == i_fts_none)
1445 got_one = fount_getat(&c, x, y, &state);
1447 got_one = state.ssfunc(&c, x, y, &state);
1456 combinef_func(line, work, im->channels, im->xsize);
1457 i_plinf(im, 0, im->xsize, y, line);
1459 fount_finish_state(&state);
1460 if (work) myfree(work);
1466 struct fount_state state;
1467 } i_fill_fountain_t;
1470 fill_fountf(i_fill_t *fill, int x, int y, int width, int channels,
1473 fount_fill_destroy(i_fill_t *fill);
1476 =item i_new_fount(xa, ya, xb, yb, type, repeat, combine, super_sample, ssample_param, count, segs)
1478 Creates a new general fill which fills with a fountain fill.
1484 i_new_fill_fount(double xa, double ya, double xb, double yb,
1485 i_fountain_type type, i_fountain_repeat repeat,
1486 int combine, int super_sample, double ssample_param,
1487 int count, i_fountain_seg *segs) {
1488 i_fill_fountain_t *fill = mymalloc(sizeof(i_fill_fountain_t));
1490 fill->base.fill_with_color = NULL;
1491 fill->base.fill_with_fcolor = fill_fountf;
1492 fill->base.destroy = fount_fill_destroy;
1494 i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
1496 fill->base.combine = NULL;
1497 fill->base.combinef = NULL;
1499 fount_init_state(&fill->state, xa, ya, xb, yb, type, repeat, combine,
1500 super_sample, ssample_param, count, segs);
1508 =head1 INTERNAL FUNCTIONS
1512 =item fount_init_state(...)
1514 Used by both the fountain fill filter and the fountain fill.
1520 fount_init_state(struct fount_state *state, double xa, double ya,
1521 double xb, double yb, i_fountain_type type,
1522 i_fountain_repeat repeat, int combine, int super_sample,
1523 double ssample_param, int count, i_fountain_seg *segs) {
1525 i_fountain_seg *my_segs = mymalloc(sizeof(i_fountain_seg) * count);
1526 /*int have_alpha = im->channels == 2 || im->channels == 4;*/
1528 memset(state, 0, sizeof(*state));
1529 /* we keep a local copy that we can adjust for speed */
1530 for (i = 0; i < count; ++i) {
1531 i_fountain_seg *seg = my_segs + i;
1534 if (seg->type < 0 || seg->type >= i_fst_end)
1535 seg->type = i_fst_linear;
1536 if (seg->color < 0 || seg->color >= i_fc_end)
1537 seg->color = i_fc_direct;
1538 if (seg->color == i_fc_hue_up || seg->color == i_fc_hue_down) {
1539 /* so we don't have to translate to HSV on each request, do it here */
1540 for (j = 0; j < 2; ++j) {
1541 i_rgb_to_hsvf(seg->c+j);
1543 if (seg->color == i_fc_hue_up) {
1544 if (seg->c[1].channel[0] <= seg->c[0].channel[0])
1545 seg->c[1].channel[0] += 1.0;
1548 if (seg->c[0].channel[0] <= seg->c[0].channel[1])
1549 seg->c[0].channel[0] += 1.0;
1552 /*printf("start %g mid %g end %g c0(%g,%g,%g,%g) c1(%g,%g,%g,%g) type %d color %d\n",
1553 seg->start, seg->middle, seg->end, seg->c[0].channel[0],
1554 seg->c[0].channel[1], seg->c[0].channel[2], seg->c[0].channel[3],
1555 seg->c[1].channel[0], seg->c[1].channel[1], seg->c[1].channel[2],
1556 seg->c[1].channel[3], seg->type, seg->color);*/
1560 /* initialize each engine */
1561 /* these are so common ... */
1562 state->lA = xb - xa;
1563 state->lB = yb - ya;
1564 state->AB = sqrt(state->lA * state->lA + state->lB * state->lB);
1569 type = i_ft_linear; /* make the invalid value valid */
1572 state->lC = ya * ya - ya * yb + xa * xa - xa * xb;
1574 state->mult = 1/linear_fount_f(xb, yb, state);
1578 state->mult = 1.0 / sqrt((double)(xb-xa)*(xb-xa)
1579 + (double)(yb-ya)*(yb-ya));
1582 case i_ft_radial_square:
1583 state->cos = state->lA / state->AB;
1584 state->sin = state->lB / state->AB;
1585 state->mult = 1.0 / state->AB;
1588 case i_ft_revolution:
1589 state->theta = atan2(yb-ya, xb-xa);
1590 state->mult = 1.0 / (PI * 2);
1594 state->theta = atan2(yb-ya, xb-xa);
1595 state->mult = 1.0 / PI;
1598 state->ffunc = fount_funcs[type];
1599 if (super_sample < 0
1600 || super_sample >= (int)(sizeof(fount_ssamples)/sizeof(*fount_ssamples))) {
1603 state->ssample_data = NULL;
1604 switch (super_sample) {
1606 ssample_param = floor(0.5 + sqrt(ssample_param));
1607 state->ssample_data = mymalloc(sizeof(i_fcolor) * ssample_param * ssample_param);
1612 ssample_param = floor(0.5+ssample_param);
1613 state->ssample_data = mymalloc(sizeof(i_fcolor) * ssample_param);
1616 state->parm = ssample_param;
1617 state->ssfunc = fount_ssamples[super_sample];
1618 if (repeat < 0 || repeat >= (sizeof(fount_repeats)/sizeof(*fount_repeats)))
1620 state->rpfunc = fount_repeats[repeat];
1621 state->segs = my_segs;
1622 state->count = count;
1626 fount_finish_state(struct fount_state *state) {
1627 if (state->ssample_data)
1628 myfree(state->ssample_data);
1629 myfree(state->segs);
1634 =item fount_getat(out, x, y, ffunc, rpfunc, state, segs, count)
1636 Evaluates the fountain fill at the given point.
1638 This is called by both the non-super-sampling and super-sampling code.
1640 You might think that it would make sense to sample the fill parameter
1641 instead, and combine those, but this breaks badly.
1647 fount_getat(i_fcolor *out, double x, double y, struct fount_state *state) {
1648 double v = (state->rpfunc)((state->ffunc)(x, y, state));
1652 while (i < state->count
1653 && (v < state->segs[i].start || v > state->segs[i].end)) {
1656 if (i < state->count) {
1657 v = (fount_interps[state->segs[i].type])(v, state->segs+i);
1658 (fount_cinterps[state->segs[i].color])(out, v, state->segs+i);
1666 =item linear_fount_f(x, y, state)
1668 Calculate the fill parameter for a linear fountain fill.
1670 Uses the point to line distance function, with some precalculation
1671 done in i_fountain().
1676 linear_fount_f(double x, double y, struct fount_state *state) {
1677 return (state->lA * x + state->lB * y + state->lC) / state->AB * state->mult;
1681 =item bilinear_fount_f(x, y, state)
1683 Calculate the fill parameter for a bi-linear fountain fill.
1688 bilinear_fount_f(double x, double y, struct fount_state *state) {
1689 return fabs((state->lA * x + state->lB * y + state->lC) / state->AB * state->mult);
1693 =item radial_fount_f(x, y, state)
1695 Calculate the fill parameter for a radial fountain fill.
1697 Simply uses the distance function.
1702 radial_fount_f(double x, double y, struct fount_state *state) {
1703 return sqrt((double)(state->xa-x)*(state->xa-x)
1704 + (double)(state->ya-y)*(state->ya-y)) * state->mult;
1708 =item square_fount_f(x, y, state)
1710 Calculate the fill parameter for a square fountain fill.
1712 Works by rotating the reference co-ordinate around the centre of the
1718 square_fount_f(double x, double y, struct fount_state *state) {
1719 int xc, yc; /* centred on A */
1720 double xt, yt; /* rotated by theta */
1723 xt = fabs(xc * state->cos + yc * state->sin);
1724 yt = fabs(-xc * state->sin + yc * state->cos);
1725 return (xt > yt ? xt : yt) * state->mult;
1729 =item revolution_fount_f(x, y, state)
1731 Calculates the fill parameter for the revolution fountain fill.
1736 revolution_fount_f(double x, double y, struct fount_state *state) {
1737 double angle = atan2(y - state->ya, x - state->xa);
1739 angle -= state->theta;
1741 angle = fmod(angle+ PI * 4, PI*2);
1744 return angle * state->mult;
1748 =item conical_fount_f(x, y, state)
1750 Calculates the fill parameter for the conical fountain fill.
1755 conical_fount_f(double x, double y, struct fount_state *state) {
1756 double angle = atan2(y - state->ya, x - state->xa);
1758 angle -= state->theta;
1761 else if (angle > PI)
1764 return fabs(angle) * state->mult;
1768 =item linear_interp(pos, seg)
1770 Calculates linear interpolation on the fill parameter. Breaks the
1771 segment into 2 regions based in the I<middle> value.
1776 linear_interp(double pos, i_fountain_seg *seg) {
1777 if (pos < seg->middle) {
1778 double len = seg->middle - seg->start;
1782 return (pos - seg->start) / len / 2;
1785 double len = seg->end - seg->middle;
1789 return 0.5 + (pos - seg->middle) / len / 2;
1794 =item sine_interp(pos, seg)
1796 Calculates sine function interpolation on the fill parameter.
1801 sine_interp(double pos, i_fountain_seg *seg) {
1802 /* I wonder if there's a simple way to smooth the transition for this */
1803 double work = linear_interp(pos, seg);
1805 return (1-cos(work * PI))/2;
1809 =item sphereup_interp(pos, seg)
1811 Calculates spherical interpolation on the fill parameter, with the cusp
1817 sphereup_interp(double pos, i_fountain_seg *seg) {
1818 double work = linear_interp(pos, seg);
1820 return sqrt(1.0 - (1-work) * (1-work));
1824 =item spheredown_interp(pos, seg)
1826 Calculates spherical interpolation on the fill parameter, with the cusp
1832 spheredown_interp(double pos, i_fountain_seg *seg) {
1833 double work = linear_interp(pos, seg);
1835 return 1-sqrt(1.0 - work * work);
1839 =item direct_cinterp(out, pos, seg)
1841 Calculates the fountain color based on direct scaling of the channels
1842 of the color channels.
1847 direct_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg) {
1849 for (ch = 0; ch < MAXCHANNELS; ++ch) {
1850 out->channel[ch] = seg->c[0].channel[ch] * (1 - pos)
1851 + seg->c[1].channel[ch] * pos;
1856 =item hue_up_cinterp(put, pos, seg)
1858 Calculates the fountain color based on scaling a HSV value. The hue
1859 increases as the fill parameter increases.
1864 hue_up_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg) {
1866 for (ch = 0; ch < MAXCHANNELS; ++ch) {
1867 out->channel[ch] = seg->c[0].channel[ch] * (1 - pos)
1868 + seg->c[1].channel[ch] * pos;
1874 =item hue_down_cinterp(put, pos, seg)
1876 Calculates the fountain color based on scaling a HSV value. The hue
1877 decreases as the fill parameter increases.
1882 hue_down_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg) {
1884 for (ch = 0; ch < MAXCHANNELS; ++ch) {
1885 out->channel[ch] = seg->c[0].channel[ch] * (1 - pos)
1886 + seg->c[1].channel[ch] * pos;
1892 =item simple_ssample(out, parm, x, y, state, ffunc, rpfunc, segs, count)
1894 Simple grid-based super-sampling.
1899 simple_ssample(i_fcolor *out, double x, double y, struct fount_state *state) {
1900 i_fcolor *work = state->ssample_data;
1902 int grid = state->parm;
1903 double base = -0.5 + 0.5 / grid;
1904 double step = 1.0 / grid;
1908 for (dx = 0; dx < grid; ++dx) {
1909 for (dy = 0; dy < grid; ++dy) {
1910 if (fount_getat(work+samp_count, x + base + step * dx,
1911 y + base + step * dy, state)) {
1916 for (ch = 0; ch < MAXCHANNELS; ++ch) {
1917 out->channel[ch] = 0;
1918 for (i = 0; i < samp_count; ++i) {
1919 out->channel[ch] += work[i].channel[ch];
1921 /* we divide by 4 rather than samp_count since if there's only one valid
1922 sample it should be mostly transparent */
1923 out->channel[ch] /= grid * grid;
1929 =item random_ssample(out, parm, x, y, state, ffunc, rpfunc, segs, count)
1931 Random super-sampling.
1936 random_ssample(i_fcolor *out, double x, double y,
1937 struct fount_state *state) {
1938 i_fcolor *work = state->ssample_data;
1940 int maxsamples = state->parm;
1941 double rand_scale = 1.0 / RAND_MAX;
1943 for (i = 0; i < maxsamples; ++i) {
1944 if (fount_getat(work+samp_count, x - 0.5 + rand() * rand_scale,
1945 y - 0.5 + rand() * rand_scale, state)) {
1949 for (ch = 0; ch < MAXCHANNELS; ++ch) {
1950 out->channel[ch] = 0;
1951 for (i = 0; i < samp_count; ++i) {
1952 out->channel[ch] += work[i].channel[ch];
1954 /* we divide by maxsamples rather than samp_count since if there's
1955 only one valid sample it should be mostly transparent */
1956 out->channel[ch] /= maxsamples;
1962 =item circle_ssample(out, parm, x, y, state, ffunc, rpfunc, segs, count)
1964 Super-sampling around the circumference of a circle.
1966 I considered saving the sin()/cos() values and transforming step-size
1967 around the circle, but that's inaccurate, though it may not matter
1973 circle_ssample(i_fcolor *out, double x, double y,
1974 struct fount_state *state) {
1975 i_fcolor *work = state->ssample_data;
1977 int maxsamples = state->parm;
1978 double angle = 2 * PI / maxsamples;
1979 double radius = 0.3; /* semi-random */
1981 for (i = 0; i < maxsamples; ++i) {
1982 if (fount_getat(work+samp_count, x + radius * cos(angle * i),
1983 y + radius * sin(angle * i), state)) {
1987 for (ch = 0; ch < MAXCHANNELS; ++ch) {
1988 out->channel[ch] = 0;
1989 for (i = 0; i < samp_count; ++i) {
1990 out->channel[ch] += work[i].channel[ch];
1992 /* we divide by maxsamples rather than samp_count since if there's
1993 only one valid sample it should be mostly transparent */
1994 out->channel[ch] /= maxsamples;
2000 =item fount_r_none(v)
2002 Implements no repeats. Simply clamps the fill value.
2007 fount_r_none(double v) {
2008 return v < 0 ? 0 : v > 1 ? 1 : v;
2012 =item fount_r_sawtooth(v)
2014 Implements sawtooth repeats. Clamps negative values and uses fmod()
2020 fount_r_sawtooth(double v) {
2021 return v < 0 ? 0 : fmod(v, 1.0);
2025 =item fount_r_triangle(v)
2027 Implements triangle repeats. Clamps negative values, uses fmod to get
2028 a range 0 through 2 and then adjusts values > 1.
2033 fount_r_triangle(double v) {
2038 return v > 1.0 ? 2.0 - v : v;
2043 =item fount_r_saw_both(v)
2045 Implements sawtooth repeats in the both postive and negative directions.
2047 Adjusts the value to be postive and then just uses fmod().
2052 fount_r_saw_both(double v) {
2055 return fmod(v, 1.0);
2059 =item fount_r_tri_both(v)
2061 Implements triangle repeats in the both postive and negative directions.
2063 Uses fmod on the absolute value, and then adjusts values > 1.
2068 fount_r_tri_both(double v) {
2069 v = fmod(fabs(v), 2.0);
2070 return v > 1.0 ? 2.0 - v : v;
2074 =item fill_fountf(fill, x, y, width, channels, data)
2076 The fill function for fountain fills.
2081 fill_fountf(i_fill_t *fill, int x, int y, int width, int channels,
2083 i_fill_fountain_t *f = (i_fill_fountain_t *)fill;
2089 if (f->state.ssfunc)
2090 got_one = f->state.ssfunc(&c, x, y, &f->state);
2092 got_one = fount_getat(&c, x, y, &f->state);
2101 =item fount_fill_destroy(fill)
2106 fount_fill_destroy(i_fill_t *fill) {
2107 i_fill_fountain_t *f = (i_fill_fountain_t *)fill;
2108 fount_finish_state(&f->state);
2116 Arnar M. Hrafnkelsson <addi@umich.edu>
2118 Tony Cook <tony@develop-help.com> (i_fountain())