10 filters.im - implements filters that operate on images
18 i_unsharp_mask(im, 2.0, 1.0);
23 filters.c implements basic filters for Imager. These filters
24 should be accessible from the filter interface as defined in
27 =head1 FUNCTION REFERENCE
29 Some of these functions are internal.
42 Clamps the input value between 0 and 255. (internal)
52 if (in>255) { return 255; }
53 else if (in>0) return in;
60 =item i_contrast(im, intensity)
62 Scales the pixel values by the amount specified.
65 intensity - scalefactor
71 i_contrast(i_img *im, float intensity) {
74 unsigned int new_color;
77 mm_log((1,"i_contrast(im %p, intensity %f)\n", im, intensity));
79 if(intensity < 0) return;
81 for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
82 i_gpix(im, x, y, &rcolor);
84 for(ch = 0; ch < im->channels; ch++) {
85 new_color = (unsigned int) rcolor.channel[ch];
86 new_color *= intensity;
91 rcolor.channel[ch] = (unsigned char) new_color;
93 i_ppix(im, x, y, &rcolor);
99 s_hardinvert_low(i_img *im, int all) {
102 int invert_channels = all ? im->channels : i_img_color_channels(im);
104 mm_log((1,"i_hardinvert(im %p)\n", im));
107 IM_COLOR *row, *entry;
109 /* always rooms to allocate a single line of i_color */
110 row = mymalloc(sizeof(IM_COLOR) * im->xsize); /* checked 17feb2005 tonyc */
112 for(y = 0; y < im->ysize; y++) {
113 IM_GLIN(im, 0, im->xsize, y, row);
115 for(x = 0; x < im->xsize; x++) {
116 for(ch = 0; ch < invert_channels; ch++) {
117 entry->channel[ch] = IM_SAMPLE_MAX - entry->channel[ch];
121 IM_PLIN(im, 0, im->xsize, y, row);
130 =item i_hardinvert(im)
132 Inverts the color channels of the input image.
140 i_hardinvert(i_img *im) {
141 s_hardinvert_low(im, 0);
145 =item i_hardinvertall(im)
147 Inverts all channels of the input image.
155 i_hardinvertall(i_img *im) {
156 s_hardinvert_low(im, 1);
160 =item i_noise(im, amount, type)
162 Inverts the pixel values by the amount specified.
165 amount - deviation in pixel values
166 type - noise individual for each channel if true
172 /* random() is non-ASCII, even if it is better than rand() */
173 #define random() rand()
177 i_noise(i_img *im, float amount, unsigned char type) {
181 float damount = amount * 2;
185 mm_log((1,"i_noise(im %p, intensity %.2f\n", im, amount));
187 if(amount < 0) return;
189 for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
190 i_gpix(im, x, y, &rcolor);
193 color_inc = (amount - (damount * ((float)random() / RAND_MAX)));
196 for(ch = 0; ch < im->channels; ch++) {
197 new_color = (int) rcolor.channel[ch];
200 new_color += (amount - (damount * ((float)random() / RAND_MAX)));
202 new_color += color_inc;
208 if(new_color > 255) {
212 rcolor.channel[ch] = (unsigned char) new_color;
215 i_ppix(im, x, y, &rcolor);
221 =item i_noise(im, amount, type)
223 Inverts the pixel values by the amount specified.
226 amount - deviation in pixel values
227 type - noise individual for each channel if true
234 =item i_applyimage(im, add_im, mode)
236 Apply's an image to another image
239 add_im - image that is applied to target
240 mode - what method is used in applying:
260 void i_applyimage(i_img *im, i_img *add_im, unsigned char mode) {
264 mm_log((1, "i_applyimage(im %p, add_im %p, mode %d", im, add_im, mode));
266 mx = (add_im->xsize <= im->xsize) ? add_im->xsize : add_im->xsize;
267 my = (add_im->ysize <= im->ysize) ? add_im->ysize : add_im->ysize;
269 for(x = 0; x < mx; x++) {
270 for(y = 0; y < my; y++) {
277 =item i_bumpmap(im, bump, channel, light_x, light_y, st)
279 Makes a bumpmap on image im using the bump image as the elevation map.
282 bump - image that contains the elevation info
283 channel - to take the elevation information from
284 light_x - x coordinate of light source
285 light_y - y coordinate of light source
286 st - length of shadow
292 i_bumpmap(i_img *im, i_img *bump, int channel, int light_x, int light_y, int st) {
295 i_color x1_color, y1_color, x2_color, y2_color, dst_color;
300 unsigned char px1, px2, py1, py2;
304 mm_log((1, "i_bumpmap(im %p, add_im %p, channel %d, light_x %d, light_y %d, st %d)\n",
305 im, bump, channel, light_x, light_y, st));
308 if(channel >= bump->channels) {
309 mm_log((1, "i_bumpmap: channel = %d while bump image only has %d channels\n", channel, bump->channels));
313 mx = (bump->xsize <= im->xsize) ? bump->xsize : im->xsize;
314 my = (bump->ysize <= im->ysize) ? bump->ysize : im->ysize;
316 i_img_empty_ch(&new_im, im->xsize, im->ysize, im->channels);
318 aX = (light_x > (mx >> 1)) ? light_x : mx - light_x;
319 aY = (light_y > (my >> 1)) ? light_y : my - light_y;
321 aL = sqrt((aX * aX) + (aY * aY));
323 for(y = 1; y < my - 1; y++) {
324 for(x = 1; x < mx - 1; x++) {
325 i_gpix(bump, x + st, y, &x1_color);
326 i_gpix(bump, x, y + st, &y1_color);
327 i_gpix(bump, x - st, y, &x2_color);
328 i_gpix(bump, x, y - st, &y2_color);
330 i_gpix(im, x, y, &dst_color);
332 px1 = x1_color.channel[channel];
333 py1 = y1_color.channel[channel];
334 px2 = x2_color.channel[channel];
335 py2 = y2_color.channel[channel];
343 fZ = (sqrt((nX * nX) + (nY * nY)) / aL);
345 tX = abs(x - light_x) / aL;
346 tY = abs(y - light_y) / aL;
348 tZ = 1 - (sqrt((tX * tX) + (tY * tY)) * fZ);
353 for(ch = 0; ch < im->channels; ch++)
354 dst_color.channel[ch] = (unsigned char) (float)(dst_color.channel[ch] * tZ);
356 i_ppix(&new_im, x, y, &dst_color);
360 i_copyto(im, &new_im, 0, 0, (int)im->xsize, (int)im->ysize, 0, 0);
362 i_img_exorcise(&new_im);
375 dotp(fvec *a, fvec *b) {
376 return a->x*b->x+a->y*b->y+a->z*b->z;
382 double d = sqrt(dotp(a,a));
396 I = Ia + Ip*( cd*Scol(N.L) + cs*(R.V)^n )
398 Here, the variables are:
400 * Ia - ambient colour
401 * Ip - intensity of the point light source
402 * cd - diffuse coefficient
403 * Scol - surface colour
404 * cs - specular coefficient
405 * n - objects shinyness
407 * L - lighting vector
408 * R - reflection vector
411 static void fvec_dump(fvec *x) {
412 printf("(%.2f %.2f %.2f)", x->x, x->y, x->z);
416 /* XXX: Should these return a code for success? */
422 =item i_bumpmap_complex(im, bump, channel, tx, ty, Lx, Ly, Lz, Ip, cd, cs, n, Ia, Il, Is)
424 Makes a bumpmap on image im using the bump image as the elevation map.
427 bump - image that contains the elevation info
428 channel - to take the elevation information from
429 tx - shift in x direction of where to start applying bumpmap
430 ty - shift in y direction of where to start applying bumpmap
431 Lx - x position/direction of light
432 Ly - y position/direction of light
433 Lz - z position/direction of light
435 cd - diffuse coefficient
436 cs - specular coefficient
437 n - surface shinyness
442 if z<0 then the L is taken to be the direction the light is shining in. Otherwise
443 the L is taken to be the position of the Light, Relative to the image.
450 i_bumpmap_complex(i_img *im,
470 float cdc[MAXCHANNELS];
471 float csc[MAXCHANNELS];
473 i_color x1_color, y1_color, x2_color, y2_color;
475 i_color Scol; /* Surface colour */
477 fvec L; /* Light vector */
478 fvec N; /* surface normal */
479 fvec R; /* Reflection vector */
480 fvec V; /* Vision vector */
482 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",
483 im, bump, channel, tx, ty, Lx, Ly, Lz, cd, cs, n, Ia, Il, Is));
485 if (channel >= bump->channels) {
486 mm_log((1, "i_bumpmap_complex: channel = %d while bump image only has %d channels\n", channel, bump->channels));
490 for(ch=0; ch<im->channels; ch++) {
491 cdc[ch] = (float)Il->channel[ch]*cd/255.f;
492 csc[ch] = (float)Is->channel[ch]*cs/255.f;
504 if (Lz < 0) { /* Light specifies a direction vector, reverse it to get the vector from surface to light */
509 } else { /* Light is the position of the light source */
517 i_img_empty_ch(&new_im, im->xsize, im->ysize, im->channels);
519 for(y = 0; y < im->ysize; y++) {
520 for(x = 0; x < im->xsize; x++) {
522 double dx = 0, dy = 0;
524 /* Calculate surface normal */
525 if (mx<x && x<Mx && my<y && y<My) {
526 i_gpix(bump, x + 1, y, &x1_color);
527 i_gpix(bump, x - 1, y, &x2_color);
528 i_gpix(bump, x, y + 1, &y1_color);
529 i_gpix(bump, x, y - 1, &y2_color);
530 dx = x2_color.channel[channel] - x1_color.channel[channel];
531 dy = y2_color.channel[channel] - y1_color.channel[channel];
541 /* Calculate Light vector if needed */
550 R.x = -L.x + 2*dp1*N.x;
551 R.y = -L.y + 2*dp1*N.y;
552 R.z = -L.z + 2*dp1*N.z;
556 dp1 = dp1<0 ?0 : dp1;
557 dp2 = pow(dp2<0 ?0 : dp2,n);
559 i_gpix(im, x, y, &Scol);
561 for(ch = 0; ch < im->channels; ch++)
563 saturate( Ia->channel[ch] + cdc[ch]*Scol.channel[ch]*dp1 + csc[ch]*dp2 );
565 i_ppix(&new_im, x, y, &Scol);
569 i_copyto(im, &new_im, 0, 0, (int)im->xsize, (int)im->ysize, 0, 0);
570 i_img_exorcise(&new_im);
575 =item i_postlevels(im, levels)
577 Quantizes Images to fewer levels.
580 levels - number of levels
586 i_postlevels(i_img *im, int levels) {
594 rv = (int) ((float)(256 / levels));
597 for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
598 i_gpix(im, x, y, &rcolor);
600 for(ch = 0; ch < im->channels; ch++) {
601 pv = (((float)rcolor.channel[ch] / 255)) * av;
602 pv = (int) ((int)pv * rv);
605 else if(pv > 255) pv = 255;
607 rcolor.channel[ch] = (unsigned char) pv;
609 i_ppix(im, x, y, &rcolor);
615 =item i_mosaic(im, size)
617 Makes an image looks like a mosaic with tilesize of size
626 i_mosaic(i_img *im, int size) {
634 sqrsize = size * size;
636 for(y = 0; y < im->ysize; y += size) for(x = 0; x < im->xsize; x += size) {
637 for(z = 0; z < 256; z++) col[z] = 0;
639 for(lx = 0; lx < size; lx++) {
640 for(ly = 0; ly < size; ly++) {
641 i_gpix(im, (x + lx), (y + ly), &rcolor);
643 for(ch = 0; ch < im->channels; ch++) {
644 col[ch] += rcolor.channel[ch];
649 for(ch = 0; ch < im->channels; ch++)
650 rcolor.channel[ch] = (int) ((float)col[ch] / sqrsize);
653 for(lx = 0; lx < size; lx++)
654 for(ly = 0; ly < size; ly++)
655 i_ppix(im, (x + lx), (y + ly), &rcolor);
662 =item i_watermark(im, wmark, tx, ty, pixdiff)
664 Applies a watermark to the target image
667 wmark - watermark image
668 tx - x coordinate of where watermark should be applied
669 ty - y coordinate of where watermark should be applied
670 pixdiff - the magnitude of the watermark, controls how visible it is
676 i_watermark(i_img *im, i_img *wmark, int tx, int ty, int pixdiff) {
680 int mx = wmark->xsize;
681 int my = wmark->ysize;
683 for(vx=0;vx<mx;vx++) for(vy=0;vy<my;vy++) {
685 i_gpix(im, tx+vx, ty+vy,&val );
686 i_gpix(wmark, vx, vy, &wval);
688 for(ch=0;ch<im->channels;ch++)
689 val.channel[ch] = saturate( val.channel[ch] + (pixdiff* (wval.channel[0]-128) )/128 );
691 i_ppix(im,tx+vx,ty+vy,&val);
697 =item i_autolevels(im, lsat, usat, skew)
699 Scales and translates each color such that it fills the range completely.
700 Skew is not implemented yet - purpose is to control the color skew that can
701 occur when changing the contrast.
704 lsat - fraction of pixels that will be truncated at the lower end of the spectrum
705 usat - fraction of pixels that will be truncated at the higher end of the spectrum
712 i_autolevels(i_img *im, float lsat, float usat, float skew) {
714 int i, x, y, rhist[256], ghist[256], bhist[256];
715 int rsum, rmin, rmax;
716 int gsum, gmin, gmax;
717 int bsum, bmin, bmax;
718 int rcl, rcu, gcl, gcu, bcl, bcu;
720 mm_log((1,"i_autolevels(im %p, lsat %f,usat %f,skew %f)\n", im, lsat,usat,skew));
723 for(i=0;i<256;i++) rhist[i]=ghist[i]=bhist[i] = 0;
724 /* create histogram for each channel */
725 for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
726 i_gpix(im, x, y, &val);
727 rhist[val.channel[0]]++;
728 ghist[val.channel[1]]++;
729 bhist[val.channel[2]]++;
738 rmin = gmin = bmin = 0;
739 rmax = gmax = bmax = 255;
741 rcu = rcl = gcu = gcl = bcu = bcl = 0;
743 for(i=0; i<256; i++) {
744 rcl += rhist[i]; if ( (rcl<rsum*lsat) ) rmin=i;
745 rcu += rhist[255-i]; if ( (rcu<rsum*usat) ) rmax=255-i;
747 gcl += ghist[i]; if ( (gcl<gsum*lsat) ) gmin=i;
748 gcu += ghist[255-i]; if ( (gcu<gsum*usat) ) gmax=255-i;
750 bcl += bhist[i]; if ( (bcl<bsum*lsat) ) bmin=i;
751 bcu += bhist[255-i]; if ( (bcu<bsum*usat) ) bmax=255-i;
754 for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
755 i_gpix(im, x, y, &val);
756 val.channel[0]=saturate((val.channel[0]-rmin)*255/(rmax-rmin));
757 val.channel[1]=saturate((val.channel[1]-gmin)*255/(gmax-gmin));
758 val.channel[2]=saturate((val.channel[2]-bmin)*255/(bmax-bmin));
759 i_ppix(im, x, y, &val);
766 Pseudo noise utility function used to generate perlin noise. (internal)
776 Noise(int x, int y) {
779 return ( 1.0 - ( (n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff) / 1073741824.0);
783 =item SmoothedNoise1(x,y)
785 Pseudo noise utility function used to generate perlin noise. (internal)
795 SmoothedNoise1(float x, float y) {
796 float corners = ( Noise(x-1, y-1)+Noise(x+1, y-1)+Noise(x-1, y+1)+Noise(x+1, y+1) ) / 16;
797 float sides = ( Noise(x-1, y) +Noise(x+1, y) +Noise(x, y-1) +Noise(x, y+1) ) / 8;
798 float center = Noise(x, y) / 4;
799 return corners + sides + center;
804 =item G_Interpolate(a, b, x)
806 Utility function used to generate perlin noise. (internal)
812 float C_Interpolate(float a, float b, float x) {
813 /* float ft = x * 3.1415927; */
815 float f = (1 - cos(ft)) * .5;
816 return a*(1-f) + b*f;
821 =item InterpolatedNoise(x, y)
823 Utility function used to generate perlin noise. (internal)
830 InterpolatedNoise(float x, float y) {
833 float fractional_X = x - integer_X;
835 float fractional_Y = y - integer_Y;
837 float v1 = SmoothedNoise1(integer_X, integer_Y);
838 float v2 = SmoothedNoise1(integer_X + 1, integer_Y);
839 float v3 = SmoothedNoise1(integer_X, integer_Y + 1);
840 float v4 = SmoothedNoise1(integer_X + 1, integer_Y + 1);
842 float i1 = C_Interpolate(v1 , v2 , fractional_X);
843 float i2 = C_Interpolate(v3 , v4 , fractional_X);
845 return C_Interpolate(i1 , i2 , fractional_Y);
851 =item PerlinNoise_2D(x, y)
853 Utility function used to generate perlin noise. (internal)
860 PerlinNoise_2D(float x, float y) {
864 int Number_Of_Octaves=6;
865 int n = Number_Of_Octaves - 1;
870 total = total + InterpolatedNoise(x * frequency, y * frequency) * amplitude;
878 =item i_radnoise(im, xo, yo, rscale, ascale)
880 Perlin-like radial noise.
883 xo - x coordinate of center
884 yo - y coordinate of center
885 rscale - radial scale
886 ascale - angular scale
892 i_radnoise(i_img *im, int xo, int yo, float rscale, float ascale) {
899 for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
900 xc = (float)x-xo+0.5;
901 yc = (float)y-yo+0.5;
902 r = rscale*sqrt(xc*xc+yc*yc)+1.2;
903 a = (PI+atan2(yc,xc))*ascale;
904 v = saturate(128+100*(PerlinNoise_2D(a,r)));
905 /* v=saturate(120+12*PerlinNoise_2D(xo+(float)x/scale,yo+(float)y/scale)); Good soft marble */
906 for(ch=0; ch<im->channels; ch++) val.channel[ch]=v;
907 i_ppix(im, x, y, &val);
913 =item i_turbnoise(im, xo, yo, scale)
915 Perlin-like 2d noise noise.
918 xo - x coordinate translation
919 yo - y coordinate translation
920 scale - scale of noise
926 i_turbnoise(i_img *im, float xo, float yo, float scale) {
931 for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
932 /* v=saturate(125*(1.0+PerlinNoise_2D(xo+(float)x/scale,yo+(float)y/scale))); */
933 v = saturate(120*(1.0+sin(xo+(float)x/scale+PerlinNoise_2D(xo+(float)x/scale,yo+(float)y/scale))));
934 for(ch=0; ch<im->channels; ch++) val.channel[ch] = v;
935 i_ppix(im, x, y, &val);
942 =item i_gradgen(im, num, xo, yo, ival, dmeasure)
944 Gradient generating function.
947 num - number of points given
948 xo - array of x coordinates
949 yo - array of y coordinates
950 ival - array of i_color objects
951 dmeasure - distance measure to be used.
953 1 = Euclidean squared
954 2 = Manhattan distance
961 i_gradgen(i_img *im, int num, int *xo, int *yo, i_color *ival, int dmeasure) {
965 int channels = im->channels;
966 int xsize = im->xsize;
967 int ysize = im->ysize;
972 mm_log((1,"i_gradgen(im %p, num %d, xo %p, yo %p, ival %p, dmeasure %d)\n", im, num, xo, yo, ival, dmeasure));
974 for(p = 0; p<num; p++) {
975 mm_log((1,"i_gradgen: (%d, %d)\n", xo[p], yo[p]));
979 /* on the systems I have sizeof(float) == sizeof(int) and thus
980 this would be same size as the arrays xo and yo point at, but this
981 may not be true for other systems
983 since the arrays here are caller controlled, I assume that on
984 overflow is a programming error rather than an end-user error, so
985 calling exit() is justified.
987 bytes = sizeof(float) * num;
988 if (bytes / num != sizeof(float)) {
989 fprintf(stderr, "integer overflow calculating memory allocation");
992 fdist = mymalloc( bytes ); /* checked 14jul05 tonyc */
994 for(y = 0; y<ysize; y++) for(x = 0; x<xsize; x++) {
997 for(p = 0; p<num; p++) {
1001 case 0: /* euclidean */
1002 fdist[p] = sqrt(xd*xd + yd*yd); /* euclidean distance */
1004 case 1: /* euclidean squared */
1005 fdist[p] = xd*xd + yd*yd; /* euclidean distance */
1007 case 2: /* euclidean squared */
1008 fdist[p] = i_max(xd*xd, yd*yd); /* manhattan distance */
1011 i_fatal(3,"i_gradgen: Unknown distance measure\n");
1016 csd = 1/((num-1)*cs);
1018 for(p = 0; p<num; p++) fdist[p] = (cs-fdist[p])*csd;
1020 for(ch = 0; ch<channels; ch++) {
1022 for(p = 0; p<num; p++) tres += ival[p].channel[ch] * fdist[p];
1023 val.channel[ch] = saturate(tres);
1025 i_ppix(im, x, y, &val);
1032 i_nearest_color_foo(i_img *im, int num, int *xo, int *yo, i_color *ival, int dmeasure) {
1035 int xsize = im->xsize;
1036 int ysize = im->ysize;
1038 mm_log((1,"i_gradgen(im %p, num %d, xo %p, yo %p, ival %p, dmeasure %d)\n", im, num, xo, yo, ival, dmeasure));
1040 for(p = 0; p<num; p++) {
1041 mm_log((1,"i_gradgen: (%d, %d)\n", xo[p], yo[p]));
1045 for(y = 0; y<ysize; y++) for(x = 0; x<xsize; x++) {
1054 case 0: /* euclidean */
1055 mindist = sqrt(xd*xd + yd*yd); /* euclidean distance */
1057 case 1: /* euclidean squared */
1058 mindist = xd*xd + yd*yd; /* euclidean distance */
1060 case 2: /* euclidean squared */
1061 mindist = i_max(xd*xd, yd*yd); /* manhattan distance */
1064 i_fatal(3,"i_nearest_color: Unknown distance measure\n");
1067 for(p = 1; p<num; p++) {
1071 case 0: /* euclidean */
1072 curdist = sqrt(xd*xd + yd*yd); /* euclidean distance */
1074 case 1: /* euclidean squared */
1075 curdist = xd*xd + yd*yd; /* euclidean distance */
1077 case 2: /* euclidean squared */
1078 curdist = i_max(xd*xd, yd*yd); /* manhattan distance */
1081 i_fatal(3,"i_nearest_color: Unknown distance measure\n");
1083 if (curdist < mindist) {
1088 i_ppix(im, x, y, &ival[midx]);
1093 =item i_nearest_color(im, num, xo, yo, oval, dmeasure)
1095 This wasn't document - quoth Addi:
1097 An arty type of filter
1099 FIXME: check IRC logs for actual text.
1107 i_img *im - image to render on.
1111 int num - number of points/colors in xo, yo, oval
1115 int *xo - array of I<num> x positions
1119 int *yo - array of I<num> y positions
1123 i_color *oval - array of I<num> colors
1125 xo, yo, oval correspond to each other, the point xo[i], yo[i] has a
1126 color something like oval[i], at least closer to that color than other
1131 int dmeasure - how we measure the distance from some point P(x,y) to
1140 euclidean distance: sqrt((x2-x1)**2 + (y2-y1)**2)
1144 square of euclidean distance: ((x2-x1)**2 + (y2-y1)**2)
1148 manhattan distance: max((y2-y1)**2, (x2-x1)**2)
1152 An invalid value causes an error exit (the program is aborted).
1160 i_nearest_color(i_img *im, int num, int *xo, int *yo, i_color *oval, int dmeasure) {
1166 int xsize = im->xsize;
1167 int ysize = im->ysize;
1169 int ival_bytes, tval_bytes;
1171 mm_log((1,"i_nearest_color(im %p, num %d, xo %p, yo %p, oval %p, dmeasure %d)\n", im, num, xo, yo, oval, dmeasure));
1176 i_push_error(0, "no points supplied to nearest_color filter");
1180 if (dmeasure < 0 || dmeasure > i_dmeasure_limit) {
1181 i_push_error(0, "distance measure invalid");
1185 tval_bytes = sizeof(float)*num*im->channels;
1186 if (tval_bytes / num != sizeof(float) * im->channels) {
1187 i_push_error(0, "integer overflow calculating memory allocation");
1190 ival_bytes = sizeof(i_color) * num;
1191 if (ival_bytes / sizeof(i_color) != num) {
1192 i_push_error(0, "integer overflow calculating memory allocation");
1195 tval = mymalloc( tval_bytes ); /* checked 17feb2005 tonyc */
1196 ival = mymalloc( ival_bytes ); /* checked 17feb2005 tonyc */
1197 cmatch = mymalloc( sizeof(int)*num ); /* checked 17feb2005 tonyc */
1199 for(p = 0; p<num; p++) {
1200 for(ch = 0; ch<im->channels; ch++) tval[ p * im->channels + ch] = 0;
1205 for(y = 0; y<ysize; y++) for(x = 0; x<xsize; x++) {
1214 case 0: /* euclidean */
1215 mindist = sqrt(xd*xd + yd*yd); /* euclidean distance */
1217 case 1: /* euclidean squared */
1218 mindist = xd*xd + yd*yd; /* euclidean distance */
1220 case 2: /* manhatten distance */
1221 mindist = i_max(xd*xd, yd*yd); /* manhattan distance */
1224 i_fatal(3,"i_nearest_color: Unknown distance measure\n");
1227 for(p = 1; p<num; p++) {
1231 case 0: /* euclidean */
1232 curdist = sqrt(xd*xd + yd*yd); /* euclidean distance */
1234 case 1: /* euclidean squared */
1235 curdist = xd*xd + yd*yd; /* euclidean distance */
1237 case 2: /* euclidean squared */
1238 curdist = i_max(xd*xd, yd*yd); /* manhattan distance */
1241 i_fatal(3,"i_nearest_color: Unknown distance measure\n");
1243 if (curdist < mindist) {
1250 i_gpix(im, x, y, &val);
1251 c2 = 1.0/(float)(cmatch[midx]);
1254 for(ch = 0; ch<im->channels; ch++)
1255 tval[midx*im->channels + ch] =
1256 c1*tval[midx*im->channels + ch] + c2 * (float) val.channel[ch];
1260 for(p = 0; p<num; p++) for(ch = 0; ch<im->channels; ch++)
1261 ival[p].channel[ch] = tval[p*im->channels + ch];
1263 i_nearest_color_foo(im, num, xo, yo, ival, dmeasure);
1269 =item i_unsharp_mask(im, stddev, scale)
1271 Perform an usharp mask, which is defined as subtracting the blurred
1272 image from double the original.
1278 i_unsharp_mask(i_img *im, double stddev, double scale) {
1284 /* it really shouldn't ever be more than 1.0, but maybe ... */
1289 i_gaussian(copy, stddev);
1290 if (im->bits == i_8_bits) {
1291 i_color *blur = mymalloc(im->xsize * sizeof(i_color)); /* checked 17feb2005 tonyc */
1292 i_color *out = mymalloc(im->xsize * sizeof(i_color)); /* checked 17feb2005 tonyc */
1294 for (y = 0; y < im->ysize; ++y) {
1295 i_glin(copy, 0, copy->xsize, y, blur);
1296 i_glin(im, 0, im->xsize, y, out);
1297 for (x = 0; x < im->xsize; ++x) {
1298 for (ch = 0; ch < im->channels; ++ch) {
1299 /*int temp = out[x].channel[ch] +
1300 scale * (out[x].channel[ch] - blur[x].channel[ch]);*/
1301 int temp = out[x].channel[ch] * 2 - blur[x].channel[ch];
1304 else if (temp > 255)
1306 out[x].channel[ch] = temp;
1309 i_plin(im, 0, im->xsize, y, out);
1316 i_fcolor *blur = mymalloc(im->xsize * sizeof(i_fcolor)); /* checked 17feb2005 tonyc */
1317 i_fcolor *out = mymalloc(im->xsize * sizeof(i_fcolor)); /* checked 17feb2005 tonyc */
1319 for (y = 0; y < im->ysize; ++y) {
1320 i_glinf(copy, 0, copy->xsize, y, blur);
1321 i_glinf(im, 0, im->xsize, y, out);
1322 for (x = 0; x < im->xsize; ++x) {
1323 for (ch = 0; ch < im->channels; ++ch) {
1324 double temp = out[x].channel[ch] +
1325 scale * (out[x].channel[ch] - blur[x].channel[ch]);
1328 else if (temp > 1.0)
1330 out[x].channel[ch] = temp;
1333 i_plinf(im, 0, im->xsize, y, out);
1339 i_img_destroy(copy);
1343 =item i_diff_image(im1, im2, mindist)
1345 Creates a new image that is transparent, except where the pixel in im2
1346 is different from im1, where it is the pixel from im2.
1348 The samples must differ by at least mindiff to be considered different.
1354 i_diff_image(i_img *im1, i_img *im2, double mindist) {
1356 int outchans, diffchans;
1360 if (im1->channels != im2->channels) {
1361 i_push_error(0, "different number of channels");
1365 outchans = diffchans = im1->channels;
1366 if (outchans == 1 || outchans == 3)
1369 xsize = i_min(im1->xsize, im2->xsize);
1370 ysize = i_min(im1->ysize, im2->ysize);
1372 out = i_sametype_chans(im1, xsize, ysize, outchans);
1374 if (im1->bits == i_8_bits && im2->bits == i_8_bits) {
1375 i_color *line1 = mymalloc(xsize * sizeof(*line1)); /* checked 17feb2005 tonyc */
1376 i_color *line2 = mymalloc(xsize * sizeof(*line1)); /* checked 17feb2005 tonyc */
1379 int imindist = (int)mindist;
1381 for (ch = 0; ch < MAXCHANNELS; ++ch)
1382 empty.channel[ch] = 0;
1384 for (y = 0; y < ysize; ++y) {
1385 i_glin(im1, 0, xsize, y, line1);
1386 i_glin(im2, 0, xsize, y, line2);
1387 if (outchans != diffchans) {
1388 /* give the output an alpha channel since it doesn't have one */
1389 for (x = 0; x < xsize; ++x)
1390 line2[x].channel[diffchans] = 255;
1392 for (x = 0; x < xsize; ++x) {
1394 for (ch = 0; ch < diffchans; ++ch) {
1395 if (line1[x].channel[ch] != line2[x].channel[ch]
1396 && abs(line1[x].channel[ch] - line2[x].channel[ch]) > imindist) {
1404 i_plin(out, 0, xsize, y, line2);
1410 i_fcolor *line1 = mymalloc(xsize * sizeof(*line1)); /* checked 17feb2005 tonyc */
1411 i_fcolor *line2 = mymalloc(xsize * sizeof(*line2)); /* checked 17feb2005 tonyc */
1414 double dist = mindist / 255.0;
1416 for (ch = 0; ch < MAXCHANNELS; ++ch)
1417 empty.channel[ch] = 0;
1419 for (y = 0; y < ysize; ++y) {
1420 i_glinf(im1, 0, xsize, y, line1);
1421 i_glinf(im2, 0, xsize, y, line2);
1422 if (outchans != diffchans) {
1423 /* give the output an alpha channel since it doesn't have one */
1424 for (x = 0; x < xsize; ++x)
1425 line2[x].channel[diffchans] = 1.0;
1427 for (x = 0; x < xsize; ++x) {
1429 for (ch = 0; ch < diffchans; ++ch) {
1430 if (line1[x].channel[ch] != line2[x].channel[ch]
1431 && fabs(line1[x].channel[ch] - line2[x].channel[ch]) > dist) {
1439 i_plinf(out, 0, xsize, y, line2);
1449 static double linear_fount_f(double x, double y, struct fount_state *state);
1450 static double bilinear_fount_f(double x, double y, struct fount_state *state);
1451 static double radial_fount_f(double x, double y, struct fount_state *state);
1452 static double square_fount_f(double x, double y, struct fount_state *state);
1453 static double revolution_fount_f(double x, double y,
1454 struct fount_state *state);
1455 static double conical_fount_f(double x, double y, struct fount_state *state);
1457 typedef double (*fount_func)(double, double, struct fount_state *);
1458 static fount_func fount_funcs[] =
1468 static double linear_interp(double pos, i_fountain_seg *seg);
1469 static double sine_interp(double pos, i_fountain_seg *seg);
1470 static double sphereup_interp(double pos, i_fountain_seg *seg);
1471 static double spheredown_interp(double pos, i_fountain_seg *seg);
1472 typedef double (*fount_interp)(double pos, i_fountain_seg *seg);
1473 static fount_interp fount_interps[] =
1482 static void direct_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg);
1483 static void hue_up_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg);
1484 static void hue_down_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg);
1485 typedef void (*fount_cinterp)(i_fcolor *out, double pos, i_fountain_seg *seg);
1486 static fount_cinterp fount_cinterps[] =
1493 typedef double (*fount_repeat)(double v);
1494 static double fount_r_none(double v);
1495 static double fount_r_sawtooth(double v);
1496 static double fount_r_triangle(double v);
1497 static double fount_r_saw_both(double v);
1498 static double fount_r_tri_both(double v);
1499 static fount_repeat fount_repeats[] =
1508 static int simple_ssample(i_fcolor *out, double x, double y,
1509 struct fount_state *state);
1510 static int random_ssample(i_fcolor *out, double x, double y,
1511 struct fount_state *state);
1512 static int circle_ssample(i_fcolor *out, double x, double y,
1513 struct fount_state *state);
1514 typedef int (*fount_ssample)(i_fcolor *out, double x, double y,
1515 struct fount_state *state);
1516 static fount_ssample fount_ssamples[] =
1525 fount_getat(i_fcolor *out, double x, double y, struct fount_state *state);
1528 Keep state information used by each type of fountain fill
1530 struct fount_state {
1531 /* precalculated for the equation of the line perpendicular to the line AB */
1542 fount_repeat rpfunc;
1543 fount_ssample ssfunc;
1545 i_fountain_seg *segs;
1550 fount_init_state(struct fount_state *state, double xa, double ya,
1551 double xb, double yb, i_fountain_type type,
1552 i_fountain_repeat repeat, int combine, int super_sample,
1553 double ssample_param, int count, i_fountain_seg *segs);
1556 fount_finish_state(struct fount_state *state);
1558 #define EPSILON (1e-6)
1561 =item i_fountain(im, xa, ya, xb, yb, type, repeat, combine, super_sample, ssample_param, count, segs)
1563 Draws a fountain fill using A(xa, ya) and B(xb, yb) as reference points.
1565 I<type> controls how the reference points are used:
1571 linear, where A is 0 and B is 1.
1575 linear in both directions from A.
1579 circular, where A is the centre of the fill, and B is a point
1582 =item i_ft_radial_square
1584 where A is the centre of the fill and B is the centre of
1585 one side of the square.
1587 =item i_ft_revolution
1589 where A is the centre of the fill and B defines the 0/1.0
1594 similar to i_ft_revolution, except that the revolution goes in both
1599 I<repeat> can be one of:
1605 values < 0 are treated as zero, values > 1 are treated as 1.
1609 negative values are treated as 0, positive values are modulo 1.0
1613 negative values are treated as zero, if (int)value is odd then the value is treated as 1-(value
1614 mod 1.0), otherwise the same as for sawtooth.
1618 like i_fr_sawtooth, except that the sawtooth pattern repeats into
1623 Like i_fr_triangle, except that negative values are handled as their
1628 If combine is non-zero then non-opaque values are combined with the
1631 I<super_sample> controls super sampling, if any. At some point I'll
1632 probably add a adaptive super-sampler. Current possible values are:
1638 No super-sampling is done.
1642 A square grid of points withing the pixel are sampled.
1646 Random points within the pixel are sampled.
1650 Points on the radius of a circle are sampled. This produces fairly
1651 good results, but is fairly slow since sin() and cos() are evaluated
1656 I<ssample_param> is intended to be roughly the number of points
1657 sampled within the pixel.
1659 I<count> and I<segs> define the segments of the fill.
1666 i_fountain(i_img *im, double xa, double ya, double xb, double yb,
1667 i_fountain_type type, i_fountain_repeat repeat,
1668 int combine, int super_sample, double ssample_param,
1669 int count, i_fountain_seg *segs) {
1670 struct fount_state state;
1672 i_fcolor *line = NULL;
1673 i_fcolor *work = NULL;
1675 i_fountain_seg *my_segs;
1676 i_fill_combine_f combine_func = NULL;
1677 i_fill_combinef_f combinef_func = NULL;
1681 /* i_fountain() allocates floating colors even for 8-bit images,
1682 so we need to do this check */
1683 line_bytes = sizeof(i_fcolor) * im->xsize;
1684 if (line_bytes / sizeof(i_fcolor) != im->xsize) {
1685 i_push_error(0, "integer overflow calculating memory allocation");
1689 line = mymalloc(line_bytes); /* checked 17feb2005 tonyc */
1691 i_get_combine(combine, &combine_func, &combinef_func);
1693 work = mymalloc(line_bytes); /* checked 17feb2005 tonyc */
1695 fount_init_state(&state, xa, ya, xb, yb, type, repeat, combine,
1696 super_sample, ssample_param, count, segs);
1697 my_segs = state.segs;
1699 for (y = 0; y < im->ysize; ++y) {
1700 i_glinf(im, 0, im->xsize, y, line);
1701 for (x = 0; x < im->xsize; ++x) {
1704 if (super_sample == i_fts_none)
1705 got_one = fount_getat(&c, x, y, &state);
1707 got_one = state.ssfunc(&c, x, y, &state);
1716 combinef_func(line, work, im->channels, im->xsize);
1717 i_plinf(im, 0, im->xsize, y, line);
1719 fount_finish_state(&state);
1720 if (work) myfree(work);
1728 struct fount_state state;
1729 } i_fill_fountain_t;
1732 fill_fountf(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width, int channels,
1735 fount_fill_destroy(i_fill_t *fill);
1737 static i_fill_fountain_t
1749 =item i_new_fill_fount(C<xa>, C<ya>, C<xb>, C<yb>, C<type>, C<repeat>, C<combine>, C<super_sample>, C<ssample_param>, C<count>, C<segs>)
1752 =synopsis fill = i_new_fill_fount(0, 0, 100, 100, i_ft_linear, i_ft_linear,
1753 =synopsis i_fr_triangle, 0, i_fts_grid, 9, 1, segs);
1756 Creates a new general fill which fills with a fountain fill.
1762 i_new_fill_fount(double xa, double ya, double xb, double yb,
1763 i_fountain_type type, i_fountain_repeat repeat,
1764 int combine, int super_sample, double ssample_param,
1765 int count, i_fountain_seg *segs) {
1766 i_fill_fountain_t *fill = mymalloc(sizeof(i_fill_fountain_t));
1768 *fill = fount_fill_proto;
1770 i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
1772 fill->base.combine = NULL;
1773 fill->base.combinef = NULL;
1775 fount_init_state(&fill->state, xa, ya, xb, yb, type, repeat, combine,
1776 super_sample, ssample_param, count, segs);
1784 =head1 INTERNAL FUNCTIONS
1788 =item fount_init_state(...)
1790 Used by both the fountain fill filter and the fountain fill.
1796 fount_init_state(struct fount_state *state, double xa, double ya,
1797 double xb, double yb, i_fountain_type type,
1798 i_fountain_repeat repeat, int combine, int super_sample,
1799 double ssample_param, int count, i_fountain_seg *segs) {
1802 i_fountain_seg *my_segs = mymalloc(sizeof(i_fountain_seg) * count); /* checked 2jul06 - duplicating original */
1803 /*int have_alpha = im->channels == 2 || im->channels == 4;*/
1805 memset(state, 0, sizeof(*state));
1806 /* we keep a local copy that we can adjust for speed */
1807 for (i = 0; i < count; ++i) {
1808 i_fountain_seg *seg = my_segs + i;
1811 if (seg->type < 0 || seg->type >= i_fst_end)
1812 seg->type = i_fst_linear;
1813 if (seg->color < 0 || seg->color >= i_fc_end)
1814 seg->color = i_fc_direct;
1815 if (seg->color == i_fc_hue_up || seg->color == i_fc_hue_down) {
1816 /* so we don't have to translate to HSV on each request, do it here */
1817 for (j = 0; j < 2; ++j) {
1818 i_rgb_to_hsvf(seg->c+j);
1820 if (seg->color == i_fc_hue_up) {
1821 if (seg->c[1].channel[0] <= seg->c[0].channel[0])
1822 seg->c[1].channel[0] += 1.0;
1825 if (seg->c[0].channel[0] <= seg->c[0].channel[1])
1826 seg->c[0].channel[0] += 1.0;
1829 /*printf("start %g mid %g end %g c0(%g,%g,%g,%g) c1(%g,%g,%g,%g) type %d color %d\n",
1830 seg->start, seg->middle, seg->end, seg->c[0].channel[0],
1831 seg->c[0].channel[1], seg->c[0].channel[2], seg->c[0].channel[3],
1832 seg->c[1].channel[0], seg->c[1].channel[1], seg->c[1].channel[2],
1833 seg->c[1].channel[3], seg->type, seg->color);*/
1837 /* initialize each engine */
1838 /* these are so common ... */
1839 state->lA = xb - xa;
1840 state->lB = yb - ya;
1841 state->AB = sqrt(state->lA * state->lA + state->lB * state->lB);
1846 type = i_ft_linear; /* make the invalid value valid */
1849 state->lC = ya * ya - ya * yb + xa * xa - xa * xb;
1851 state->mult = 1/linear_fount_f(xb, yb, state);
1855 state->mult = 1.0 / sqrt((double)(xb-xa)*(xb-xa)
1856 + (double)(yb-ya)*(yb-ya));
1859 case i_ft_radial_square:
1860 state->cos = state->lA / state->AB;
1861 state->sin = state->lB / state->AB;
1862 state->mult = 1.0 / state->AB;
1865 case i_ft_revolution:
1866 state->theta = atan2(yb-ya, xb-xa);
1867 state->mult = 1.0 / (PI * 2);
1871 state->theta = atan2(yb-ya, xb-xa);
1872 state->mult = 1.0 / PI;
1875 state->ffunc = fount_funcs[type];
1876 if (super_sample < 0
1877 || super_sample >= (int)(sizeof(fount_ssamples)/sizeof(*fount_ssamples))) {
1880 state->ssample_data = NULL;
1881 switch (super_sample) {
1883 ssample_param = floor(0.5 + sqrt(ssample_param));
1884 bytes = ssample_param * ssample_param * sizeof(i_fcolor);
1885 if (bytes / sizeof(i_fcolor) == ssample_param * ssample_param) {
1886 state->ssample_data = mymalloc(sizeof(i_fcolor) * ssample_param * ssample_param); /* checked 1jul06 tonyc */
1889 super_sample = i_fts_none;
1895 ssample_param = floor(0.5+ssample_param);
1896 bytes = sizeof(i_fcolor) * ssample_param;
1897 if (bytes / sizeof(i_fcolor) == ssample_param) {
1898 state->ssample_data = mymalloc(sizeof(i_fcolor) * ssample_param);
1901 super_sample = i_fts_none;
1905 state->parm = ssample_param;
1906 state->ssfunc = fount_ssamples[super_sample];
1907 if (repeat < 0 || repeat >= (sizeof(fount_repeats)/sizeof(*fount_repeats)))
1909 state->rpfunc = fount_repeats[repeat];
1910 state->segs = my_segs;
1911 state->count = count;
1915 fount_finish_state(struct fount_state *state) {
1916 if (state->ssample_data)
1917 myfree(state->ssample_data);
1918 myfree(state->segs);
1923 =item fount_getat(out, x, y, ffunc, rpfunc, state, segs, count)
1925 Evaluates the fountain fill at the given point.
1927 This is called by both the non-super-sampling and super-sampling code.
1929 You might think that it would make sense to sample the fill parameter
1930 instead, and combine those, but this breaks badly.
1936 fount_getat(i_fcolor *out, double x, double y, struct fount_state *state) {
1937 double v = (state->rpfunc)((state->ffunc)(x, y, state));
1941 while (i < state->count
1942 && (v < state->segs[i].start || v > state->segs[i].end)) {
1945 if (i < state->count) {
1946 v = (fount_interps[state->segs[i].type])(v, state->segs+i);
1947 (fount_cinterps[state->segs[i].color])(out, v, state->segs+i);
1955 =item linear_fount_f(x, y, state)
1957 Calculate the fill parameter for a linear fountain fill.
1959 Uses the point to line distance function, with some precalculation
1960 done in i_fountain().
1965 linear_fount_f(double x, double y, struct fount_state *state) {
1966 return (state->lA * x + state->lB * y + state->lC) / state->AB * state->mult;
1970 =item bilinear_fount_f(x, y, state)
1972 Calculate the fill parameter for a bi-linear fountain fill.
1977 bilinear_fount_f(double x, double y, struct fount_state *state) {
1978 return fabs((state->lA * x + state->lB * y + state->lC) / state->AB * state->mult);
1982 =item radial_fount_f(x, y, state)
1984 Calculate the fill parameter for a radial fountain fill.
1986 Simply uses the distance function.
1991 radial_fount_f(double x, double y, struct fount_state *state) {
1992 return sqrt((double)(state->xa-x)*(state->xa-x)
1993 + (double)(state->ya-y)*(state->ya-y)) * state->mult;
1997 =item square_fount_f(x, y, state)
1999 Calculate the fill parameter for a square fountain fill.
2001 Works by rotating the reference co-ordinate around the centre of the
2007 square_fount_f(double x, double y, struct fount_state *state) {
2008 int xc, yc; /* centred on A */
2009 double xt, yt; /* rotated by theta */
2012 xt = fabs(xc * state->cos + yc * state->sin);
2013 yt = fabs(-xc * state->sin + yc * state->cos);
2014 return (xt > yt ? xt : yt) * state->mult;
2018 =item revolution_fount_f(x, y, state)
2020 Calculates the fill parameter for the revolution fountain fill.
2025 revolution_fount_f(double x, double y, struct fount_state *state) {
2026 double angle = atan2(y - state->ya, x - state->xa);
2028 angle -= state->theta;
2030 angle = fmod(angle+ PI * 4, PI*2);
2033 return angle * state->mult;
2037 =item conical_fount_f(x, y, state)
2039 Calculates the fill parameter for the conical fountain fill.
2044 conical_fount_f(double x, double y, struct fount_state *state) {
2045 double angle = atan2(y - state->ya, x - state->xa);
2047 angle -= state->theta;
2050 else if (angle > PI)
2053 return fabs(angle) * state->mult;
2057 =item linear_interp(pos, seg)
2059 Calculates linear interpolation on the fill parameter. Breaks the
2060 segment into 2 regions based in the I<middle> value.
2065 linear_interp(double pos, i_fountain_seg *seg) {
2066 if (pos < seg->middle) {
2067 double len = seg->middle - seg->start;
2071 return (pos - seg->start) / len / 2;
2074 double len = seg->end - seg->middle;
2078 return 0.5 + (pos - seg->middle) / len / 2;
2083 =item sine_interp(pos, seg)
2085 Calculates sine function interpolation on the fill parameter.
2090 sine_interp(double pos, i_fountain_seg *seg) {
2091 /* I wonder if there's a simple way to smooth the transition for this */
2092 double work = linear_interp(pos, seg);
2094 return (1-cos(work * PI))/2;
2098 =item sphereup_interp(pos, seg)
2100 Calculates spherical interpolation on the fill parameter, with the cusp
2106 sphereup_interp(double pos, i_fountain_seg *seg) {
2107 double work = linear_interp(pos, seg);
2109 return sqrt(1.0 - (1-work) * (1-work));
2113 =item spheredown_interp(pos, seg)
2115 Calculates spherical interpolation on the fill parameter, with the cusp
2121 spheredown_interp(double pos, i_fountain_seg *seg) {
2122 double work = linear_interp(pos, seg);
2124 return 1-sqrt(1.0 - work * work);
2128 =item direct_cinterp(out, pos, seg)
2130 Calculates the fountain color based on direct scaling of the channels
2131 of the color channels.
2136 direct_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg) {
2138 for (ch = 0; ch < MAXCHANNELS; ++ch) {
2139 out->channel[ch] = seg->c[0].channel[ch] * (1 - pos)
2140 + seg->c[1].channel[ch] * pos;
2145 =item hue_up_cinterp(put, pos, seg)
2147 Calculates the fountain color based on scaling a HSV value. The hue
2148 increases as the fill parameter increases.
2153 hue_up_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg) {
2155 for (ch = 0; ch < MAXCHANNELS; ++ch) {
2156 out->channel[ch] = seg->c[0].channel[ch] * (1 - pos)
2157 + seg->c[1].channel[ch] * pos;
2163 =item hue_down_cinterp(put, pos, seg)
2165 Calculates the fountain color based on scaling a HSV value. The hue
2166 decreases as the fill parameter increases.
2171 hue_down_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg) {
2173 for (ch = 0; ch < MAXCHANNELS; ++ch) {
2174 out->channel[ch] = seg->c[0].channel[ch] * (1 - pos)
2175 + seg->c[1].channel[ch] * pos;
2181 =item simple_ssample(out, parm, x, y, state, ffunc, rpfunc, segs, count)
2183 Simple grid-based super-sampling.
2188 simple_ssample(i_fcolor *out, double x, double y, struct fount_state *state) {
2189 i_fcolor *work = state->ssample_data;
2191 int grid = state->parm;
2192 double base = -0.5 + 0.5 / grid;
2193 double step = 1.0 / grid;
2197 for (dx = 0; dx < grid; ++dx) {
2198 for (dy = 0; dy < grid; ++dy) {
2199 if (fount_getat(work+samp_count, x + base + step * dx,
2200 y + base + step * dy, state)) {
2205 for (ch = 0; ch < MAXCHANNELS; ++ch) {
2206 out->channel[ch] = 0;
2207 for (i = 0; i < samp_count; ++i) {
2208 out->channel[ch] += work[i].channel[ch];
2210 /* we divide by 4 rather than samp_count since if there's only one valid
2211 sample it should be mostly transparent */
2212 out->channel[ch] /= grid * grid;
2218 =item random_ssample(out, parm, x, y, state, ffunc, rpfunc, segs, count)
2220 Random super-sampling.
2225 random_ssample(i_fcolor *out, double x, double y,
2226 struct fount_state *state) {
2227 i_fcolor *work = state->ssample_data;
2229 int maxsamples = state->parm;
2230 double rand_scale = 1.0 / RAND_MAX;
2232 for (i = 0; i < maxsamples; ++i) {
2233 if (fount_getat(work+samp_count, x - 0.5 + rand() * rand_scale,
2234 y - 0.5 + rand() * rand_scale, state)) {
2238 for (ch = 0; ch < MAXCHANNELS; ++ch) {
2239 out->channel[ch] = 0;
2240 for (i = 0; i < samp_count; ++i) {
2241 out->channel[ch] += work[i].channel[ch];
2243 /* we divide by maxsamples rather than samp_count since if there's
2244 only one valid sample it should be mostly transparent */
2245 out->channel[ch] /= maxsamples;
2251 =item circle_ssample(out, parm, x, y, state, ffunc, rpfunc, segs, count)
2253 Super-sampling around the circumference of a circle.
2255 I considered saving the sin()/cos() values and transforming step-size
2256 around the circle, but that's inaccurate, though it may not matter
2262 circle_ssample(i_fcolor *out, double x, double y,
2263 struct fount_state *state) {
2264 i_fcolor *work = state->ssample_data;
2266 int maxsamples = state->parm;
2267 double angle = 2 * PI / maxsamples;
2268 double radius = 0.3; /* semi-random */
2270 for (i = 0; i < maxsamples; ++i) {
2271 if (fount_getat(work+samp_count, x + radius * cos(angle * i),
2272 y + radius * sin(angle * i), state)) {
2276 for (ch = 0; ch < MAXCHANNELS; ++ch) {
2277 out->channel[ch] = 0;
2278 for (i = 0; i < samp_count; ++i) {
2279 out->channel[ch] += work[i].channel[ch];
2281 /* we divide by maxsamples rather than samp_count since if there's
2282 only one valid sample it should be mostly transparent */
2283 out->channel[ch] /= maxsamples;
2289 =item fount_r_none(v)
2291 Implements no repeats. Simply clamps the fill value.
2296 fount_r_none(double v) {
2297 return v < 0 ? 0 : v > 1 ? 1 : v;
2301 =item fount_r_sawtooth(v)
2303 Implements sawtooth repeats. Clamps negative values and uses fmod()
2309 fount_r_sawtooth(double v) {
2310 return v < 0 ? 0 : fmod(v, 1.0);
2314 =item fount_r_triangle(v)
2316 Implements triangle repeats. Clamps negative values, uses fmod to get
2317 a range 0 through 2 and then adjusts values > 1.
2322 fount_r_triangle(double v) {
2327 return v > 1.0 ? 2.0 - v : v;
2332 =item fount_r_saw_both(v)
2334 Implements sawtooth repeats in the both postive and negative directions.
2336 Adjusts the value to be postive and then just uses fmod().
2341 fount_r_saw_both(double v) {
2344 return fmod(v, 1.0);
2348 =item fount_r_tri_both(v)
2350 Implements triangle repeats in the both postive and negative directions.
2352 Uses fmod on the absolute value, and then adjusts values > 1.
2357 fount_r_tri_both(double v) {
2358 v = fmod(fabs(v), 2.0);
2359 return v > 1.0 ? 2.0 - v : v;
2363 =item fill_fountf(fill, x, y, width, channels, data)
2365 The fill function for fountain fills.
2370 fill_fountf(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
2371 int channels, i_fcolor *data) {
2372 i_fill_fountain_t *f = (i_fill_fountain_t *)fill;
2378 if (f->state.ssfunc)
2379 got_one = f->state.ssfunc(&c, x, y, &f->state);
2381 got_one = fount_getat(&c, x, y, &f->state);
2390 =item fount_fill_destroy(fill)
2395 fount_fill_destroy(i_fill_t *fill) {
2396 i_fill_fountain_t *f = (i_fill_fountain_t *)fill;
2397 fount_finish_state(&f->state);
2405 Arnar M. Hrafnkelsson <addi@umich.edu>
2407 Tony Cook <tony@develop-help.com> (i_fountain())