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);
1344 =item i_unsharp_mask(im, stddev, scale)
1346 Perform an usharp mask, which is defined as subtracting the blurred
1347 image from double the original.
1353 i_unsharp_mask(i_img *im, double stddev, double scale) {
1360 /* it really shouldn't ever be more than 1.0, but maybe ... */
1365 i_gaussian(copy, stddev);
1366 if (im->bits == i_8_bits) {
1367 i_color *blur = mymalloc(im->xsize * sizeof(i_color)); /* checked 17feb2005 tonyc */
1368 i_color *out = mymalloc(im->xsize * sizeof(i_color)); /* checked 17feb2005 tonyc */
1370 for (y = 0; y < im->ysize; ++y) {
1371 i_glin(copy, 0, copy->xsize, y, blur);
1372 i_glin(im, 0, im->xsize, y, out);
1373 for (x = 0; x < im->xsize; ++x) {
1374 for (ch = 0; ch < im->channels; ++ch) {
1375 /*int temp = out[x].channel[ch] +
1376 scale * (out[x].channel[ch] - blur[x].channel[ch]);*/
1377 int temp = out[x].channel[ch] * 2 - blur[x].channel[ch];
1380 else if (temp > 255)
1382 out[x].channel[ch] = temp;
1385 i_plin(im, 0, im->xsize, y, out);
1392 i_fcolor *blur = mymalloc(im->xsize * sizeof(i_fcolor)); /* checked 17feb2005 tonyc */
1393 i_fcolor *out = mymalloc(im->xsize * sizeof(i_fcolor)); /* checked 17feb2005 tonyc */
1395 for (y = 0; y < im->ysize; ++y) {
1396 i_glinf(copy, 0, copy->xsize, y, blur);
1397 i_glinf(im, 0, im->xsize, y, out);
1398 for (x = 0; x < im->xsize; ++x) {
1399 for (ch = 0; ch < im->channels; ++ch) {
1400 double temp = out[x].channel[ch] +
1401 scale * (out[x].channel[ch] - blur[x].channel[ch]);
1404 else if (temp > 1.0)
1406 out[x].channel[ch] = temp;
1409 i_plinf(im, 0, im->xsize, y, out);
1415 i_img_destroy(copy);
1419 =item i_diff_image(im1, im2, mindist)
1421 Creates a new image that is transparent, except where the pixel in im2
1422 is different from im1, where it is the pixel from im2.
1424 The samples must differ by at least mindiff to be considered different.
1430 i_diff_image(i_img *im1, i_img *im2, double mindist) {
1432 int outchans, diffchans;
1433 i_img_dim xsize, ysize;
1437 if (im1->channels != im2->channels) {
1438 i_push_error(0, "different number of channels");
1442 outchans = diffchans = im1->channels;
1443 if (outchans == 1 || outchans == 3)
1446 xsize = i_min(im1->xsize, im2->xsize);
1447 ysize = i_min(im1->ysize, im2->ysize);
1449 out = i_sametype_chans(im1, xsize, ysize, outchans);
1451 if (im1->bits == i_8_bits && im2->bits == i_8_bits) {
1452 i_color *line1 = mymalloc(xsize * sizeof(*line1)); /* checked 17feb2005 tonyc */
1453 i_color *line2 = mymalloc(xsize * sizeof(*line1)); /* checked 17feb2005 tonyc */
1457 int imindist = (int)mindist;
1459 for (ch = 0; ch < MAXCHANNELS; ++ch)
1460 empty.channel[ch] = 0;
1462 for (y = 0; y < ysize; ++y) {
1463 i_glin(im1, 0, xsize, y, line1);
1464 i_glin(im2, 0, xsize, y, line2);
1465 if (outchans != diffchans) {
1466 /* give the output an alpha channel since it doesn't have one */
1467 for (x = 0; x < xsize; ++x)
1468 line2[x].channel[diffchans] = 255;
1470 for (x = 0; x < xsize; ++x) {
1472 for (ch = 0; ch < diffchans; ++ch) {
1473 if (line1[x].channel[ch] != line2[x].channel[ch]
1474 && abs(line1[x].channel[ch] - line2[x].channel[ch]) > imindist) {
1482 i_plin(out, 0, xsize, y, line2);
1488 i_fcolor *line1 = mymalloc(xsize * sizeof(*line1)); /* checked 17feb2005 tonyc */
1489 i_fcolor *line2 = mymalloc(xsize * sizeof(*line2)); /* checked 17feb2005 tonyc */
1493 double dist = mindist / 255.0;
1495 for (ch = 0; ch < MAXCHANNELS; ++ch)
1496 empty.channel[ch] = 0;
1498 for (y = 0; y < ysize; ++y) {
1499 i_glinf(im1, 0, xsize, y, line1);
1500 i_glinf(im2, 0, xsize, y, line2);
1501 if (outchans != diffchans) {
1502 /* give the output an alpha channel since it doesn't have one */
1503 for (x = 0; x < xsize; ++x)
1504 line2[x].channel[diffchans] = 1.0;
1506 for (x = 0; x < xsize; ++x) {
1508 for (ch = 0; ch < diffchans; ++ch) {
1509 if (line1[x].channel[ch] != line2[x].channel[ch]
1510 && fabs(line1[x].channel[ch] - line2[x].channel[ch]) > dist) {
1518 i_plinf(out, 0, xsize, y, line2);
1528 static double linear_fount_f(double x, double y, struct fount_state *state);
1529 static double bilinear_fount_f(double x, double y, struct fount_state *state);
1530 static double radial_fount_f(double x, double y, struct fount_state *state);
1531 static double square_fount_f(double x, double y, struct fount_state *state);
1532 static double revolution_fount_f(double x, double y,
1533 struct fount_state *state);
1534 static double conical_fount_f(double x, double y, struct fount_state *state);
1536 typedef double (*fount_func)(double, double, struct fount_state *);
1537 static fount_func fount_funcs[] =
1547 static double linear_interp(double pos, i_fountain_seg *seg);
1548 static double sine_interp(double pos, i_fountain_seg *seg);
1549 static double sphereup_interp(double pos, i_fountain_seg *seg);
1550 static double spheredown_interp(double pos, i_fountain_seg *seg);
1551 typedef double (*fount_interp)(double pos, i_fountain_seg *seg);
1552 static fount_interp fount_interps[] =
1561 static void direct_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg);
1562 static void hue_up_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg);
1563 static void hue_down_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg);
1564 typedef void (*fount_cinterp)(i_fcolor *out, double pos, i_fountain_seg *seg);
1565 static fount_cinterp fount_cinterps[] =
1572 typedef double (*fount_repeat)(double v);
1573 static double fount_r_none(double v);
1574 static double fount_r_sawtooth(double v);
1575 static double fount_r_triangle(double v);
1576 static double fount_r_saw_both(double v);
1577 static double fount_r_tri_both(double v);
1578 static fount_repeat fount_repeats[] =
1587 static int simple_ssample(i_fcolor *out, double x, double y,
1588 struct fount_state *state);
1589 static int random_ssample(i_fcolor *out, double x, double y,
1590 struct fount_state *state);
1591 static int circle_ssample(i_fcolor *out, double x, double y,
1592 struct fount_state *state);
1593 typedef int (*fount_ssample)(i_fcolor *out, double x, double y,
1594 struct fount_state *state);
1595 static fount_ssample fount_ssamples[] =
1604 fount_getat(i_fcolor *out, double x, double y, struct fount_state *state);
1607 Keep state information used by each type of fountain fill
1609 struct fount_state {
1610 /* precalculated for the equation of the line perpendicular to the line AB */
1621 fount_repeat rpfunc;
1622 fount_ssample ssfunc;
1624 i_fountain_seg *segs;
1629 fount_init_state(struct fount_state *state, double xa, double ya,
1630 double xb, double yb, i_fountain_type type,
1631 i_fountain_repeat repeat, int combine, int super_sample,
1632 double ssample_param, int count, i_fountain_seg *segs);
1635 fount_finish_state(struct fount_state *state);
1637 #define EPSILON (1e-6)
1640 =item i_fountain(im, xa, ya, xb, yb, type, repeat, combine, super_sample, ssample_param, count, segs)
1642 Draws a fountain fill using A(xa, ya) and B(xb, yb) as reference points.
1644 I<type> controls how the reference points are used:
1650 linear, where A is 0 and B is 1.
1654 linear in both directions from A.
1658 circular, where A is the centre of the fill, and B is a point
1661 =item i_ft_radial_square
1663 where A is the centre of the fill and B is the centre of
1664 one side of the square.
1666 =item i_ft_revolution
1668 where A is the centre of the fill and B defines the 0/1.0
1673 similar to i_ft_revolution, except that the revolution goes in both
1678 I<repeat> can be one of:
1684 values < 0 are treated as zero, values > 1 are treated as 1.
1688 negative values are treated as 0, positive values are modulo 1.0
1692 negative values are treated as zero, if (int)value is odd then the value is treated as 1-(value
1693 mod 1.0), otherwise the same as for sawtooth.
1697 like i_fr_sawtooth, except that the sawtooth pattern repeats into
1702 Like i_fr_triangle, except that negative values are handled as their
1707 If combine is non-zero then non-opaque values are combined with the
1710 I<super_sample> controls super sampling, if any. At some point I'll
1711 probably add a adaptive super-sampler. Current possible values are:
1717 No super-sampling is done.
1721 A square grid of points withing the pixel are sampled.
1725 Random points within the pixel are sampled.
1729 Points on the radius of a circle are sampled. This produces fairly
1730 good results, but is fairly slow since sin() and cos() are evaluated
1735 I<ssample_param> is intended to be roughly the number of points
1736 sampled within the pixel.
1738 I<count> and I<segs> define the segments of the fill.
1745 i_fountain(i_img *im, double xa, double ya, double xb, double yb,
1746 i_fountain_type type, i_fountain_repeat repeat,
1747 int combine, int super_sample, double ssample_param,
1748 int count, i_fountain_seg *segs) {
1749 struct fount_state state;
1751 i_fcolor *line = NULL;
1752 i_fcolor *work = NULL;
1754 i_fill_combine_f combine_func = NULL;
1755 i_fill_combinef_f combinef_func = NULL;
1760 /* i_fountain() allocates floating colors even for 8-bit images,
1761 so we need to do this check */
1762 line_bytes = sizeof(i_fcolor) * im->xsize;
1763 if (line_bytes / sizeof(i_fcolor) != im->xsize) {
1764 i_push_error(0, "integer overflow calculating memory allocation");
1768 line = mymalloc(line_bytes); /* checked 17feb2005 tonyc */
1770 i_get_combine(combine, &combine_func, &combinef_func);
1771 if (combinef_func) {
1772 work = mymalloc(line_bytes); /* checked 17feb2005 tonyc */
1775 fount_init_state(&state, xa, ya, xb, yb, type, repeat, combine,
1776 super_sample, ssample_param, count, segs);
1778 for (y = 0; y < im->ysize; ++y) {
1779 i_glinf(im, 0, im->xsize, y, line);
1780 for (x = 0; x < im->xsize; ++x) {
1783 if (super_sample == i_fts_none)
1784 got_one = fount_getat(&c, x, y, &state);
1786 got_one = state.ssfunc(&c, x, y, &state);
1795 combinef_func(line, work, im->channels, im->xsize);
1796 i_plinf(im, 0, im->xsize, y, line);
1798 fount_finish_state(&state);
1807 struct fount_state state;
1808 } i_fill_fountain_t;
1811 fill_fountf(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width, int channels,
1814 fount_fill_destroy(i_fill_t *fill);
1816 static i_fill_fountain_t
1828 =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>)
1831 =synopsis fill = i_new_fill_fount(0, 0, 100, 100, i_ft_linear, i_ft_linear,
1832 =synopsis i_fr_triangle, 0, i_fts_grid, 9, 1, segs);
1835 Creates a new general fill which fills with a fountain fill.
1841 i_new_fill_fount(double xa, double ya, double xb, double yb,
1842 i_fountain_type type, i_fountain_repeat repeat,
1843 int combine, int super_sample, double ssample_param,
1844 int count, i_fountain_seg *segs) {
1845 i_fill_fountain_t *fill = mymalloc(sizeof(i_fill_fountain_t));
1847 *fill = fount_fill_proto;
1849 i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
1851 fill->base.combine = NULL;
1852 fill->base.combinef = NULL;
1854 fount_init_state(&fill->state, xa, ya, xb, yb, type, repeat, combine,
1855 super_sample, ssample_param, count, segs);
1863 =head1 INTERNAL FUNCTIONS
1867 =item fount_init_state(...)
1869 Used by both the fountain fill filter and the fountain fill.
1875 fount_init_state(struct fount_state *state, double xa, double ya,
1876 double xb, double yb, i_fountain_type type,
1877 i_fountain_repeat repeat, int combine, int super_sample,
1878 double ssample_param, int count, i_fountain_seg *segs) {
1881 i_fountain_seg *my_segs = mymalloc(sizeof(i_fountain_seg) * count); /* checked 2jul06 - duplicating original */
1882 /*int have_alpha = im->channels == 2 || im->channels == 4;*/
1884 memset(state, 0, sizeof(*state));
1885 /* we keep a local copy that we can adjust for speed */
1886 for (i = 0; i < count; ++i) {
1887 i_fountain_seg *seg = my_segs + i;
1890 if (seg->type < 0 || seg->type >= i_fst_end)
1891 seg->type = i_fst_linear;
1892 if (seg->color < 0 || seg->color >= i_fc_end)
1893 seg->color = i_fc_direct;
1894 if (seg->color == i_fc_hue_up || seg->color == i_fc_hue_down) {
1895 /* so we don't have to translate to HSV on each request, do it here */
1896 for (j = 0; j < 2; ++j) {
1897 i_rgb_to_hsvf(seg->c+j);
1899 if (seg->color == i_fc_hue_up) {
1900 if (seg->c[1].channel[0] <= seg->c[0].channel[0])
1901 seg->c[1].channel[0] += 1.0;
1904 if (seg->c[0].channel[0] <= seg->c[0].channel[1])
1905 seg->c[0].channel[0] += 1.0;
1908 /*printf("start %g mid %g end %g c0(%g,%g,%g,%g) c1(%g,%g,%g,%g) type %d color %d\n",
1909 seg->start, seg->middle, seg->end, seg->c[0].channel[0],
1910 seg->c[0].channel[1], seg->c[0].channel[2], seg->c[0].channel[3],
1911 seg->c[1].channel[0], seg->c[1].channel[1], seg->c[1].channel[2],
1912 seg->c[1].channel[3], seg->type, seg->color);*/
1916 /* initialize each engine */
1917 /* these are so common ... */
1918 state->lA = xb - xa;
1919 state->lB = yb - ya;
1920 state->AB = sqrt(state->lA * state->lA + state->lB * state->lB);
1925 type = i_ft_linear; /* make the invalid value valid */
1928 state->lC = ya * ya - ya * yb + xa * xa - xa * xb;
1930 state->mult = 1/linear_fount_f(xb, yb, state);
1934 state->mult = 1.0 / sqrt((double)(xb-xa)*(xb-xa)
1935 + (double)(yb-ya)*(yb-ya));
1938 case i_ft_radial_square:
1939 state->cos = state->lA / state->AB;
1940 state->sin = state->lB / state->AB;
1941 state->mult = 1.0 / state->AB;
1944 case i_ft_revolution:
1945 state->theta = atan2(yb-ya, xb-xa);
1946 state->mult = 1.0 / (PI * 2);
1950 state->theta = atan2(yb-ya, xb-xa);
1951 state->mult = 1.0 / PI;
1954 state->ffunc = fount_funcs[type];
1955 if (super_sample < 0
1956 || super_sample >= (int)(sizeof(fount_ssamples)/sizeof(*fount_ssamples))) {
1959 state->ssample_data = NULL;
1960 switch (super_sample) {
1962 ssample_param = floor(0.5 + sqrt(ssample_param));
1963 bytes = ssample_param * ssample_param * sizeof(i_fcolor);
1964 if (bytes / sizeof(i_fcolor) == ssample_param * ssample_param) {
1965 state->ssample_data = mymalloc(sizeof(i_fcolor) * ssample_param * ssample_param); /* checked 1jul06 tonyc */
1968 super_sample = i_fts_none;
1974 ssample_param = floor(0.5+ssample_param);
1975 bytes = sizeof(i_fcolor) * ssample_param;
1976 if (bytes / sizeof(i_fcolor) == ssample_param) {
1977 state->ssample_data = mymalloc(sizeof(i_fcolor) * ssample_param);
1980 super_sample = i_fts_none;
1984 state->parm = ssample_param;
1985 state->ssfunc = fount_ssamples[super_sample];
1986 if (repeat < 0 || repeat >= (sizeof(fount_repeats)/sizeof(*fount_repeats)))
1988 state->rpfunc = fount_repeats[repeat];
1989 state->segs = my_segs;
1990 state->count = count;
1994 fount_finish_state(struct fount_state *state) {
1995 if (state->ssample_data)
1996 myfree(state->ssample_data);
1997 myfree(state->segs);
2002 =item fount_getat(out, x, y, ffunc, rpfunc, state, segs, count)
2004 Evaluates the fountain fill at the given point.
2006 This is called by both the non-super-sampling and super-sampling code.
2008 You might think that it would make sense to sample the fill parameter
2009 instead, and combine those, but this breaks badly.
2015 fount_getat(i_fcolor *out, double x, double y, struct fount_state *state) {
2016 double v = (state->rpfunc)((state->ffunc)(x, y, state));
2020 while (i < state->count
2021 && (v < state->segs[i].start || v > state->segs[i].end)) {
2024 if (i < state->count) {
2025 v = (fount_interps[state->segs[i].type])(v, state->segs+i);
2026 (fount_cinterps[state->segs[i].color])(out, v, state->segs+i);
2034 =item linear_fount_f(x, y, state)
2036 Calculate the fill parameter for a linear fountain fill.
2038 Uses the point to line distance function, with some precalculation
2039 done in i_fountain().
2044 linear_fount_f(double x, double y, struct fount_state *state) {
2045 return (state->lA * x + state->lB * y + state->lC) / state->AB * state->mult;
2049 =item bilinear_fount_f(x, y, state)
2051 Calculate the fill parameter for a bi-linear fountain fill.
2056 bilinear_fount_f(double x, double y, struct fount_state *state) {
2057 return fabs((state->lA * x + state->lB * y + state->lC) / state->AB * state->mult);
2061 =item radial_fount_f(x, y, state)
2063 Calculate the fill parameter for a radial fountain fill.
2065 Simply uses the distance function.
2070 radial_fount_f(double x, double y, struct fount_state *state) {
2071 return sqrt((double)(state->xa-x)*(state->xa-x)
2072 + (double)(state->ya-y)*(state->ya-y)) * state->mult;
2076 =item square_fount_f(x, y, state)
2078 Calculate the fill parameter for a square fountain fill.
2080 Works by rotating the reference co-ordinate around the centre of the
2086 square_fount_f(double x, double y, struct fount_state *state) {
2087 i_img_dim xc, yc; /* centred on A */
2088 double xt, yt; /* rotated by theta */
2091 xt = fabs(xc * state->cos + yc * state->sin);
2092 yt = fabs(-xc * state->sin + yc * state->cos);
2093 return (xt > yt ? xt : yt) * state->mult;
2097 =item revolution_fount_f(x, y, state)
2099 Calculates the fill parameter for the revolution fountain fill.
2104 revolution_fount_f(double x, double y, struct fount_state *state) {
2105 double angle = atan2(y - state->ya, x - state->xa);
2107 angle -= state->theta;
2109 angle = fmod(angle+ PI * 4, PI*2);
2112 return angle * state->mult;
2116 =item conical_fount_f(x, y, state)
2118 Calculates the fill parameter for the conical fountain fill.
2123 conical_fount_f(double x, double y, struct fount_state *state) {
2124 double angle = atan2(y - state->ya, x - state->xa);
2126 angle -= state->theta;
2129 else if (angle > PI)
2132 return fabs(angle) * state->mult;
2136 =item linear_interp(pos, seg)
2138 Calculates linear interpolation on the fill parameter. Breaks the
2139 segment into 2 regions based in the I<middle> value.
2144 linear_interp(double pos, i_fountain_seg *seg) {
2145 if (pos < seg->middle) {
2146 double len = seg->middle - seg->start;
2150 return (pos - seg->start) / len / 2;
2153 double len = seg->end - seg->middle;
2157 return 0.5 + (pos - seg->middle) / len / 2;
2162 =item sine_interp(pos, seg)
2164 Calculates sine function interpolation on the fill parameter.
2169 sine_interp(double pos, i_fountain_seg *seg) {
2170 /* I wonder if there's a simple way to smooth the transition for this */
2171 double work = linear_interp(pos, seg);
2173 return (1-cos(work * PI))/2;
2177 =item sphereup_interp(pos, seg)
2179 Calculates spherical interpolation on the fill parameter, with the cusp
2185 sphereup_interp(double pos, i_fountain_seg *seg) {
2186 double work = linear_interp(pos, seg);
2188 return sqrt(1.0 - (1-work) * (1-work));
2192 =item spheredown_interp(pos, seg)
2194 Calculates spherical interpolation on the fill parameter, with the cusp
2200 spheredown_interp(double pos, i_fountain_seg *seg) {
2201 double work = linear_interp(pos, seg);
2203 return 1-sqrt(1.0 - work * work);
2207 =item direct_cinterp(out, pos, seg)
2209 Calculates the fountain color based on direct scaling of the channels
2210 of the color channels.
2215 direct_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg) {
2217 for (ch = 0; ch < MAXCHANNELS; ++ch) {
2218 out->channel[ch] = seg->c[0].channel[ch] * (1 - pos)
2219 + seg->c[1].channel[ch] * pos;
2224 =item hue_up_cinterp(put, pos, seg)
2226 Calculates the fountain color based on scaling a HSV value. The hue
2227 increases as the fill parameter increases.
2232 hue_up_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 hue_down_cinterp(put, pos, seg)
2244 Calculates the fountain color based on scaling a HSV value. The hue
2245 decreases as the fill parameter increases.
2250 hue_down_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg) {
2252 for (ch = 0; ch < MAXCHANNELS; ++ch) {
2253 out->channel[ch] = seg->c[0].channel[ch] * (1 - pos)
2254 + seg->c[1].channel[ch] * pos;
2260 =item simple_ssample(out, parm, x, y, state, ffunc, rpfunc, segs, count)
2262 Simple grid-based super-sampling.
2267 simple_ssample(i_fcolor *out, double x, double y, struct fount_state *state) {
2268 i_fcolor *work = state->ssample_data;
2270 int grid = state->parm;
2271 double base = -0.5 + 0.5 / grid;
2272 double step = 1.0 / grid;
2276 for (dx = 0; dx < grid; ++dx) {
2277 for (dy = 0; dy < grid; ++dy) {
2278 if (fount_getat(work+samp_count, x + base + step * dx,
2279 y + base + step * dy, state)) {
2284 for (ch = 0; ch < MAXCHANNELS; ++ch) {
2285 out->channel[ch] = 0;
2286 for (i = 0; i < samp_count; ++i) {
2287 out->channel[ch] += work[i].channel[ch];
2289 /* we divide by 4 rather than samp_count since if there's only one valid
2290 sample it should be mostly transparent */
2291 out->channel[ch] /= grid * grid;
2297 =item random_ssample(out, parm, x, y, state, ffunc, rpfunc, segs, count)
2299 Random super-sampling.
2304 random_ssample(i_fcolor *out, double x, double y,
2305 struct fount_state *state) {
2306 i_fcolor *work = state->ssample_data;
2308 int maxsamples = state->parm;
2309 double rand_scale = 1.0 / RAND_MAX;
2311 for (i = 0; i < maxsamples; ++i) {
2312 if (fount_getat(work+samp_count, x - 0.5 + rand() * rand_scale,
2313 y - 0.5 + rand() * rand_scale, state)) {
2317 for (ch = 0; ch < MAXCHANNELS; ++ch) {
2318 out->channel[ch] = 0;
2319 for (i = 0; i < samp_count; ++i) {
2320 out->channel[ch] += work[i].channel[ch];
2322 /* we divide by maxsamples rather than samp_count since if there's
2323 only one valid sample it should be mostly transparent */
2324 out->channel[ch] /= maxsamples;
2330 =item circle_ssample(out, parm, x, y, state, ffunc, rpfunc, segs, count)
2332 Super-sampling around the circumference of a circle.
2334 I considered saving the sin()/cos() values and transforming step-size
2335 around the circle, but that's inaccurate, though it may not matter
2341 circle_ssample(i_fcolor *out, double x, double y,
2342 struct fount_state *state) {
2343 i_fcolor *work = state->ssample_data;
2345 int maxsamples = state->parm;
2346 double angle = 2 * PI / maxsamples;
2347 double radius = 0.3; /* semi-random */
2349 for (i = 0; i < maxsamples; ++i) {
2350 if (fount_getat(work+samp_count, x + radius * cos(angle * i),
2351 y + radius * sin(angle * i), state)) {
2355 for (ch = 0; ch < MAXCHANNELS; ++ch) {
2356 out->channel[ch] = 0;
2357 for (i = 0; i < samp_count; ++i) {
2358 out->channel[ch] += work[i].channel[ch];
2360 /* we divide by maxsamples rather than samp_count since if there's
2361 only one valid sample it should be mostly transparent */
2362 out->channel[ch] /= maxsamples;
2368 =item fount_r_none(v)
2370 Implements no repeats. Simply clamps the fill value.
2375 fount_r_none(double v) {
2376 return v < 0 ? 0 : v > 1 ? 1 : v;
2380 =item fount_r_sawtooth(v)
2382 Implements sawtooth repeats. Clamps negative values and uses fmod()
2388 fount_r_sawtooth(double v) {
2389 return v < 0 ? 0 : fmod(v, 1.0);
2393 =item fount_r_triangle(v)
2395 Implements triangle repeats. Clamps negative values, uses fmod to get
2396 a range 0 through 2 and then adjusts values > 1.
2401 fount_r_triangle(double v) {
2406 return v > 1.0 ? 2.0 - v : v;
2411 =item fount_r_saw_both(v)
2413 Implements sawtooth repeats in the both postive and negative directions.
2415 Adjusts the value to be postive and then just uses fmod().
2420 fount_r_saw_both(double v) {
2423 return fmod(v, 1.0);
2427 =item fount_r_tri_both(v)
2429 Implements triangle repeats in the both postive and negative directions.
2431 Uses fmod on the absolute value, and then adjusts values > 1.
2436 fount_r_tri_both(double v) {
2437 v = fmod(fabs(v), 2.0);
2438 return v > 1.0 ? 2.0 - v : v;
2442 =item fill_fountf(fill, x, y, width, channels, data)
2444 The fill function for fountain fills.
2449 fill_fountf(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
2450 int channels, i_fcolor *data) {
2451 i_fill_fountain_t *f = (i_fill_fountain_t *)fill;
2457 if (f->state.ssfunc)
2458 got_one = f->state.ssfunc(&c, x, y, &f->state);
2460 got_one = fount_getat(&c, x, y, &f->state);
2470 =item fount_fill_destroy(fill)
2475 fount_fill_destroy(i_fill_t *fill) {
2476 i_fill_fountain_t *f = (i_fill_fountain_t *)fill;
2477 fount_finish_state(&f->state);
2485 Arnar M. Hrafnkelsson <addi@umich.edu>
2487 Tony Cook <tony@develop-help.com> (i_fountain())