10 filters.im - implements filters that operate on images
18 i_unsharp_mask(im, 2.0, 1.0);
23 filters.c implements basic filters for Imager. These filters
24 should be accessible from the filter interface as defined in
27 =head1 FUNCTION REFERENCE
29 Some of these functions are internal.
42 Clamps the input value between 0 and 255. (internal)
52 if (in>255) { return 255; }
53 else if (in>0) return in;
60 =item i_contrast(im, intensity)
62 Scales the pixel values by the amount specified.
65 intensity - scalefactor
71 i_contrast(i_img *im, float intensity) {
74 unsigned int new_color;
77 mm_log((1,"i_contrast(im %p, intensity %f)\n", im, intensity));
79 if(intensity < 0) return;
81 for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
82 i_gpix(im, x, y, &rcolor);
84 for(ch = 0; ch < im->channels; ch++) {
85 new_color = (unsigned int) rcolor.channel[ch];
86 new_color *= intensity;
91 rcolor.channel[ch] = (unsigned char) new_color;
93 i_ppix(im, x, y, &rcolor);
99 s_hardinvert_low(i_img *im, int all) {
102 int invert_channels = all ? im->channels : i_img_color_channels(im);
104 mm_log((1,"i_hardinvert(im %p)\n", im));
107 IM_COLOR *row, *entry;
109 /* always rooms to allocate a single line of i_color */
110 row = mymalloc(sizeof(IM_COLOR) * im->xsize); /* checked 17feb2005 tonyc */
112 for(y = 0; y < im->ysize; y++) {
113 IM_GLIN(im, 0, im->xsize, y, row);
115 for(x = 0; x < im->xsize; x++) {
116 for(ch = 0; ch < invert_channels; ch++) {
117 entry->channel[ch] = IM_SAMPLE_MAX - entry->channel[ch];
121 IM_PLIN(im, 0, im->xsize, y, row);
130 =item i_hardinvert(im)
132 Inverts the color channels of the input image.
140 i_hardinvert(i_img *im) {
141 s_hardinvert_low(im, 0);
145 =item i_hardinvertall(im)
147 Inverts all channels of the input image.
155 i_hardinvertall(i_img *im) {
156 s_hardinvert_low(im, 1);
160 =item i_noise(im, amount, type)
162 Adjusts the sample values randomly by the amount specified.
164 If type is 0, adjust all channels in a pixel by the same (random)
165 amount amount, if non-zero adjust each sample independently.
168 amount - deviation in pixel values
169 type - noise individual for each channel if true
175 /* random() is non-ASCII, even if it is better than rand() */
176 #define random() rand()
180 i_noise(i_img *im, float amount, unsigned char type) {
184 float damount = amount * 2;
188 mm_log((1,"i_noise(im %p, intensity %.2f\n", im, amount));
190 if(amount < 0) return;
192 for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
193 i_gpix(im, x, y, &rcolor);
196 color_inc = (amount - (damount * ((float)random() / RAND_MAX)));
199 for(ch = 0; ch < im->channels; ch++) {
200 new_color = (int) rcolor.channel[ch];
203 new_color += (amount - (damount * ((float)random() / RAND_MAX)));
205 new_color += color_inc;
211 if(new_color > 255) {
215 rcolor.channel[ch] = (unsigned char) new_color;
218 i_ppix(im, x, y, &rcolor);
223 =item i_bumpmap(im, bump, channel, light_x, light_y, st)
225 Makes a bumpmap on image im using the bump image as the elevation map.
228 bump - image that contains the elevation info
229 channel - to take the elevation information from
230 light_x - x coordinate of light source
231 light_y - y coordinate of light source
232 st - length of shadow
238 i_bumpmap(i_img *im, i_img *bump, int channel, i_img_dim light_x, i_img_dim light_y, i_img_dim st) {
242 i_color x1_color, y1_color, x2_color, y2_color, dst_color;
247 unsigned char px1, px2, py1, py2;
251 mm_log((1, "i_bumpmap(im %p, add_im %p, channel %d, light(" i_DFp "), st %" i_DF ")\n",
252 im, bump, channel, i_DFcp(light_x, light_y), i_DFc(st)));
255 if(channel >= bump->channels) {
256 mm_log((1, "i_bumpmap: channel = %d while bump image only has %d channels\n", channel, bump->channels));
260 mx = (bump->xsize <= im->xsize) ? bump->xsize : im->xsize;
261 my = (bump->ysize <= im->ysize) ? bump->ysize : im->ysize;
263 i_img_empty_ch(&new_im, im->xsize, im->ysize, im->channels);
265 aX = (light_x > (mx >> 1)) ? light_x : mx - light_x;
266 aY = (light_y > (my >> 1)) ? light_y : my - light_y;
268 aL = sqrt((aX * aX) + (aY * aY));
270 for(y = 1; y < my - 1; y++) {
271 for(x = 1; x < mx - 1; x++) {
272 i_gpix(bump, x + st, y, &x1_color);
273 i_gpix(bump, x, y + st, &y1_color);
274 i_gpix(bump, x - st, y, &x2_color);
275 i_gpix(bump, x, y - st, &y2_color);
277 i_gpix(im, x, y, &dst_color);
279 px1 = x1_color.channel[channel];
280 py1 = y1_color.channel[channel];
281 px2 = x2_color.channel[channel];
282 py2 = y2_color.channel[channel];
290 fZ = (sqrt((nX * nX) + (nY * nY)) / aL);
292 tX = i_abs(x - light_x) / aL;
293 tY = i_abs(y - light_y) / aL;
295 tZ = 1 - (sqrt((tX * tX) + (tY * tY)) * fZ);
300 for(ch = 0; ch < im->channels; ch++)
301 dst_color.channel[ch] = (unsigned char) (float)(dst_color.channel[ch] * tZ);
303 i_ppix(&new_im, x, y, &dst_color);
307 i_copyto(im, &new_im, 0, 0, im->xsize, im->ysize, 0, 0);
309 i_img_exorcise(&new_im);
322 dotp(fvec *a, fvec *b) {
323 return a->x*b->x+a->y*b->y+a->z*b->z;
329 double d = sqrt(dotp(a,a));
343 I = Ia + Ip*( cd*Scol(N.L) + cs*(R.V)^n )
345 Here, the variables are:
347 * Ia - ambient colour
348 * Ip - intensity of the point light source
349 * cd - diffuse coefficient
350 * Scol - surface colour
351 * cs - specular coefficient
352 * n - objects shinyness
354 * L - lighting vector
355 * R - reflection vector
358 static void fvec_dump(fvec *x) {
359 printf("(%.2f %.2f %.2f)", x->x, x->y, x->z);
363 /* XXX: Should these return a code for success? */
369 =item i_bumpmap_complex(im, bump, channel, tx, ty, Lx, Ly, Lz, Ip, cd, cs, n, Ia, Il, Is)
371 Makes a bumpmap on image im using the bump image as the elevation map.
374 bump - image that contains the elevation info
375 channel - to take the elevation information from
376 tx - shift in x direction of where to start applying bumpmap
377 ty - shift in y direction of where to start applying bumpmap
378 Lx - x position/direction of light
379 Ly - y position/direction of light
380 Lz - z position/direction of light
382 cd - diffuse coefficient
383 cs - specular coefficient
384 n - surface shinyness
389 if z<0 then the L is taken to be the direction the light is shining in. Otherwise
390 the L is taken to be the position of the Light, Relative to the image.
397 i_bumpmap_complex(i_img *im,
416 i_img_dim mx, Mx, my, My;
418 float cdc[MAXCHANNELS];
419 float csc[MAXCHANNELS];
421 i_color x1_color, y1_color, x2_color, y2_color;
423 i_color Scol; /* Surface colour */
425 fvec L; /* Light vector */
426 fvec N; /* surface normal */
427 fvec R; /* Reflection vector */
428 fvec V; /* Vision vector */
430 mm_log((1, "i_bumpmap_complex(im %p, bump %p, channel %d, t(" i_DFp
431 "), Lx %.2f, Ly %.2f, Lz %.2f, cd %.2f, cs %.2f, n %.2f, Ia %p, Il %p, Is %p)\n",
432 im, bump, channel, i_DFcp(tx, ty), Lx, Ly, Lz, cd, cs, n, Ia, Il, Is));
434 if (channel >= bump->channels) {
435 mm_log((1, "i_bumpmap_complex: channel = %d while bump image only has %d channels\n", channel, bump->channels));
439 for(ch=0; ch<im->channels; ch++) {
440 cdc[ch] = (float)Il->channel[ch]*cd/255.f;
441 csc[ch] = (float)Is->channel[ch]*cs/255.f;
453 if (Lz < 0) { /* Light specifies a direction vector, reverse it to get the vector from surface to light */
458 } else { /* Light is the position of the light source */
466 i_img_empty_ch(&new_im, im->xsize, im->ysize, im->channels);
468 for(y = 0; y < im->ysize; y++) {
469 for(x = 0; x < im->xsize; x++) {
471 double dx = 0, dy = 0;
473 /* Calculate surface normal */
474 if (mx<x && x<Mx && my<y && y<My) {
475 i_gpix(bump, x + 1, y, &x1_color);
476 i_gpix(bump, x - 1, y, &x2_color);
477 i_gpix(bump, x, y + 1, &y1_color);
478 i_gpix(bump, x, y - 1, &y2_color);
479 dx = x2_color.channel[channel] - x1_color.channel[channel];
480 dy = y2_color.channel[channel] - y1_color.channel[channel];
490 /* Calculate Light vector if needed */
499 R.x = -L.x + 2*dp1*N.x;
500 R.y = -L.y + 2*dp1*N.y;
501 R.z = -L.z + 2*dp1*N.z;
505 dp1 = dp1<0 ?0 : dp1;
506 dp2 = pow(dp2<0 ?0 : dp2,n);
508 i_gpix(im, x, y, &Scol);
510 for(ch = 0; ch < im->channels; ch++)
512 saturate( Ia->channel[ch] + cdc[ch]*Scol.channel[ch]*dp1 + csc[ch]*dp2 );
514 i_ppix(&new_im, x, y, &Scol);
518 i_copyto(im, &new_im, 0, 0, im->xsize, im->ysize, 0, 0);
519 i_img_exorcise(&new_im);
524 =item i_postlevels(im, levels)
526 Quantizes Images to fewer levels.
529 levels - number of levels
535 i_postlevels(i_img *im, int levels) {
544 rv = (int) ((float)(256 / levels));
547 for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
548 i_gpix(im, x, y, &rcolor);
550 for(ch = 0; ch < im->channels; ch++) {
551 pv = (((float)rcolor.channel[ch] / 255)) * av;
552 pv = (int) ((int)pv * rv);
555 else if(pv > 255) pv = 255;
557 rcolor.channel[ch] = (unsigned char) pv;
559 i_ppix(im, x, y, &rcolor);
565 =item i_mosaic(im, size)
567 Makes an image looks like a mosaic with tilesize of size
576 i_mosaic(i_img *im, i_img_dim size) {
585 sqrsize = size * size;
587 for(y = 0; y < im->ysize; y += size) for(x = 0; x < im->xsize; x += size) {
588 for(z = 0; z < 256; z++) col[z] = 0;
590 for(lx = 0; lx < size; lx++) {
591 for(ly = 0; ly < size; ly++) {
592 i_gpix(im, (x + lx), (y + ly), &rcolor);
594 for(ch = 0; ch < im->channels; ch++) {
595 col[ch] += rcolor.channel[ch];
600 for(ch = 0; ch < im->channels; ch++)
601 rcolor.channel[ch] = (int) ((float)col[ch] / sqrsize);
604 for(lx = 0; lx < size; lx++)
605 for(ly = 0; ly < size; ly++)
606 i_ppix(im, (x + lx), (y + ly), &rcolor);
613 =item i_watermark(im, wmark, tx, ty, pixdiff)
615 Applies a watermark to the target image
618 wmark - watermark image
619 tx - x coordinate of where watermark should be applied
620 ty - y coordinate of where watermark should be applied
621 pixdiff - the magnitude of the watermark, controls how visible it is
627 i_watermark(i_img *im, i_img *wmark, i_img_dim tx, i_img_dim ty, int pixdiff) {
632 i_img_dim mx = wmark->xsize;
633 i_img_dim my = wmark->ysize;
635 for(vx=0;vx<mx;vx++) for(vy=0;vy<my;vy++) {
637 i_gpix(im, tx+vx, ty+vy,&val );
638 i_gpix(wmark, vx, vy, &wval);
640 for(ch=0;ch<im->channels;ch++)
641 val.channel[ch] = saturate( val.channel[ch] + (pixdiff* (wval.channel[0]-128) )/128 );
643 i_ppix(im,tx+vx,ty+vy,&val);
649 =item i_autolevels(im, lsat, usat, skew)
651 Scales and translates each color such that it fills the range completely.
652 Skew is not implemented yet - purpose is to control the color skew that can
653 occur when changing the contrast.
656 lsat - fraction of pixels that will be truncated at the lower end of the spectrum
657 usat - fraction of pixels that will be truncated at the higher end of the spectrum
664 i_autolevels(i_img *im, float lsat, float usat, float skew) {
666 i_img_dim i, x, y, rhist[256], ghist[256], bhist[256];
667 i_img_dim rsum, rmin, rmax;
668 i_img_dim gsum, gmin, gmax;
669 i_img_dim bsum, bmin, bmax;
670 i_img_dim rcl, rcu, gcl, gcu, bcl, bcu;
672 mm_log((1,"i_autolevels(im %p, lsat %f,usat %f,skew %f)\n", im, lsat,usat,skew));
675 for(i=0;i<256;i++) rhist[i]=ghist[i]=bhist[i] = 0;
676 /* create histogram for each channel */
677 for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
678 i_gpix(im, x, y, &val);
679 rhist[val.channel[0]]++;
680 ghist[val.channel[1]]++;
681 bhist[val.channel[2]]++;
690 rmin = gmin = bmin = 0;
691 rmax = gmax = bmax = 255;
693 rcu = rcl = gcu = gcl = bcu = bcl = 0;
695 for(i=0; i<256; i++) {
696 rcl += rhist[i]; if ( (rcl<rsum*lsat) ) rmin=i;
697 rcu += rhist[255-i]; if ( (rcu<rsum*usat) ) rmax=255-i;
699 gcl += ghist[i]; if ( (gcl<gsum*lsat) ) gmin=i;
700 gcu += ghist[255-i]; if ( (gcu<gsum*usat) ) gmax=255-i;
702 bcl += bhist[i]; if ( (bcl<bsum*lsat) ) bmin=i;
703 bcu += bhist[255-i]; if ( (bcu<bsum*usat) ) bmax=255-i;
706 for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
707 i_gpix(im, x, y, &val);
708 val.channel[0]=saturate((val.channel[0]-rmin)*255/(rmax-rmin));
709 val.channel[1]=saturate((val.channel[1]-gmin)*255/(gmax-gmin));
710 val.channel[2]=saturate((val.channel[2]-bmin)*255/(bmax-bmin));
711 i_ppix(im, x, y, &val);
718 Pseudo noise utility function used to generate perlin noise. (internal)
728 Noise(i_img_dim x, i_img_dim y) {
729 i_img_dim n = x + y * 57;
731 return ( 1.0 - ( (n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff) / 1073741824.0);
735 =item SmoothedNoise1(x,y)
737 Pseudo noise utility function used to generate perlin noise. (internal)
747 SmoothedNoise1(double x, double y) {
748 double corners = ( Noise(x-1, y-1)+Noise(x+1, y-1)+Noise(x-1, y+1)+Noise(x+1, y+1) ) / 16;
749 double sides = ( Noise(x-1, y) +Noise(x+1, y) +Noise(x, y-1) +Noise(x, y+1) ) / 8;
750 double center = Noise(x, y) / 4;
751 return corners + sides + center;
756 =item G_Interpolate(a, b, x)
758 Utility function used to generate perlin noise. (internal)
765 C_Interpolate(double a, double b, double x) {
766 /* float ft = x * 3.1415927; */
768 double f = (1 - cos(ft)) * .5;
769 return a*(1-f) + b*f;
774 =item InterpolatedNoise(x, y)
776 Utility function used to generate perlin noise. (internal)
783 InterpolatedNoise(double x, double y) {
785 i_img_dim integer_X = x;
786 double fractional_X = x - integer_X;
787 i_img_dim integer_Y = y;
788 double fractional_Y = y - integer_Y;
790 double v1 = SmoothedNoise1(integer_X, integer_Y);
791 double v2 = SmoothedNoise1(integer_X + 1, integer_Y);
792 double v3 = SmoothedNoise1(integer_X, integer_Y + 1);
793 double v4 = SmoothedNoise1(integer_X + 1, integer_Y + 1);
795 double i1 = C_Interpolate(v1 , v2 , fractional_X);
796 double i2 = C_Interpolate(v3 , v4 , fractional_X);
798 return C_Interpolate(i1 , i2 , fractional_Y);
804 =item PerlinNoise_2D(x, y)
806 Utility function used to generate perlin noise. (internal)
813 PerlinNoise_2D(float x, float y) {
817 int Number_Of_Octaves=6;
818 int n = Number_Of_Octaves - 1;
823 total = total + InterpolatedNoise(x * frequency, y * frequency) * amplitude;
831 =item i_radnoise(im, xo, yo, rscale, ascale)
833 Perlin-like radial noise.
836 xo - x coordinate of center
837 yo - y coordinate of center
838 rscale - radial scale
839 ascale - angular scale
845 i_radnoise(i_img *im, i_img_dim xo, i_img_dim yo, double rscale, double ascale) {
853 for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
854 xc = (double)x-xo+0.5;
855 yc = (double)y-yo+0.5;
856 r = rscale*sqrt(xc*xc+yc*yc)+1.2;
857 a = (PI+atan2(yc,xc))*ascale;
858 v = saturate(128+100*(PerlinNoise_2D(a,r)));
859 /* v=saturate(120+12*PerlinNoise_2D(xo+(float)x/scale,yo+(float)y/scale)); Good soft marble */
860 for(ch=0; ch<im->channels; ch++) val.channel[ch]=v;
861 i_ppix(im, x, y, &val);
867 =item i_turbnoise(im, xo, yo, scale)
869 Perlin-like 2d noise noise.
872 xo - x coordinate translation
873 yo - y coordinate translation
874 scale - scale of noise
880 i_turbnoise(i_img *im, double xo, double yo, double scale) {
886 for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
887 /* v=saturate(125*(1.0+PerlinNoise_2D(xo+(float)x/scale,yo+(float)y/scale))); */
888 v = saturate(120*(1.0+sin(xo+(double)x/scale+PerlinNoise_2D(xo+(double)x/scale,yo+(float)y/scale))));
889 for(ch=0; ch<im->channels; ch++) val.channel[ch] = v;
890 i_ppix(im, x, y, &val);
897 =item i_gradgen(im, num, xo, yo, ival, dmeasure)
899 Gradient generating function.
902 num - number of points given
903 xo - array of x coordinates
904 yo - array of y coordinates
905 ival - array of i_color objects
906 dmeasure - distance measure to be used.
908 1 = Euclidean squared
909 2 = Manhattan distance
916 i_gradgen(i_img *im, int num, i_img_dim *xo, i_img_dim *yo, i_color *ival, int dmeasure) {
921 int channels = im->channels;
922 i_img_dim xsize = im->xsize;
923 i_img_dim ysize = im->ysize;
928 mm_log((1,"i_gradgen(im %p, num %d, xo %p, yo %p, ival %p, dmeasure %d)\n", im, num, xo, yo, ival, dmeasure));
930 for(p = 0; p<num; p++) {
931 mm_log((1,"i_gradgen: p%d(" i_DFp ")\n", p, i_DFcp(xo[p], yo[p])));
935 /* on the systems I have sizeof(float) == sizeof(int) and thus
936 this would be same size as the arrays xo and yo point at, but this
937 may not be true for other systems
939 since the arrays here are caller controlled, I assume that on
940 overflow is a programming error rather than an end-user error, so
941 calling exit() is justified.
943 bytes = sizeof(double) * num;
944 if (bytes / num != sizeof(double)) {
945 fprintf(stderr, "integer overflow calculating memory allocation");
948 fdist = mymalloc( bytes ); /* checked 14jul05 tonyc */
950 for(y = 0; y<ysize; y++) for(x = 0; x<xsize; x++) {
953 for(p = 0; p<num; p++) {
954 i_img_dim xd = x-xo[p];
955 i_img_dim yd = y-yo[p];
957 case 0: /* euclidean */
958 fdist[p] = sqrt(xd*xd + yd*yd); /* euclidean distance */
960 case 1: /* euclidean squared */
961 fdist[p] = xd*xd + yd*yd; /* euclidean distance */
963 case 2: /* euclidean squared */
964 fdist[p] = i_max(xd*xd, yd*yd); /* manhattan distance */
967 i_fatal(3,"i_gradgen: Unknown distance measure\n");
972 csd = 1/((num-1)*cs);
974 for(p = 0; p<num; p++) fdist[p] = (cs-fdist[p])*csd;
976 for(ch = 0; ch<channels; ch++) {
978 for(p = 0; p<num; p++) tres += ival[p].channel[ch] * fdist[p];
979 val.channel[ch] = saturate(tres);
981 i_ppix(im, x, y, &val);
988 i_nearest_color_foo(i_img *im, int num, i_img_dim *xo, i_img_dim *yo, i_color *ival, int dmeasure) {
992 i_img_dim xsize = im->xsize;
993 i_img_dim ysize = im->ysize;
995 mm_log((1,"i_gradgen(im %p, num %d, xo %p, yo %p, ival %p, dmeasure %d)\n", im, num, xo, yo, ival, dmeasure));
997 for(p = 0; p<num; p++) {
998 mm_log((1,"i_gradgen: p%d(" i_DFp ")\n", p, i_DFcp(xo[p], yo[p])));
1002 for(y = 0; y<ysize; y++) for(x = 0; x<xsize; x++) {
1007 i_img_dim xd = x-xo[0];
1008 i_img_dim yd = y-yo[0];
1011 case 0: /* euclidean */
1012 mindist = sqrt(xd*xd + yd*yd); /* euclidean distance */
1014 case 1: /* euclidean squared */
1015 mindist = xd*xd + yd*yd; /* euclidean distance */
1017 case 2: /* euclidean squared */
1018 mindist = i_max(xd*xd, yd*yd); /* manhattan distance */
1021 i_fatal(3,"i_nearest_color: Unknown distance measure\n");
1024 for(p = 1; p<num; p++) {
1028 case 0: /* euclidean */
1029 curdist = sqrt(xd*xd + yd*yd); /* euclidean distance */
1031 case 1: /* euclidean squared */
1032 curdist = xd*xd + yd*yd; /* euclidean distance */
1034 case 2: /* euclidean squared */
1035 curdist = i_max(xd*xd, yd*yd); /* manhattan distance */
1038 i_fatal(3,"i_nearest_color: Unknown distance measure\n");
1040 if (curdist < mindist) {
1045 i_ppix(im, x, y, &ival[midx]);
1050 =item i_nearest_color(im, num, xo, yo, oval, dmeasure)
1052 This wasn't document - quoth Addi:
1054 An arty type of filter
1056 FIXME: check IRC logs for actual text.
1064 i_img *im - image to render on.
1068 int num - number of points/colors in xo, yo, oval
1072 i_img_dim *xo - array of I<num> x positions
1076 i_img_dim *yo - array of I<num> y positions
1080 i_color *oval - array of I<num> colors
1082 xo, yo, oval correspond to each other, the point xo[i], yo[i] has a
1083 color something like oval[i], at least closer to that color than other
1088 int dmeasure - how we measure the distance from some point P(x,y) to
1097 euclidean distance: sqrt((x2-x1)**2 + (y2-y1)**2)
1101 square of euclidean distance: ((x2-x1)**2 + (y2-y1)**2)
1105 manhattan distance: max((y2-y1)**2, (x2-x1)**2)
1109 An invalid value causes an error exit (the program is aborted).
1117 i_nearest_color(i_img *im, int num, i_img_dim *xo, i_img_dim *yo, i_color *oval, int dmeasure) {
1124 i_img_dim xsize = im->xsize;
1125 i_img_dim ysize = im->ysize;
1127 size_t ival_bytes, tval_bytes;
1129 mm_log((1,"i_nearest_color(im %p, num %d, xo %p, yo %p, oval %p, dmeasure %d)\n", im, num, xo, yo, oval, dmeasure));
1134 i_push_error(0, "no points supplied to nearest_color filter");
1138 if (dmeasure < 0 || dmeasure > i_dmeasure_limit) {
1139 i_push_error(0, "distance measure invalid");
1143 tval_bytes = sizeof(float)*num*im->channels;
1144 if (tval_bytes / num != sizeof(float) * im->channels) {
1145 i_push_error(0, "integer overflow calculating memory allocation");
1148 ival_bytes = sizeof(i_color) * num;
1149 if (ival_bytes / sizeof(i_color) != num) {
1150 i_push_error(0, "integer overflow calculating memory allocation");
1153 tval = mymalloc( tval_bytes ); /* checked 17feb2005 tonyc */
1154 ival = mymalloc( ival_bytes ); /* checked 17feb2005 tonyc */
1155 cmatch = mymalloc( sizeof(int)*num ); /* checked 17feb2005 tonyc */
1157 for(p = 0; p<num; p++) {
1158 for(ch = 0; ch<im->channels; ch++) tval[ p * im->channels + ch] = 0;
1163 for(y = 0; y<ysize; y++) for(x = 0; x<xsize; x++) {
1168 i_img_dim xd = x-xo[0];
1169 i_img_dim yd = y-yo[0];
1172 case 0: /* euclidean */
1173 mindist = sqrt(xd*xd + yd*yd); /* euclidean distance */
1175 case 1: /* euclidean squared */
1176 mindist = xd*xd + yd*yd; /* euclidean distance */
1178 case 2: /* manhatten distance */
1179 mindist = i_max(xd*xd, yd*yd); /* manhattan distance */
1182 i_fatal(3,"i_nearest_color: Unknown distance measure\n");
1185 for(p = 1; p<num; p++) {
1189 case 0: /* euclidean */
1190 curdist = sqrt(xd*xd + yd*yd); /* euclidean distance */
1192 case 1: /* euclidean squared */
1193 curdist = xd*xd + yd*yd; /* euclidean distance */
1195 case 2: /* euclidean squared */
1196 curdist = i_max(xd*xd, yd*yd); /* manhattan distance */
1199 i_fatal(3,"i_nearest_color: Unknown distance measure\n");
1201 if (curdist < mindist) {
1208 i_gpix(im, x, y, &val);
1209 c2 = 1.0/(float)(cmatch[midx]);
1212 for(ch = 0; ch<im->channels; ch++)
1213 tval[midx*im->channels + ch] =
1214 c1*tval[midx*im->channels + ch] + c2 * (float) val.channel[ch];
1218 for(p = 0; p<num; p++) {
1219 for(ch = 0; ch<im->channels; ch++)
1220 ival[p].channel[ch] = tval[p*im->channels + ch];
1222 /* avoid uninitialized value messages from valgrind */
1223 while (ch < MAXCHANNELS)
1224 ival[p].channel[ch++] = 0;
1227 i_nearest_color_foo(im, num, xo, yo, ival, dmeasure);
1233 =item i_unsharp_mask(im, stddev, scale)
1235 Perform an usharp mask, which is defined as subtracting the blurred
1236 image from double the original.
1242 i_unsharp_mask(i_img *im, double stddev, double scale) {
1249 /* it really shouldn't ever be more than 1.0, but maybe ... */
1254 i_gaussian(copy, stddev);
1255 if (im->bits == i_8_bits) {
1256 i_color *blur = mymalloc(im->xsize * sizeof(i_color)); /* checked 17feb2005 tonyc */
1257 i_color *out = mymalloc(im->xsize * sizeof(i_color)); /* checked 17feb2005 tonyc */
1259 for (y = 0; y < im->ysize; ++y) {
1260 i_glin(copy, 0, copy->xsize, y, blur);
1261 i_glin(im, 0, im->xsize, y, out);
1262 for (x = 0; x < im->xsize; ++x) {
1263 for (ch = 0; ch < im->channels; ++ch) {
1264 /*int temp = out[x].channel[ch] +
1265 scale * (out[x].channel[ch] - blur[x].channel[ch]);*/
1266 int temp = out[x].channel[ch] * 2 - blur[x].channel[ch];
1269 else if (temp > 255)
1271 out[x].channel[ch] = temp;
1274 i_plin(im, 0, im->xsize, y, out);
1281 i_fcolor *blur = mymalloc(im->xsize * sizeof(i_fcolor)); /* checked 17feb2005 tonyc */
1282 i_fcolor *out = mymalloc(im->xsize * sizeof(i_fcolor)); /* checked 17feb2005 tonyc */
1284 for (y = 0; y < im->ysize; ++y) {
1285 i_glinf(copy, 0, copy->xsize, y, blur);
1286 i_glinf(im, 0, im->xsize, y, out);
1287 for (x = 0; x < im->xsize; ++x) {
1288 for (ch = 0; ch < im->channels; ++ch) {
1289 double temp = out[x].channel[ch] +
1290 scale * (out[x].channel[ch] - blur[x].channel[ch]);
1293 else if (temp > 1.0)
1295 out[x].channel[ch] = temp;
1298 i_plinf(im, 0, im->xsize, y, out);
1304 i_img_destroy(copy);
1308 =item i_diff_image(im1, im2, mindist)
1310 Creates a new image that is transparent, except where the pixel in im2
1311 is different from im1, where it is the pixel from im2.
1313 The samples must differ by at least mindiff to be considered different.
1319 i_diff_image(i_img *im1, i_img *im2, double mindist) {
1321 int outchans, diffchans;
1322 i_img_dim xsize, ysize;
1325 if (im1->channels != im2->channels) {
1326 i_push_error(0, "different number of channels");
1330 outchans = diffchans = im1->channels;
1331 if (outchans == 1 || outchans == 3)
1334 xsize = i_min(im1->xsize, im2->xsize);
1335 ysize = i_min(im1->ysize, im2->ysize);
1337 out = i_sametype_chans(im1, xsize, ysize, outchans);
1339 if (im1->bits == i_8_bits && im2->bits == i_8_bits) {
1340 i_color *line1 = mymalloc(xsize * sizeof(*line1)); /* checked 17feb2005 tonyc */
1341 i_color *line2 = mymalloc(xsize * sizeof(*line1)); /* checked 17feb2005 tonyc */
1345 int imindist = (int)mindist;
1347 for (ch = 0; ch < MAXCHANNELS; ++ch)
1348 empty.channel[ch] = 0;
1350 for (y = 0; y < ysize; ++y) {
1351 i_glin(im1, 0, xsize, y, line1);
1352 i_glin(im2, 0, xsize, y, line2);
1353 if (outchans != diffchans) {
1354 /* give the output an alpha channel since it doesn't have one */
1355 for (x = 0; x < xsize; ++x)
1356 line2[x].channel[diffchans] = 255;
1358 for (x = 0; x < xsize; ++x) {
1360 for (ch = 0; ch < diffchans; ++ch) {
1361 if (line1[x].channel[ch] != line2[x].channel[ch]
1362 && abs(line1[x].channel[ch] - line2[x].channel[ch]) > imindist) {
1370 i_plin(out, 0, xsize, y, line2);
1376 i_fcolor *line1 = mymalloc(xsize * sizeof(*line1)); /* checked 17feb2005 tonyc */
1377 i_fcolor *line2 = mymalloc(xsize * sizeof(*line2)); /* checked 17feb2005 tonyc */
1381 double dist = mindist / 255.0;
1383 for (ch = 0; ch < MAXCHANNELS; ++ch)
1384 empty.channel[ch] = 0;
1386 for (y = 0; y < ysize; ++y) {
1387 i_glinf(im1, 0, xsize, y, line1);
1388 i_glinf(im2, 0, xsize, y, line2);
1389 if (outchans != diffchans) {
1390 /* give the output an alpha channel since it doesn't have one */
1391 for (x = 0; x < xsize; ++x)
1392 line2[x].channel[diffchans] = 1.0;
1394 for (x = 0; x < xsize; ++x) {
1396 for (ch = 0; ch < diffchans; ++ch) {
1397 if (line1[x].channel[ch] != line2[x].channel[ch]
1398 && fabs(line1[x].channel[ch] - line2[x].channel[ch]) > dist) {
1406 i_plinf(out, 0, xsize, y, line2);
1416 static double linear_fount_f(double x, double y, struct fount_state *state);
1417 static double bilinear_fount_f(double x, double y, struct fount_state *state);
1418 static double radial_fount_f(double x, double y, struct fount_state *state);
1419 static double square_fount_f(double x, double y, struct fount_state *state);
1420 static double revolution_fount_f(double x, double y,
1421 struct fount_state *state);
1422 static double conical_fount_f(double x, double y, struct fount_state *state);
1424 typedef double (*fount_func)(double, double, struct fount_state *);
1425 static fount_func fount_funcs[] =
1435 static double linear_interp(double pos, i_fountain_seg *seg);
1436 static double sine_interp(double pos, i_fountain_seg *seg);
1437 static double sphereup_interp(double pos, i_fountain_seg *seg);
1438 static double spheredown_interp(double pos, i_fountain_seg *seg);
1439 typedef double (*fount_interp)(double pos, i_fountain_seg *seg);
1440 static fount_interp fount_interps[] =
1449 static void direct_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg);
1450 static void hue_up_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg);
1451 static void hue_down_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg);
1452 typedef void (*fount_cinterp)(i_fcolor *out, double pos, i_fountain_seg *seg);
1453 static fount_cinterp fount_cinterps[] =
1460 typedef double (*fount_repeat)(double v);
1461 static double fount_r_none(double v);
1462 static double fount_r_sawtooth(double v);
1463 static double fount_r_triangle(double v);
1464 static double fount_r_saw_both(double v);
1465 static double fount_r_tri_both(double v);
1466 static fount_repeat fount_repeats[] =
1475 static int simple_ssample(i_fcolor *out, double x, double y,
1476 struct fount_state *state);
1477 static int random_ssample(i_fcolor *out, double x, double y,
1478 struct fount_state *state);
1479 static int circle_ssample(i_fcolor *out, double x, double y,
1480 struct fount_state *state);
1481 typedef int (*fount_ssample)(i_fcolor *out, double x, double y,
1482 struct fount_state *state);
1483 static fount_ssample fount_ssamples[] =
1492 fount_getat(i_fcolor *out, double x, double y, struct fount_state *state);
1495 Keep state information used by each type of fountain fill
1497 struct fount_state {
1498 /* precalculated for the equation of the line perpendicular to the line AB */
1509 fount_repeat rpfunc;
1510 fount_ssample ssfunc;
1512 i_fountain_seg *segs;
1517 fount_init_state(struct fount_state *state, double xa, double ya,
1518 double xb, double yb, i_fountain_type type,
1519 i_fountain_repeat repeat, int combine, int super_sample,
1520 double ssample_param, int count, i_fountain_seg *segs);
1523 fount_finish_state(struct fount_state *state);
1525 #define EPSILON (1e-6)
1528 =item i_fountain(im, xa, ya, xb, yb, type, repeat, combine, super_sample, ssample_param, count, segs)
1530 Draws a fountain fill using A(xa, ya) and B(xb, yb) as reference points.
1532 I<type> controls how the reference points are used:
1538 linear, where A is 0 and B is 1.
1542 linear in both directions from A.
1546 circular, where A is the centre of the fill, and B is a point
1549 =item i_ft_radial_square
1551 where A is the centre of the fill and B is the centre of
1552 one side of the square.
1554 =item i_ft_revolution
1556 where A is the centre of the fill and B defines the 0/1.0
1561 similar to i_ft_revolution, except that the revolution goes in both
1566 I<repeat> can be one of:
1572 values < 0 are treated as zero, values > 1 are treated as 1.
1576 negative values are treated as 0, positive values are modulo 1.0
1580 negative values are treated as zero, if (int)value is odd then the value is treated as 1-(value
1581 mod 1.0), otherwise the same as for sawtooth.
1585 like i_fr_sawtooth, except that the sawtooth pattern repeats into
1590 Like i_fr_triangle, except that negative values are handled as their
1595 If combine is non-zero then non-opaque values are combined with the
1598 I<super_sample> controls super sampling, if any. At some point I'll
1599 probably add a adaptive super-sampler. Current possible values are:
1605 No super-sampling is done.
1609 A square grid of points withing the pixel are sampled.
1613 Random points within the pixel are sampled.
1617 Points on the radius of a circle are sampled. This produces fairly
1618 good results, but is fairly slow since sin() and cos() are evaluated
1623 I<ssample_param> is intended to be roughly the number of points
1624 sampled within the pixel.
1626 I<count> and I<segs> define the segments of the fill.
1633 i_fountain(i_img *im, double xa, double ya, double xb, double yb,
1634 i_fountain_type type, i_fountain_repeat repeat,
1635 int combine, int super_sample, double ssample_param,
1636 int count, i_fountain_seg *segs) {
1637 struct fount_state state;
1639 i_fcolor *line = NULL;
1640 i_fcolor *work = NULL;
1642 i_fountain_seg *my_segs;
1643 i_fill_combine_f combine_func = NULL;
1644 i_fill_combinef_f combinef_func = NULL;
1648 /* i_fountain() allocates floating colors even for 8-bit images,
1649 so we need to do this check */
1650 line_bytes = sizeof(i_fcolor) * im->xsize;
1651 if (line_bytes / sizeof(i_fcolor) != im->xsize) {
1652 i_push_error(0, "integer overflow calculating memory allocation");
1656 line = mymalloc(line_bytes); /* checked 17feb2005 tonyc */
1658 i_get_combine(combine, &combine_func, &combinef_func);
1660 work = mymalloc(line_bytes); /* checked 17feb2005 tonyc */
1662 fount_init_state(&state, xa, ya, xb, yb, type, repeat, combine,
1663 super_sample, ssample_param, count, segs);
1664 my_segs = state.segs;
1666 for (y = 0; y < im->ysize; ++y) {
1667 i_glinf(im, 0, im->xsize, y, line);
1668 for (x = 0; x < im->xsize; ++x) {
1671 if (super_sample == i_fts_none)
1672 got_one = fount_getat(&c, x, y, &state);
1674 got_one = state.ssfunc(&c, x, y, &state);
1683 combinef_func(line, work, im->channels, im->xsize);
1684 i_plinf(im, 0, im->xsize, y, line);
1686 fount_finish_state(&state);
1687 if (work) myfree(work);
1695 struct fount_state state;
1696 } i_fill_fountain_t;
1699 fill_fountf(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width, int channels,
1702 fount_fill_destroy(i_fill_t *fill);
1704 static i_fill_fountain_t
1716 =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>)
1719 =synopsis fill = i_new_fill_fount(0, 0, 100, 100, i_ft_linear, i_ft_linear,
1720 =synopsis i_fr_triangle, 0, i_fts_grid, 9, 1, segs);
1723 Creates a new general fill which fills with a fountain fill.
1729 i_new_fill_fount(double xa, double ya, double xb, double yb,
1730 i_fountain_type type, i_fountain_repeat repeat,
1731 int combine, int super_sample, double ssample_param,
1732 int count, i_fountain_seg *segs) {
1733 i_fill_fountain_t *fill = mymalloc(sizeof(i_fill_fountain_t));
1735 *fill = fount_fill_proto;
1737 i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
1739 fill->base.combine = NULL;
1740 fill->base.combinef = NULL;
1742 fount_init_state(&fill->state, xa, ya, xb, yb, type, repeat, combine,
1743 super_sample, ssample_param, count, segs);
1751 =head1 INTERNAL FUNCTIONS
1755 =item fount_init_state(...)
1757 Used by both the fountain fill filter and the fountain fill.
1763 fount_init_state(struct fount_state *state, double xa, double ya,
1764 double xb, double yb, i_fountain_type type,
1765 i_fountain_repeat repeat, int combine, int super_sample,
1766 double ssample_param, int count, i_fountain_seg *segs) {
1769 i_fountain_seg *my_segs = mymalloc(sizeof(i_fountain_seg) * count); /* checked 2jul06 - duplicating original */
1770 /*int have_alpha = im->channels == 2 || im->channels == 4;*/
1772 memset(state, 0, sizeof(*state));
1773 /* we keep a local copy that we can adjust for speed */
1774 for (i = 0; i < count; ++i) {
1775 i_fountain_seg *seg = my_segs + i;
1778 if (seg->type < 0 || seg->type >= i_fst_end)
1779 seg->type = i_fst_linear;
1780 if (seg->color < 0 || seg->color >= i_fc_end)
1781 seg->color = i_fc_direct;
1782 if (seg->color == i_fc_hue_up || seg->color == i_fc_hue_down) {
1783 /* so we don't have to translate to HSV on each request, do it here */
1784 for (j = 0; j < 2; ++j) {
1785 i_rgb_to_hsvf(seg->c+j);
1787 if (seg->color == i_fc_hue_up) {
1788 if (seg->c[1].channel[0] <= seg->c[0].channel[0])
1789 seg->c[1].channel[0] += 1.0;
1792 if (seg->c[0].channel[0] <= seg->c[0].channel[1])
1793 seg->c[0].channel[0] += 1.0;
1796 /*printf("start %g mid %g end %g c0(%g,%g,%g,%g) c1(%g,%g,%g,%g) type %d color %d\n",
1797 seg->start, seg->middle, seg->end, seg->c[0].channel[0],
1798 seg->c[0].channel[1], seg->c[0].channel[2], seg->c[0].channel[3],
1799 seg->c[1].channel[0], seg->c[1].channel[1], seg->c[1].channel[2],
1800 seg->c[1].channel[3], seg->type, seg->color);*/
1804 /* initialize each engine */
1805 /* these are so common ... */
1806 state->lA = xb - xa;
1807 state->lB = yb - ya;
1808 state->AB = sqrt(state->lA * state->lA + state->lB * state->lB);
1813 type = i_ft_linear; /* make the invalid value valid */
1816 state->lC = ya * ya - ya * yb + xa * xa - xa * xb;
1818 state->mult = 1/linear_fount_f(xb, yb, state);
1822 state->mult = 1.0 / sqrt((double)(xb-xa)*(xb-xa)
1823 + (double)(yb-ya)*(yb-ya));
1826 case i_ft_radial_square:
1827 state->cos = state->lA / state->AB;
1828 state->sin = state->lB / state->AB;
1829 state->mult = 1.0 / state->AB;
1832 case i_ft_revolution:
1833 state->theta = atan2(yb-ya, xb-xa);
1834 state->mult = 1.0 / (PI * 2);
1838 state->theta = atan2(yb-ya, xb-xa);
1839 state->mult = 1.0 / PI;
1842 state->ffunc = fount_funcs[type];
1843 if (super_sample < 0
1844 || super_sample >= (int)(sizeof(fount_ssamples)/sizeof(*fount_ssamples))) {
1847 state->ssample_data = NULL;
1848 switch (super_sample) {
1850 ssample_param = floor(0.5 + sqrt(ssample_param));
1851 bytes = ssample_param * ssample_param * sizeof(i_fcolor);
1852 if (bytes / sizeof(i_fcolor) == ssample_param * ssample_param) {
1853 state->ssample_data = mymalloc(sizeof(i_fcolor) * ssample_param * ssample_param); /* checked 1jul06 tonyc */
1856 super_sample = i_fts_none;
1862 ssample_param = floor(0.5+ssample_param);
1863 bytes = sizeof(i_fcolor) * ssample_param;
1864 if (bytes / sizeof(i_fcolor) == ssample_param) {
1865 state->ssample_data = mymalloc(sizeof(i_fcolor) * ssample_param);
1868 super_sample = i_fts_none;
1872 state->parm = ssample_param;
1873 state->ssfunc = fount_ssamples[super_sample];
1874 if (repeat < 0 || repeat >= (sizeof(fount_repeats)/sizeof(*fount_repeats)))
1876 state->rpfunc = fount_repeats[repeat];
1877 state->segs = my_segs;
1878 state->count = count;
1882 fount_finish_state(struct fount_state *state) {
1883 if (state->ssample_data)
1884 myfree(state->ssample_data);
1885 myfree(state->segs);
1890 =item fount_getat(out, x, y, ffunc, rpfunc, state, segs, count)
1892 Evaluates the fountain fill at the given point.
1894 This is called by both the non-super-sampling and super-sampling code.
1896 You might think that it would make sense to sample the fill parameter
1897 instead, and combine those, but this breaks badly.
1903 fount_getat(i_fcolor *out, double x, double y, struct fount_state *state) {
1904 double v = (state->rpfunc)((state->ffunc)(x, y, state));
1908 while (i < state->count
1909 && (v < state->segs[i].start || v > state->segs[i].end)) {
1912 if (i < state->count) {
1913 v = (fount_interps[state->segs[i].type])(v, state->segs+i);
1914 (fount_cinterps[state->segs[i].color])(out, v, state->segs+i);
1922 =item linear_fount_f(x, y, state)
1924 Calculate the fill parameter for a linear fountain fill.
1926 Uses the point to line distance function, with some precalculation
1927 done in i_fountain().
1932 linear_fount_f(double x, double y, struct fount_state *state) {
1933 return (state->lA * x + state->lB * y + state->lC) / state->AB * state->mult;
1937 =item bilinear_fount_f(x, y, state)
1939 Calculate the fill parameter for a bi-linear fountain fill.
1944 bilinear_fount_f(double x, double y, struct fount_state *state) {
1945 return fabs((state->lA * x + state->lB * y + state->lC) / state->AB * state->mult);
1949 =item radial_fount_f(x, y, state)
1951 Calculate the fill parameter for a radial fountain fill.
1953 Simply uses the distance function.
1958 radial_fount_f(double x, double y, struct fount_state *state) {
1959 return sqrt((double)(state->xa-x)*(state->xa-x)
1960 + (double)(state->ya-y)*(state->ya-y)) * state->mult;
1964 =item square_fount_f(x, y, state)
1966 Calculate the fill parameter for a square fountain fill.
1968 Works by rotating the reference co-ordinate around the centre of the
1974 square_fount_f(double x, double y, struct fount_state *state) {
1975 i_img_dim xc, yc; /* centred on A */
1976 double xt, yt; /* rotated by theta */
1979 xt = fabs(xc * state->cos + yc * state->sin);
1980 yt = fabs(-xc * state->sin + yc * state->cos);
1981 return (xt > yt ? xt : yt) * state->mult;
1985 =item revolution_fount_f(x, y, state)
1987 Calculates the fill parameter for the revolution fountain fill.
1992 revolution_fount_f(double x, double y, struct fount_state *state) {
1993 double angle = atan2(y - state->ya, x - state->xa);
1995 angle -= state->theta;
1997 angle = fmod(angle+ PI * 4, PI*2);
2000 return angle * state->mult;
2004 =item conical_fount_f(x, y, state)
2006 Calculates the fill parameter for the conical fountain fill.
2011 conical_fount_f(double x, double y, struct fount_state *state) {
2012 double angle = atan2(y - state->ya, x - state->xa);
2014 angle -= state->theta;
2017 else if (angle > PI)
2020 return fabs(angle) * state->mult;
2024 =item linear_interp(pos, seg)
2026 Calculates linear interpolation on the fill parameter. Breaks the
2027 segment into 2 regions based in the I<middle> value.
2032 linear_interp(double pos, i_fountain_seg *seg) {
2033 if (pos < seg->middle) {
2034 double len = seg->middle - seg->start;
2038 return (pos - seg->start) / len / 2;
2041 double len = seg->end - seg->middle;
2045 return 0.5 + (pos - seg->middle) / len / 2;
2050 =item sine_interp(pos, seg)
2052 Calculates sine function interpolation on the fill parameter.
2057 sine_interp(double pos, i_fountain_seg *seg) {
2058 /* I wonder if there's a simple way to smooth the transition for this */
2059 double work = linear_interp(pos, seg);
2061 return (1-cos(work * PI))/2;
2065 =item sphereup_interp(pos, seg)
2067 Calculates spherical interpolation on the fill parameter, with the cusp
2073 sphereup_interp(double pos, i_fountain_seg *seg) {
2074 double work = linear_interp(pos, seg);
2076 return sqrt(1.0 - (1-work) * (1-work));
2080 =item spheredown_interp(pos, seg)
2082 Calculates spherical interpolation on the fill parameter, with the cusp
2088 spheredown_interp(double pos, i_fountain_seg *seg) {
2089 double work = linear_interp(pos, seg);
2091 return 1-sqrt(1.0 - work * work);
2095 =item direct_cinterp(out, pos, seg)
2097 Calculates the fountain color based on direct scaling of the channels
2098 of the color channels.
2103 direct_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg) {
2105 for (ch = 0; ch < MAXCHANNELS; ++ch) {
2106 out->channel[ch] = seg->c[0].channel[ch] * (1 - pos)
2107 + seg->c[1].channel[ch] * pos;
2112 =item hue_up_cinterp(put, pos, seg)
2114 Calculates the fountain color based on scaling a HSV value. The hue
2115 increases as the fill parameter increases.
2120 hue_up_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg) {
2122 for (ch = 0; ch < MAXCHANNELS; ++ch) {
2123 out->channel[ch] = seg->c[0].channel[ch] * (1 - pos)
2124 + seg->c[1].channel[ch] * pos;
2130 =item hue_down_cinterp(put, pos, seg)
2132 Calculates the fountain color based on scaling a HSV value. The hue
2133 decreases as the fill parameter increases.
2138 hue_down_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg) {
2140 for (ch = 0; ch < MAXCHANNELS; ++ch) {
2141 out->channel[ch] = seg->c[0].channel[ch] * (1 - pos)
2142 + seg->c[1].channel[ch] * pos;
2148 =item simple_ssample(out, parm, x, y, state, ffunc, rpfunc, segs, count)
2150 Simple grid-based super-sampling.
2155 simple_ssample(i_fcolor *out, double x, double y, struct fount_state *state) {
2156 i_fcolor *work = state->ssample_data;
2158 int grid = state->parm;
2159 double base = -0.5 + 0.5 / grid;
2160 double step = 1.0 / grid;
2164 for (dx = 0; dx < grid; ++dx) {
2165 for (dy = 0; dy < grid; ++dy) {
2166 if (fount_getat(work+samp_count, x + base + step * dx,
2167 y + base + step * dy, state)) {
2172 for (ch = 0; ch < MAXCHANNELS; ++ch) {
2173 out->channel[ch] = 0;
2174 for (i = 0; i < samp_count; ++i) {
2175 out->channel[ch] += work[i].channel[ch];
2177 /* we divide by 4 rather than samp_count since if there's only one valid
2178 sample it should be mostly transparent */
2179 out->channel[ch] /= grid * grid;
2185 =item random_ssample(out, parm, x, y, state, ffunc, rpfunc, segs, count)
2187 Random super-sampling.
2192 random_ssample(i_fcolor *out, double x, double y,
2193 struct fount_state *state) {
2194 i_fcolor *work = state->ssample_data;
2196 int maxsamples = state->parm;
2197 double rand_scale = 1.0 / RAND_MAX;
2199 for (i = 0; i < maxsamples; ++i) {
2200 if (fount_getat(work+samp_count, x - 0.5 + rand() * rand_scale,
2201 y - 0.5 + rand() * rand_scale, state)) {
2205 for (ch = 0; ch < MAXCHANNELS; ++ch) {
2206 out->channel[ch] = 0;
2207 for (i = 0; i < samp_count; ++i) {
2208 out->channel[ch] += work[i].channel[ch];
2210 /* we divide by maxsamples rather than samp_count since if there's
2211 only one valid sample it should be mostly transparent */
2212 out->channel[ch] /= maxsamples;
2218 =item circle_ssample(out, parm, x, y, state, ffunc, rpfunc, segs, count)
2220 Super-sampling around the circumference of a circle.
2222 I considered saving the sin()/cos() values and transforming step-size
2223 around the circle, but that's inaccurate, though it may not matter
2229 circle_ssample(i_fcolor *out, double x, double y,
2230 struct fount_state *state) {
2231 i_fcolor *work = state->ssample_data;
2233 int maxsamples = state->parm;
2234 double angle = 2 * PI / maxsamples;
2235 double radius = 0.3; /* semi-random */
2237 for (i = 0; i < maxsamples; ++i) {
2238 if (fount_getat(work+samp_count, x + radius * cos(angle * i),
2239 y + radius * sin(angle * i), state)) {
2243 for (ch = 0; ch < MAXCHANNELS; ++ch) {
2244 out->channel[ch] = 0;
2245 for (i = 0; i < samp_count; ++i) {
2246 out->channel[ch] += work[i].channel[ch];
2248 /* we divide by maxsamples rather than samp_count since if there's
2249 only one valid sample it should be mostly transparent */
2250 out->channel[ch] /= maxsamples;
2256 =item fount_r_none(v)
2258 Implements no repeats. Simply clamps the fill value.
2263 fount_r_none(double v) {
2264 return v < 0 ? 0 : v > 1 ? 1 : v;
2268 =item fount_r_sawtooth(v)
2270 Implements sawtooth repeats. Clamps negative values and uses fmod()
2276 fount_r_sawtooth(double v) {
2277 return v < 0 ? 0 : fmod(v, 1.0);
2281 =item fount_r_triangle(v)
2283 Implements triangle repeats. Clamps negative values, uses fmod to get
2284 a range 0 through 2 and then adjusts values > 1.
2289 fount_r_triangle(double v) {
2294 return v > 1.0 ? 2.0 - v : v;
2299 =item fount_r_saw_both(v)
2301 Implements sawtooth repeats in the both postive and negative directions.
2303 Adjusts the value to be postive and then just uses fmod().
2308 fount_r_saw_both(double v) {
2311 return fmod(v, 1.0);
2315 =item fount_r_tri_both(v)
2317 Implements triangle repeats in the both postive and negative directions.
2319 Uses fmod on the absolute value, and then adjusts values > 1.
2324 fount_r_tri_both(double v) {
2325 v = fmod(fabs(v), 2.0);
2326 return v > 1.0 ? 2.0 - v : v;
2330 =item fill_fountf(fill, x, y, width, channels, data)
2332 The fill function for fountain fills.
2337 fill_fountf(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
2338 int channels, i_fcolor *data) {
2339 i_fill_fountain_t *f = (i_fill_fountain_t *)fill;
2345 if (f->state.ssfunc)
2346 got_one = f->state.ssfunc(&c, x, y, &f->state);
2348 got_one = fount_getat(&c, x, y, &f->state);
2357 =item fount_fill_destroy(fill)
2362 fount_fill_destroy(i_fill_t *fill) {
2363 i_fill_fountain_t *f = (i_fill_fountain_t *)fill;
2364 fount_finish_state(&f->state);
2372 Arnar M. Hrafnkelsson <addi@umich.edu>
2374 Tony Cook <tony@develop-help.com> (i_fountain())