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);
652 =item i_autolevels_mono(im, lsat, usat)
654 Do autolevels, but monochromatically.
660 i_autolevels_mono(i_img *im, float lsat, float usat) {
662 i_img_dim i, x, y, hist[256];
663 i_img_dim sum_lum, min_lum, max_lum;
664 i_img_dim upper_accum, lower_accum;
667 int adapt_channels = im->channels == 4 ? 2 : 1;
668 int color_channels = i_img_color_channels(im);
669 i_img_dim color_samples = im->xsize * color_channels;
672 im_log((aIMCTX, 1,"i_autolevels_mono(im %p, lsat %f,usat %f)\n", im, lsat,usat));
674 /* build the histogram in 8-bits, unless the image has a very small
675 range it should make little difference to the result */
677 for (i = 0; i < 256; i++)
680 row = mymalloc(im->xsize * sizeof(i_color));
681 /* create histogram for each channel */
682 for (y = 0; y < im->ysize; y++) {
684 i_glin(im, 0, im->xsize, y, row);
685 if (im->channels > 2)
686 i_adapt_colors(adapt_channels, im->channels, row, im->xsize);
687 for (x = 0; x < im->xsize; x++) {
688 hist[p->channel[0]]++;
694 for(i = 0; i < 256; i++) {
701 lower_accum = upper_accum = 0;
703 for(i=0; i<256; i++) {
704 lower_accum += hist[i];
705 if (lower_accum < sum_lum * lsat)
708 upper_accum += hist[255-i];
709 if (upper_accum < sum_lum * usat)
714 IM_SAMPLE_T *srow = mymalloc(color_samples * sizeof(IM_SAMPLE_T));
716 IM_WORK_T low = min_lum;
718 IM_WORK_T low = min_lum / 255.0 * IM_SAMPLE_MAX;
720 IM_WORK_T scale = 255.0 / (max_lum - min_lum);
722 for(y = 0; y < im->ysize; y++) {
723 IM_GSAMP(im, 0, im->xsize, y, srow, NULL, color_channels);
724 for(i = 0; i < color_samples; ++i) {
725 IM_WORK_T tmp = (srow[i] - low) * scale;
726 srow[i] = IM_LIMIT(tmp);
728 IM_PSAMP(im, 0, im->xsize, y, srow, NULL, color_channels);
736 =item i_autolevels(im, lsat, usat, skew)
738 Scales and translates each color such that it fills the range completely.
739 Skew is not implemented yet - purpose is to control the color skew that can
740 occur when changing the contrast.
743 lsat - fraction of pixels that will be truncated at the lower end of the spectrum
744 usat - fraction of pixels that will be truncated at the higher end of the spectrum
747 Note: this code calculates levels and adjusts each channel separately,
748 which will typically cause a color shift.
754 i_autolevels(i_img *im, float lsat, float usat, float skew) {
756 i_img_dim i, x, y, rhist[256], ghist[256], bhist[256];
757 i_img_dim rsum, rmin, rmax;
758 i_img_dim gsum, gmin, gmax;
759 i_img_dim bsum, bmin, bmax;
760 i_img_dim rcl, rcu, gcl, gcu, bcl, bcu;
763 im_log((aIMCTX, 1,"i_autolevels(im %p, lsat %f,usat %f,skew %f)\n", im, lsat,usat,skew));
766 for(i=0;i<256;i++) rhist[i]=ghist[i]=bhist[i] = 0;
767 /* create histogram for each channel */
768 for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
769 i_gpix(im, x, y, &val);
770 rhist[val.channel[0]]++;
771 ghist[val.channel[1]]++;
772 bhist[val.channel[2]]++;
781 rmin = gmin = bmin = 0;
782 rmax = gmax = bmax = 255;
784 rcu = rcl = gcu = gcl = bcu = bcl = 0;
786 for(i=0; i<256; i++) {
787 rcl += rhist[i]; if ( (rcl<rsum*lsat) ) rmin=i;
788 rcu += rhist[255-i]; if ( (rcu<rsum*usat) ) rmax=255-i;
790 gcl += ghist[i]; if ( (gcl<gsum*lsat) ) gmin=i;
791 gcu += ghist[255-i]; if ( (gcu<gsum*usat) ) gmax=255-i;
793 bcl += bhist[i]; if ( (bcl<bsum*lsat) ) bmin=i;
794 bcu += bhist[255-i]; if ( (bcu<bsum*usat) ) bmax=255-i;
797 for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
798 i_gpix(im, x, y, &val);
799 val.channel[0]=saturate((val.channel[0]-rmin)*255/(rmax-rmin));
800 val.channel[1]=saturate((val.channel[1]-gmin)*255/(gmax-gmin));
801 val.channel[2]=saturate((val.channel[2]-bmin)*255/(bmax-bmin));
802 i_ppix(im, x, y, &val);
809 Pseudo noise utility function used to generate perlin noise. (internal)
819 Noise(i_img_dim x, i_img_dim y) {
820 i_img_dim n = x + y * 57;
822 return ( 1.0 - ( (n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff) / 1073741824.0);
826 =item SmoothedNoise1(x,y)
828 Pseudo noise utility function used to generate perlin noise. (internal)
838 SmoothedNoise1(double x, double y) {
839 double corners = ( Noise(x-1, y-1)+Noise(x+1, y-1)+Noise(x-1, y+1)+Noise(x+1, y+1) ) / 16;
840 double sides = ( Noise(x-1, y) +Noise(x+1, y) +Noise(x, y-1) +Noise(x, y+1) ) / 8;
841 double center = Noise(x, y) / 4;
842 return corners + sides + center;
847 =item G_Interpolate(a, b, x)
849 Utility function used to generate perlin noise. (internal)
856 C_Interpolate(double a, double b, double x) {
857 /* float ft = x * 3.1415927; */
859 double f = (1 - cos(ft)) * .5;
860 return a*(1-f) + b*f;
865 =item InterpolatedNoise(x, y)
867 Utility function used to generate perlin noise. (internal)
874 InterpolatedNoise(double x, double y) {
876 i_img_dim integer_X = x;
877 double fractional_X = x - integer_X;
878 i_img_dim integer_Y = y;
879 double fractional_Y = y - integer_Y;
881 double v1 = SmoothedNoise1(integer_X, integer_Y);
882 double v2 = SmoothedNoise1(integer_X + 1, integer_Y);
883 double v3 = SmoothedNoise1(integer_X, integer_Y + 1);
884 double v4 = SmoothedNoise1(integer_X + 1, integer_Y + 1);
886 double i1 = C_Interpolate(v1 , v2 , fractional_X);
887 double i2 = C_Interpolate(v3 , v4 , fractional_X);
889 return C_Interpolate(i1 , i2 , fractional_Y);
895 =item PerlinNoise_2D(x, y)
897 Utility function used to generate perlin noise. (internal)
904 PerlinNoise_2D(float x, float y) {
908 int Number_Of_Octaves=6;
909 int n = Number_Of_Octaves - 1;
914 total = total + InterpolatedNoise(x * frequency, y * frequency) * amplitude;
922 =item i_radnoise(im, xo, yo, rscale, ascale)
924 Perlin-like radial noise.
927 xo - x coordinate of center
928 yo - y coordinate of center
929 rscale - radial scale
930 ascale - angular scale
936 i_radnoise(i_img *im, i_img_dim xo, i_img_dim yo, double rscale, double ascale) {
944 for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
945 xc = (double)x-xo+0.5;
946 yc = (double)y-yo+0.5;
947 r = rscale*sqrt(xc*xc+yc*yc)+1.2;
948 a = (PI+atan2(yc,xc))*ascale;
949 v = saturate(128+100*(PerlinNoise_2D(a,r)));
950 /* v=saturate(120+12*PerlinNoise_2D(xo+(float)x/scale,yo+(float)y/scale)); Good soft marble */
951 for(ch=0; ch<im->channels; ch++) val.channel[ch]=v;
952 i_ppix(im, x, y, &val);
958 =item i_turbnoise(im, xo, yo, scale)
960 Perlin-like 2d noise noise.
963 xo - x coordinate translation
964 yo - y coordinate translation
965 scale - scale of noise
971 i_turbnoise(i_img *im, double xo, double yo, double scale) {
977 for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
978 /* v=saturate(125*(1.0+PerlinNoise_2D(xo+(float)x/scale,yo+(float)y/scale))); */
979 v = saturate(120*(1.0+sin(xo+(double)x/scale+PerlinNoise_2D(xo+(double)x/scale,yo+(float)y/scale))));
980 for(ch=0; ch<im->channels; ch++) val.channel[ch] = v;
981 i_ppix(im, x, y, &val);
988 =item i_gradgen(im, num, xo, yo, ival, dmeasure)
990 Gradient generating function.
993 num - number of points given
994 xo - array of x coordinates
995 yo - array of y coordinates
996 ival - array of i_color objects
997 dmeasure - distance measure to be used.
999 1 = Euclidean squared
1000 2 = Manhattan distance
1007 i_gradgen(i_img *im, int num, i_img_dim *xo, i_img_dim *yo, i_color *ival, int dmeasure) {
1012 int channels = im->channels;
1013 i_img_dim xsize = im->xsize;
1014 i_img_dim ysize = im->ysize;
1020 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));
1022 for(p = 0; p<num; p++) {
1023 im_log((aIMCTX,1,"i_gradgen: p%d(" i_DFp ")\n", p, i_DFcp(xo[p], yo[p])));
1027 /* on the systems I have sizeof(float) == sizeof(int) and thus
1028 this would be same size as the arrays xo and yo point at, but this
1029 may not be true for other systems
1031 since the arrays here are caller controlled, I assume that on
1032 overflow is a programming error rather than an end-user error, so
1033 calling exit() is justified.
1035 bytes = sizeof(double) * num;
1036 if (bytes / num != sizeof(double)) {
1037 fprintf(stderr, "integer overflow calculating memory allocation");
1040 fdist = mymalloc( bytes ); /* checked 14jul05 tonyc */
1042 for(y = 0; y<ysize; y++) for(x = 0; x<xsize; x++) {
1045 for(p = 0; p<num; p++) {
1046 i_img_dim xd = x-xo[p];
1047 i_img_dim yd = y-yo[p];
1049 case 0: /* euclidean */
1050 fdist[p] = sqrt(xd*xd + yd*yd); /* euclidean distance */
1052 case 1: /* euclidean squared */
1053 fdist[p] = xd*xd + yd*yd; /* euclidean distance */
1055 case 2: /* euclidean squared */
1056 fdist[p] = i_max(xd*xd, yd*yd); /* manhattan distance */
1059 im_fatal(aIMCTX, 3,"i_gradgen: Unknown distance measure\n");
1064 csd = 1/((num-1)*cs);
1066 for(p = 0; p<num; p++) fdist[p] = (cs-fdist[p])*csd;
1068 for(ch = 0; ch<channels; ch++) {
1070 for(p = 0; p<num; p++) tres += ival[p].channel[ch] * fdist[p];
1071 val.channel[ch] = saturate(tres);
1073 i_ppix(im, x, y, &val);
1080 i_nearest_color_foo(i_img *im, int num, i_img_dim *xo, i_img_dim *yo, i_color *ival, int dmeasure) {
1084 i_img_dim xsize = im->xsize;
1085 i_img_dim ysize = im->ysize;
1088 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));
1090 for(p = 0; p<num; p++) {
1091 im_log((aIMCTX, 1,"i_gradgen: p%d(" i_DFp ")\n", p, i_DFcp(xo[p], yo[p])));
1095 for(y = 0; y<ysize; y++) for(x = 0; x<xsize; x++) {
1100 i_img_dim xd = x-xo[0];
1101 i_img_dim yd = y-yo[0];
1104 case 0: /* euclidean */
1105 mindist = sqrt(xd*xd + yd*yd); /* euclidean distance */
1107 case 1: /* euclidean squared */
1108 mindist = xd*xd + yd*yd; /* euclidean distance */
1110 case 2: /* euclidean squared */
1111 mindist = i_max(xd*xd, yd*yd); /* manhattan distance */
1114 im_fatal(aIMCTX, 3,"i_nearest_color: Unknown distance measure\n");
1117 for(p = 1; p<num; p++) {
1121 case 0: /* euclidean */
1122 curdist = sqrt(xd*xd + yd*yd); /* euclidean distance */
1124 case 1: /* euclidean squared */
1125 curdist = xd*xd + yd*yd; /* euclidean distance */
1127 case 2: /* euclidean squared */
1128 curdist = i_max(xd*xd, yd*yd); /* manhattan distance */
1131 im_fatal(aIMCTX, 3,"i_nearest_color: Unknown distance measure\n");
1133 if (curdist < mindist) {
1138 i_ppix(im, x, y, &ival[midx]);
1143 =item i_nearest_color(im, num, xo, yo, oval, dmeasure)
1145 This wasn't document - quoth Addi:
1147 An arty type of filter
1149 FIXME: check IRC logs for actual text.
1157 i_img *im - image to render on.
1161 int num - number of points/colors in xo, yo, oval
1165 i_img_dim *xo - array of I<num> x positions
1169 i_img_dim *yo - array of I<num> y positions
1173 i_color *oval - array of I<num> colors
1175 xo, yo, oval correspond to each other, the point xo[i], yo[i] has a
1176 color something like oval[i], at least closer to that color than other
1181 int dmeasure - how we measure the distance from some point P(x,y) to
1190 euclidean distance: sqrt((x2-x1)**2 + (y2-y1)**2)
1194 square of euclidean distance: ((x2-x1)**2 + (y2-y1)**2)
1198 manhattan distance: max((y2-y1)**2, (x2-x1)**2)
1202 An invalid value causes an error exit (the program is aborted).
1210 i_nearest_color(i_img *im, int num, i_img_dim *xo, i_img_dim *yo, i_color *oval, int dmeasure) {
1217 i_img_dim xsize = im->xsize;
1218 i_img_dim ysize = im->ysize;
1220 size_t ival_bytes, tval_bytes;
1223 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));
1228 i_push_error(0, "no points supplied to nearest_color filter");
1232 if (dmeasure < 0 || dmeasure > i_dmeasure_limit) {
1233 i_push_error(0, "distance measure invalid");
1237 tval_bytes = sizeof(float)*num*im->channels;
1238 if (tval_bytes / num != sizeof(float) * im->channels) {
1239 i_push_error(0, "integer overflow calculating memory allocation");
1242 ival_bytes = sizeof(i_color) * num;
1243 if (ival_bytes / sizeof(i_color) != num) {
1244 i_push_error(0, "integer overflow calculating memory allocation");
1247 tval = mymalloc( tval_bytes ); /* checked 17feb2005 tonyc */
1248 ival = mymalloc( ival_bytes ); /* checked 17feb2005 tonyc */
1249 cmatch = mymalloc( sizeof(int)*num ); /* checked 17feb2005 tonyc */
1251 for(p = 0; p<num; p++) {
1252 for(ch = 0; ch<im->channels; ch++) tval[ p * im->channels + ch] = 0;
1257 for(y = 0; y<ysize; y++) for(x = 0; x<xsize; x++) {
1262 i_img_dim xd = x-xo[0];
1263 i_img_dim yd = y-yo[0];
1266 case 0: /* euclidean */
1267 mindist = sqrt(xd*xd + yd*yd); /* euclidean distance */
1269 case 1: /* euclidean squared */
1270 mindist = xd*xd + yd*yd; /* euclidean distance */
1272 case 2: /* manhatten distance */
1273 mindist = i_max(xd*xd, yd*yd); /* manhattan distance */
1276 im_fatal(aIMCTX, 3,"i_nearest_color: Unknown distance measure\n");
1279 for(p = 1; p<num; p++) {
1283 case 0: /* euclidean */
1284 curdist = sqrt(xd*xd + yd*yd); /* euclidean distance */
1286 case 1: /* euclidean squared */
1287 curdist = xd*xd + yd*yd; /* euclidean distance */
1289 case 2: /* euclidean squared */
1290 curdist = i_max(xd*xd, yd*yd); /* manhattan distance */
1293 im_fatal(aIMCTX, 3,"i_nearest_color: Unknown distance measure\n");
1295 if (curdist < mindist) {
1302 i_gpix(im, x, y, &val);
1303 c2 = 1.0/(float)(cmatch[midx]);
1306 for(ch = 0; ch<im->channels; ch++)
1307 tval[midx*im->channels + ch] =
1308 c1*tval[midx*im->channels + ch] + c2 * (float) val.channel[ch];
1312 for(p = 0; p<num; p++) {
1313 for(ch = 0; ch<im->channels; ch++)
1314 ival[p].channel[ch] = tval[p*im->channels + ch];
1316 /* avoid uninitialized value messages from valgrind */
1317 while (ch < MAXCHANNELS)
1318 ival[p].channel[ch++] = 0;
1321 i_nearest_color_foo(im, num, xo, yo, ival, dmeasure);
1327 =item i_unsharp_mask(im, stddev, scale)
1329 Perform an usharp mask, which is defined as subtracting the blurred
1330 image from double the original.
1336 i_unsharp_mask(i_img *im, double stddev, double scale) {
1343 /* it really shouldn't ever be more than 1.0, but maybe ... */
1348 i_gaussian(copy, stddev);
1349 if (im->bits == i_8_bits) {
1350 i_color *blur = mymalloc(im->xsize * sizeof(i_color)); /* checked 17feb2005 tonyc */
1351 i_color *out = mymalloc(im->xsize * sizeof(i_color)); /* checked 17feb2005 tonyc */
1353 for (y = 0; y < im->ysize; ++y) {
1354 i_glin(copy, 0, copy->xsize, y, blur);
1355 i_glin(im, 0, im->xsize, y, out);
1356 for (x = 0; x < im->xsize; ++x) {
1357 for (ch = 0; ch < im->channels; ++ch) {
1358 /*int temp = out[x].channel[ch] +
1359 scale * (out[x].channel[ch] - blur[x].channel[ch]);*/
1360 int temp = out[x].channel[ch] * 2 - blur[x].channel[ch];
1363 else if (temp > 255)
1365 out[x].channel[ch] = temp;
1368 i_plin(im, 0, im->xsize, y, out);
1375 i_fcolor *blur = mymalloc(im->xsize * sizeof(i_fcolor)); /* checked 17feb2005 tonyc */
1376 i_fcolor *out = mymalloc(im->xsize * sizeof(i_fcolor)); /* checked 17feb2005 tonyc */
1378 for (y = 0; y < im->ysize; ++y) {
1379 i_glinf(copy, 0, copy->xsize, y, blur);
1380 i_glinf(im, 0, im->xsize, y, out);
1381 for (x = 0; x < im->xsize; ++x) {
1382 for (ch = 0; ch < im->channels; ++ch) {
1383 double temp = out[x].channel[ch] +
1384 scale * (out[x].channel[ch] - blur[x].channel[ch]);
1387 else if (temp > 1.0)
1389 out[x].channel[ch] = temp;
1392 i_plinf(im, 0, im->xsize, y, out);
1398 i_img_destroy(copy);
1402 =item i_diff_image(im1, im2, mindist)
1404 Creates a new image that is transparent, except where the pixel in im2
1405 is different from im1, where it is the pixel from im2.
1407 The samples must differ by at least mindiff to be considered different.
1413 i_diff_image(i_img *im1, i_img *im2, double mindist) {
1415 int outchans, diffchans;
1416 i_img_dim xsize, ysize;
1420 if (im1->channels != im2->channels) {
1421 i_push_error(0, "different number of channels");
1425 outchans = diffchans = im1->channels;
1426 if (outchans == 1 || outchans == 3)
1429 xsize = i_min(im1->xsize, im2->xsize);
1430 ysize = i_min(im1->ysize, im2->ysize);
1432 out = i_sametype_chans(im1, xsize, ysize, outchans);
1434 if (im1->bits == i_8_bits && im2->bits == i_8_bits) {
1435 i_color *line1 = mymalloc(xsize * sizeof(*line1)); /* checked 17feb2005 tonyc */
1436 i_color *line2 = mymalloc(xsize * sizeof(*line1)); /* checked 17feb2005 tonyc */
1440 int imindist = (int)mindist;
1442 for (ch = 0; ch < MAXCHANNELS; ++ch)
1443 empty.channel[ch] = 0;
1445 for (y = 0; y < ysize; ++y) {
1446 i_glin(im1, 0, xsize, y, line1);
1447 i_glin(im2, 0, xsize, y, line2);
1448 if (outchans != diffchans) {
1449 /* give the output an alpha channel since it doesn't have one */
1450 for (x = 0; x < xsize; ++x)
1451 line2[x].channel[diffchans] = 255;
1453 for (x = 0; x < xsize; ++x) {
1455 for (ch = 0; ch < diffchans; ++ch) {
1456 if (line1[x].channel[ch] != line2[x].channel[ch]
1457 && abs(line1[x].channel[ch] - line2[x].channel[ch]) > imindist) {
1465 i_plin(out, 0, xsize, y, line2);
1471 i_fcolor *line1 = mymalloc(xsize * sizeof(*line1)); /* checked 17feb2005 tonyc */
1472 i_fcolor *line2 = mymalloc(xsize * sizeof(*line2)); /* checked 17feb2005 tonyc */
1476 double dist = mindist / 255.0;
1478 for (ch = 0; ch < MAXCHANNELS; ++ch)
1479 empty.channel[ch] = 0;
1481 for (y = 0; y < ysize; ++y) {
1482 i_glinf(im1, 0, xsize, y, line1);
1483 i_glinf(im2, 0, xsize, y, line2);
1484 if (outchans != diffchans) {
1485 /* give the output an alpha channel since it doesn't have one */
1486 for (x = 0; x < xsize; ++x)
1487 line2[x].channel[diffchans] = 1.0;
1489 for (x = 0; x < xsize; ++x) {
1491 for (ch = 0; ch < diffchans; ++ch) {
1492 if (line1[x].channel[ch] != line2[x].channel[ch]
1493 && fabs(line1[x].channel[ch] - line2[x].channel[ch]) > dist) {
1501 i_plinf(out, 0, xsize, y, line2);
1511 static double linear_fount_f(double x, double y, struct fount_state *state);
1512 static double bilinear_fount_f(double x, double y, struct fount_state *state);
1513 static double radial_fount_f(double x, double y, struct fount_state *state);
1514 static double square_fount_f(double x, double y, struct fount_state *state);
1515 static double revolution_fount_f(double x, double y,
1516 struct fount_state *state);
1517 static double conical_fount_f(double x, double y, struct fount_state *state);
1519 typedef double (*fount_func)(double, double, struct fount_state *);
1520 static fount_func fount_funcs[] =
1530 static double linear_interp(double pos, i_fountain_seg *seg);
1531 static double sine_interp(double pos, i_fountain_seg *seg);
1532 static double sphereup_interp(double pos, i_fountain_seg *seg);
1533 static double spheredown_interp(double pos, i_fountain_seg *seg);
1534 typedef double (*fount_interp)(double pos, i_fountain_seg *seg);
1535 static fount_interp fount_interps[] =
1544 static void direct_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg);
1545 static void hue_up_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg);
1546 static void hue_down_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg);
1547 typedef void (*fount_cinterp)(i_fcolor *out, double pos, i_fountain_seg *seg);
1548 static fount_cinterp fount_cinterps[] =
1555 typedef double (*fount_repeat)(double v);
1556 static double fount_r_none(double v);
1557 static double fount_r_sawtooth(double v);
1558 static double fount_r_triangle(double v);
1559 static double fount_r_saw_both(double v);
1560 static double fount_r_tri_both(double v);
1561 static fount_repeat fount_repeats[] =
1570 static int simple_ssample(i_fcolor *out, double x, double y,
1571 struct fount_state *state);
1572 static int random_ssample(i_fcolor *out, double x, double y,
1573 struct fount_state *state);
1574 static int circle_ssample(i_fcolor *out, double x, double y,
1575 struct fount_state *state);
1576 typedef int (*fount_ssample)(i_fcolor *out, double x, double y,
1577 struct fount_state *state);
1578 static fount_ssample fount_ssamples[] =
1587 fount_getat(i_fcolor *out, double x, double y, struct fount_state *state);
1590 Keep state information used by each type of fountain fill
1592 struct fount_state {
1593 /* precalculated for the equation of the line perpendicular to the line AB */
1604 fount_repeat rpfunc;
1605 fount_ssample ssfunc;
1607 i_fountain_seg *segs;
1612 fount_init_state(struct fount_state *state, double xa, double ya,
1613 double xb, double yb, i_fountain_type type,
1614 i_fountain_repeat repeat, int combine, int super_sample,
1615 double ssample_param, int count, i_fountain_seg *segs);
1618 fount_finish_state(struct fount_state *state);
1620 #define EPSILON (1e-6)
1623 =item i_fountain(im, xa, ya, xb, yb, type, repeat, combine, super_sample, ssample_param, count, segs)
1625 Draws a fountain fill using A(xa, ya) and B(xb, yb) as reference points.
1627 I<type> controls how the reference points are used:
1633 linear, where A is 0 and B is 1.
1637 linear in both directions from A.
1641 circular, where A is the centre of the fill, and B is a point
1644 =item i_ft_radial_square
1646 where A is the centre of the fill and B is the centre of
1647 one side of the square.
1649 =item i_ft_revolution
1651 where A is the centre of the fill and B defines the 0/1.0
1656 similar to i_ft_revolution, except that the revolution goes in both
1661 I<repeat> can be one of:
1667 values < 0 are treated as zero, values > 1 are treated as 1.
1671 negative values are treated as 0, positive values are modulo 1.0
1675 negative values are treated as zero, if (int)value is odd then the value is treated as 1-(value
1676 mod 1.0), otherwise the same as for sawtooth.
1680 like i_fr_sawtooth, except that the sawtooth pattern repeats into
1685 Like i_fr_triangle, except that negative values are handled as their
1690 If combine is non-zero then non-opaque values are combined with the
1693 I<super_sample> controls super sampling, if any. At some point I'll
1694 probably add a adaptive super-sampler. Current possible values are:
1700 No super-sampling is done.
1704 A square grid of points withing the pixel are sampled.
1708 Random points within the pixel are sampled.
1712 Points on the radius of a circle are sampled. This produces fairly
1713 good results, but is fairly slow since sin() and cos() are evaluated
1718 I<ssample_param> is intended to be roughly the number of points
1719 sampled within the pixel.
1721 I<count> and I<segs> define the segments of the fill.
1728 i_fountain(i_img *im, double xa, double ya, double xb, double yb,
1729 i_fountain_type type, i_fountain_repeat repeat,
1730 int combine, int super_sample, double ssample_param,
1731 int count, i_fountain_seg *segs) {
1732 struct fount_state state;
1734 i_fcolor *line = NULL;
1735 i_fcolor *work = NULL;
1737 i_fill_combine_f combine_func = NULL;
1738 i_fill_combinef_f combinef_func = NULL;
1743 /* i_fountain() allocates floating colors even for 8-bit images,
1744 so we need to do this check */
1745 line_bytes = sizeof(i_fcolor) * im->xsize;
1746 if (line_bytes / sizeof(i_fcolor) != im->xsize) {
1747 i_push_error(0, "integer overflow calculating memory allocation");
1751 line = mymalloc(line_bytes); /* checked 17feb2005 tonyc */
1753 i_get_combine(combine, &combine_func, &combinef_func);
1755 work = mymalloc(line_bytes); /* checked 17feb2005 tonyc */
1757 fount_init_state(&state, xa, ya, xb, yb, type, repeat, combine,
1758 super_sample, ssample_param, count, segs);
1760 for (y = 0; y < im->ysize; ++y) {
1761 i_glinf(im, 0, im->xsize, y, line);
1762 for (x = 0; x < im->xsize; ++x) {
1765 if (super_sample == i_fts_none)
1766 got_one = fount_getat(&c, x, y, &state);
1768 got_one = state.ssfunc(&c, x, y, &state);
1777 combinef_func(line, work, im->channels, im->xsize);
1778 i_plinf(im, 0, im->xsize, y, line);
1780 fount_finish_state(&state);
1781 if (work) myfree(work);
1789 struct fount_state state;
1790 } i_fill_fountain_t;
1793 fill_fountf(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width, int channels,
1796 fount_fill_destroy(i_fill_t *fill);
1798 static i_fill_fountain_t
1810 =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>)
1813 =synopsis fill = i_new_fill_fount(0, 0, 100, 100, i_ft_linear, i_ft_linear,
1814 =synopsis i_fr_triangle, 0, i_fts_grid, 9, 1, segs);
1817 Creates a new general fill which fills with a fountain fill.
1823 i_new_fill_fount(double xa, double ya, double xb, double yb,
1824 i_fountain_type type, i_fountain_repeat repeat,
1825 int combine, int super_sample, double ssample_param,
1826 int count, i_fountain_seg *segs) {
1827 i_fill_fountain_t *fill = mymalloc(sizeof(i_fill_fountain_t));
1829 *fill = fount_fill_proto;
1831 i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
1833 fill->base.combine = NULL;
1834 fill->base.combinef = NULL;
1836 fount_init_state(&fill->state, xa, ya, xb, yb, type, repeat, combine,
1837 super_sample, ssample_param, count, segs);
1845 =head1 INTERNAL FUNCTIONS
1849 =item fount_init_state(...)
1851 Used by both the fountain fill filter and the fountain fill.
1857 fount_init_state(struct fount_state *state, double xa, double ya,
1858 double xb, double yb, i_fountain_type type,
1859 i_fountain_repeat repeat, int combine, int super_sample,
1860 double ssample_param, int count, i_fountain_seg *segs) {
1863 i_fountain_seg *my_segs = mymalloc(sizeof(i_fountain_seg) * count); /* checked 2jul06 - duplicating original */
1864 /*int have_alpha = im->channels == 2 || im->channels == 4;*/
1866 memset(state, 0, sizeof(*state));
1867 /* we keep a local copy that we can adjust for speed */
1868 for (i = 0; i < count; ++i) {
1869 i_fountain_seg *seg = my_segs + i;
1872 if (seg->type < 0 || seg->type >= i_fst_end)
1873 seg->type = i_fst_linear;
1874 if (seg->color < 0 || seg->color >= i_fc_end)
1875 seg->color = i_fc_direct;
1876 if (seg->color == i_fc_hue_up || seg->color == i_fc_hue_down) {
1877 /* so we don't have to translate to HSV on each request, do it here */
1878 for (j = 0; j < 2; ++j) {
1879 i_rgb_to_hsvf(seg->c+j);
1881 if (seg->color == i_fc_hue_up) {
1882 if (seg->c[1].channel[0] <= seg->c[0].channel[0])
1883 seg->c[1].channel[0] += 1.0;
1886 if (seg->c[0].channel[0] <= seg->c[0].channel[1])
1887 seg->c[0].channel[0] += 1.0;
1890 /*printf("start %g mid %g end %g c0(%g,%g,%g,%g) c1(%g,%g,%g,%g) type %d color %d\n",
1891 seg->start, seg->middle, seg->end, seg->c[0].channel[0],
1892 seg->c[0].channel[1], seg->c[0].channel[2], seg->c[0].channel[3],
1893 seg->c[1].channel[0], seg->c[1].channel[1], seg->c[1].channel[2],
1894 seg->c[1].channel[3], seg->type, seg->color);*/
1898 /* initialize each engine */
1899 /* these are so common ... */
1900 state->lA = xb - xa;
1901 state->lB = yb - ya;
1902 state->AB = sqrt(state->lA * state->lA + state->lB * state->lB);
1907 type = i_ft_linear; /* make the invalid value valid */
1910 state->lC = ya * ya - ya * yb + xa * xa - xa * xb;
1912 state->mult = 1/linear_fount_f(xb, yb, state);
1916 state->mult = 1.0 / sqrt((double)(xb-xa)*(xb-xa)
1917 + (double)(yb-ya)*(yb-ya));
1920 case i_ft_radial_square:
1921 state->cos = state->lA / state->AB;
1922 state->sin = state->lB / state->AB;
1923 state->mult = 1.0 / state->AB;
1926 case i_ft_revolution:
1927 state->theta = atan2(yb-ya, xb-xa);
1928 state->mult = 1.0 / (PI * 2);
1932 state->theta = atan2(yb-ya, xb-xa);
1933 state->mult = 1.0 / PI;
1936 state->ffunc = fount_funcs[type];
1937 if (super_sample < 0
1938 || super_sample >= (int)(sizeof(fount_ssamples)/sizeof(*fount_ssamples))) {
1941 state->ssample_data = NULL;
1942 switch (super_sample) {
1944 ssample_param = floor(0.5 + sqrt(ssample_param));
1945 bytes = ssample_param * ssample_param * sizeof(i_fcolor);
1946 if (bytes / sizeof(i_fcolor) == ssample_param * ssample_param) {
1947 state->ssample_data = mymalloc(sizeof(i_fcolor) * ssample_param * ssample_param); /* checked 1jul06 tonyc */
1950 super_sample = i_fts_none;
1956 ssample_param = floor(0.5+ssample_param);
1957 bytes = sizeof(i_fcolor) * ssample_param;
1958 if (bytes / sizeof(i_fcolor) == ssample_param) {
1959 state->ssample_data = mymalloc(sizeof(i_fcolor) * ssample_param);
1962 super_sample = i_fts_none;
1966 state->parm = ssample_param;
1967 state->ssfunc = fount_ssamples[super_sample];
1968 if (repeat < 0 || repeat >= (sizeof(fount_repeats)/sizeof(*fount_repeats)))
1970 state->rpfunc = fount_repeats[repeat];
1971 state->segs = my_segs;
1972 state->count = count;
1976 fount_finish_state(struct fount_state *state) {
1977 if (state->ssample_data)
1978 myfree(state->ssample_data);
1979 myfree(state->segs);
1984 =item fount_getat(out, x, y, ffunc, rpfunc, state, segs, count)
1986 Evaluates the fountain fill at the given point.
1988 This is called by both the non-super-sampling and super-sampling code.
1990 You might think that it would make sense to sample the fill parameter
1991 instead, and combine those, but this breaks badly.
1997 fount_getat(i_fcolor *out, double x, double y, struct fount_state *state) {
1998 double v = (state->rpfunc)((state->ffunc)(x, y, state));
2002 while (i < state->count
2003 && (v < state->segs[i].start || v > state->segs[i].end)) {
2006 if (i < state->count) {
2007 v = (fount_interps[state->segs[i].type])(v, state->segs+i);
2008 (fount_cinterps[state->segs[i].color])(out, v, state->segs+i);
2016 =item linear_fount_f(x, y, state)
2018 Calculate the fill parameter for a linear fountain fill.
2020 Uses the point to line distance function, with some precalculation
2021 done in i_fountain().
2026 linear_fount_f(double x, double y, struct fount_state *state) {
2027 return (state->lA * x + state->lB * y + state->lC) / state->AB * state->mult;
2031 =item bilinear_fount_f(x, y, state)
2033 Calculate the fill parameter for a bi-linear fountain fill.
2038 bilinear_fount_f(double x, double y, struct fount_state *state) {
2039 return fabs((state->lA * x + state->lB * y + state->lC) / state->AB * state->mult);
2043 =item radial_fount_f(x, y, state)
2045 Calculate the fill parameter for a radial fountain fill.
2047 Simply uses the distance function.
2052 radial_fount_f(double x, double y, struct fount_state *state) {
2053 return sqrt((double)(state->xa-x)*(state->xa-x)
2054 + (double)(state->ya-y)*(state->ya-y)) * state->mult;
2058 =item square_fount_f(x, y, state)
2060 Calculate the fill parameter for a square fountain fill.
2062 Works by rotating the reference co-ordinate around the centre of the
2068 square_fount_f(double x, double y, struct fount_state *state) {
2069 i_img_dim xc, yc; /* centred on A */
2070 double xt, yt; /* rotated by theta */
2073 xt = fabs(xc * state->cos + yc * state->sin);
2074 yt = fabs(-xc * state->sin + yc * state->cos);
2075 return (xt > yt ? xt : yt) * state->mult;
2079 =item revolution_fount_f(x, y, state)
2081 Calculates the fill parameter for the revolution fountain fill.
2086 revolution_fount_f(double x, double y, struct fount_state *state) {
2087 double angle = atan2(y - state->ya, x - state->xa);
2089 angle -= state->theta;
2091 angle = fmod(angle+ PI * 4, PI*2);
2094 return angle * state->mult;
2098 =item conical_fount_f(x, y, state)
2100 Calculates the fill parameter for the conical fountain fill.
2105 conical_fount_f(double x, double y, struct fount_state *state) {
2106 double angle = atan2(y - state->ya, x - state->xa);
2108 angle -= state->theta;
2111 else if (angle > PI)
2114 return fabs(angle) * state->mult;
2118 =item linear_interp(pos, seg)
2120 Calculates linear interpolation on the fill parameter. Breaks the
2121 segment into 2 regions based in the I<middle> value.
2126 linear_interp(double pos, i_fountain_seg *seg) {
2127 if (pos < seg->middle) {
2128 double len = seg->middle - seg->start;
2132 return (pos - seg->start) / len / 2;
2135 double len = seg->end - seg->middle;
2139 return 0.5 + (pos - seg->middle) / len / 2;
2144 =item sine_interp(pos, seg)
2146 Calculates sine function interpolation on the fill parameter.
2151 sine_interp(double pos, i_fountain_seg *seg) {
2152 /* I wonder if there's a simple way to smooth the transition for this */
2153 double work = linear_interp(pos, seg);
2155 return (1-cos(work * PI))/2;
2159 =item sphereup_interp(pos, seg)
2161 Calculates spherical interpolation on the fill parameter, with the cusp
2167 sphereup_interp(double pos, i_fountain_seg *seg) {
2168 double work = linear_interp(pos, seg);
2170 return sqrt(1.0 - (1-work) * (1-work));
2174 =item spheredown_interp(pos, seg)
2176 Calculates spherical interpolation on the fill parameter, with the cusp
2182 spheredown_interp(double pos, i_fountain_seg *seg) {
2183 double work = linear_interp(pos, seg);
2185 return 1-sqrt(1.0 - work * work);
2189 =item direct_cinterp(out, pos, seg)
2191 Calculates the fountain color based on direct scaling of the channels
2192 of the color channels.
2197 direct_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg) {
2199 for (ch = 0; ch < MAXCHANNELS; ++ch) {
2200 out->channel[ch] = seg->c[0].channel[ch] * (1 - pos)
2201 + seg->c[1].channel[ch] * pos;
2206 =item hue_up_cinterp(put, pos, seg)
2208 Calculates the fountain color based on scaling a HSV value. The hue
2209 increases as the fill parameter increases.
2214 hue_up_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg) {
2216 for (ch = 0; ch < MAXCHANNELS; ++ch) {
2217 out->channel[ch] = seg->c[0].channel[ch] * (1 - pos)
2218 + seg->c[1].channel[ch] * pos;
2224 =item hue_down_cinterp(put, pos, seg)
2226 Calculates the fountain color based on scaling a HSV value. The hue
2227 decreases as the fill parameter increases.
2232 hue_down_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg) {
2234 for (ch = 0; ch < MAXCHANNELS; ++ch) {
2235 out->channel[ch] = seg->c[0].channel[ch] * (1 - pos)
2236 + seg->c[1].channel[ch] * pos;
2242 =item simple_ssample(out, parm, x, y, state, ffunc, rpfunc, segs, count)
2244 Simple grid-based super-sampling.
2249 simple_ssample(i_fcolor *out, double x, double y, struct fount_state *state) {
2250 i_fcolor *work = state->ssample_data;
2252 int grid = state->parm;
2253 double base = -0.5 + 0.5 / grid;
2254 double step = 1.0 / grid;
2258 for (dx = 0; dx < grid; ++dx) {
2259 for (dy = 0; dy < grid; ++dy) {
2260 if (fount_getat(work+samp_count, x + base + step * dx,
2261 y + base + step * dy, state)) {
2266 for (ch = 0; ch < MAXCHANNELS; ++ch) {
2267 out->channel[ch] = 0;
2268 for (i = 0; i < samp_count; ++i) {
2269 out->channel[ch] += work[i].channel[ch];
2271 /* we divide by 4 rather than samp_count since if there's only one valid
2272 sample it should be mostly transparent */
2273 out->channel[ch] /= grid * grid;
2279 =item random_ssample(out, parm, x, y, state, ffunc, rpfunc, segs, count)
2281 Random super-sampling.
2286 random_ssample(i_fcolor *out, double x, double y,
2287 struct fount_state *state) {
2288 i_fcolor *work = state->ssample_data;
2290 int maxsamples = state->parm;
2291 double rand_scale = 1.0 / RAND_MAX;
2293 for (i = 0; i < maxsamples; ++i) {
2294 if (fount_getat(work+samp_count, x - 0.5 + rand() * rand_scale,
2295 y - 0.5 + rand() * rand_scale, state)) {
2299 for (ch = 0; ch < MAXCHANNELS; ++ch) {
2300 out->channel[ch] = 0;
2301 for (i = 0; i < samp_count; ++i) {
2302 out->channel[ch] += work[i].channel[ch];
2304 /* we divide by maxsamples rather than samp_count since if there's
2305 only one valid sample it should be mostly transparent */
2306 out->channel[ch] /= maxsamples;
2312 =item circle_ssample(out, parm, x, y, state, ffunc, rpfunc, segs, count)
2314 Super-sampling around the circumference of a circle.
2316 I considered saving the sin()/cos() values and transforming step-size
2317 around the circle, but that's inaccurate, though it may not matter
2323 circle_ssample(i_fcolor *out, double x, double y,
2324 struct fount_state *state) {
2325 i_fcolor *work = state->ssample_data;
2327 int maxsamples = state->parm;
2328 double angle = 2 * PI / maxsamples;
2329 double radius = 0.3; /* semi-random */
2331 for (i = 0; i < maxsamples; ++i) {
2332 if (fount_getat(work+samp_count, x + radius * cos(angle * i),
2333 y + radius * sin(angle * i), state)) {
2337 for (ch = 0; ch < MAXCHANNELS; ++ch) {
2338 out->channel[ch] = 0;
2339 for (i = 0; i < samp_count; ++i) {
2340 out->channel[ch] += work[i].channel[ch];
2342 /* we divide by maxsamples rather than samp_count since if there's
2343 only one valid sample it should be mostly transparent */
2344 out->channel[ch] /= maxsamples;
2350 =item fount_r_none(v)
2352 Implements no repeats. Simply clamps the fill value.
2357 fount_r_none(double v) {
2358 return v < 0 ? 0 : v > 1 ? 1 : v;
2362 =item fount_r_sawtooth(v)
2364 Implements sawtooth repeats. Clamps negative values and uses fmod()
2370 fount_r_sawtooth(double v) {
2371 return v < 0 ? 0 : fmod(v, 1.0);
2375 =item fount_r_triangle(v)
2377 Implements triangle repeats. Clamps negative values, uses fmod to get
2378 a range 0 through 2 and then adjusts values > 1.
2383 fount_r_triangle(double v) {
2388 return v > 1.0 ? 2.0 - v : v;
2393 =item fount_r_saw_both(v)
2395 Implements sawtooth repeats in the both postive and negative directions.
2397 Adjusts the value to be postive and then just uses fmod().
2402 fount_r_saw_both(double v) {
2405 return fmod(v, 1.0);
2409 =item fount_r_tri_both(v)
2411 Implements triangle repeats in the both postive and negative directions.
2413 Uses fmod on the absolute value, and then adjusts values > 1.
2418 fount_r_tri_both(double v) {
2419 v = fmod(fabs(v), 2.0);
2420 return v > 1.0 ? 2.0 - v : v;
2424 =item fill_fountf(fill, x, y, width, channels, data)
2426 The fill function for fountain fills.
2431 fill_fountf(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
2432 int channels, i_fcolor *data) {
2433 i_fill_fountain_t *f = (i_fill_fountain_t *)fill;
2439 if (f->state.ssfunc)
2440 got_one = f->state.ssfunc(&c, x, y, &f->state);
2442 got_one = fount_getat(&c, x, y, &f->state);
2452 =item fount_fill_destroy(fill)
2457 fount_fill_destroy(i_fill_t *fill) {
2458 i_fill_fountain_t *f = (i_fill_fountain_t *)fill;
2459 fount_finish_state(&f->state);
2467 Arnar M. Hrafnkelsson <addi@umich.edu>
2469 Tony Cook <tony@develop-help.com> (i_fountain())