1 #define IMAGER_NO_CONTEXT
11 filters.im - implements filters that operate on images
19 i_unsharp_mask(im, 2.0, 1.0);
24 filters.c implements basic filters for Imager. These filters
25 should be accessible from the filter interface as defined in
28 =head1 FUNCTION REFERENCE
30 Some of these functions are internal.
43 Clamps the input value between 0 and 255. (internal)
53 if (in>255) { return 255; }
54 else if (in>0) return in;
61 =item i_contrast(im, intensity)
63 Scales the pixel values by the amount specified.
66 intensity - scalefactor
72 i_contrast(i_img *im, float intensity) {
75 unsigned int new_color;
79 im_log((aIMCTX, 1,"i_contrast(im %p, intensity %f)\n", im, intensity));
81 if(intensity < 0) return;
83 for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
84 i_gpix(im, x, y, &rcolor);
86 for(ch = 0; ch < im->channels; ch++) {
87 new_color = (unsigned int) rcolor.channel[ch];
88 new_color *= intensity;
93 rcolor.channel[ch] = (unsigned char) new_color;
95 i_ppix(im, x, y, &rcolor);
101 s_hardinvert_low(i_img *im, int all) {
104 int invert_channels = all ? im->channels : i_img_color_channels(im);
107 im_log((aIMCTX,1,"i_hardinvert)low(im %p, all %d)\n", im, all));
110 IM_COLOR *row, *entry;
112 /* always rooms to allocate a single line of i_color */
113 row = mymalloc(sizeof(IM_COLOR) * im->xsize); /* checked 17feb2005 tonyc */
115 for(y = 0; y < im->ysize; y++) {
116 IM_GLIN(im, 0, im->xsize, y, row);
118 for(x = 0; x < im->xsize; x++) {
119 for(ch = 0; ch < invert_channels; ch++) {
120 entry->channel[ch] = IM_SAMPLE_MAX - entry->channel[ch];
124 IM_PLIN(im, 0, im->xsize, y, row);
133 =item i_hardinvert(im)
135 Inverts the color channels of the input image.
143 i_hardinvert(i_img *im) {
144 s_hardinvert_low(im, 0);
148 =item i_hardinvertall(im)
150 Inverts all channels of the input image.
158 i_hardinvertall(i_img *im) {
159 s_hardinvert_low(im, 1);
163 =item i_noise(im, amount, type)
165 Adjusts the sample values randomly by the amount specified.
167 If type is 0, adjust all channels in a pixel by the same (random)
168 amount amount, if non-zero adjust each sample independently.
171 amount - deviation in pixel values
172 type - noise individual for each channel if true
178 /* random() is non-ASCII, even if it is better than rand() */
179 #define random() rand()
183 i_noise(i_img *im, float amount, unsigned char type) {
187 float damount = amount * 2;
192 im_log((aIMCTX, 1,"i_noise(im %p, intensity %.2f\n", im, amount));
194 if(amount < 0) return;
196 for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
197 i_gpix(im, x, y, &rcolor);
200 color_inc = (amount - (damount * ((float)random() / RAND_MAX)));
203 for(ch = 0; ch < im->channels; ch++) {
204 new_color = (int) rcolor.channel[ch];
207 new_color += (amount - (damount * ((float)random() / RAND_MAX)));
209 new_color += color_inc;
215 if(new_color > 255) {
219 rcolor.channel[ch] = (unsigned char) new_color;
222 i_ppix(im, x, y, &rcolor);
227 =item i_bumpmap(im, bump, channel, light_x, light_y, st)
229 Makes a bumpmap on image im using the bump image as the elevation map.
232 bump - image that contains the elevation info
233 channel - to take the elevation information from
234 light_x - x coordinate of light source
235 light_y - y coordinate of light source
236 st - length of shadow
242 i_bumpmap(i_img *im, i_img *bump, int channel, i_img_dim light_x, i_img_dim light_y, i_img_dim st) {
246 i_color x1_color, y1_color, x2_color, y2_color, dst_color;
251 unsigned char px1, px2, py1, py2;
255 im_log((aIMCTX, 1, "i_bumpmap(im %p, add_im %p, channel %d, light(" i_DFp "), st %" i_DF ")\n",
256 im, bump, channel, i_DFcp(light_x, light_y), i_DFc(st)));
259 if(channel >= bump->channels) {
260 im_log((aIMCTX, 1, "i_bumpmap: channel = %d while bump image only has %d channels\n", channel, bump->channels));
264 mx = (bump->xsize <= im->xsize) ? bump->xsize : im->xsize;
265 my = (bump->ysize <= im->ysize) ? bump->ysize : im->ysize;
267 i_img_empty_ch(&new_im, im->xsize, im->ysize, im->channels);
269 aX = (light_x > (mx >> 1)) ? light_x : mx - light_x;
270 aY = (light_y > (my >> 1)) ? light_y : my - light_y;
272 aL = sqrt((aX * aX) + (aY * aY));
274 for(y = 1; y < my - 1; y++) {
275 for(x = 1; x < mx - 1; x++) {
276 i_gpix(bump, x + st, y, &x1_color);
277 i_gpix(bump, x, y + st, &y1_color);
278 i_gpix(bump, x - st, y, &x2_color);
279 i_gpix(bump, x, y - st, &y2_color);
281 i_gpix(im, x, y, &dst_color);
283 px1 = x1_color.channel[channel];
284 py1 = y1_color.channel[channel];
285 px2 = x2_color.channel[channel];
286 py2 = y2_color.channel[channel];
294 fZ = (sqrt((nX * nX) + (nY * nY)) / aL);
296 tX = i_abs(x - light_x) / aL;
297 tY = i_abs(y - light_y) / aL;
299 tZ = 1 - (sqrt((tX * tX) + (tY * tY)) * fZ);
304 for(ch = 0; ch < im->channels; ch++)
305 dst_color.channel[ch] = (unsigned char) (float)(dst_color.channel[ch] * tZ);
307 i_ppix(&new_im, x, y, &dst_color);
311 i_copyto(im, &new_im, 0, 0, im->xsize, im->ysize, 0, 0);
313 i_img_exorcise(&new_im);
326 dotp(fvec *a, fvec *b) {
327 return a->x*b->x+a->y*b->y+a->z*b->z;
333 double d = sqrt(dotp(a,a));
347 I = Ia + Ip*( cd*Scol(N.L) + cs*(R.V)^n )
349 Here, the variables are:
351 * Ia - ambient colour
352 * Ip - intensity of the point light source
353 * cd - diffuse coefficient
354 * Scol - surface colour
355 * cs - specular coefficient
356 * n - objects shinyness
358 * L - lighting vector
359 * R - reflection vector
362 static void fvec_dump(fvec *x) {
363 printf("(%.2f %.2f %.2f)", x->x, x->y, x->z);
367 /* XXX: Should these return a code for success? */
373 =item i_bumpmap_complex(im, bump, channel, tx, ty, Lx, Ly, Lz, Ip, cd, cs, n, Ia, Il, Is)
375 Makes a bumpmap on image im using the bump image as the elevation map.
378 bump - image that contains the elevation info
379 channel - to take the elevation information from
380 tx - shift in x direction of where to start applying bumpmap
381 ty - shift in y direction of where to start applying bumpmap
382 Lx - x position/direction of light
383 Ly - y position/direction of light
384 Lz - z position/direction of light
386 cd - diffuse coefficient
387 cs - specular coefficient
388 n - surface shinyness
393 if z<0 then the L is taken to be the direction the light is shining in. Otherwise
394 the L is taken to be the position of the Light, Relative to the image.
401 i_bumpmap_complex(i_img *im,
420 i_img_dim mx, Mx, my, My;
422 float cdc[MAXCHANNELS];
423 float csc[MAXCHANNELS];
425 i_color x1_color, y1_color, x2_color, y2_color;
427 i_color Scol; /* Surface colour */
429 fvec L; /* Light vector */
430 fvec N; /* surface normal */
431 fvec R; /* Reflection vector */
432 fvec V; /* Vision vector */
436 im_log((aIMCTX, 1, "i_bumpmap_complex(im %p, bump %p, channel %d, t(" i_DFp
437 "), Lx %.2f, Ly %.2f, Lz %.2f, cd %.2f, cs %.2f, n %.2f, Ia %p, Il %p, Is %p)\n",
438 im, bump, channel, i_DFcp(tx, ty), Lx, Ly, Lz, cd, cs, n, Ia, Il, Is));
440 if (channel >= bump->channels) {
441 im_log((aIMCTX, 1, "i_bumpmap_complex: channel = %d while bump image only has %d channels\n", channel, bump->channels));
445 for(ch=0; ch<im->channels; ch++) {
446 cdc[ch] = (float)Il->channel[ch]*cd/255.f;
447 csc[ch] = (float)Is->channel[ch]*cs/255.f;
459 if (Lz < 0) { /* Light specifies a direction vector, reverse it to get the vector from surface to light */
464 } else { /* Light is the position of the light source */
472 i_img_empty_ch(&new_im, im->xsize, im->ysize, im->channels);
474 for(y = 0; y < im->ysize; y++) {
475 for(x = 0; x < im->xsize; x++) {
477 double dx = 0, dy = 0;
479 /* Calculate surface normal */
480 if (mx<x && x<Mx && my<y && y<My) {
481 i_gpix(bump, x + 1, y, &x1_color);
482 i_gpix(bump, x - 1, y, &x2_color);
483 i_gpix(bump, x, y + 1, &y1_color);
484 i_gpix(bump, x, y - 1, &y2_color);
485 dx = x2_color.channel[channel] - x1_color.channel[channel];
486 dy = y2_color.channel[channel] - y1_color.channel[channel];
496 /* Calculate Light vector if needed */
505 R.x = -L.x + 2*dp1*N.x;
506 R.y = -L.y + 2*dp1*N.y;
507 R.z = -L.z + 2*dp1*N.z;
511 dp1 = dp1<0 ?0 : dp1;
512 dp2 = pow(dp2<0 ?0 : dp2,n);
514 i_gpix(im, x, y, &Scol);
516 for(ch = 0; ch < im->channels; ch++)
518 saturate( Ia->channel[ch] + cdc[ch]*Scol.channel[ch]*dp1 + csc[ch]*dp2 );
520 i_ppix(&new_im, x, y, &Scol);
524 i_copyto(im, &new_im, 0, 0, im->xsize, im->ysize, 0, 0);
525 i_img_exorcise(&new_im);
530 =item i_postlevels(im, levels)
532 Quantizes Images to fewer levels.
535 levels - number of levels
541 i_postlevels(i_img *im, int levels) {
550 rv = (int) ((float)(256 / levels));
553 for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
554 i_gpix(im, x, y, &rcolor);
556 for(ch = 0; ch < im->channels; ch++) {
557 pv = (((float)rcolor.channel[ch] / 255)) * av;
558 pv = (int) ((int)pv * rv);
561 else if(pv > 255) pv = 255;
563 rcolor.channel[ch] = (unsigned char) pv;
565 i_ppix(im, x, y, &rcolor);
571 =item i_mosaic(im, size)
573 Makes an image looks like a mosaic with tilesize of size
582 i_mosaic(i_img *im, i_img_dim size) {
591 sqrsize = size * size;
593 for(y = 0; y < im->ysize; y += size) for(x = 0; x < im->xsize; x += size) {
594 for(z = 0; z < 256; z++) col[z] = 0;
596 for(lx = 0; lx < size; lx++) {
597 for(ly = 0; ly < size; ly++) {
598 i_gpix(im, (x + lx), (y + ly), &rcolor);
600 for(ch = 0; ch < im->channels; ch++) {
601 col[ch] += rcolor.channel[ch];
606 for(ch = 0; ch < im->channels; ch++)
607 rcolor.channel[ch] = (int) ((float)col[ch] / sqrsize);
610 for(lx = 0; lx < size; lx++)
611 for(ly = 0; ly < size; ly++)
612 i_ppix(im, (x + lx), (y + ly), &rcolor);
619 =item i_watermark(im, wmark, tx, ty, pixdiff)
621 Applies a watermark to the target image
624 wmark - watermark image
625 tx - x coordinate of where watermark should be applied
626 ty - y coordinate of where watermark should be applied
627 pixdiff - the magnitude of the watermark, controls how visible it is
633 i_watermark(i_img *im, i_img *wmark, i_img_dim tx, i_img_dim ty, int pixdiff) {
638 i_img_dim mx = wmark->xsize;
639 i_img_dim my = wmark->ysize;
641 for(vx=0;vx<mx;vx++) for(vy=0;vy<my;vy++) {
643 i_gpix(im, tx+vx, ty+vy,&val );
644 i_gpix(wmark, vx, vy, &wval);
646 for(ch=0;ch<im->channels;ch++)
647 val.channel[ch] = saturate( val.channel[ch] + (pixdiff* (wval.channel[0]-128) )/128 );
649 i_ppix(im,tx+vx,ty+vy,&val);
655 =item i_autolevels(im, lsat, usat, skew)
657 Scales and translates each color such that it fills the range completely.
658 Skew is not implemented yet - purpose is to control the color skew that can
659 occur when changing the contrast.
662 lsat - fraction of pixels that will be truncated at the lower end of the spectrum
663 usat - fraction of pixels that will be truncated at the higher end of the spectrum
670 i_autolevels(i_img *im, float lsat, float usat, float skew) {
672 i_img_dim i, x, y, rhist[256], ghist[256], bhist[256];
673 i_img_dim rsum, rmin, rmax;
674 i_img_dim gsum, gmin, gmax;
675 i_img_dim bsum, bmin, bmax;
676 i_img_dim rcl, rcu, gcl, gcu, bcl, bcu;
679 im_log((aIMCTX, 1,"i_autolevels(im %p, lsat %f,usat %f,skew %f)\n", im, lsat,usat,skew));
682 for(i=0;i<256;i++) rhist[i]=ghist[i]=bhist[i] = 0;
683 /* create histogram for each channel */
684 for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
685 i_gpix(im, x, y, &val);
686 rhist[val.channel[0]]++;
687 ghist[val.channel[1]]++;
688 bhist[val.channel[2]]++;
697 rmin = gmin = bmin = 0;
698 rmax = gmax = bmax = 255;
700 rcu = rcl = gcu = gcl = bcu = bcl = 0;
702 for(i=0; i<256; i++) {
703 rcl += rhist[i]; if ( (rcl<rsum*lsat) ) rmin=i;
704 rcu += rhist[255-i]; if ( (rcu<rsum*usat) ) rmax=255-i;
706 gcl += ghist[i]; if ( (gcl<gsum*lsat) ) gmin=i;
707 gcu += ghist[255-i]; if ( (gcu<gsum*usat) ) gmax=255-i;
709 bcl += bhist[i]; if ( (bcl<bsum*lsat) ) bmin=i;
710 bcu += bhist[255-i]; if ( (bcu<bsum*usat) ) bmax=255-i;
713 for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
714 i_gpix(im, x, y, &val);
715 val.channel[0]=saturate((val.channel[0]-rmin)*255/(rmax-rmin));
716 val.channel[1]=saturate((val.channel[1]-gmin)*255/(gmax-gmin));
717 val.channel[2]=saturate((val.channel[2]-bmin)*255/(bmax-bmin));
718 i_ppix(im, x, y, &val);
725 Pseudo noise utility function used to generate perlin noise. (internal)
735 Noise(i_img_dim x, i_img_dim y) {
736 i_img_dim n = x + y * 57;
738 return ( 1.0 - ( (n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff) / 1073741824.0);
742 =item SmoothedNoise1(x,y)
744 Pseudo noise utility function used to generate perlin noise. (internal)
754 SmoothedNoise1(double x, double y) {
755 double corners = ( Noise(x-1, y-1)+Noise(x+1, y-1)+Noise(x-1, y+1)+Noise(x+1, y+1) ) / 16;
756 double sides = ( Noise(x-1, y) +Noise(x+1, y) +Noise(x, y-1) +Noise(x, y+1) ) / 8;
757 double center = Noise(x, y) / 4;
758 return corners + sides + center;
763 =item G_Interpolate(a, b, x)
765 Utility function used to generate perlin noise. (internal)
772 C_Interpolate(double a, double b, double x) {
773 /* float ft = x * 3.1415927; */
775 double f = (1 - cos(ft)) * .5;
776 return a*(1-f) + b*f;
781 =item InterpolatedNoise(x, y)
783 Utility function used to generate perlin noise. (internal)
790 InterpolatedNoise(double x, double y) {
792 i_img_dim integer_X = x;
793 double fractional_X = x - integer_X;
794 i_img_dim integer_Y = y;
795 double fractional_Y = y - integer_Y;
797 double v1 = SmoothedNoise1(integer_X, integer_Y);
798 double v2 = SmoothedNoise1(integer_X + 1, integer_Y);
799 double v3 = SmoothedNoise1(integer_X, integer_Y + 1);
800 double v4 = SmoothedNoise1(integer_X + 1, integer_Y + 1);
802 double i1 = C_Interpolate(v1 , v2 , fractional_X);
803 double i2 = C_Interpolate(v3 , v4 , fractional_X);
805 return C_Interpolate(i1 , i2 , fractional_Y);
811 =item PerlinNoise_2D(x, y)
813 Utility function used to generate perlin noise. (internal)
820 PerlinNoise_2D(float x, float y) {
824 int Number_Of_Octaves=6;
825 int n = Number_Of_Octaves - 1;
830 total = total + InterpolatedNoise(x * frequency, y * frequency) * amplitude;
838 =item i_radnoise(im, xo, yo, rscale, ascale)
840 Perlin-like radial noise.
843 xo - x coordinate of center
844 yo - y coordinate of center
845 rscale - radial scale
846 ascale - angular scale
852 i_radnoise(i_img *im, i_img_dim xo, i_img_dim yo, double rscale, double ascale) {
860 for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
861 xc = (double)x-xo+0.5;
862 yc = (double)y-yo+0.5;
863 r = rscale*sqrt(xc*xc+yc*yc)+1.2;
864 a = (PI+atan2(yc,xc))*ascale;
865 v = saturate(128+100*(PerlinNoise_2D(a,r)));
866 /* v=saturate(120+12*PerlinNoise_2D(xo+(float)x/scale,yo+(float)y/scale)); Good soft marble */
867 for(ch=0; ch<im->channels; ch++) val.channel[ch]=v;
868 i_ppix(im, x, y, &val);
874 =item i_turbnoise(im, xo, yo, scale)
876 Perlin-like 2d noise noise.
879 xo - x coordinate translation
880 yo - y coordinate translation
881 scale - scale of noise
887 i_turbnoise(i_img *im, double xo, double yo, double scale) {
893 for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
894 /* v=saturate(125*(1.0+PerlinNoise_2D(xo+(float)x/scale,yo+(float)y/scale))); */
895 v = saturate(120*(1.0+sin(xo+(double)x/scale+PerlinNoise_2D(xo+(double)x/scale,yo+(float)y/scale))));
896 for(ch=0; ch<im->channels; ch++) val.channel[ch] = v;
897 i_ppix(im, x, y, &val);
904 =item i_gradgen(im, num, xo, yo, ival, dmeasure)
906 Gradient generating function.
909 num - number of points given
910 xo - array of x coordinates
911 yo - array of y coordinates
912 ival - array of i_color objects
913 dmeasure - distance measure to be used.
915 1 = Euclidean squared
916 2 = Manhattan distance
923 i_gradgen(i_img *im, int num, i_img_dim *xo, i_img_dim *yo, i_color *ival, int dmeasure) {
928 int channels = im->channels;
929 i_img_dim xsize = im->xsize;
930 i_img_dim ysize = im->ysize;
936 im_log((aIMCTX, 1,"i_gradgen(im %p, num %d, xo %p, yo %p, ival %p, dmeasure %d)\n", im, num, xo, yo, ival, dmeasure));
938 for(p = 0; p<num; p++) {
939 im_log((aIMCTX,1,"i_gradgen: p%d(" i_DFp ")\n", p, i_DFcp(xo[p], yo[p])));
943 /* on the systems I have sizeof(float) == sizeof(int) and thus
944 this would be same size as the arrays xo and yo point at, but this
945 may not be true for other systems
947 since the arrays here are caller controlled, I assume that on
948 overflow is a programming error rather than an end-user error, so
949 calling exit() is justified.
951 bytes = sizeof(double) * num;
952 if (bytes / num != sizeof(double)) {
953 fprintf(stderr, "integer overflow calculating memory allocation");
956 fdist = mymalloc( bytes ); /* checked 14jul05 tonyc */
958 for(y = 0; y<ysize; y++) for(x = 0; x<xsize; x++) {
961 for(p = 0; p<num; p++) {
962 i_img_dim xd = x-xo[p];
963 i_img_dim yd = y-yo[p];
965 case 0: /* euclidean */
966 fdist[p] = sqrt(xd*xd + yd*yd); /* euclidean distance */
968 case 1: /* euclidean squared */
969 fdist[p] = xd*xd + yd*yd; /* euclidean distance */
971 case 2: /* euclidean squared */
972 fdist[p] = i_max(xd*xd, yd*yd); /* manhattan distance */
975 i_fatal(3,"i_gradgen: Unknown distance measure\n");
980 csd = 1/((num-1)*cs);
982 for(p = 0; p<num; p++) fdist[p] = (cs-fdist[p])*csd;
984 for(ch = 0; ch<channels; ch++) {
986 for(p = 0; p<num; p++) tres += ival[p].channel[ch] * fdist[p];
987 val.channel[ch] = saturate(tres);
989 i_ppix(im, x, y, &val);
996 i_nearest_color_foo(i_img *im, int num, i_img_dim *xo, i_img_dim *yo, i_color *ival, int dmeasure) {
1000 i_img_dim xsize = im->xsize;
1001 i_img_dim ysize = im->ysize;
1004 im_log((aIMCTX,1,"i_gradgen(im %p, num %d, xo %p, yo %p, ival %p, dmeasure %d)\n", im, num, xo, yo, ival, dmeasure));
1006 for(p = 0; p<num; p++) {
1007 im_log((aIMCTX, 1,"i_gradgen: p%d(" i_DFp ")\n", p, i_DFcp(xo[p], yo[p])));
1011 for(y = 0; y<ysize; y++) for(x = 0; x<xsize; x++) {
1016 i_img_dim xd = x-xo[0];
1017 i_img_dim yd = y-yo[0];
1020 case 0: /* euclidean */
1021 mindist = sqrt(xd*xd + yd*yd); /* euclidean distance */
1023 case 1: /* euclidean squared */
1024 mindist = xd*xd + yd*yd; /* euclidean distance */
1026 case 2: /* euclidean squared */
1027 mindist = i_max(xd*xd, yd*yd); /* manhattan distance */
1030 i_fatal(3,"i_nearest_color: Unknown distance measure\n");
1033 for(p = 1; p<num; p++) {
1037 case 0: /* euclidean */
1038 curdist = sqrt(xd*xd + yd*yd); /* euclidean distance */
1040 case 1: /* euclidean squared */
1041 curdist = xd*xd + yd*yd; /* euclidean distance */
1043 case 2: /* euclidean squared */
1044 curdist = i_max(xd*xd, yd*yd); /* manhattan distance */
1047 i_fatal(3,"i_nearest_color: Unknown distance measure\n");
1049 if (curdist < mindist) {
1054 i_ppix(im, x, y, &ival[midx]);
1059 =item i_nearest_color(im, num, xo, yo, oval, dmeasure)
1061 This wasn't document - quoth Addi:
1063 An arty type of filter
1065 FIXME: check IRC logs for actual text.
1073 i_img *im - image to render on.
1077 int num - number of points/colors in xo, yo, oval
1081 i_img_dim *xo - array of I<num> x positions
1085 i_img_dim *yo - array of I<num> y positions
1089 i_color *oval - array of I<num> colors
1091 xo, yo, oval correspond to each other, the point xo[i], yo[i] has a
1092 color something like oval[i], at least closer to that color than other
1097 int dmeasure - how we measure the distance from some point P(x,y) to
1106 euclidean distance: sqrt((x2-x1)**2 + (y2-y1)**2)
1110 square of euclidean distance: ((x2-x1)**2 + (y2-y1)**2)
1114 manhattan distance: max((y2-y1)**2, (x2-x1)**2)
1118 An invalid value causes an error exit (the program is aborted).
1126 i_nearest_color(i_img *im, int num, i_img_dim *xo, i_img_dim *yo, i_color *oval, int dmeasure) {
1133 i_img_dim xsize = im->xsize;
1134 i_img_dim ysize = im->ysize;
1136 size_t ival_bytes, tval_bytes;
1139 im_log((aIMCTX, 1,"i_nearest_color(im %p, num %d, xo %p, yo %p, oval %p, dmeasure %d)\n", im, num, xo, yo, oval, dmeasure));
1144 i_push_error(0, "no points supplied to nearest_color filter");
1148 if (dmeasure < 0 || dmeasure > i_dmeasure_limit) {
1149 i_push_error(0, "distance measure invalid");
1153 tval_bytes = sizeof(float)*num*im->channels;
1154 if (tval_bytes / num != sizeof(float) * im->channels) {
1155 i_push_error(0, "integer overflow calculating memory allocation");
1158 ival_bytes = sizeof(i_color) * num;
1159 if (ival_bytes / sizeof(i_color) != num) {
1160 i_push_error(0, "integer overflow calculating memory allocation");
1163 tval = mymalloc( tval_bytes ); /* checked 17feb2005 tonyc */
1164 ival = mymalloc( ival_bytes ); /* checked 17feb2005 tonyc */
1165 cmatch = mymalloc( sizeof(int)*num ); /* checked 17feb2005 tonyc */
1167 for(p = 0; p<num; p++) {
1168 for(ch = 0; ch<im->channels; ch++) tval[ p * im->channels + ch] = 0;
1173 for(y = 0; y<ysize; y++) for(x = 0; x<xsize; x++) {
1178 i_img_dim xd = x-xo[0];
1179 i_img_dim yd = y-yo[0];
1182 case 0: /* euclidean */
1183 mindist = sqrt(xd*xd + yd*yd); /* euclidean distance */
1185 case 1: /* euclidean squared */
1186 mindist = xd*xd + yd*yd; /* euclidean distance */
1188 case 2: /* manhatten distance */
1189 mindist = i_max(xd*xd, yd*yd); /* manhattan distance */
1192 i_fatal(3,"i_nearest_color: Unknown distance measure\n");
1195 for(p = 1; p<num; p++) {
1199 case 0: /* euclidean */
1200 curdist = sqrt(xd*xd + yd*yd); /* euclidean distance */
1202 case 1: /* euclidean squared */
1203 curdist = xd*xd + yd*yd; /* euclidean distance */
1205 case 2: /* euclidean squared */
1206 curdist = i_max(xd*xd, yd*yd); /* manhattan distance */
1209 i_fatal(3,"i_nearest_color: Unknown distance measure\n");
1211 if (curdist < mindist) {
1218 i_gpix(im, x, y, &val);
1219 c2 = 1.0/(float)(cmatch[midx]);
1222 for(ch = 0; ch<im->channels; ch++)
1223 tval[midx*im->channels + ch] =
1224 c1*tval[midx*im->channels + ch] + c2 * (float) val.channel[ch];
1228 for(p = 0; p<num; p++) {
1229 for(ch = 0; ch<im->channels; ch++)
1230 ival[p].channel[ch] = tval[p*im->channels + ch];
1232 /* avoid uninitialized value messages from valgrind */
1233 while (ch < MAXCHANNELS)
1234 ival[p].channel[ch++] = 0;
1237 i_nearest_color_foo(im, num, xo, yo, ival, dmeasure);
1243 =item i_unsharp_mask(im, stddev, scale)
1245 Perform an usharp mask, which is defined as subtracting the blurred
1246 image from double the original.
1252 i_unsharp_mask(i_img *im, double stddev, double scale) {
1259 /* it really shouldn't ever be more than 1.0, but maybe ... */
1264 i_gaussian(copy, stddev);
1265 if (im->bits == i_8_bits) {
1266 i_color *blur = mymalloc(im->xsize * sizeof(i_color)); /* checked 17feb2005 tonyc */
1267 i_color *out = mymalloc(im->xsize * sizeof(i_color)); /* checked 17feb2005 tonyc */
1269 for (y = 0; y < im->ysize; ++y) {
1270 i_glin(copy, 0, copy->xsize, y, blur);
1271 i_glin(im, 0, im->xsize, y, out);
1272 for (x = 0; x < im->xsize; ++x) {
1273 for (ch = 0; ch < im->channels; ++ch) {
1274 /*int temp = out[x].channel[ch] +
1275 scale * (out[x].channel[ch] - blur[x].channel[ch]);*/
1276 int temp = out[x].channel[ch] * 2 - blur[x].channel[ch];
1279 else if (temp > 255)
1281 out[x].channel[ch] = temp;
1284 i_plin(im, 0, im->xsize, y, out);
1291 i_fcolor *blur = mymalloc(im->xsize * sizeof(i_fcolor)); /* checked 17feb2005 tonyc */
1292 i_fcolor *out = mymalloc(im->xsize * sizeof(i_fcolor)); /* checked 17feb2005 tonyc */
1294 for (y = 0; y < im->ysize; ++y) {
1295 i_glinf(copy, 0, copy->xsize, y, blur);
1296 i_glinf(im, 0, im->xsize, y, out);
1297 for (x = 0; x < im->xsize; ++x) {
1298 for (ch = 0; ch < im->channels; ++ch) {
1299 double temp = out[x].channel[ch] +
1300 scale * (out[x].channel[ch] - blur[x].channel[ch]);
1303 else if (temp > 1.0)
1305 out[x].channel[ch] = temp;
1308 i_plinf(im, 0, im->xsize, y, out);
1314 i_img_destroy(copy);
1318 =item i_diff_image(im1, im2, mindist)
1320 Creates a new image that is transparent, except where the pixel in im2
1321 is different from im1, where it is the pixel from im2.
1323 The samples must differ by at least mindiff to be considered different.
1329 i_diff_image(i_img *im1, i_img *im2, double mindist) {
1331 int outchans, diffchans;
1332 i_img_dim xsize, ysize;
1336 if (im1->channels != im2->channels) {
1337 i_push_error(0, "different number of channels");
1341 outchans = diffchans = im1->channels;
1342 if (outchans == 1 || outchans == 3)
1345 xsize = i_min(im1->xsize, im2->xsize);
1346 ysize = i_min(im1->ysize, im2->ysize);
1348 out = i_sametype_chans(im1, xsize, ysize, outchans);
1350 if (im1->bits == i_8_bits && im2->bits == i_8_bits) {
1351 i_color *line1 = mymalloc(xsize * sizeof(*line1)); /* checked 17feb2005 tonyc */
1352 i_color *line2 = mymalloc(xsize * sizeof(*line1)); /* checked 17feb2005 tonyc */
1356 int imindist = (int)mindist;
1358 for (ch = 0; ch < MAXCHANNELS; ++ch)
1359 empty.channel[ch] = 0;
1361 for (y = 0; y < ysize; ++y) {
1362 i_glin(im1, 0, xsize, y, line1);
1363 i_glin(im2, 0, xsize, y, line2);
1364 if (outchans != diffchans) {
1365 /* give the output an alpha channel since it doesn't have one */
1366 for (x = 0; x < xsize; ++x)
1367 line2[x].channel[diffchans] = 255;
1369 for (x = 0; x < xsize; ++x) {
1371 for (ch = 0; ch < diffchans; ++ch) {
1372 if (line1[x].channel[ch] != line2[x].channel[ch]
1373 && abs(line1[x].channel[ch] - line2[x].channel[ch]) > imindist) {
1381 i_plin(out, 0, xsize, y, line2);
1387 i_fcolor *line1 = mymalloc(xsize * sizeof(*line1)); /* checked 17feb2005 tonyc */
1388 i_fcolor *line2 = mymalloc(xsize * sizeof(*line2)); /* checked 17feb2005 tonyc */
1392 double dist = mindist / 255.0;
1394 for (ch = 0; ch < MAXCHANNELS; ++ch)
1395 empty.channel[ch] = 0;
1397 for (y = 0; y < ysize; ++y) {
1398 i_glinf(im1, 0, xsize, y, line1);
1399 i_glinf(im2, 0, xsize, y, line2);
1400 if (outchans != diffchans) {
1401 /* give the output an alpha channel since it doesn't have one */
1402 for (x = 0; x < xsize; ++x)
1403 line2[x].channel[diffchans] = 1.0;
1405 for (x = 0; x < xsize; ++x) {
1407 for (ch = 0; ch < diffchans; ++ch) {
1408 if (line1[x].channel[ch] != line2[x].channel[ch]
1409 && fabs(line1[x].channel[ch] - line2[x].channel[ch]) > dist) {
1417 i_plinf(out, 0, xsize, y, line2);
1427 static double linear_fount_f(double x, double y, struct fount_state *state);
1428 static double bilinear_fount_f(double x, double y, struct fount_state *state);
1429 static double radial_fount_f(double x, double y, struct fount_state *state);
1430 static double square_fount_f(double x, double y, struct fount_state *state);
1431 static double revolution_fount_f(double x, double y,
1432 struct fount_state *state);
1433 static double conical_fount_f(double x, double y, struct fount_state *state);
1435 typedef double (*fount_func)(double, double, struct fount_state *);
1436 static fount_func fount_funcs[] =
1446 static double linear_interp(double pos, i_fountain_seg *seg);
1447 static double sine_interp(double pos, i_fountain_seg *seg);
1448 static double sphereup_interp(double pos, i_fountain_seg *seg);
1449 static double spheredown_interp(double pos, i_fountain_seg *seg);
1450 typedef double (*fount_interp)(double pos, i_fountain_seg *seg);
1451 static fount_interp fount_interps[] =
1460 static void direct_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg);
1461 static void hue_up_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg);
1462 static void hue_down_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg);
1463 typedef void (*fount_cinterp)(i_fcolor *out, double pos, i_fountain_seg *seg);
1464 static fount_cinterp fount_cinterps[] =
1471 typedef double (*fount_repeat)(double v);
1472 static double fount_r_none(double v);
1473 static double fount_r_sawtooth(double v);
1474 static double fount_r_triangle(double v);
1475 static double fount_r_saw_both(double v);
1476 static double fount_r_tri_both(double v);
1477 static fount_repeat fount_repeats[] =
1486 static int simple_ssample(i_fcolor *out, double x, double y,
1487 struct fount_state *state);
1488 static int random_ssample(i_fcolor *out, double x, double y,
1489 struct fount_state *state);
1490 static int circle_ssample(i_fcolor *out, double x, double y,
1491 struct fount_state *state);
1492 typedef int (*fount_ssample)(i_fcolor *out, double x, double y,
1493 struct fount_state *state);
1494 static fount_ssample fount_ssamples[] =
1503 fount_getat(i_fcolor *out, double x, double y, struct fount_state *state);
1506 Keep state information used by each type of fountain fill
1508 struct fount_state {
1509 /* precalculated for the equation of the line perpendicular to the line AB */
1520 fount_repeat rpfunc;
1521 fount_ssample ssfunc;
1523 i_fountain_seg *segs;
1528 fount_init_state(struct fount_state *state, double xa, double ya,
1529 double xb, double yb, i_fountain_type type,
1530 i_fountain_repeat repeat, int combine, int super_sample,
1531 double ssample_param, int count, i_fountain_seg *segs);
1534 fount_finish_state(struct fount_state *state);
1536 #define EPSILON (1e-6)
1539 =item i_fountain(im, xa, ya, xb, yb, type, repeat, combine, super_sample, ssample_param, count, segs)
1541 Draws a fountain fill using A(xa, ya) and B(xb, yb) as reference points.
1543 I<type> controls how the reference points are used:
1549 linear, where A is 0 and B is 1.
1553 linear in both directions from A.
1557 circular, where A is the centre of the fill, and B is a point
1560 =item i_ft_radial_square
1562 where A is the centre of the fill and B is the centre of
1563 one side of the square.
1565 =item i_ft_revolution
1567 where A is the centre of the fill and B defines the 0/1.0
1572 similar to i_ft_revolution, except that the revolution goes in both
1577 I<repeat> can be one of:
1583 values < 0 are treated as zero, values > 1 are treated as 1.
1587 negative values are treated as 0, positive values are modulo 1.0
1591 negative values are treated as zero, if (int)value is odd then the value is treated as 1-(value
1592 mod 1.0), otherwise the same as for sawtooth.
1596 like i_fr_sawtooth, except that the sawtooth pattern repeats into
1601 Like i_fr_triangle, except that negative values are handled as their
1606 If combine is non-zero then non-opaque values are combined with the
1609 I<super_sample> controls super sampling, if any. At some point I'll
1610 probably add a adaptive super-sampler. Current possible values are:
1616 No super-sampling is done.
1620 A square grid of points withing the pixel are sampled.
1624 Random points within the pixel are sampled.
1628 Points on the radius of a circle are sampled. This produces fairly
1629 good results, but is fairly slow since sin() and cos() are evaluated
1634 I<ssample_param> is intended to be roughly the number of points
1635 sampled within the pixel.
1637 I<count> and I<segs> define the segments of the fill.
1644 i_fountain(i_img *im, double xa, double ya, double xb, double yb,
1645 i_fountain_type type, i_fountain_repeat repeat,
1646 int combine, int super_sample, double ssample_param,
1647 int count, i_fountain_seg *segs) {
1648 struct fount_state state;
1650 i_fcolor *line = NULL;
1651 i_fcolor *work = NULL;
1653 i_fountain_seg *my_segs;
1654 i_fill_combine_f combine_func = NULL;
1655 i_fill_combinef_f combinef_func = NULL;
1660 /* i_fountain() allocates floating colors even for 8-bit images,
1661 so we need to do this check */
1662 line_bytes = sizeof(i_fcolor) * im->xsize;
1663 if (line_bytes / sizeof(i_fcolor) != im->xsize) {
1664 i_push_error(0, "integer overflow calculating memory allocation");
1668 line = mymalloc(line_bytes); /* checked 17feb2005 tonyc */
1670 i_get_combine(combine, &combine_func, &combinef_func);
1672 work = mymalloc(line_bytes); /* checked 17feb2005 tonyc */
1674 fount_init_state(&state, xa, ya, xb, yb, type, repeat, combine,
1675 super_sample, ssample_param, count, segs);
1676 my_segs = state.segs;
1678 for (y = 0; y < im->ysize; ++y) {
1679 i_glinf(im, 0, im->xsize, y, line);
1680 for (x = 0; x < im->xsize; ++x) {
1683 if (super_sample == i_fts_none)
1684 got_one = fount_getat(&c, x, y, &state);
1686 got_one = state.ssfunc(&c, x, y, &state);
1695 combinef_func(line, work, im->channels, im->xsize);
1696 i_plinf(im, 0, im->xsize, y, line);
1698 fount_finish_state(&state);
1699 if (work) myfree(work);
1707 struct fount_state state;
1708 } i_fill_fountain_t;
1711 fill_fountf(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width, int channels,
1714 fount_fill_destroy(i_fill_t *fill);
1716 static i_fill_fountain_t
1728 =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>)
1731 =synopsis fill = i_new_fill_fount(0, 0, 100, 100, i_ft_linear, i_ft_linear,
1732 =synopsis i_fr_triangle, 0, i_fts_grid, 9, 1, segs);
1735 Creates a new general fill which fills with a fountain fill.
1741 i_new_fill_fount(double xa, double ya, double xb, double yb,
1742 i_fountain_type type, i_fountain_repeat repeat,
1743 int combine, int super_sample, double ssample_param,
1744 int count, i_fountain_seg *segs) {
1745 i_fill_fountain_t *fill = mymalloc(sizeof(i_fill_fountain_t));
1747 *fill = fount_fill_proto;
1749 i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
1751 fill->base.combine = NULL;
1752 fill->base.combinef = NULL;
1754 fount_init_state(&fill->state, xa, ya, xb, yb, type, repeat, combine,
1755 super_sample, ssample_param, count, segs);
1763 =head1 INTERNAL FUNCTIONS
1767 =item fount_init_state(...)
1769 Used by both the fountain fill filter and the fountain fill.
1775 fount_init_state(struct fount_state *state, double xa, double ya,
1776 double xb, double yb, i_fountain_type type,
1777 i_fountain_repeat repeat, int combine, int super_sample,
1778 double ssample_param, int count, i_fountain_seg *segs) {
1781 i_fountain_seg *my_segs = mymalloc(sizeof(i_fountain_seg) * count); /* checked 2jul06 - duplicating original */
1782 /*int have_alpha = im->channels == 2 || im->channels == 4;*/
1784 memset(state, 0, sizeof(*state));
1785 /* we keep a local copy that we can adjust for speed */
1786 for (i = 0; i < count; ++i) {
1787 i_fountain_seg *seg = my_segs + i;
1790 if (seg->type < 0 || seg->type >= i_fst_end)
1791 seg->type = i_fst_linear;
1792 if (seg->color < 0 || seg->color >= i_fc_end)
1793 seg->color = i_fc_direct;
1794 if (seg->color == i_fc_hue_up || seg->color == i_fc_hue_down) {
1795 /* so we don't have to translate to HSV on each request, do it here */
1796 for (j = 0; j < 2; ++j) {
1797 i_rgb_to_hsvf(seg->c+j);
1799 if (seg->color == i_fc_hue_up) {
1800 if (seg->c[1].channel[0] <= seg->c[0].channel[0])
1801 seg->c[1].channel[0] += 1.0;
1804 if (seg->c[0].channel[0] <= seg->c[0].channel[1])
1805 seg->c[0].channel[0] += 1.0;
1808 /*printf("start %g mid %g end %g c0(%g,%g,%g,%g) c1(%g,%g,%g,%g) type %d color %d\n",
1809 seg->start, seg->middle, seg->end, seg->c[0].channel[0],
1810 seg->c[0].channel[1], seg->c[0].channel[2], seg->c[0].channel[3],
1811 seg->c[1].channel[0], seg->c[1].channel[1], seg->c[1].channel[2],
1812 seg->c[1].channel[3], seg->type, seg->color);*/
1816 /* initialize each engine */
1817 /* these are so common ... */
1818 state->lA = xb - xa;
1819 state->lB = yb - ya;
1820 state->AB = sqrt(state->lA * state->lA + state->lB * state->lB);
1825 type = i_ft_linear; /* make the invalid value valid */
1828 state->lC = ya * ya - ya * yb + xa * xa - xa * xb;
1830 state->mult = 1/linear_fount_f(xb, yb, state);
1834 state->mult = 1.0 / sqrt((double)(xb-xa)*(xb-xa)
1835 + (double)(yb-ya)*(yb-ya));
1838 case i_ft_radial_square:
1839 state->cos = state->lA / state->AB;
1840 state->sin = state->lB / state->AB;
1841 state->mult = 1.0 / state->AB;
1844 case i_ft_revolution:
1845 state->theta = atan2(yb-ya, xb-xa);
1846 state->mult = 1.0 / (PI * 2);
1850 state->theta = atan2(yb-ya, xb-xa);
1851 state->mult = 1.0 / PI;
1854 state->ffunc = fount_funcs[type];
1855 if (super_sample < 0
1856 || super_sample >= (int)(sizeof(fount_ssamples)/sizeof(*fount_ssamples))) {
1859 state->ssample_data = NULL;
1860 switch (super_sample) {
1862 ssample_param = floor(0.5 + sqrt(ssample_param));
1863 bytes = ssample_param * ssample_param * sizeof(i_fcolor);
1864 if (bytes / sizeof(i_fcolor) == ssample_param * ssample_param) {
1865 state->ssample_data = mymalloc(sizeof(i_fcolor) * ssample_param * ssample_param); /* checked 1jul06 tonyc */
1868 super_sample = i_fts_none;
1874 ssample_param = floor(0.5+ssample_param);
1875 bytes = sizeof(i_fcolor) * ssample_param;
1876 if (bytes / sizeof(i_fcolor) == ssample_param) {
1877 state->ssample_data = mymalloc(sizeof(i_fcolor) * ssample_param);
1880 super_sample = i_fts_none;
1884 state->parm = ssample_param;
1885 state->ssfunc = fount_ssamples[super_sample];
1886 if (repeat < 0 || repeat >= (sizeof(fount_repeats)/sizeof(*fount_repeats)))
1888 state->rpfunc = fount_repeats[repeat];
1889 state->segs = my_segs;
1890 state->count = count;
1894 fount_finish_state(struct fount_state *state) {
1895 if (state->ssample_data)
1896 myfree(state->ssample_data);
1897 myfree(state->segs);
1902 =item fount_getat(out, x, y, ffunc, rpfunc, state, segs, count)
1904 Evaluates the fountain fill at the given point.
1906 This is called by both the non-super-sampling and super-sampling code.
1908 You might think that it would make sense to sample the fill parameter
1909 instead, and combine those, but this breaks badly.
1915 fount_getat(i_fcolor *out, double x, double y, struct fount_state *state) {
1916 double v = (state->rpfunc)((state->ffunc)(x, y, state));
1920 while (i < state->count
1921 && (v < state->segs[i].start || v > state->segs[i].end)) {
1924 if (i < state->count) {
1925 v = (fount_interps[state->segs[i].type])(v, state->segs+i);
1926 (fount_cinterps[state->segs[i].color])(out, v, state->segs+i);
1934 =item linear_fount_f(x, y, state)
1936 Calculate the fill parameter for a linear fountain fill.
1938 Uses the point to line distance function, with some precalculation
1939 done in i_fountain().
1944 linear_fount_f(double x, double y, struct fount_state *state) {
1945 return (state->lA * x + state->lB * y + state->lC) / state->AB * state->mult;
1949 =item bilinear_fount_f(x, y, state)
1951 Calculate the fill parameter for a bi-linear fountain fill.
1956 bilinear_fount_f(double x, double y, struct fount_state *state) {
1957 return fabs((state->lA * x + state->lB * y + state->lC) / state->AB * state->mult);
1961 =item radial_fount_f(x, y, state)
1963 Calculate the fill parameter for a radial fountain fill.
1965 Simply uses the distance function.
1970 radial_fount_f(double x, double y, struct fount_state *state) {
1971 return sqrt((double)(state->xa-x)*(state->xa-x)
1972 + (double)(state->ya-y)*(state->ya-y)) * state->mult;
1976 =item square_fount_f(x, y, state)
1978 Calculate the fill parameter for a square fountain fill.
1980 Works by rotating the reference co-ordinate around the centre of the
1986 square_fount_f(double x, double y, struct fount_state *state) {
1987 i_img_dim xc, yc; /* centred on A */
1988 double xt, yt; /* rotated by theta */
1991 xt = fabs(xc * state->cos + yc * state->sin);
1992 yt = fabs(-xc * state->sin + yc * state->cos);
1993 return (xt > yt ? xt : yt) * state->mult;
1997 =item revolution_fount_f(x, y, state)
1999 Calculates the fill parameter for the revolution fountain fill.
2004 revolution_fount_f(double x, double y, struct fount_state *state) {
2005 double angle = atan2(y - state->ya, x - state->xa);
2007 angle -= state->theta;
2009 angle = fmod(angle+ PI * 4, PI*2);
2012 return angle * state->mult;
2016 =item conical_fount_f(x, y, state)
2018 Calculates the fill parameter for the conical fountain fill.
2023 conical_fount_f(double x, double y, struct fount_state *state) {
2024 double angle = atan2(y - state->ya, x - state->xa);
2026 angle -= state->theta;
2029 else if (angle > PI)
2032 return fabs(angle) * state->mult;
2036 =item linear_interp(pos, seg)
2038 Calculates linear interpolation on the fill parameter. Breaks the
2039 segment into 2 regions based in the I<middle> value.
2044 linear_interp(double pos, i_fountain_seg *seg) {
2045 if (pos < seg->middle) {
2046 double len = seg->middle - seg->start;
2050 return (pos - seg->start) / len / 2;
2053 double len = seg->end - seg->middle;
2057 return 0.5 + (pos - seg->middle) / len / 2;
2062 =item sine_interp(pos, seg)
2064 Calculates sine function interpolation on the fill parameter.
2069 sine_interp(double pos, i_fountain_seg *seg) {
2070 /* I wonder if there's a simple way to smooth the transition for this */
2071 double work = linear_interp(pos, seg);
2073 return (1-cos(work * PI))/2;
2077 =item sphereup_interp(pos, seg)
2079 Calculates spherical interpolation on the fill parameter, with the cusp
2085 sphereup_interp(double pos, i_fountain_seg *seg) {
2086 double work = linear_interp(pos, seg);
2088 return sqrt(1.0 - (1-work) * (1-work));
2092 =item spheredown_interp(pos, seg)
2094 Calculates spherical interpolation on the fill parameter, with the cusp
2100 spheredown_interp(double pos, i_fountain_seg *seg) {
2101 double work = linear_interp(pos, seg);
2103 return 1-sqrt(1.0 - work * work);
2107 =item direct_cinterp(out, pos, seg)
2109 Calculates the fountain color based on direct scaling of the channels
2110 of the color channels.
2115 direct_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg) {
2117 for (ch = 0; ch < MAXCHANNELS; ++ch) {
2118 out->channel[ch] = seg->c[0].channel[ch] * (1 - pos)
2119 + seg->c[1].channel[ch] * pos;
2124 =item hue_up_cinterp(put, pos, seg)
2126 Calculates the fountain color based on scaling a HSV value. The hue
2127 increases as the fill parameter increases.
2132 hue_up_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg) {
2134 for (ch = 0; ch < MAXCHANNELS; ++ch) {
2135 out->channel[ch] = seg->c[0].channel[ch] * (1 - pos)
2136 + seg->c[1].channel[ch] * pos;
2142 =item hue_down_cinterp(put, pos, seg)
2144 Calculates the fountain color based on scaling a HSV value. The hue
2145 decreases as the fill parameter increases.
2150 hue_down_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg) {
2152 for (ch = 0; ch < MAXCHANNELS; ++ch) {
2153 out->channel[ch] = seg->c[0].channel[ch] * (1 - pos)
2154 + seg->c[1].channel[ch] * pos;
2160 =item simple_ssample(out, parm, x, y, state, ffunc, rpfunc, segs, count)
2162 Simple grid-based super-sampling.
2167 simple_ssample(i_fcolor *out, double x, double y, struct fount_state *state) {
2168 i_fcolor *work = state->ssample_data;
2170 int grid = state->parm;
2171 double base = -0.5 + 0.5 / grid;
2172 double step = 1.0 / grid;
2176 for (dx = 0; dx < grid; ++dx) {
2177 for (dy = 0; dy < grid; ++dy) {
2178 if (fount_getat(work+samp_count, x + base + step * dx,
2179 y + base + step * dy, state)) {
2184 for (ch = 0; ch < MAXCHANNELS; ++ch) {
2185 out->channel[ch] = 0;
2186 for (i = 0; i < samp_count; ++i) {
2187 out->channel[ch] += work[i].channel[ch];
2189 /* we divide by 4 rather than samp_count since if there's only one valid
2190 sample it should be mostly transparent */
2191 out->channel[ch] /= grid * grid;
2197 =item random_ssample(out, parm, x, y, state, ffunc, rpfunc, segs, count)
2199 Random super-sampling.
2204 random_ssample(i_fcolor *out, double x, double y,
2205 struct fount_state *state) {
2206 i_fcolor *work = state->ssample_data;
2208 int maxsamples = state->parm;
2209 double rand_scale = 1.0 / RAND_MAX;
2211 for (i = 0; i < maxsamples; ++i) {
2212 if (fount_getat(work+samp_count, x - 0.5 + rand() * rand_scale,
2213 y - 0.5 + rand() * rand_scale, state)) {
2217 for (ch = 0; ch < MAXCHANNELS; ++ch) {
2218 out->channel[ch] = 0;
2219 for (i = 0; i < samp_count; ++i) {
2220 out->channel[ch] += work[i].channel[ch];
2222 /* we divide by maxsamples rather than samp_count since if there's
2223 only one valid sample it should be mostly transparent */
2224 out->channel[ch] /= maxsamples;
2230 =item circle_ssample(out, parm, x, y, state, ffunc, rpfunc, segs, count)
2232 Super-sampling around the circumference of a circle.
2234 I considered saving the sin()/cos() values and transforming step-size
2235 around the circle, but that's inaccurate, though it may not matter
2241 circle_ssample(i_fcolor *out, double x, double y,
2242 struct fount_state *state) {
2243 i_fcolor *work = state->ssample_data;
2245 int maxsamples = state->parm;
2246 double angle = 2 * PI / maxsamples;
2247 double radius = 0.3; /* semi-random */
2249 for (i = 0; i < maxsamples; ++i) {
2250 if (fount_getat(work+samp_count, x + radius * cos(angle * i),
2251 y + radius * sin(angle * i), state)) {
2255 for (ch = 0; ch < MAXCHANNELS; ++ch) {
2256 out->channel[ch] = 0;
2257 for (i = 0; i < samp_count; ++i) {
2258 out->channel[ch] += work[i].channel[ch];
2260 /* we divide by maxsamples rather than samp_count since if there's
2261 only one valid sample it should be mostly transparent */
2262 out->channel[ch] /= maxsamples;
2268 =item fount_r_none(v)
2270 Implements no repeats. Simply clamps the fill value.
2275 fount_r_none(double v) {
2276 return v < 0 ? 0 : v > 1 ? 1 : v;
2280 =item fount_r_sawtooth(v)
2282 Implements sawtooth repeats. Clamps negative values and uses fmod()
2288 fount_r_sawtooth(double v) {
2289 return v < 0 ? 0 : fmod(v, 1.0);
2293 =item fount_r_triangle(v)
2295 Implements triangle repeats. Clamps negative values, uses fmod to get
2296 a range 0 through 2 and then adjusts values > 1.
2301 fount_r_triangle(double v) {
2306 return v > 1.0 ? 2.0 - v : v;
2311 =item fount_r_saw_both(v)
2313 Implements sawtooth repeats in the both postive and negative directions.
2315 Adjusts the value to be postive and then just uses fmod().
2320 fount_r_saw_both(double v) {
2323 return fmod(v, 1.0);
2327 =item fount_r_tri_both(v)
2329 Implements triangle repeats in the both postive and negative directions.
2331 Uses fmod on the absolute value, and then adjusts values > 1.
2336 fount_r_tri_both(double v) {
2337 v = fmod(fabs(v), 2.0);
2338 return v > 1.0 ? 2.0 - v : v;
2342 =item fill_fountf(fill, x, y, width, channels, data)
2344 The fill function for fountain fills.
2349 fill_fountf(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
2350 int channels, i_fcolor *data) {
2351 i_fill_fountain_t *f = (i_fill_fountain_t *)fill;
2357 if (f->state.ssfunc)
2358 got_one = f->state.ssfunc(&c, x, y, &f->state);
2360 got_one = fount_getat(&c, x, y, &f->state);
2369 =item fount_fill_destroy(fill)
2374 fount_fill_destroy(i_fill_t *fill) {
2375 i_fill_fountain_t *f = (i_fill_fountain_t *)fill;
2376 fount_finish_state(&f->state);
2384 Arnar M. Hrafnkelsson <addi@umich.edu>
2386 Tony Cook <tony@develop-help.com> (i_fountain())