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,
419 i_img_dim mx, Mx, my, My;
421 float cdc[MAXCHANNELS];
422 float csc[MAXCHANNELS];
424 i_color x1_color, y1_color, x2_color, y2_color;
426 i_color Scol; /* Surface colour */
428 fvec L; /* Light vector */
429 fvec N; /* surface normal */
430 fvec R; /* Reflection vector */
431 fvec V; /* Vision vector */
435 im_log((aIMCTX, 1, "i_bumpmap_complex(im %p, bump %p, channel %d, t(" i_DFp
436 "), Lx %.2f, Ly %.2f, Lz %.2f, cd %.2f, cs %.2f, n %.2f, Ia %p, Il %p, Is %p)\n",
437 im, bump, channel, i_DFcp(tx, ty), Lx, Ly, Lz, cd, cs, n, Ia, Il, Is));
439 if (channel >= bump->channels) {
440 im_log((aIMCTX, 1, "i_bumpmap_complex: channel = %d while bump image only has %d channels\n", channel, bump->channels));
444 for(ch=0; ch<im->channels; ch++) {
445 cdc[ch] = (float)Il->channel[ch]*cd/255.f;
446 csc[ch] = (float)Is->channel[ch]*cs/255.f;
458 if (Lz < 0) { /* Light specifies a direction vector, reverse it to get the vector from surface to light */
463 } else { /* Light is the position of the light source */
470 i_img_empty_ch(&new_im, im->xsize, im->ysize, im->channels);
472 for(y = 0; y < im->ysize; y++) {
473 for(x = 0; x < im->xsize; x++) {
475 double dx = 0, dy = 0;
477 /* Calculate surface normal */
478 if (mx<x && x<Mx && my<y && y<My) {
479 i_gpix(bump, x + 1, y, &x1_color);
480 i_gpix(bump, x - 1, y, &x2_color);
481 i_gpix(bump, x, y + 1, &y1_color);
482 i_gpix(bump, x, y - 1, &y2_color);
483 dx = x2_color.channel[channel] - x1_color.channel[channel];
484 dy = y2_color.channel[channel] - y1_color.channel[channel];
494 /* Calculate Light vector if needed */
503 R.x = -L.x + 2*dp1*N.x;
504 R.y = -L.y + 2*dp1*N.y;
505 R.z = -L.z + 2*dp1*N.z;
509 dp1 = dp1<0 ?0 : dp1;
510 dp2 = pow(dp2<0 ?0 : dp2,n);
512 i_gpix(im, x, y, &Scol);
514 for(ch = 0; ch < im->channels; ch++)
516 saturate( Ia->channel[ch] + cdc[ch]*Scol.channel[ch]*dp1 + csc[ch]*dp2 );
518 i_ppix(&new_im, x, y, &Scol);
522 i_copyto(im, &new_im, 0, 0, im->xsize, im->ysize, 0, 0);
523 i_img_exorcise(&new_im);
528 =item i_postlevels(im, levels)
530 Quantizes Images to fewer levels.
533 levels - number of levels
539 i_postlevels(i_img *im, int levels) {
548 rv = (int) ((float)(256 / levels));
551 for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
552 i_gpix(im, x, y, &rcolor);
554 for(ch = 0; ch < im->channels; ch++) {
555 pv = (((float)rcolor.channel[ch] / 255)) * av;
556 pv = (int) ((int)pv * rv);
559 else if(pv > 255) pv = 255;
561 rcolor.channel[ch] = (unsigned char) pv;
563 i_ppix(im, x, y, &rcolor);
569 =item i_mosaic(im, size)
571 Makes an image looks like a mosaic with tilesize of size
580 i_mosaic(i_img *im, i_img_dim size) {
589 sqrsize = size * size;
591 for(y = 0; y < im->ysize; y += size) for(x = 0; x < im->xsize; x += size) {
592 for(z = 0; z < 256; z++) col[z] = 0;
594 for(lx = 0; lx < size; lx++) {
595 for(ly = 0; ly < size; ly++) {
596 i_gpix(im, (x + lx), (y + ly), &rcolor);
598 for(ch = 0; ch < im->channels; ch++) {
599 col[ch] += rcolor.channel[ch];
604 for(ch = 0; ch < im->channels; ch++)
605 rcolor.channel[ch] = (int) ((float)col[ch] / sqrsize);
608 for(lx = 0; lx < size; lx++)
609 for(ly = 0; ly < size; ly++)
610 i_ppix(im, (x + lx), (y + ly), &rcolor);
617 =item i_watermark(im, wmark, tx, ty, pixdiff)
619 Applies a watermark to the target image
622 wmark - watermark image
623 tx - x coordinate of where watermark should be applied
624 ty - y coordinate of where watermark should be applied
625 pixdiff - the magnitude of the watermark, controls how visible it is
631 i_watermark(i_img *im, i_img *wmark, i_img_dim tx, i_img_dim ty, int pixdiff) {
636 i_img_dim mx = wmark->xsize;
637 i_img_dim my = wmark->ysize;
639 for(vx=0;vx<mx;vx++) for(vy=0;vy<my;vy++) {
641 i_gpix(im, tx+vx, ty+vy,&val );
642 i_gpix(wmark, vx, vy, &wval);
644 for(ch=0;ch<im->channels;ch++)
645 val.channel[ch] = saturate( val.channel[ch] + (pixdiff* (wval.channel[0]-128) )/128 );
647 i_ppix(im,tx+vx,ty+vy,&val);
653 =item i_autolevels(im, lsat, usat, skew)
655 Scales and translates each color such that it fills the range completely.
656 Skew is not implemented yet - purpose is to control the color skew that can
657 occur when changing the contrast.
660 lsat - fraction of pixels that will be truncated at the lower end of the spectrum
661 usat - fraction of pixels that will be truncated at the higher end of the spectrum
668 i_autolevels(i_img *im, float lsat, float usat, float skew) {
670 i_img_dim i, x, y, rhist[256], ghist[256], bhist[256];
671 i_img_dim rsum, rmin, rmax;
672 i_img_dim gsum, gmin, gmax;
673 i_img_dim bsum, bmin, bmax;
674 i_img_dim rcl, rcu, gcl, gcu, bcl, bcu;
677 im_log((aIMCTX, 1,"i_autolevels(im %p, lsat %f,usat %f,skew %f)\n", im, lsat,usat,skew));
680 for(i=0;i<256;i++) rhist[i]=ghist[i]=bhist[i] = 0;
681 /* create histogram for each channel */
682 for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
683 i_gpix(im, x, y, &val);
684 rhist[val.channel[0]]++;
685 ghist[val.channel[1]]++;
686 bhist[val.channel[2]]++;
695 rmin = gmin = bmin = 0;
696 rmax = gmax = bmax = 255;
698 rcu = rcl = gcu = gcl = bcu = bcl = 0;
700 for(i=0; i<256; i++) {
701 rcl += rhist[i]; if ( (rcl<rsum*lsat) ) rmin=i;
702 rcu += rhist[255-i]; if ( (rcu<rsum*usat) ) rmax=255-i;
704 gcl += ghist[i]; if ( (gcl<gsum*lsat) ) gmin=i;
705 gcu += ghist[255-i]; if ( (gcu<gsum*usat) ) gmax=255-i;
707 bcl += bhist[i]; if ( (bcl<bsum*lsat) ) bmin=i;
708 bcu += bhist[255-i]; if ( (bcu<bsum*usat) ) bmax=255-i;
711 for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
712 i_gpix(im, x, y, &val);
713 val.channel[0]=saturate((val.channel[0]-rmin)*255/(rmax-rmin));
714 val.channel[1]=saturate((val.channel[1]-gmin)*255/(gmax-gmin));
715 val.channel[2]=saturate((val.channel[2]-bmin)*255/(bmax-bmin));
716 i_ppix(im, x, y, &val);
723 Pseudo noise utility function used to generate perlin noise. (internal)
733 Noise(i_img_dim x, i_img_dim y) {
734 i_img_dim n = x + y * 57;
736 return ( 1.0 - ( (n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff) / 1073741824.0);
740 =item SmoothedNoise1(x,y)
742 Pseudo noise utility function used to generate perlin noise. (internal)
752 SmoothedNoise1(double x, double y) {
753 double corners = ( Noise(x-1, y-1)+Noise(x+1, y-1)+Noise(x-1, y+1)+Noise(x+1, y+1) ) / 16;
754 double sides = ( Noise(x-1, y) +Noise(x+1, y) +Noise(x, y-1) +Noise(x, y+1) ) / 8;
755 double center = Noise(x, y) / 4;
756 return corners + sides + center;
761 =item G_Interpolate(a, b, x)
763 Utility function used to generate perlin noise. (internal)
770 C_Interpolate(double a, double b, double x) {
771 /* float ft = x * 3.1415927; */
773 double f = (1 - cos(ft)) * .5;
774 return a*(1-f) + b*f;
779 =item InterpolatedNoise(x, y)
781 Utility function used to generate perlin noise. (internal)
788 InterpolatedNoise(double x, double y) {
790 i_img_dim integer_X = x;
791 double fractional_X = x - integer_X;
792 i_img_dim integer_Y = y;
793 double fractional_Y = y - integer_Y;
795 double v1 = SmoothedNoise1(integer_X, integer_Y);
796 double v2 = SmoothedNoise1(integer_X + 1, integer_Y);
797 double v3 = SmoothedNoise1(integer_X, integer_Y + 1);
798 double v4 = SmoothedNoise1(integer_X + 1, integer_Y + 1);
800 double i1 = C_Interpolate(v1 , v2 , fractional_X);
801 double i2 = C_Interpolate(v3 , v4 , fractional_X);
803 return C_Interpolate(i1 , i2 , fractional_Y);
809 =item PerlinNoise_2D(x, y)
811 Utility function used to generate perlin noise. (internal)
818 PerlinNoise_2D(float x, float y) {
822 int Number_Of_Octaves=6;
823 int n = Number_Of_Octaves - 1;
828 total = total + InterpolatedNoise(x * frequency, y * frequency) * amplitude;
836 =item i_radnoise(im, xo, yo, rscale, ascale)
838 Perlin-like radial noise.
841 xo - x coordinate of center
842 yo - y coordinate of center
843 rscale - radial scale
844 ascale - angular scale
850 i_radnoise(i_img *im, i_img_dim xo, i_img_dim yo, double rscale, double ascale) {
858 for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
859 xc = (double)x-xo+0.5;
860 yc = (double)y-yo+0.5;
861 r = rscale*sqrt(xc*xc+yc*yc)+1.2;
862 a = (PI+atan2(yc,xc))*ascale;
863 v = saturate(128+100*(PerlinNoise_2D(a,r)));
864 /* v=saturate(120+12*PerlinNoise_2D(xo+(float)x/scale,yo+(float)y/scale)); Good soft marble */
865 for(ch=0; ch<im->channels; ch++) val.channel[ch]=v;
866 i_ppix(im, x, y, &val);
872 =item i_turbnoise(im, xo, yo, scale)
874 Perlin-like 2d noise noise.
877 xo - x coordinate translation
878 yo - y coordinate translation
879 scale - scale of noise
885 i_turbnoise(i_img *im, double xo, double yo, double scale) {
891 for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
892 /* v=saturate(125*(1.0+PerlinNoise_2D(xo+(float)x/scale,yo+(float)y/scale))); */
893 v = saturate(120*(1.0+sin(xo+(double)x/scale+PerlinNoise_2D(xo+(double)x/scale,yo+(float)y/scale))));
894 for(ch=0; ch<im->channels; ch++) val.channel[ch] = v;
895 i_ppix(im, x, y, &val);
902 =item i_gradgen(im, num, xo, yo, ival, dmeasure)
904 Gradient generating function.
907 num - number of points given
908 xo - array of x coordinates
909 yo - array of y coordinates
910 ival - array of i_color objects
911 dmeasure - distance measure to be used.
913 1 = Euclidean squared
914 2 = Manhattan distance
921 i_gradgen(i_img *im, int num, i_img_dim *xo, i_img_dim *yo, i_color *ival, int dmeasure) {
926 int channels = im->channels;
927 i_img_dim xsize = im->xsize;
928 i_img_dim ysize = im->ysize;
934 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));
936 for(p = 0; p<num; p++) {
937 im_log((aIMCTX,1,"i_gradgen: p%d(" i_DFp ")\n", p, i_DFcp(xo[p], yo[p])));
941 /* on the systems I have sizeof(float) == sizeof(int) and thus
942 this would be same size as the arrays xo and yo point at, but this
943 may not be true for other systems
945 since the arrays here are caller controlled, I assume that on
946 overflow is a programming error rather than an end-user error, so
947 calling exit() is justified.
949 bytes = sizeof(double) * num;
950 if (bytes / num != sizeof(double)) {
951 fprintf(stderr, "integer overflow calculating memory allocation");
954 fdist = mymalloc( bytes ); /* checked 14jul05 tonyc */
956 for(y = 0; y<ysize; y++) for(x = 0; x<xsize; x++) {
959 for(p = 0; p<num; p++) {
960 i_img_dim xd = x-xo[p];
961 i_img_dim yd = y-yo[p];
963 case 0: /* euclidean */
964 fdist[p] = sqrt(xd*xd + yd*yd); /* euclidean distance */
966 case 1: /* euclidean squared */
967 fdist[p] = xd*xd + yd*yd; /* euclidean distance */
969 case 2: /* euclidean squared */
970 fdist[p] = i_max(xd*xd, yd*yd); /* manhattan distance */
973 im_fatal(aIMCTX, 3,"i_gradgen: Unknown distance measure\n");
978 csd = 1/((num-1)*cs);
980 for(p = 0; p<num; p++) fdist[p] = (cs-fdist[p])*csd;
982 for(ch = 0; ch<channels; ch++) {
984 for(p = 0; p<num; p++) tres += ival[p].channel[ch] * fdist[p];
985 val.channel[ch] = saturate(tres);
987 i_ppix(im, x, y, &val);
994 i_nearest_color_foo(i_img *im, int num, i_img_dim *xo, i_img_dim *yo, i_color *ival, int dmeasure) {
998 i_img_dim xsize = im->xsize;
999 i_img_dim ysize = im->ysize;
1002 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));
1004 for(p = 0; p<num; p++) {
1005 im_log((aIMCTX, 1,"i_gradgen: p%d(" i_DFp ")\n", p, i_DFcp(xo[p], yo[p])));
1009 for(y = 0; y<ysize; y++) for(x = 0; x<xsize; x++) {
1014 i_img_dim xd = x-xo[0];
1015 i_img_dim yd = y-yo[0];
1018 case 0: /* euclidean */
1019 mindist = sqrt(xd*xd + yd*yd); /* euclidean distance */
1021 case 1: /* euclidean squared */
1022 mindist = xd*xd + yd*yd; /* euclidean distance */
1024 case 2: /* euclidean squared */
1025 mindist = i_max(xd*xd, yd*yd); /* manhattan distance */
1028 im_fatal(aIMCTX, 3,"i_nearest_color: Unknown distance measure\n");
1031 for(p = 1; p<num; p++) {
1035 case 0: /* euclidean */
1036 curdist = sqrt(xd*xd + yd*yd); /* euclidean distance */
1038 case 1: /* euclidean squared */
1039 curdist = xd*xd + yd*yd; /* euclidean distance */
1041 case 2: /* euclidean squared */
1042 curdist = i_max(xd*xd, yd*yd); /* manhattan distance */
1045 im_fatal(aIMCTX, 3,"i_nearest_color: Unknown distance measure\n");
1047 if (curdist < mindist) {
1052 i_ppix(im, x, y, &ival[midx]);
1057 =item i_nearest_color(im, num, xo, yo, oval, dmeasure)
1059 This wasn't document - quoth Addi:
1061 An arty type of filter
1063 FIXME: check IRC logs for actual text.
1071 i_img *im - image to render on.
1075 int num - number of points/colors in xo, yo, oval
1079 i_img_dim *xo - array of I<num> x positions
1083 i_img_dim *yo - array of I<num> y positions
1087 i_color *oval - array of I<num> colors
1089 xo, yo, oval correspond to each other, the point xo[i], yo[i] has a
1090 color something like oval[i], at least closer to that color than other
1095 int dmeasure - how we measure the distance from some point P(x,y) to
1104 euclidean distance: sqrt((x2-x1)**2 + (y2-y1)**2)
1108 square of euclidean distance: ((x2-x1)**2 + (y2-y1)**2)
1112 manhattan distance: max((y2-y1)**2, (x2-x1)**2)
1116 An invalid value causes an error exit (the program is aborted).
1124 i_nearest_color(i_img *im, int num, i_img_dim *xo, i_img_dim *yo, i_color *oval, int dmeasure) {
1131 i_img_dim xsize = im->xsize;
1132 i_img_dim ysize = im->ysize;
1134 size_t ival_bytes, tval_bytes;
1137 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));
1142 i_push_error(0, "no points supplied to nearest_color filter");
1146 if (dmeasure < 0 || dmeasure > i_dmeasure_limit) {
1147 i_push_error(0, "distance measure invalid");
1151 tval_bytes = sizeof(float)*num*im->channels;
1152 if (tval_bytes / num != sizeof(float) * im->channels) {
1153 i_push_error(0, "integer overflow calculating memory allocation");
1156 ival_bytes = sizeof(i_color) * num;
1157 if (ival_bytes / sizeof(i_color) != num) {
1158 i_push_error(0, "integer overflow calculating memory allocation");
1161 tval = mymalloc( tval_bytes ); /* checked 17feb2005 tonyc */
1162 ival = mymalloc( ival_bytes ); /* checked 17feb2005 tonyc */
1163 cmatch = mymalloc( sizeof(int)*num ); /* checked 17feb2005 tonyc */
1165 for(p = 0; p<num; p++) {
1166 for(ch = 0; ch<im->channels; ch++) tval[ p * im->channels + ch] = 0;
1171 for(y = 0; y<ysize; y++) for(x = 0; x<xsize; x++) {
1176 i_img_dim xd = x-xo[0];
1177 i_img_dim yd = y-yo[0];
1180 case 0: /* euclidean */
1181 mindist = sqrt(xd*xd + yd*yd); /* euclidean distance */
1183 case 1: /* euclidean squared */
1184 mindist = xd*xd + yd*yd; /* euclidean distance */
1186 case 2: /* manhatten distance */
1187 mindist = i_max(xd*xd, yd*yd); /* manhattan distance */
1190 im_fatal(aIMCTX, 3,"i_nearest_color: Unknown distance measure\n");
1193 for(p = 1; p<num; p++) {
1197 case 0: /* euclidean */
1198 curdist = sqrt(xd*xd + yd*yd); /* euclidean distance */
1200 case 1: /* euclidean squared */
1201 curdist = xd*xd + yd*yd; /* euclidean distance */
1203 case 2: /* euclidean squared */
1204 curdist = i_max(xd*xd, yd*yd); /* manhattan distance */
1207 im_fatal(aIMCTX, 3,"i_nearest_color: Unknown distance measure\n");
1209 if (curdist < mindist) {
1216 i_gpix(im, x, y, &val);
1217 c2 = 1.0/(float)(cmatch[midx]);
1220 for(ch = 0; ch<im->channels; ch++)
1221 tval[midx*im->channels + ch] =
1222 c1*tval[midx*im->channels + ch] + c2 * (float) val.channel[ch];
1226 for(p = 0; p<num; p++) {
1227 for(ch = 0; ch<im->channels; ch++)
1228 ival[p].channel[ch] = tval[p*im->channels + ch];
1230 /* avoid uninitialized value messages from valgrind */
1231 while (ch < MAXCHANNELS)
1232 ival[p].channel[ch++] = 0;
1235 i_nearest_color_foo(im, num, xo, yo, ival, dmeasure);
1241 =item i_unsharp_mask(im, stddev, scale)
1243 Perform an usharp mask, which is defined as subtracting the blurred
1244 image from double the original.
1250 i_unsharp_mask(i_img *im, double stddev, double scale) {
1257 /* it really shouldn't ever be more than 1.0, but maybe ... */
1262 i_gaussian(copy, stddev);
1263 if (im->bits == i_8_bits) {
1264 i_color *blur = mymalloc(im->xsize * sizeof(i_color)); /* checked 17feb2005 tonyc */
1265 i_color *out = mymalloc(im->xsize * sizeof(i_color)); /* checked 17feb2005 tonyc */
1267 for (y = 0; y < im->ysize; ++y) {
1268 i_glin(copy, 0, copy->xsize, y, blur);
1269 i_glin(im, 0, im->xsize, y, out);
1270 for (x = 0; x < im->xsize; ++x) {
1271 for (ch = 0; ch < im->channels; ++ch) {
1272 /*int temp = out[x].channel[ch] +
1273 scale * (out[x].channel[ch] - blur[x].channel[ch]);*/
1274 int temp = out[x].channel[ch] * 2 - blur[x].channel[ch];
1277 else if (temp > 255)
1279 out[x].channel[ch] = temp;
1282 i_plin(im, 0, im->xsize, y, out);
1289 i_fcolor *blur = mymalloc(im->xsize * sizeof(i_fcolor)); /* checked 17feb2005 tonyc */
1290 i_fcolor *out = mymalloc(im->xsize * sizeof(i_fcolor)); /* checked 17feb2005 tonyc */
1292 for (y = 0; y < im->ysize; ++y) {
1293 i_glinf(copy, 0, copy->xsize, y, blur);
1294 i_glinf(im, 0, im->xsize, y, out);
1295 for (x = 0; x < im->xsize; ++x) {
1296 for (ch = 0; ch < im->channels; ++ch) {
1297 double temp = out[x].channel[ch] +
1298 scale * (out[x].channel[ch] - blur[x].channel[ch]);
1301 else if (temp > 1.0)
1303 out[x].channel[ch] = temp;
1306 i_plinf(im, 0, im->xsize, y, out);
1312 i_img_destroy(copy);
1316 =item i_diff_image(im1, im2, mindist)
1318 Creates a new image that is transparent, except where the pixel in im2
1319 is different from im1, where it is the pixel from im2.
1321 The samples must differ by at least mindiff to be considered different.
1327 i_diff_image(i_img *im1, i_img *im2, double mindist) {
1329 int outchans, diffchans;
1330 i_img_dim xsize, ysize;
1334 if (im1->channels != im2->channels) {
1335 i_push_error(0, "different number of channels");
1339 outchans = diffchans = im1->channels;
1340 if (outchans == 1 || outchans == 3)
1343 xsize = i_min(im1->xsize, im2->xsize);
1344 ysize = i_min(im1->ysize, im2->ysize);
1346 out = i_sametype_chans(im1, xsize, ysize, outchans);
1348 if (im1->bits == i_8_bits && im2->bits == i_8_bits) {
1349 i_color *line1 = mymalloc(xsize * sizeof(*line1)); /* checked 17feb2005 tonyc */
1350 i_color *line2 = mymalloc(xsize * sizeof(*line1)); /* checked 17feb2005 tonyc */
1354 int imindist = (int)mindist;
1356 for (ch = 0; ch < MAXCHANNELS; ++ch)
1357 empty.channel[ch] = 0;
1359 for (y = 0; y < ysize; ++y) {
1360 i_glin(im1, 0, xsize, y, line1);
1361 i_glin(im2, 0, xsize, y, line2);
1362 if (outchans != diffchans) {
1363 /* give the output an alpha channel since it doesn't have one */
1364 for (x = 0; x < xsize; ++x)
1365 line2[x].channel[diffchans] = 255;
1367 for (x = 0; x < xsize; ++x) {
1369 for (ch = 0; ch < diffchans; ++ch) {
1370 if (line1[x].channel[ch] != line2[x].channel[ch]
1371 && abs(line1[x].channel[ch] - line2[x].channel[ch]) > imindist) {
1379 i_plin(out, 0, xsize, y, line2);
1385 i_fcolor *line1 = mymalloc(xsize * sizeof(*line1)); /* checked 17feb2005 tonyc */
1386 i_fcolor *line2 = mymalloc(xsize * sizeof(*line2)); /* checked 17feb2005 tonyc */
1390 double dist = mindist / 255.0;
1392 for (ch = 0; ch < MAXCHANNELS; ++ch)
1393 empty.channel[ch] = 0;
1395 for (y = 0; y < ysize; ++y) {
1396 i_glinf(im1, 0, xsize, y, line1);
1397 i_glinf(im2, 0, xsize, y, line2);
1398 if (outchans != diffchans) {
1399 /* give the output an alpha channel since it doesn't have one */
1400 for (x = 0; x < xsize; ++x)
1401 line2[x].channel[diffchans] = 1.0;
1403 for (x = 0; x < xsize; ++x) {
1405 for (ch = 0; ch < diffchans; ++ch) {
1406 if (line1[x].channel[ch] != line2[x].channel[ch]
1407 && fabs(line1[x].channel[ch] - line2[x].channel[ch]) > dist) {
1415 i_plinf(out, 0, xsize, y, line2);
1425 static double linear_fount_f(double x, double y, struct fount_state *state);
1426 static double bilinear_fount_f(double x, double y, struct fount_state *state);
1427 static double radial_fount_f(double x, double y, struct fount_state *state);
1428 static double square_fount_f(double x, double y, struct fount_state *state);
1429 static double revolution_fount_f(double x, double y,
1430 struct fount_state *state);
1431 static double conical_fount_f(double x, double y, struct fount_state *state);
1433 typedef double (*fount_func)(double, double, struct fount_state *);
1434 static fount_func fount_funcs[] =
1444 static double linear_interp(double pos, i_fountain_seg *seg);
1445 static double sine_interp(double pos, i_fountain_seg *seg);
1446 static double sphereup_interp(double pos, i_fountain_seg *seg);
1447 static double spheredown_interp(double pos, i_fountain_seg *seg);
1448 typedef double (*fount_interp)(double pos, i_fountain_seg *seg);
1449 static fount_interp fount_interps[] =
1458 static void direct_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg);
1459 static void hue_up_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg);
1460 static void hue_down_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg);
1461 typedef void (*fount_cinterp)(i_fcolor *out, double pos, i_fountain_seg *seg);
1462 static fount_cinterp fount_cinterps[] =
1469 typedef double (*fount_repeat)(double v);
1470 static double fount_r_none(double v);
1471 static double fount_r_sawtooth(double v);
1472 static double fount_r_triangle(double v);
1473 static double fount_r_saw_both(double v);
1474 static double fount_r_tri_both(double v);
1475 static fount_repeat fount_repeats[] =
1484 static int simple_ssample(i_fcolor *out, double x, double y,
1485 struct fount_state *state);
1486 static int random_ssample(i_fcolor *out, double x, double y,
1487 struct fount_state *state);
1488 static int circle_ssample(i_fcolor *out, double x, double y,
1489 struct fount_state *state);
1490 typedef int (*fount_ssample)(i_fcolor *out, double x, double y,
1491 struct fount_state *state);
1492 static fount_ssample fount_ssamples[] =
1501 fount_getat(i_fcolor *out, double x, double y, struct fount_state *state);
1504 Keep state information used by each type of fountain fill
1506 struct fount_state {
1507 /* precalculated for the equation of the line perpendicular to the line AB */
1518 fount_repeat rpfunc;
1519 fount_ssample ssfunc;
1521 i_fountain_seg *segs;
1526 fount_init_state(struct fount_state *state, double xa, double ya,
1527 double xb, double yb, i_fountain_type type,
1528 i_fountain_repeat repeat, int combine, int super_sample,
1529 double ssample_param, int count, i_fountain_seg *segs);
1532 fount_finish_state(struct fount_state *state);
1534 #define EPSILON (1e-6)
1537 =item i_fountain(im, xa, ya, xb, yb, type, repeat, combine, super_sample, ssample_param, count, segs)
1539 Draws a fountain fill using A(xa, ya) and B(xb, yb) as reference points.
1541 I<type> controls how the reference points are used:
1547 linear, where A is 0 and B is 1.
1551 linear in both directions from A.
1555 circular, where A is the centre of the fill, and B is a point
1558 =item i_ft_radial_square
1560 where A is the centre of the fill and B is the centre of
1561 one side of the square.
1563 =item i_ft_revolution
1565 where A is the centre of the fill and B defines the 0/1.0
1570 similar to i_ft_revolution, except that the revolution goes in both
1575 I<repeat> can be one of:
1581 values < 0 are treated as zero, values > 1 are treated as 1.
1585 negative values are treated as 0, positive values are modulo 1.0
1589 negative values are treated as zero, if (int)value is odd then the value is treated as 1-(value
1590 mod 1.0), otherwise the same as for sawtooth.
1594 like i_fr_sawtooth, except that the sawtooth pattern repeats into
1599 Like i_fr_triangle, except that negative values are handled as their
1604 If combine is non-zero then non-opaque values are combined with the
1607 I<super_sample> controls super sampling, if any. At some point I'll
1608 probably add a adaptive super-sampler. Current possible values are:
1614 No super-sampling is done.
1618 A square grid of points withing the pixel are sampled.
1622 Random points within the pixel are sampled.
1626 Points on the radius of a circle are sampled. This produces fairly
1627 good results, but is fairly slow since sin() and cos() are evaluated
1632 I<ssample_param> is intended to be roughly the number of points
1633 sampled within the pixel.
1635 I<count> and I<segs> define the segments of the fill.
1642 i_fountain(i_img *im, double xa, double ya, double xb, double yb,
1643 i_fountain_type type, i_fountain_repeat repeat,
1644 int combine, int super_sample, double ssample_param,
1645 int count, i_fountain_seg *segs) {
1646 struct fount_state state;
1648 i_fcolor *line = NULL;
1649 i_fcolor *work = NULL;
1651 i_fill_combine_f combine_func = NULL;
1652 i_fill_combinef_f combinef_func = NULL;
1657 /* i_fountain() allocates floating colors even for 8-bit images,
1658 so we need to do this check */
1659 line_bytes = sizeof(i_fcolor) * im->xsize;
1660 if (line_bytes / sizeof(i_fcolor) != im->xsize) {
1661 i_push_error(0, "integer overflow calculating memory allocation");
1665 line = mymalloc(line_bytes); /* checked 17feb2005 tonyc */
1667 i_get_combine(combine, &combine_func, &combinef_func);
1669 work = mymalloc(line_bytes); /* checked 17feb2005 tonyc */
1671 fount_init_state(&state, xa, ya, xb, yb, type, repeat, combine,
1672 super_sample, ssample_param, count, segs);
1674 for (y = 0; y < im->ysize; ++y) {
1675 i_glinf(im, 0, im->xsize, y, line);
1676 for (x = 0; x < im->xsize; ++x) {
1679 if (super_sample == i_fts_none)
1680 got_one = fount_getat(&c, x, y, &state);
1682 got_one = state.ssfunc(&c, x, y, &state);
1691 combinef_func(line, work, im->channels, im->xsize);
1692 i_plinf(im, 0, im->xsize, y, line);
1694 fount_finish_state(&state);
1695 if (work) myfree(work);
1703 struct fount_state state;
1704 } i_fill_fountain_t;
1707 fill_fountf(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width, int channels,
1710 fount_fill_destroy(i_fill_t *fill);
1712 static i_fill_fountain_t
1724 =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>)
1727 =synopsis fill = i_new_fill_fount(0, 0, 100, 100, i_ft_linear, i_ft_linear,
1728 =synopsis i_fr_triangle, 0, i_fts_grid, 9, 1, segs);
1731 Creates a new general fill which fills with a fountain fill.
1737 i_new_fill_fount(double xa, double ya, double xb, double yb,
1738 i_fountain_type type, i_fountain_repeat repeat,
1739 int combine, int super_sample, double ssample_param,
1740 int count, i_fountain_seg *segs) {
1741 i_fill_fountain_t *fill = mymalloc(sizeof(i_fill_fountain_t));
1743 *fill = fount_fill_proto;
1745 i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
1747 fill->base.combine = NULL;
1748 fill->base.combinef = NULL;
1750 fount_init_state(&fill->state, xa, ya, xb, yb, type, repeat, combine,
1751 super_sample, ssample_param, count, segs);
1759 =head1 INTERNAL FUNCTIONS
1763 =item fount_init_state(...)
1765 Used by both the fountain fill filter and the fountain fill.
1771 fount_init_state(struct fount_state *state, double xa, double ya,
1772 double xb, double yb, i_fountain_type type,
1773 i_fountain_repeat repeat, int combine, int super_sample,
1774 double ssample_param, int count, i_fountain_seg *segs) {
1777 i_fountain_seg *my_segs = mymalloc(sizeof(i_fountain_seg) * count); /* checked 2jul06 - duplicating original */
1778 /*int have_alpha = im->channels == 2 || im->channels == 4;*/
1780 memset(state, 0, sizeof(*state));
1781 /* we keep a local copy that we can adjust for speed */
1782 for (i = 0; i < count; ++i) {
1783 i_fountain_seg *seg = my_segs + i;
1786 if (seg->type < 0 || seg->type >= i_fst_end)
1787 seg->type = i_fst_linear;
1788 if (seg->color < 0 || seg->color >= i_fc_end)
1789 seg->color = i_fc_direct;
1790 if (seg->color == i_fc_hue_up || seg->color == i_fc_hue_down) {
1791 /* so we don't have to translate to HSV on each request, do it here */
1792 for (j = 0; j < 2; ++j) {
1793 i_rgb_to_hsvf(seg->c+j);
1795 if (seg->color == i_fc_hue_up) {
1796 if (seg->c[1].channel[0] <= seg->c[0].channel[0])
1797 seg->c[1].channel[0] += 1.0;
1800 if (seg->c[0].channel[0] <= seg->c[0].channel[1])
1801 seg->c[0].channel[0] += 1.0;
1804 /*printf("start %g mid %g end %g c0(%g,%g,%g,%g) c1(%g,%g,%g,%g) type %d color %d\n",
1805 seg->start, seg->middle, seg->end, seg->c[0].channel[0],
1806 seg->c[0].channel[1], seg->c[0].channel[2], seg->c[0].channel[3],
1807 seg->c[1].channel[0], seg->c[1].channel[1], seg->c[1].channel[2],
1808 seg->c[1].channel[3], seg->type, seg->color);*/
1812 /* initialize each engine */
1813 /* these are so common ... */
1814 state->lA = xb - xa;
1815 state->lB = yb - ya;
1816 state->AB = sqrt(state->lA * state->lA + state->lB * state->lB);
1821 type = i_ft_linear; /* make the invalid value valid */
1824 state->lC = ya * ya - ya * yb + xa * xa - xa * xb;
1826 state->mult = 1/linear_fount_f(xb, yb, state);
1830 state->mult = 1.0 / sqrt((double)(xb-xa)*(xb-xa)
1831 + (double)(yb-ya)*(yb-ya));
1834 case i_ft_radial_square:
1835 state->cos = state->lA / state->AB;
1836 state->sin = state->lB / state->AB;
1837 state->mult = 1.0 / state->AB;
1840 case i_ft_revolution:
1841 state->theta = atan2(yb-ya, xb-xa);
1842 state->mult = 1.0 / (PI * 2);
1846 state->theta = atan2(yb-ya, xb-xa);
1847 state->mult = 1.0 / PI;
1850 state->ffunc = fount_funcs[type];
1851 if (super_sample < 0
1852 || super_sample >= (int)(sizeof(fount_ssamples)/sizeof(*fount_ssamples))) {
1855 state->ssample_data = NULL;
1856 switch (super_sample) {
1858 ssample_param = floor(0.5 + sqrt(ssample_param));
1859 bytes = ssample_param * ssample_param * sizeof(i_fcolor);
1860 if (bytes / sizeof(i_fcolor) == ssample_param * ssample_param) {
1861 state->ssample_data = mymalloc(sizeof(i_fcolor) * ssample_param * ssample_param); /* checked 1jul06 tonyc */
1864 super_sample = i_fts_none;
1870 ssample_param = floor(0.5+ssample_param);
1871 bytes = sizeof(i_fcolor) * ssample_param;
1872 if (bytes / sizeof(i_fcolor) == ssample_param) {
1873 state->ssample_data = mymalloc(sizeof(i_fcolor) * ssample_param);
1876 super_sample = i_fts_none;
1880 state->parm = ssample_param;
1881 state->ssfunc = fount_ssamples[super_sample];
1882 if (repeat < 0 || repeat >= (sizeof(fount_repeats)/sizeof(*fount_repeats)))
1884 state->rpfunc = fount_repeats[repeat];
1885 state->segs = my_segs;
1886 state->count = count;
1890 fount_finish_state(struct fount_state *state) {
1891 if (state->ssample_data)
1892 myfree(state->ssample_data);
1893 myfree(state->segs);
1898 =item fount_getat(out, x, y, ffunc, rpfunc, state, segs, count)
1900 Evaluates the fountain fill at the given point.
1902 This is called by both the non-super-sampling and super-sampling code.
1904 You might think that it would make sense to sample the fill parameter
1905 instead, and combine those, but this breaks badly.
1911 fount_getat(i_fcolor *out, double x, double y, struct fount_state *state) {
1912 double v = (state->rpfunc)((state->ffunc)(x, y, state));
1916 while (i < state->count
1917 && (v < state->segs[i].start || v > state->segs[i].end)) {
1920 if (i < state->count) {
1921 v = (fount_interps[state->segs[i].type])(v, state->segs+i);
1922 (fount_cinterps[state->segs[i].color])(out, v, state->segs+i);
1930 =item linear_fount_f(x, y, state)
1932 Calculate the fill parameter for a linear fountain fill.
1934 Uses the point to line distance function, with some precalculation
1935 done in i_fountain().
1940 linear_fount_f(double x, double y, struct fount_state *state) {
1941 return (state->lA * x + state->lB * y + state->lC) / state->AB * state->mult;
1945 =item bilinear_fount_f(x, y, state)
1947 Calculate the fill parameter for a bi-linear fountain fill.
1952 bilinear_fount_f(double x, double y, struct fount_state *state) {
1953 return fabs((state->lA * x + state->lB * y + state->lC) / state->AB * state->mult);
1957 =item radial_fount_f(x, y, state)
1959 Calculate the fill parameter for a radial fountain fill.
1961 Simply uses the distance function.
1966 radial_fount_f(double x, double y, struct fount_state *state) {
1967 return sqrt((double)(state->xa-x)*(state->xa-x)
1968 + (double)(state->ya-y)*(state->ya-y)) * state->mult;
1972 =item square_fount_f(x, y, state)
1974 Calculate the fill parameter for a square fountain fill.
1976 Works by rotating the reference co-ordinate around the centre of the
1982 square_fount_f(double x, double y, struct fount_state *state) {
1983 i_img_dim xc, yc; /* centred on A */
1984 double xt, yt; /* rotated by theta */
1987 xt = fabs(xc * state->cos + yc * state->sin);
1988 yt = fabs(-xc * state->sin + yc * state->cos);
1989 return (xt > yt ? xt : yt) * state->mult;
1993 =item revolution_fount_f(x, y, state)
1995 Calculates the fill parameter for the revolution fountain fill.
2000 revolution_fount_f(double x, double y, struct fount_state *state) {
2001 double angle = atan2(y - state->ya, x - state->xa);
2003 angle -= state->theta;
2005 angle = fmod(angle+ PI * 4, PI*2);
2008 return angle * state->mult;
2012 =item conical_fount_f(x, y, state)
2014 Calculates the fill parameter for the conical fountain fill.
2019 conical_fount_f(double x, double y, struct fount_state *state) {
2020 double angle = atan2(y - state->ya, x - state->xa);
2022 angle -= state->theta;
2025 else if (angle > PI)
2028 return fabs(angle) * state->mult;
2032 =item linear_interp(pos, seg)
2034 Calculates linear interpolation on the fill parameter. Breaks the
2035 segment into 2 regions based in the I<middle> value.
2040 linear_interp(double pos, i_fountain_seg *seg) {
2041 if (pos < seg->middle) {
2042 double len = seg->middle - seg->start;
2046 return (pos - seg->start) / len / 2;
2049 double len = seg->end - seg->middle;
2053 return 0.5 + (pos - seg->middle) / len / 2;
2058 =item sine_interp(pos, seg)
2060 Calculates sine function interpolation on the fill parameter.
2065 sine_interp(double pos, i_fountain_seg *seg) {
2066 /* I wonder if there's a simple way to smooth the transition for this */
2067 double work = linear_interp(pos, seg);
2069 return (1-cos(work * PI))/2;
2073 =item sphereup_interp(pos, seg)
2075 Calculates spherical interpolation on the fill parameter, with the cusp
2081 sphereup_interp(double pos, i_fountain_seg *seg) {
2082 double work = linear_interp(pos, seg);
2084 return sqrt(1.0 - (1-work) * (1-work));
2088 =item spheredown_interp(pos, seg)
2090 Calculates spherical interpolation on the fill parameter, with the cusp
2096 spheredown_interp(double pos, i_fountain_seg *seg) {
2097 double work = linear_interp(pos, seg);
2099 return 1-sqrt(1.0 - work * work);
2103 =item direct_cinterp(out, pos, seg)
2105 Calculates the fountain color based on direct scaling of the channels
2106 of the color channels.
2111 direct_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg) {
2113 for (ch = 0; ch < MAXCHANNELS; ++ch) {
2114 out->channel[ch] = seg->c[0].channel[ch] * (1 - pos)
2115 + seg->c[1].channel[ch] * pos;
2120 =item hue_up_cinterp(put, pos, seg)
2122 Calculates the fountain color based on scaling a HSV value. The hue
2123 increases as the fill parameter increases.
2128 hue_up_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg) {
2130 for (ch = 0; ch < MAXCHANNELS; ++ch) {
2131 out->channel[ch] = seg->c[0].channel[ch] * (1 - pos)
2132 + seg->c[1].channel[ch] * pos;
2138 =item hue_down_cinterp(put, pos, seg)
2140 Calculates the fountain color based on scaling a HSV value. The hue
2141 decreases as the fill parameter increases.
2146 hue_down_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg) {
2148 for (ch = 0; ch < MAXCHANNELS; ++ch) {
2149 out->channel[ch] = seg->c[0].channel[ch] * (1 - pos)
2150 + seg->c[1].channel[ch] * pos;
2156 =item simple_ssample(out, parm, x, y, state, ffunc, rpfunc, segs, count)
2158 Simple grid-based super-sampling.
2163 simple_ssample(i_fcolor *out, double x, double y, struct fount_state *state) {
2164 i_fcolor *work = state->ssample_data;
2166 int grid = state->parm;
2167 double base = -0.5 + 0.5 / grid;
2168 double step = 1.0 / grid;
2172 for (dx = 0; dx < grid; ++dx) {
2173 for (dy = 0; dy < grid; ++dy) {
2174 if (fount_getat(work+samp_count, x + base + step * dx,
2175 y + base + step * dy, state)) {
2180 for (ch = 0; ch < MAXCHANNELS; ++ch) {
2181 out->channel[ch] = 0;
2182 for (i = 0; i < samp_count; ++i) {
2183 out->channel[ch] += work[i].channel[ch];
2185 /* we divide by 4 rather than samp_count since if there's only one valid
2186 sample it should be mostly transparent */
2187 out->channel[ch] /= grid * grid;
2193 =item random_ssample(out, parm, x, y, state, ffunc, rpfunc, segs, count)
2195 Random super-sampling.
2200 random_ssample(i_fcolor *out, double x, double y,
2201 struct fount_state *state) {
2202 i_fcolor *work = state->ssample_data;
2204 int maxsamples = state->parm;
2205 double rand_scale = 1.0 / RAND_MAX;
2207 for (i = 0; i < maxsamples; ++i) {
2208 if (fount_getat(work+samp_count, x - 0.5 + rand() * rand_scale,
2209 y - 0.5 + rand() * rand_scale, state)) {
2213 for (ch = 0; ch < MAXCHANNELS; ++ch) {
2214 out->channel[ch] = 0;
2215 for (i = 0; i < samp_count; ++i) {
2216 out->channel[ch] += work[i].channel[ch];
2218 /* we divide by maxsamples rather than samp_count since if there's
2219 only one valid sample it should be mostly transparent */
2220 out->channel[ch] /= maxsamples;
2226 =item circle_ssample(out, parm, x, y, state, ffunc, rpfunc, segs, count)
2228 Super-sampling around the circumference of a circle.
2230 I considered saving the sin()/cos() values and transforming step-size
2231 around the circle, but that's inaccurate, though it may not matter
2237 circle_ssample(i_fcolor *out, double x, double y,
2238 struct fount_state *state) {
2239 i_fcolor *work = state->ssample_data;
2241 int maxsamples = state->parm;
2242 double angle = 2 * PI / maxsamples;
2243 double radius = 0.3; /* semi-random */
2245 for (i = 0; i < maxsamples; ++i) {
2246 if (fount_getat(work+samp_count, x + radius * cos(angle * i),
2247 y + radius * sin(angle * i), state)) {
2251 for (ch = 0; ch < MAXCHANNELS; ++ch) {
2252 out->channel[ch] = 0;
2253 for (i = 0; i < samp_count; ++i) {
2254 out->channel[ch] += work[i].channel[ch];
2256 /* we divide by maxsamples rather than samp_count since if there's
2257 only one valid sample it should be mostly transparent */
2258 out->channel[ch] /= maxsamples;
2264 =item fount_r_none(v)
2266 Implements no repeats. Simply clamps the fill value.
2271 fount_r_none(double v) {
2272 return v < 0 ? 0 : v > 1 ? 1 : v;
2276 =item fount_r_sawtooth(v)
2278 Implements sawtooth repeats. Clamps negative values and uses fmod()
2284 fount_r_sawtooth(double v) {
2285 return v < 0 ? 0 : fmod(v, 1.0);
2289 =item fount_r_triangle(v)
2291 Implements triangle repeats. Clamps negative values, uses fmod to get
2292 a range 0 through 2 and then adjusts values > 1.
2297 fount_r_triangle(double v) {
2302 return v > 1.0 ? 2.0 - v : v;
2307 =item fount_r_saw_both(v)
2309 Implements sawtooth repeats in the both postive and negative directions.
2311 Adjusts the value to be postive and then just uses fmod().
2316 fount_r_saw_both(double v) {
2319 return fmod(v, 1.0);
2323 =item fount_r_tri_both(v)
2325 Implements triangle repeats in the both postive and negative directions.
2327 Uses fmod on the absolute value, and then adjusts values > 1.
2332 fount_r_tri_both(double v) {
2333 v = fmod(fabs(v), 2.0);
2334 return v > 1.0 ? 2.0 - v : v;
2338 =item fill_fountf(fill, x, y, width, channels, data)
2340 The fill function for fountain fills.
2345 fill_fountf(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
2346 int channels, i_fcolor *data) {
2347 i_fill_fountain_t *f = (i_fill_fountain_t *)fill;
2353 if (f->state.ssfunc)
2354 got_one = f->state.ssfunc(&c, x, y, &f->state);
2356 got_one = fount_getat(&c, x, y, &f->state);
2366 =item fount_fill_destroy(fill)
2371 fount_fill_destroy(i_fill_t *fill) {
2372 i_fill_fountain_t *f = (i_fill_fountain_t *)fill;
2373 fount_finish_state(&f->state);
2381 Arnar M. Hrafnkelsson <addi@umich.edu>
2383 Tony Cook <tony@develop-help.com> (i_fountain())