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++) {
700 for (i = 0; i < 256; ++i) {
701 if (lower_accum < sum_lum * lsat)
703 lower_accum += hist[i];
708 for(i = 255; i >= 0; i--) {
709 if (upper_accum < sum_lum * usat)
711 upper_accum += hist[i];
715 IM_SAMPLE_T *srow = mymalloc(color_samples * sizeof(IM_SAMPLE_T));
717 IM_WORK_T low = min_lum;
718 i_sample_t lookup[256];
720 IM_WORK_T low = min_lum / 255.0 * IM_SAMPLE_MAX;
722 double scale = 255.0 / (max_lum - min_lum);
725 for (i = 0; i < 256; ++i) {
726 IM_WORK_T tmp = (i - low) * scale;
727 lookup[i] = IM_LIMIT(tmp);
731 for(y = 0; y < im->ysize; y++) {
732 IM_GSAMP(im, 0, im->xsize, y, srow, NULL, color_channels);
733 for(i = 0; i < color_samples; ++i) {
735 srow[i] = lookup[srow[i]];
737 IM_WORK_T tmp = (srow[i] - low) * scale;
738 srow[i] = IM_LIMIT(tmp);
741 IM_PSAMP(im, 0, im->xsize, y, srow, NULL, color_channels);
749 =item i_autolevels(im, lsat, usat, skew)
751 Scales and translates each color such that it fills the range completely.
752 Skew is not implemented yet - purpose is to control the color skew that can
753 occur when changing the contrast.
756 lsat - fraction of pixels that will be truncated at the lower end of the spectrum
757 usat - fraction of pixels that will be truncated at the higher end of the spectrum
760 Note: this code calculates levels and adjusts each channel separately,
761 which will typically cause a color shift.
767 i_autolevels(i_img *im, float lsat, float usat, float skew) {
769 i_img_dim i, x, y, rhist[256], ghist[256], bhist[256];
770 i_img_dim rsum, rmin, rmax;
771 i_img_dim gsum, gmin, gmax;
772 i_img_dim bsum, bmin, bmax;
773 i_img_dim rcl, rcu, gcl, gcu, bcl, bcu;
776 im_log((aIMCTX, 1,"i_autolevels(im %p, lsat %f,usat %f,skew %f)\n", im, lsat,usat,skew));
779 for(i=0;i<256;i++) rhist[i]=ghist[i]=bhist[i] = 0;
780 /* create histogram for each channel */
781 for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
782 i_gpix(im, x, y, &val);
783 rhist[val.channel[0]]++;
784 ghist[val.channel[1]]++;
785 bhist[val.channel[2]]++;
794 rmin = gmin = bmin = 0;
795 rmax = gmax = bmax = 255;
797 rcu = rcl = gcu = gcl = bcu = bcl = 0;
799 for(i=0; i<256; i++) {
800 rcl += rhist[i]; if ( (rcl<rsum*lsat) ) rmin=i;
801 rcu += rhist[255-i]; if ( (rcu<rsum*usat) ) rmax=255-i;
803 gcl += ghist[i]; if ( (gcl<gsum*lsat) ) gmin=i;
804 gcu += ghist[255-i]; if ( (gcu<gsum*usat) ) gmax=255-i;
806 bcl += bhist[i]; if ( (bcl<bsum*lsat) ) bmin=i;
807 bcu += bhist[255-i]; if ( (bcu<bsum*usat) ) bmax=255-i;
810 for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
811 i_gpix(im, x, y, &val);
812 val.channel[0]=saturate((val.channel[0]-rmin)*255/(rmax-rmin));
813 val.channel[1]=saturate((val.channel[1]-gmin)*255/(gmax-gmin));
814 val.channel[2]=saturate((val.channel[2]-bmin)*255/(bmax-bmin));
815 i_ppix(im, x, y, &val);
822 Pseudo noise utility function used to generate perlin noise. (internal)
832 Noise(i_img_dim x, i_img_dim y) {
833 i_img_dim n = x + y * 57;
835 return ( 1.0 - ( (n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff) / 1073741824.0);
839 =item SmoothedNoise1(x,y)
841 Pseudo noise utility function used to generate perlin noise. (internal)
851 SmoothedNoise1(double x, double y) {
852 double corners = ( Noise(x-1, y-1)+Noise(x+1, y-1)+Noise(x-1, y+1)+Noise(x+1, y+1) ) / 16;
853 double sides = ( Noise(x-1, y) +Noise(x+1, y) +Noise(x, y-1) +Noise(x, y+1) ) / 8;
854 double center = Noise(x, y) / 4;
855 return corners + sides + center;
860 =item G_Interpolate(a, b, x)
862 Utility function used to generate perlin noise. (internal)
869 C_Interpolate(double a, double b, double x) {
870 /* float ft = x * 3.1415927; */
872 double f = (1 - cos(ft)) * .5;
873 return a*(1-f) + b*f;
878 =item InterpolatedNoise(x, y)
880 Utility function used to generate perlin noise. (internal)
887 InterpolatedNoise(double x, double y) {
889 i_img_dim integer_X = x;
890 double fractional_X = x - integer_X;
891 i_img_dim integer_Y = y;
892 double fractional_Y = y - integer_Y;
894 double v1 = SmoothedNoise1(integer_X, integer_Y);
895 double v2 = SmoothedNoise1(integer_X + 1, integer_Y);
896 double v3 = SmoothedNoise1(integer_X, integer_Y + 1);
897 double v4 = SmoothedNoise1(integer_X + 1, integer_Y + 1);
899 double i1 = C_Interpolate(v1 , v2 , fractional_X);
900 double i2 = C_Interpolate(v3 , v4 , fractional_X);
902 return C_Interpolate(i1 , i2 , fractional_Y);
908 =item PerlinNoise_2D(x, y)
910 Utility function used to generate perlin noise. (internal)
917 PerlinNoise_2D(float x, float y) {
921 int Number_Of_Octaves=6;
922 int n = Number_Of_Octaves - 1;
927 total = total + InterpolatedNoise(x * frequency, y * frequency) * amplitude;
935 =item i_radnoise(im, xo, yo, rscale, ascale)
937 Perlin-like radial noise.
940 xo - x coordinate of center
941 yo - y coordinate of center
942 rscale - radial scale
943 ascale - angular scale
949 i_radnoise(i_img *im, i_img_dim xo, i_img_dim yo, double rscale, double ascale) {
957 for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
958 xc = (double)x-xo+0.5;
959 yc = (double)y-yo+0.5;
960 r = rscale*sqrt(xc*xc+yc*yc)+1.2;
961 a = (PI+atan2(yc,xc))*ascale;
962 v = saturate(128+100*(PerlinNoise_2D(a,r)));
963 /* v=saturate(120+12*PerlinNoise_2D(xo+(float)x/scale,yo+(float)y/scale)); Good soft marble */
964 for(ch=0; ch<im->channels; ch++) val.channel[ch]=v;
965 i_ppix(im, x, y, &val);
971 =item i_turbnoise(im, xo, yo, scale)
973 Perlin-like 2d noise noise.
976 xo - x coordinate translation
977 yo - y coordinate translation
978 scale - scale of noise
984 i_turbnoise(i_img *im, double xo, double yo, double scale) {
990 for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
991 /* v=saturate(125*(1.0+PerlinNoise_2D(xo+(float)x/scale,yo+(float)y/scale))); */
992 v = saturate(120*(1.0+sin(xo+(double)x/scale+PerlinNoise_2D(xo+(double)x/scale,yo+(float)y/scale))));
993 for(ch=0; ch<im->channels; ch++) val.channel[ch] = v;
994 i_ppix(im, x, y, &val);
1001 =item i_gradgen(im, num, xo, yo, ival, dmeasure)
1003 Gradient generating function.
1006 num - number of points given
1007 xo - array of x coordinates
1008 yo - array of y coordinates
1009 ival - array of i_color objects
1010 dmeasure - distance measure to be used.
1012 1 = Euclidean squared
1013 2 = Manhattan distance
1020 i_gradgen(i_img *im, int num, i_img_dim *xo, i_img_dim *yo, i_color *ival, int dmeasure) {
1025 int channels = im->channels;
1026 i_img_dim xsize = im->xsize;
1027 i_img_dim ysize = im->ysize;
1033 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));
1035 for(p = 0; p<num; p++) {
1036 im_log((aIMCTX,1,"i_gradgen: p%d(" i_DFp ")\n", p, i_DFcp(xo[p], yo[p])));
1040 /* on the systems I have sizeof(float) == sizeof(int) and thus
1041 this would be same size as the arrays xo and yo point at, but this
1042 may not be true for other systems
1044 since the arrays here are caller controlled, I assume that on
1045 overflow is a programming error rather than an end-user error, so
1046 calling exit() is justified.
1048 bytes = sizeof(double) * num;
1049 if (bytes / num != sizeof(double)) {
1050 fprintf(stderr, "integer overflow calculating memory allocation");
1053 fdist = mymalloc( bytes ); /* checked 14jul05 tonyc */
1055 for(y = 0; y<ysize; y++) for(x = 0; x<xsize; x++) {
1058 for(p = 0; p<num; p++) {
1059 i_img_dim xd = x-xo[p];
1060 i_img_dim yd = y-yo[p];
1062 case 0: /* euclidean */
1063 fdist[p] = sqrt(xd*xd + yd*yd); /* euclidean distance */
1065 case 1: /* euclidean squared */
1066 fdist[p] = xd*xd + yd*yd; /* euclidean distance */
1068 case 2: /* euclidean squared */
1069 fdist[p] = i_max(xd*xd, yd*yd); /* manhattan distance */
1072 im_fatal(aIMCTX, 3,"i_gradgen: Unknown distance measure\n");
1077 csd = 1/((num-1)*cs);
1079 for(p = 0; p<num; p++) fdist[p] = (cs-fdist[p])*csd;
1081 for(ch = 0; ch<channels; ch++) {
1083 for(p = 0; p<num; p++) tres += ival[p].channel[ch] * fdist[p];
1084 val.channel[ch] = saturate(tres);
1086 i_ppix(im, x, y, &val);
1093 i_nearest_color_foo(i_img *im, int num, i_img_dim *xo, i_img_dim *yo, i_color *ival, int dmeasure) {
1097 i_img_dim xsize = im->xsize;
1098 i_img_dim ysize = im->ysize;
1101 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));
1103 for(p = 0; p<num; p++) {
1104 im_log((aIMCTX, 1,"i_gradgen: p%d(" i_DFp ")\n", p, i_DFcp(xo[p], yo[p])));
1108 for(y = 0; y<ysize; y++) for(x = 0; x<xsize; x++) {
1113 i_img_dim xd = x-xo[0];
1114 i_img_dim yd = y-yo[0];
1117 case 0: /* euclidean */
1118 mindist = sqrt(xd*xd + yd*yd); /* euclidean distance */
1120 case 1: /* euclidean squared */
1121 mindist = xd*xd + yd*yd; /* euclidean distance */
1123 case 2: /* euclidean squared */
1124 mindist = i_max(xd*xd, yd*yd); /* manhattan distance */
1127 im_fatal(aIMCTX, 3,"i_nearest_color: Unknown distance measure\n");
1130 for(p = 1; p<num; p++) {
1134 case 0: /* euclidean */
1135 curdist = sqrt(xd*xd + yd*yd); /* euclidean distance */
1137 case 1: /* euclidean squared */
1138 curdist = xd*xd + yd*yd; /* euclidean distance */
1140 case 2: /* euclidean squared */
1141 curdist = i_max(xd*xd, yd*yd); /* manhattan distance */
1144 im_fatal(aIMCTX, 3,"i_nearest_color: Unknown distance measure\n");
1146 if (curdist < mindist) {
1151 i_ppix(im, x, y, &ival[midx]);
1156 =item i_nearest_color(im, num, xo, yo, oval, dmeasure)
1158 This wasn't document - quoth Addi:
1160 An arty type of filter
1162 FIXME: check IRC logs for actual text.
1170 i_img *im - image to render on.
1174 int num - number of points/colors in xo, yo, oval
1178 i_img_dim *xo - array of I<num> x positions
1182 i_img_dim *yo - array of I<num> y positions
1186 i_color *oval - array of I<num> colors
1188 xo, yo, oval correspond to each other, the point xo[i], yo[i] has a
1189 color something like oval[i], at least closer to that color than other
1194 int dmeasure - how we measure the distance from some point P(x,y) to
1203 euclidean distance: sqrt((x2-x1)**2 + (y2-y1)**2)
1207 square of euclidean distance: ((x2-x1)**2 + (y2-y1)**2)
1211 manhattan distance: max((y2-y1)**2, (x2-x1)**2)
1215 An invalid value causes an error exit (the program is aborted).
1223 i_nearest_color(i_img *im, int num, i_img_dim *xo, i_img_dim *yo, i_color *oval, int dmeasure) {
1230 i_img_dim xsize = im->xsize;
1231 i_img_dim ysize = im->ysize;
1233 size_t ival_bytes, tval_bytes;
1236 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));
1241 i_push_error(0, "no points supplied to nearest_color filter");
1245 if (dmeasure < 0 || dmeasure > i_dmeasure_limit) {
1246 i_push_error(0, "distance measure invalid");
1250 tval_bytes = sizeof(float)*num*im->channels;
1251 if (tval_bytes / num != sizeof(float) * im->channels) {
1252 i_push_error(0, "integer overflow calculating memory allocation");
1255 ival_bytes = sizeof(i_color) * num;
1256 if (ival_bytes / sizeof(i_color) != num) {
1257 i_push_error(0, "integer overflow calculating memory allocation");
1260 tval = mymalloc( tval_bytes ); /* checked 17feb2005 tonyc */
1261 ival = mymalloc( ival_bytes ); /* checked 17feb2005 tonyc */
1262 cmatch = mymalloc( sizeof(int)*num ); /* checked 17feb2005 tonyc */
1264 for(p = 0; p<num; p++) {
1265 for(ch = 0; ch<im->channels; ch++) tval[ p * im->channels + ch] = 0;
1270 for(y = 0; y<ysize; y++) for(x = 0; x<xsize; x++) {
1275 i_img_dim xd = x-xo[0];
1276 i_img_dim yd = y-yo[0];
1279 case 0: /* euclidean */
1280 mindist = sqrt(xd*xd + yd*yd); /* euclidean distance */
1282 case 1: /* euclidean squared */
1283 mindist = xd*xd + yd*yd; /* euclidean distance */
1285 case 2: /* manhatten distance */
1286 mindist = i_max(xd*xd, yd*yd); /* manhattan distance */
1289 im_fatal(aIMCTX, 3,"i_nearest_color: Unknown distance measure\n");
1292 for(p = 1; p<num; p++) {
1296 case 0: /* euclidean */
1297 curdist = sqrt(xd*xd + yd*yd); /* euclidean distance */
1299 case 1: /* euclidean squared */
1300 curdist = xd*xd + yd*yd; /* euclidean distance */
1302 case 2: /* euclidean squared */
1303 curdist = i_max(xd*xd, yd*yd); /* manhattan distance */
1306 im_fatal(aIMCTX, 3,"i_nearest_color: Unknown distance measure\n");
1308 if (curdist < mindist) {
1315 i_gpix(im, x, y, &val);
1316 c2 = 1.0/(float)(cmatch[midx]);
1319 for(ch = 0; ch<im->channels; ch++)
1320 tval[midx*im->channels + ch] =
1321 c1*tval[midx*im->channels + ch] + c2 * (float) val.channel[ch];
1325 for(p = 0; p<num; p++) {
1326 for(ch = 0; ch<im->channels; ch++)
1327 ival[p].channel[ch] = tval[p*im->channels + ch];
1329 /* avoid uninitialized value messages from valgrind */
1330 while (ch < MAXCHANNELS)
1331 ival[p].channel[ch++] = 0;
1334 i_nearest_color_foo(im, num, xo, yo, ival, dmeasure);
1340 =item i_unsharp_mask(im, stddev, scale)
1342 Perform an usharp mask, which is defined as subtracting the blurred
1343 image from double the original.
1349 i_unsharp_mask(i_img *im, double stddev, double scale) {
1356 /* it really shouldn't ever be more than 1.0, but maybe ... */
1361 i_gaussian(copy, stddev);
1362 if (im->bits == i_8_bits) {
1363 i_color *blur = mymalloc(im->xsize * sizeof(i_color)); /* checked 17feb2005 tonyc */
1364 i_color *out = mymalloc(im->xsize * sizeof(i_color)); /* checked 17feb2005 tonyc */
1366 for (y = 0; y < im->ysize; ++y) {
1367 i_glin(copy, 0, copy->xsize, y, blur);
1368 i_glin(im, 0, im->xsize, y, out);
1369 for (x = 0; x < im->xsize; ++x) {
1370 for (ch = 0; ch < im->channels; ++ch) {
1371 /*int temp = out[x].channel[ch] +
1372 scale * (out[x].channel[ch] - blur[x].channel[ch]);*/
1373 int temp = out[x].channel[ch] * 2 - blur[x].channel[ch];
1376 else if (temp > 255)
1378 out[x].channel[ch] = temp;
1381 i_plin(im, 0, im->xsize, y, out);
1388 i_fcolor *blur = mymalloc(im->xsize * sizeof(i_fcolor)); /* checked 17feb2005 tonyc */
1389 i_fcolor *out = mymalloc(im->xsize * sizeof(i_fcolor)); /* checked 17feb2005 tonyc */
1391 for (y = 0; y < im->ysize; ++y) {
1392 i_glinf(copy, 0, copy->xsize, y, blur);
1393 i_glinf(im, 0, im->xsize, y, out);
1394 for (x = 0; x < im->xsize; ++x) {
1395 for (ch = 0; ch < im->channels; ++ch) {
1396 double temp = out[x].channel[ch] +
1397 scale * (out[x].channel[ch] - blur[x].channel[ch]);
1400 else if (temp > 1.0)
1402 out[x].channel[ch] = temp;
1405 i_plinf(im, 0, im->xsize, y, out);
1411 i_img_destroy(copy);
1415 =item i_diff_image(im1, im2, mindist)
1417 Creates a new image that is transparent, except where the pixel in im2
1418 is different from im1, where it is the pixel from im2.
1420 The samples must differ by at least mindiff to be considered different.
1426 i_diff_image(i_img *im1, i_img *im2, double mindist) {
1428 int outchans, diffchans;
1429 i_img_dim xsize, ysize;
1433 if (im1->channels != im2->channels) {
1434 i_push_error(0, "different number of channels");
1438 outchans = diffchans = im1->channels;
1439 if (outchans == 1 || outchans == 3)
1442 xsize = i_min(im1->xsize, im2->xsize);
1443 ysize = i_min(im1->ysize, im2->ysize);
1445 out = i_sametype_chans(im1, xsize, ysize, outchans);
1447 if (im1->bits == i_8_bits && im2->bits == i_8_bits) {
1448 i_color *line1 = mymalloc(xsize * sizeof(*line1)); /* checked 17feb2005 tonyc */
1449 i_color *line2 = mymalloc(xsize * sizeof(*line1)); /* checked 17feb2005 tonyc */
1453 int imindist = (int)mindist;
1455 for (ch = 0; ch < MAXCHANNELS; ++ch)
1456 empty.channel[ch] = 0;
1458 for (y = 0; y < ysize; ++y) {
1459 i_glin(im1, 0, xsize, y, line1);
1460 i_glin(im2, 0, xsize, y, line2);
1461 if (outchans != diffchans) {
1462 /* give the output an alpha channel since it doesn't have one */
1463 for (x = 0; x < xsize; ++x)
1464 line2[x].channel[diffchans] = 255;
1466 for (x = 0; x < xsize; ++x) {
1468 for (ch = 0; ch < diffchans; ++ch) {
1469 if (line1[x].channel[ch] != line2[x].channel[ch]
1470 && abs(line1[x].channel[ch] - line2[x].channel[ch]) > imindist) {
1478 i_plin(out, 0, xsize, y, line2);
1484 i_fcolor *line1 = mymalloc(xsize * sizeof(*line1)); /* checked 17feb2005 tonyc */
1485 i_fcolor *line2 = mymalloc(xsize * sizeof(*line2)); /* checked 17feb2005 tonyc */
1489 double dist = mindist / 255.0;
1491 for (ch = 0; ch < MAXCHANNELS; ++ch)
1492 empty.channel[ch] = 0;
1494 for (y = 0; y < ysize; ++y) {
1495 i_glinf(im1, 0, xsize, y, line1);
1496 i_glinf(im2, 0, xsize, y, line2);
1497 if (outchans != diffchans) {
1498 /* give the output an alpha channel since it doesn't have one */
1499 for (x = 0; x < xsize; ++x)
1500 line2[x].channel[diffchans] = 1.0;
1502 for (x = 0; x < xsize; ++x) {
1504 for (ch = 0; ch < diffchans; ++ch) {
1505 if (line1[x].channel[ch] != line2[x].channel[ch]
1506 && fabs(line1[x].channel[ch] - line2[x].channel[ch]) > dist) {
1514 i_plinf(out, 0, xsize, y, line2);
1524 static double linear_fount_f(double x, double y, struct fount_state *state);
1525 static double bilinear_fount_f(double x, double y, struct fount_state *state);
1526 static double radial_fount_f(double x, double y, struct fount_state *state);
1527 static double square_fount_f(double x, double y, struct fount_state *state);
1528 static double revolution_fount_f(double x, double y,
1529 struct fount_state *state);
1530 static double conical_fount_f(double x, double y, struct fount_state *state);
1532 typedef double (*fount_func)(double, double, struct fount_state *);
1533 static fount_func fount_funcs[] =
1543 static double linear_interp(double pos, i_fountain_seg *seg);
1544 static double sine_interp(double pos, i_fountain_seg *seg);
1545 static double sphereup_interp(double pos, i_fountain_seg *seg);
1546 static double spheredown_interp(double pos, i_fountain_seg *seg);
1547 typedef double (*fount_interp)(double pos, i_fountain_seg *seg);
1548 static fount_interp fount_interps[] =
1557 static void direct_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg);
1558 static void hue_up_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg);
1559 static void hue_down_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg);
1560 typedef void (*fount_cinterp)(i_fcolor *out, double pos, i_fountain_seg *seg);
1561 static fount_cinterp fount_cinterps[] =
1568 typedef double (*fount_repeat)(double v);
1569 static double fount_r_none(double v);
1570 static double fount_r_sawtooth(double v);
1571 static double fount_r_triangle(double v);
1572 static double fount_r_saw_both(double v);
1573 static double fount_r_tri_both(double v);
1574 static fount_repeat fount_repeats[] =
1583 static int simple_ssample(i_fcolor *out, double x, double y,
1584 struct fount_state *state);
1585 static int random_ssample(i_fcolor *out, double x, double y,
1586 struct fount_state *state);
1587 static int circle_ssample(i_fcolor *out, double x, double y,
1588 struct fount_state *state);
1589 typedef int (*fount_ssample)(i_fcolor *out, double x, double y,
1590 struct fount_state *state);
1591 static fount_ssample fount_ssamples[] =
1600 fount_getat(i_fcolor *out, double x, double y, struct fount_state *state);
1603 Keep state information used by each type of fountain fill
1605 struct fount_state {
1606 /* precalculated for the equation of the line perpendicular to the line AB */
1617 fount_repeat rpfunc;
1618 fount_ssample ssfunc;
1620 i_fountain_seg *segs;
1625 fount_init_state(struct fount_state *state, double xa, double ya,
1626 double xb, double yb, i_fountain_type type,
1627 i_fountain_repeat repeat, int combine, int super_sample,
1628 double ssample_param, int count, i_fountain_seg *segs);
1631 fount_finish_state(struct fount_state *state);
1633 #define EPSILON (1e-6)
1636 =item i_fountain(im, xa, ya, xb, yb, type, repeat, combine, super_sample, ssample_param, count, segs)
1638 Draws a fountain fill using A(xa, ya) and B(xb, yb) as reference points.
1640 I<type> controls how the reference points are used:
1646 linear, where A is 0 and B is 1.
1650 linear in both directions from A.
1654 circular, where A is the centre of the fill, and B is a point
1657 =item i_ft_radial_square
1659 where A is the centre of the fill and B is the centre of
1660 one side of the square.
1662 =item i_ft_revolution
1664 where A is the centre of the fill and B defines the 0/1.0
1669 similar to i_ft_revolution, except that the revolution goes in both
1674 I<repeat> can be one of:
1680 values < 0 are treated as zero, values > 1 are treated as 1.
1684 negative values are treated as 0, positive values are modulo 1.0
1688 negative values are treated as zero, if (int)value is odd then the value is treated as 1-(value
1689 mod 1.0), otherwise the same as for sawtooth.
1693 like i_fr_sawtooth, except that the sawtooth pattern repeats into
1698 Like i_fr_triangle, except that negative values are handled as their
1703 If combine is non-zero then non-opaque values are combined with the
1706 I<super_sample> controls super sampling, if any. At some point I'll
1707 probably add a adaptive super-sampler. Current possible values are:
1713 No super-sampling is done.
1717 A square grid of points withing the pixel are sampled.
1721 Random points within the pixel are sampled.
1725 Points on the radius of a circle are sampled. This produces fairly
1726 good results, but is fairly slow since sin() and cos() are evaluated
1731 I<ssample_param> is intended to be roughly the number of points
1732 sampled within the pixel.
1734 I<count> and I<segs> define the segments of the fill.
1741 i_fountain(i_img *im, double xa, double ya, double xb, double yb,
1742 i_fountain_type type, i_fountain_repeat repeat,
1743 int combine, int super_sample, double ssample_param,
1744 int count, i_fountain_seg *segs) {
1745 struct fount_state state;
1747 i_fcolor *line = NULL;
1748 i_fcolor *work = NULL;
1750 i_fill_combine_f combine_func = NULL;
1751 i_fill_combinef_f combinef_func = NULL;
1756 /* i_fountain() allocates floating colors even for 8-bit images,
1757 so we need to do this check */
1758 line_bytes = sizeof(i_fcolor) * im->xsize;
1759 if (line_bytes / sizeof(i_fcolor) != im->xsize) {
1760 i_push_error(0, "integer overflow calculating memory allocation");
1764 line = mymalloc(line_bytes); /* checked 17feb2005 tonyc */
1766 i_get_combine(combine, &combine_func, &combinef_func);
1768 work = mymalloc(line_bytes); /* checked 17feb2005 tonyc */
1770 fount_init_state(&state, xa, ya, xb, yb, type, repeat, combine,
1771 super_sample, ssample_param, count, segs);
1773 for (y = 0; y < im->ysize; ++y) {
1774 i_glinf(im, 0, im->xsize, y, line);
1775 for (x = 0; x < im->xsize; ++x) {
1778 if (super_sample == i_fts_none)
1779 got_one = fount_getat(&c, x, y, &state);
1781 got_one = state.ssfunc(&c, x, y, &state);
1790 combinef_func(line, work, im->channels, im->xsize);
1791 i_plinf(im, 0, im->xsize, y, line);
1793 fount_finish_state(&state);
1794 if (work) myfree(work);
1802 struct fount_state state;
1803 } i_fill_fountain_t;
1806 fill_fountf(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width, int channels,
1809 fount_fill_destroy(i_fill_t *fill);
1811 static i_fill_fountain_t
1823 =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>)
1826 =synopsis fill = i_new_fill_fount(0, 0, 100, 100, i_ft_linear, i_ft_linear,
1827 =synopsis i_fr_triangle, 0, i_fts_grid, 9, 1, segs);
1830 Creates a new general fill which fills with a fountain fill.
1836 i_new_fill_fount(double xa, double ya, double xb, double yb,
1837 i_fountain_type type, i_fountain_repeat repeat,
1838 int combine, int super_sample, double ssample_param,
1839 int count, i_fountain_seg *segs) {
1840 i_fill_fountain_t *fill = mymalloc(sizeof(i_fill_fountain_t));
1842 *fill = fount_fill_proto;
1844 i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
1846 fill->base.combine = NULL;
1847 fill->base.combinef = NULL;
1849 fount_init_state(&fill->state, xa, ya, xb, yb, type, repeat, combine,
1850 super_sample, ssample_param, count, segs);
1858 =head1 INTERNAL FUNCTIONS
1862 =item fount_init_state(...)
1864 Used by both the fountain fill filter and the fountain fill.
1870 fount_init_state(struct fount_state *state, double xa, double ya,
1871 double xb, double yb, i_fountain_type type,
1872 i_fountain_repeat repeat, int combine, int super_sample,
1873 double ssample_param, int count, i_fountain_seg *segs) {
1876 i_fountain_seg *my_segs = mymalloc(sizeof(i_fountain_seg) * count); /* checked 2jul06 - duplicating original */
1877 /*int have_alpha = im->channels == 2 || im->channels == 4;*/
1879 memset(state, 0, sizeof(*state));
1880 /* we keep a local copy that we can adjust for speed */
1881 for (i = 0; i < count; ++i) {
1882 i_fountain_seg *seg = my_segs + i;
1885 if (seg->type < 0 || seg->type >= i_fst_end)
1886 seg->type = i_fst_linear;
1887 if (seg->color < 0 || seg->color >= i_fc_end)
1888 seg->color = i_fc_direct;
1889 if (seg->color == i_fc_hue_up || seg->color == i_fc_hue_down) {
1890 /* so we don't have to translate to HSV on each request, do it here */
1891 for (j = 0; j < 2; ++j) {
1892 i_rgb_to_hsvf(seg->c+j);
1894 if (seg->color == i_fc_hue_up) {
1895 if (seg->c[1].channel[0] <= seg->c[0].channel[0])
1896 seg->c[1].channel[0] += 1.0;
1899 if (seg->c[0].channel[0] <= seg->c[0].channel[1])
1900 seg->c[0].channel[0] += 1.0;
1903 /*printf("start %g mid %g end %g c0(%g,%g,%g,%g) c1(%g,%g,%g,%g) type %d color %d\n",
1904 seg->start, seg->middle, seg->end, seg->c[0].channel[0],
1905 seg->c[0].channel[1], seg->c[0].channel[2], seg->c[0].channel[3],
1906 seg->c[1].channel[0], seg->c[1].channel[1], seg->c[1].channel[2],
1907 seg->c[1].channel[3], seg->type, seg->color);*/
1911 /* initialize each engine */
1912 /* these are so common ... */
1913 state->lA = xb - xa;
1914 state->lB = yb - ya;
1915 state->AB = sqrt(state->lA * state->lA + state->lB * state->lB);
1920 type = i_ft_linear; /* make the invalid value valid */
1923 state->lC = ya * ya - ya * yb + xa * xa - xa * xb;
1925 state->mult = 1/linear_fount_f(xb, yb, state);
1929 state->mult = 1.0 / sqrt((double)(xb-xa)*(xb-xa)
1930 + (double)(yb-ya)*(yb-ya));
1933 case i_ft_radial_square:
1934 state->cos = state->lA / state->AB;
1935 state->sin = state->lB / state->AB;
1936 state->mult = 1.0 / state->AB;
1939 case i_ft_revolution:
1940 state->theta = atan2(yb-ya, xb-xa);
1941 state->mult = 1.0 / (PI * 2);
1945 state->theta = atan2(yb-ya, xb-xa);
1946 state->mult = 1.0 / PI;
1949 state->ffunc = fount_funcs[type];
1950 if (super_sample < 0
1951 || super_sample >= (int)(sizeof(fount_ssamples)/sizeof(*fount_ssamples))) {
1954 state->ssample_data = NULL;
1955 switch (super_sample) {
1957 ssample_param = floor(0.5 + sqrt(ssample_param));
1958 bytes = ssample_param * ssample_param * sizeof(i_fcolor);
1959 if (bytes / sizeof(i_fcolor) == ssample_param * ssample_param) {
1960 state->ssample_data = mymalloc(sizeof(i_fcolor) * ssample_param * ssample_param); /* checked 1jul06 tonyc */
1963 super_sample = i_fts_none;
1969 ssample_param = floor(0.5+ssample_param);
1970 bytes = sizeof(i_fcolor) * ssample_param;
1971 if (bytes / sizeof(i_fcolor) == ssample_param) {
1972 state->ssample_data = mymalloc(sizeof(i_fcolor) * ssample_param);
1975 super_sample = i_fts_none;
1979 state->parm = ssample_param;
1980 state->ssfunc = fount_ssamples[super_sample];
1981 if (repeat < 0 || repeat >= (sizeof(fount_repeats)/sizeof(*fount_repeats)))
1983 state->rpfunc = fount_repeats[repeat];
1984 state->segs = my_segs;
1985 state->count = count;
1989 fount_finish_state(struct fount_state *state) {
1990 if (state->ssample_data)
1991 myfree(state->ssample_data);
1992 myfree(state->segs);
1997 =item fount_getat(out, x, y, ffunc, rpfunc, state, segs, count)
1999 Evaluates the fountain fill at the given point.
2001 This is called by both the non-super-sampling and super-sampling code.
2003 You might think that it would make sense to sample the fill parameter
2004 instead, and combine those, but this breaks badly.
2010 fount_getat(i_fcolor *out, double x, double y, struct fount_state *state) {
2011 double v = (state->rpfunc)((state->ffunc)(x, y, state));
2015 while (i < state->count
2016 && (v < state->segs[i].start || v > state->segs[i].end)) {
2019 if (i < state->count) {
2020 v = (fount_interps[state->segs[i].type])(v, state->segs+i);
2021 (fount_cinterps[state->segs[i].color])(out, v, state->segs+i);
2029 =item linear_fount_f(x, y, state)
2031 Calculate the fill parameter for a linear fountain fill.
2033 Uses the point to line distance function, with some precalculation
2034 done in i_fountain().
2039 linear_fount_f(double x, double y, struct fount_state *state) {
2040 return (state->lA * x + state->lB * y + state->lC) / state->AB * state->mult;
2044 =item bilinear_fount_f(x, y, state)
2046 Calculate the fill parameter for a bi-linear fountain fill.
2051 bilinear_fount_f(double x, double y, struct fount_state *state) {
2052 return fabs((state->lA * x + state->lB * y + state->lC) / state->AB * state->mult);
2056 =item radial_fount_f(x, y, state)
2058 Calculate the fill parameter for a radial fountain fill.
2060 Simply uses the distance function.
2065 radial_fount_f(double x, double y, struct fount_state *state) {
2066 return sqrt((double)(state->xa-x)*(state->xa-x)
2067 + (double)(state->ya-y)*(state->ya-y)) * state->mult;
2071 =item square_fount_f(x, y, state)
2073 Calculate the fill parameter for a square fountain fill.
2075 Works by rotating the reference co-ordinate around the centre of the
2081 square_fount_f(double x, double y, struct fount_state *state) {
2082 i_img_dim xc, yc; /* centred on A */
2083 double xt, yt; /* rotated by theta */
2086 xt = fabs(xc * state->cos + yc * state->sin);
2087 yt = fabs(-xc * state->sin + yc * state->cos);
2088 return (xt > yt ? xt : yt) * state->mult;
2092 =item revolution_fount_f(x, y, state)
2094 Calculates the fill parameter for the revolution fountain fill.
2099 revolution_fount_f(double x, double y, struct fount_state *state) {
2100 double angle = atan2(y - state->ya, x - state->xa);
2102 angle -= state->theta;
2104 angle = fmod(angle+ PI * 4, PI*2);
2107 return angle * state->mult;
2111 =item conical_fount_f(x, y, state)
2113 Calculates the fill parameter for the conical fountain fill.
2118 conical_fount_f(double x, double y, struct fount_state *state) {
2119 double angle = atan2(y - state->ya, x - state->xa);
2121 angle -= state->theta;
2124 else if (angle > PI)
2127 return fabs(angle) * state->mult;
2131 =item linear_interp(pos, seg)
2133 Calculates linear interpolation on the fill parameter. Breaks the
2134 segment into 2 regions based in the I<middle> value.
2139 linear_interp(double pos, i_fountain_seg *seg) {
2140 if (pos < seg->middle) {
2141 double len = seg->middle - seg->start;
2145 return (pos - seg->start) / len / 2;
2148 double len = seg->end - seg->middle;
2152 return 0.5 + (pos - seg->middle) / len / 2;
2157 =item sine_interp(pos, seg)
2159 Calculates sine function interpolation on the fill parameter.
2164 sine_interp(double pos, i_fountain_seg *seg) {
2165 /* I wonder if there's a simple way to smooth the transition for this */
2166 double work = linear_interp(pos, seg);
2168 return (1-cos(work * PI))/2;
2172 =item sphereup_interp(pos, seg)
2174 Calculates spherical interpolation on the fill parameter, with the cusp
2180 sphereup_interp(double pos, i_fountain_seg *seg) {
2181 double work = linear_interp(pos, seg);
2183 return sqrt(1.0 - (1-work) * (1-work));
2187 =item spheredown_interp(pos, seg)
2189 Calculates spherical interpolation on the fill parameter, with the cusp
2195 spheredown_interp(double pos, i_fountain_seg *seg) {
2196 double work = linear_interp(pos, seg);
2198 return 1-sqrt(1.0 - work * work);
2202 =item direct_cinterp(out, pos, seg)
2204 Calculates the fountain color based on direct scaling of the channels
2205 of the color channels.
2210 direct_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg) {
2212 for (ch = 0; ch < MAXCHANNELS; ++ch) {
2213 out->channel[ch] = seg->c[0].channel[ch] * (1 - pos)
2214 + seg->c[1].channel[ch] * pos;
2219 =item hue_up_cinterp(put, pos, seg)
2221 Calculates the fountain color based on scaling a HSV value. The hue
2222 increases as the fill parameter increases.
2227 hue_up_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg) {
2229 for (ch = 0; ch < MAXCHANNELS; ++ch) {
2230 out->channel[ch] = seg->c[0].channel[ch] * (1 - pos)
2231 + seg->c[1].channel[ch] * pos;
2237 =item hue_down_cinterp(put, pos, seg)
2239 Calculates the fountain color based on scaling a HSV value. The hue
2240 decreases as the fill parameter increases.
2245 hue_down_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg) {
2247 for (ch = 0; ch < MAXCHANNELS; ++ch) {
2248 out->channel[ch] = seg->c[0].channel[ch] * (1 - pos)
2249 + seg->c[1].channel[ch] * pos;
2255 =item simple_ssample(out, parm, x, y, state, ffunc, rpfunc, segs, count)
2257 Simple grid-based super-sampling.
2262 simple_ssample(i_fcolor *out, double x, double y, struct fount_state *state) {
2263 i_fcolor *work = state->ssample_data;
2265 int grid = state->parm;
2266 double base = -0.5 + 0.5 / grid;
2267 double step = 1.0 / grid;
2271 for (dx = 0; dx < grid; ++dx) {
2272 for (dy = 0; dy < grid; ++dy) {
2273 if (fount_getat(work+samp_count, x + base + step * dx,
2274 y + base + step * dy, state)) {
2279 for (ch = 0; ch < MAXCHANNELS; ++ch) {
2280 out->channel[ch] = 0;
2281 for (i = 0; i < samp_count; ++i) {
2282 out->channel[ch] += work[i].channel[ch];
2284 /* we divide by 4 rather than samp_count since if there's only one valid
2285 sample it should be mostly transparent */
2286 out->channel[ch] /= grid * grid;
2292 =item random_ssample(out, parm, x, y, state, ffunc, rpfunc, segs, count)
2294 Random super-sampling.
2299 random_ssample(i_fcolor *out, double x, double y,
2300 struct fount_state *state) {
2301 i_fcolor *work = state->ssample_data;
2303 int maxsamples = state->parm;
2304 double rand_scale = 1.0 / RAND_MAX;
2306 for (i = 0; i < maxsamples; ++i) {
2307 if (fount_getat(work+samp_count, x - 0.5 + rand() * rand_scale,
2308 y - 0.5 + rand() * rand_scale, state)) {
2312 for (ch = 0; ch < MAXCHANNELS; ++ch) {
2313 out->channel[ch] = 0;
2314 for (i = 0; i < samp_count; ++i) {
2315 out->channel[ch] += work[i].channel[ch];
2317 /* we divide by maxsamples rather than samp_count since if there's
2318 only one valid sample it should be mostly transparent */
2319 out->channel[ch] /= maxsamples;
2325 =item circle_ssample(out, parm, x, y, state, ffunc, rpfunc, segs, count)
2327 Super-sampling around the circumference of a circle.
2329 I considered saving the sin()/cos() values and transforming step-size
2330 around the circle, but that's inaccurate, though it may not matter
2336 circle_ssample(i_fcolor *out, double x, double y,
2337 struct fount_state *state) {
2338 i_fcolor *work = state->ssample_data;
2340 int maxsamples = state->parm;
2341 double angle = 2 * PI / maxsamples;
2342 double radius = 0.3; /* semi-random */
2344 for (i = 0; i < maxsamples; ++i) {
2345 if (fount_getat(work+samp_count, x + radius * cos(angle * i),
2346 y + radius * sin(angle * i), state)) {
2350 for (ch = 0; ch < MAXCHANNELS; ++ch) {
2351 out->channel[ch] = 0;
2352 for (i = 0; i < samp_count; ++i) {
2353 out->channel[ch] += work[i].channel[ch];
2355 /* we divide by maxsamples rather than samp_count since if there's
2356 only one valid sample it should be mostly transparent */
2357 out->channel[ch] /= maxsamples;
2363 =item fount_r_none(v)
2365 Implements no repeats. Simply clamps the fill value.
2370 fount_r_none(double v) {
2371 return v < 0 ? 0 : v > 1 ? 1 : v;
2375 =item fount_r_sawtooth(v)
2377 Implements sawtooth repeats. Clamps negative values and uses fmod()
2383 fount_r_sawtooth(double v) {
2384 return v < 0 ? 0 : fmod(v, 1.0);
2388 =item fount_r_triangle(v)
2390 Implements triangle repeats. Clamps negative values, uses fmod to get
2391 a range 0 through 2 and then adjusts values > 1.
2396 fount_r_triangle(double v) {
2401 return v > 1.0 ? 2.0 - v : v;
2406 =item fount_r_saw_both(v)
2408 Implements sawtooth repeats in the both postive and negative directions.
2410 Adjusts the value to be postive and then just uses fmod().
2415 fount_r_saw_both(double v) {
2418 return fmod(v, 1.0);
2422 =item fount_r_tri_both(v)
2424 Implements triangle repeats in the both postive and negative directions.
2426 Uses fmod on the absolute value, and then adjusts values > 1.
2431 fount_r_tri_both(double v) {
2432 v = fmod(fabs(v), 2.0);
2433 return v > 1.0 ? 2.0 - v : v;
2437 =item fill_fountf(fill, x, y, width, channels, data)
2439 The fill function for fountain fills.
2444 fill_fountf(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
2445 int channels, i_fcolor *data) {
2446 i_fill_fountain_t *f = (i_fill_fountain_t *)fill;
2452 if (f->state.ssfunc)
2453 got_one = f->state.ssfunc(&c, x, y, &f->state);
2455 got_one = fount_getat(&c, x, y, &f->state);
2465 =item fount_fill_destroy(fill)
2470 fount_fill_destroy(i_fill_t *fill) {
2471 i_fill_fountain_t *f = (i_fill_fountain_t *)fill;
2472 fount_finish_state(&f->state);
2480 Arnar M. Hrafnkelsson <addi@umich.edu>
2482 Tony Cook <tony@develop-help.com> (i_fountain())