File Coverage

filters.im
Criterion Covered Total %
statement 749 876 85.5
branch 377 472 79.8
condition n/a
subroutine n/a
pod n/a
total 1126 1348 83.5


line stmt bran cond sub pod time code
1             #define IMAGER_NO_CONTEXT
2             #include "imager.h"
3             #include "imageri.h"
4             #include
5             #include
6              
7              
8             /*
9             =head1 NAME
10              
11             filters.im - implements filters that operate on images
12              
13             =head1 SYNOPSIS
14              
15            
16             i_contrast(im, 0.8);
17             i_hardinvert(im);
18             i_hardinvertall(im);
19             i_unsharp_mask(im, 2.0, 1.0);
20             ... and more
21              
22             =head1 DESCRIPTION
23              
24             filters.c implements basic filters for Imager. These filters
25             should be accessible from the filter interface as defined in
26             the pod for Imager.
27              
28             =head1 FUNCTION REFERENCE
29              
30             Some of these functions are internal.
31              
32             =over
33              
34             =cut
35             */
36              
37              
38              
39              
40             /*
41             =item saturate(in)
42              
43             Clamps the input value between 0 and 255. (internal)
44              
45             in - input integer
46              
47             =cut
48             */
49              
50             static
51             unsigned char
52 315000           saturate(int in) {
53 315000 100         if (in>255) { return 255; }
54 301409 100         else if (in>0) return in;
55 109185           return 0;
56             }
57              
58              
59              
60             /*
61             =item i_contrast(im, intensity)
62              
63             Scales the pixel values by the amount specified.
64              
65             im - image object
66             intensity - scalefactor
67              
68             =cut
69             */
70              
71             void
72 1           i_contrast(i_img *im, float intensity) {
73             i_img_dim x, y;
74             int ch;
75             unsigned int new_color;
76             i_color rcolor;
77 1           dIMCTXim(im);
78            
79 1           im_log((aIMCTX, 1,"i_contrast(im %p, intensity %f)\n", im, intensity));
80            
81 1 50         if(intensity < 0) return;
82            
83 22651 100         for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
    100          
84 22500           i_gpix(im, x, y, &rcolor);
85            
86 90000 100         for(ch = 0; ch < im->channels; ch++) {
87 67500           new_color = (unsigned int) rcolor.channel[ch];
88 67500           new_color *= intensity;
89            
90 67500 50         if(new_color > 255) {
91 0           new_color = 255;
92             }
93 67500           rcolor.channel[ch] = (unsigned char) new_color;
94             }
95 22500           i_ppix(im, x, y, &rcolor);
96             }
97             }
98              
99              
100             static int
101 5           s_hardinvert_low(i_img *im, int all) {
102             i_img_dim x, y;
103             int ch;
104 5 100         int invert_channels = all ? im->channels : i_img_color_channels(im);
105 5           dIMCTXim(im);
106              
107 5           im_log((aIMCTX,1,"i_hardinvert)low(im %p, all %d)\n", im, all));
108            
109 5 100         #code im->bits <= 8
110             IM_COLOR *row, *entry;
111            
112             /* always rooms to allocate a single line of i_color */
113 5           row = mymalloc(sizeof(IM_COLOR) * im->xsize); /* checked 17feb2005 tonyc */
114              
115 159 100         for(y = 0; y < im->ysize; y++) {
    100          
116 154           IM_GLIN(im, 0, im->xsize, y, row);
117 154           entry = row;
118 22658 100         for(x = 0; x < im->xsize; x++) {
    100          
119 90018 100         for(ch = 0; ch < invert_channels; ch++) {
    100          
120 67514           entry->channel[ch] = IM_SAMPLE_MAX - entry->channel[ch];
121             }
122 22504           ++entry;
123             }
124 154           IM_PLIN(im, 0, im->xsize, y, row);
125             }
126 5           myfree(row);
127             #/code
128              
129 5           return 1;
130             }
131              
132             /*
133             =item i_hardinvert(im)
134              
135             Inverts the color channels of the input image.
136              
137             im - image object
138              
139             =cut
140             */
141              
142             void
143 3           i_hardinvert(i_img *im) {
144 3           s_hardinvert_low(im, 0);
145 3           }
146              
147             /*
148             =item i_hardinvertall(im)
149              
150             Inverts all channels of the input image.
151              
152             im - image object
153              
154             =cut
155             */
156              
157             void
158 2           i_hardinvertall(i_img *im) {
159 2           s_hardinvert_low(im, 1);
160 2           }
161              
162             /*
163             =item i_noise(im, amount, type)
164              
165             Adjusts the sample values randomly by the amount specified.
166              
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.
169              
170             im - image object
171             amount - deviation in pixel values
172             type - noise individual for each channel if true
173              
174             =cut
175             */
176              
177             #ifdef WIN32
178             /* random() is non-ASCII, even if it is better than rand() */
179             #define random() rand()
180             #endif
181              
182             void
183 1           i_noise(i_img *im, float amount, unsigned char type) {
184             i_img_dim x, y;
185             int ch;
186             int new_color;
187 1           float damount = amount * 2;
188             i_color rcolor;
189 1           int color_inc = 0;
190 1           dIMCTXim(im);
191            
192 1           im_log((aIMCTX, 1,"i_noise(im %p, intensity %.2f\n", im, amount));
193            
194 1 50         if(amount < 0) return;
195            
196 22651 100         for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
    100          
197 22500           i_gpix(im, x, y, &rcolor);
198            
199 22500 50         if(type == 0) {
200 22500           color_inc = (amount - (damount * ((double)random() / RAND_MAX)));
201             }
202            
203 90000 100         for(ch = 0; ch < im->channels; ch++) {
204 67500           new_color = (int) rcolor.channel[ch];
205            
206 67500 50         if(type != 0) {
207 0           new_color += (amount - (damount * ((double)random() / RAND_MAX)));
208             } else {
209 67500           new_color += color_inc;
210             }
211            
212 67500 100         if(new_color < 0) {
213 17838           new_color = 0;
214             }
215 67500 50         if(new_color > 255) {
216 0           new_color = 255;
217             }
218            
219 67500           rcolor.channel[ch] = (unsigned char) new_color;
220             }
221            
222 22500           i_ppix(im, x, y, &rcolor);
223             }
224             }
225              
226             /*
227             =item i_bumpmap(im, bump, channel, light_x, light_y, st)
228              
229             Makes a bumpmap on image im using the bump image as the elevation map.
230              
231             im - target image
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
237              
238             =cut
239             */
240              
241             void
242 1           i_bumpmap(i_img *im, i_img *bump, int channel, i_img_dim light_x, i_img_dim light_y, i_img_dim st) {
243             i_img_dim x, y;
244             int ch;
245             i_img_dim mx, my;
246             i_color x1_color, y1_color, x2_color, y2_color, dst_color;
247             double nX, nY;
248             double tX, tY, tZ;
249             double aX, aY, aL;
250             double fZ;
251             unsigned char px1, px2, py1, py2;
252 1           dIMCTXim(im);
253             i_img new_im;
254              
255 1           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)));
257              
258              
259 1 50         if(channel >= bump->channels) {
260 0           im_log((aIMCTX, 1, "i_bumpmap: channel = %d while bump image only has %d channels\n", channel, bump->channels));
261 0           return;
262             }
263              
264 1           mx = (bump->xsize <= im->xsize) ? bump->xsize : im->xsize;
265 1           my = (bump->ysize <= im->ysize) ? bump->ysize : im->ysize;
266              
267 1           i_img_empty_ch(&new_im, im->xsize, im->ysize, im->channels);
268            
269 1 50         aX = (light_x > (mx >> 1)) ? light_x : mx - light_x;
270 1 50         aY = (light_y > (my >> 1)) ? light_y : my - light_y;
271              
272 1           aL = sqrt((aX * aX) + (aY * aY));
273              
274 149 100         for(y = 1; y < my - 1; y++) {
275 22052 100         for(x = 1; x < mx - 1; x++) {
276 21904           i_gpix(bump, x + st, y, &x1_color);
277 21904           i_gpix(bump, x, y + st, &y1_color);
278 21904           i_gpix(bump, x - st, y, &x2_color);
279 21904           i_gpix(bump, x, y - st, &y2_color);
280              
281 21904           i_gpix(im, x, y, &dst_color);
282              
283 21904           px1 = x1_color.channel[channel];
284 21904           py1 = y1_color.channel[channel];
285 21904           px2 = x2_color.channel[channel];
286 21904           py2 = y2_color.channel[channel];
287              
288 21904           nX = px1 - px2;
289 21904           nY = py1 - py2;
290              
291 21904           nX += 128;
292 21904           nY += 128;
293              
294 21904           fZ = (sqrt((nX * nX) + (nY * nY)) / aL);
295            
296 21904           tX = i_abs(x - light_x) / aL;
297 21904           tY = i_abs(y - light_y) / aL;
298              
299 21904           tZ = 1 - (sqrt((tX * tX) + (tY * tY)) * fZ);
300            
301 21904 100         if(tZ < 0) tZ = 0;
302 21904 50         if(tZ > 2) tZ = 2;
303              
304 87616 100         for(ch = 0; ch < im->channels; ch++)
305 65712           dst_color.channel[ch] = (unsigned char) (float)(dst_color.channel[ch] * tZ);
306            
307 21904           i_ppix(&new_im, x, y, &dst_color);
308             }
309             }
310              
311 1           i_copyto(im, &new_im, 0, 0, im->xsize, im->ysize, 0, 0);
312            
313 1           i_img_exorcise(&new_im);
314             }
315              
316              
317              
318              
319             typedef struct {
320             double x,y,z;
321             } fvec;
322              
323              
324             static
325             float
326 67501           dotp(fvec *a, fvec *b) {
327 67501           return a->x*b->x+a->y*b->y+a->z*b->z;
328             }
329              
330             static
331             void
332 22501           normalize(fvec *a) {
333 22501           double d = sqrt(dotp(a,a));
334 22501           a->x /= d;
335 22501           a->y /= d;
336 22501           a->z /= d;
337 22501           }
338              
339              
340             /*
341             positive directions:
342            
343             x - right,
344             y - down
345             z - out of the plane
346            
347             I = Ia + Ip*( cd*Scol(N.L) + cs*(R.V)^n )
348            
349             Here, the variables are:
350            
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
357             * N - normal vector
358             * L - lighting vector
359             * R - reflection vector
360             * V - vision vector
361              
362             static void fvec_dump(fvec *x) {
363             printf("(%.2f %.2f %.2f)", x->x, x->y, x->z);
364             }
365             */
366              
367             /* XXX: Should these return a code for success? */
368              
369              
370              
371              
372             /*
373             =item i_bumpmap_complex(im, bump, channel, tx, ty, Lx, Ly, Lz, Ip, cd, cs, n, Ia, Il, Is)
374              
375             Makes a bumpmap on image im using the bump image as the elevation map.
376              
377             im - target image
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
385             Ip - light intensity
386             cd - diffuse coefficient
387             cs - specular coefficient
388             n - surface shinyness
389             Ia - ambient colour
390             Il - light colour
391             Is - specular colour
392              
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.
395              
396             =cut
397             */
398              
399              
400             void
401 1           i_bumpmap_complex(i_img *im,
402             i_img *bump,
403             int channel,
404             i_img_dim tx,
405             i_img_dim ty,
406             double Lx,
407             double Ly,
408             double Lz,
409             float cd,
410             float cs,
411             float n,
412             i_color *Ia,
413             i_color *Il,
414             i_color *Is) {
415             i_img new_im;
416            
417             i_img_dim x, y;
418             int ch;
419             i_img_dim mx, Mx, my, My;
420            
421             float cdc[MAXCHANNELS];
422             float csc[MAXCHANNELS];
423              
424             i_color x1_color, y1_color, x2_color, y2_color;
425              
426             i_color Scol; /* Surface colour */
427              
428             fvec L; /* Light vector */
429             fvec N; /* surface normal */
430             fvec R; /* Reflection vector */
431             fvec V; /* Vision vector */
432              
433 1           dIMCTXim(im);
434              
435 1           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));
438            
439 1 50         if (channel >= bump->channels) {
440 0           im_log((aIMCTX, 1, "i_bumpmap_complex: channel = %d while bump image only has %d channels\n", channel, bump->channels));
441 0           return;
442             }
443              
444 4 100         for(ch=0; chchannels; ch++) {
445 3           cdc[ch] = (float)Il->channel[ch]*cd/255.f;
446 3           csc[ch] = (float)Is->channel[ch]*cs/255.f;
447             }
448              
449 1           mx = 1;
450 1           my = 1;
451 1           Mx = bump->xsize-1;
452 1           My = bump->ysize-1;
453            
454 1           V.x = 0;
455 1           V.y = 0;
456 1           V.z = 1;
457            
458 1 50         if (Lz < 0) { /* Light specifies a direction vector, reverse it to get the vector from surface to light */
459 1           L.x = -Lx;
460 1           L.y = -Ly;
461 1           L.z = -Lz;
462 1           normalize(&L);
463             } else { /* Light is the position of the light source */
464 0           L.x = -0.2;
465 0           L.y = -0.4;
466 0           L.z = 1;
467 0           normalize(&L);
468             }
469              
470 1           i_img_empty_ch(&new_im, im->xsize, im->ysize, im->channels);
471              
472 151 100         for(y = 0; y < im->ysize; y++) {
473 22650 100         for(x = 0; x < im->xsize; x++) {
474             double dp1, dp2;
475 22500           double dx = 0, dy = 0;
476              
477             /* Calculate surface normal */
478 22500 100         if (mx
    100          
    100          
    100          
479 21609           i_gpix(bump, x + 1, y, &x1_color);
480 21609           i_gpix(bump, x - 1, y, &x2_color);
481 21609           i_gpix(bump, x, y + 1, &y1_color);
482 21609           i_gpix(bump, x, y - 1, &y2_color);
483 21609           dx = x2_color.channel[channel] - x1_color.channel[channel];
484 21609           dy = y2_color.channel[channel] - y1_color.channel[channel];
485             } else {
486 891           dx = 0;
487 891           dy = 0;
488             }
489 22500           N.x = -dx * 0.015;
490 22500           N.y = -dy * 0.015;
491 22500           N.z = 1;
492 22500           normalize(&N);
493              
494             /* Calculate Light vector if needed */
495 22500 50         if (Lz>=0) {
496 0           L.x = Lx - x;
497 0           L.y = Ly - y;
498 0           L.z = Lz;
499 0           normalize(&L);
500             }
501            
502 22500           dp1 = dotp(&L,&N);
503 22500           R.x = -L.x + 2*dp1*N.x;
504 22500           R.y = -L.y + 2*dp1*N.y;
505 22500           R.z = -L.z + 2*dp1*N.z;
506            
507 22500           dp2 = dotp(&R,&V);
508              
509 22500 100         dp1 = dp1<0 ?0 : dp1;
510 22500 100         dp2 = pow(dp2<0 ?0 : dp2,n);
511              
512 22500           i_gpix(im, x, y, &Scol);
513              
514 90000 100         for(ch = 0; ch < im->channels; ch++)
515 67500           Scol.channel[ch] =
516 67500           saturate( Ia->channel[ch] + cdc[ch]*Scol.channel[ch]*dp1 + csc[ch]*dp2 );
517            
518 22500           i_ppix(&new_im, x, y, &Scol);
519             }
520             }
521            
522 1           i_copyto(im, &new_im, 0, 0, im->xsize, im->ysize, 0, 0);
523 1           i_img_exorcise(&new_im);
524             }
525              
526              
527             /*
528             =item i_postlevels(im, levels)
529              
530             Quantizes Images to fewer levels.
531              
532             im - target image
533             levels - number of levels
534              
535             =cut
536             */
537              
538             void
539 1           i_postlevels(i_img *im, int levels) {
540             i_img_dim x, y;
541             int ch;
542             float pv;
543             int rv;
544             float av;
545              
546             i_color rcolor;
547              
548 1           rv = (int) ((float)(256 / levels));
549 1           av = (float)levels;
550              
551 22651 100         for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
    100          
552 22500           i_gpix(im, x, y, &rcolor);
553              
554 90000 100         for(ch = 0; ch < im->channels; ch++) {
555 67500           pv = (((float)rcolor.channel[ch] / 255)) * av;
556 67500           pv = (int) ((int)pv * rv);
557              
558 67500 50         if(pv < 0) pv = 0;
559 67500 50         else if(pv > 255) pv = 255;
560              
561 67500           rcolor.channel[ch] = (unsigned char) pv;
562             }
563 22500           i_ppix(im, x, y, &rcolor);
564             }
565 1           }
566              
567              
568             /*
569             =item i_mosaic(im, size)
570              
571             Makes an image looks like a mosaic with tilesize of size
572              
573             im - target image
574             size - size of tiles
575              
576             =cut
577             */
578              
579             void
580 1           i_mosaic(i_img *im, i_img_dim size) {
581             i_img_dim x, y;
582             int ch, z;
583             i_img_dim lx, ly;
584             long sqrsize;
585              
586             i_color rcolor;
587             long col[256];
588            
589 1           sqrsize = size * size;
590            
591 381 100         for(y = 0; y < im->ysize; y += size) for(x = 0; x < im->xsize; x += size) {
    100          
592 92777 100         for(z = 0; z < 256; z++) col[z] = 0;
593            
594 3249 100         for(lx = 0; lx < size; lx++) {
595 25992 100         for(ly = 0; ly < size; ly++) {
596 23104           i_gpix(im, (x + lx), (y + ly), &rcolor);
597            
598 92416 100         for(ch = 0; ch < im->channels; ch++) {
599 69312           col[ch] += rcolor.channel[ch];
600             }
601             }
602             }
603            
604 1444 100         for(ch = 0; ch < im->channels; ch++)
605 1083           rcolor.channel[ch] = (int) ((float)col[ch] / sqrsize);
606            
607            
608 3249 100         for(lx = 0; lx < size; lx++)
609 25992 100         for(ly = 0; ly < size; ly++)
610 23104           i_ppix(im, (x + lx), (y + ly), &rcolor);
611            
612             }
613 1           }
614              
615              
616             /*
617             =item i_watermark(im, wmark, tx, ty, pixdiff)
618              
619             Applies a watermark to the target image
620              
621             im - 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
626              
627             =cut
628             */
629              
630             void
631 1           i_watermark(i_img *im, i_img *wmark, i_img_dim tx, i_img_dim ty, int pixdiff) {
632             i_img_dim vx, vy;
633             int ch;
634             i_color val, wval;
635              
636 1           i_img_dim mx = wmark->xsize;
637 1           i_img_dim my = wmark->ysize;
638              
639 22651 100         for(vx=0;vx
    100          
640            
641 22500           i_gpix(im, tx+vx, ty+vy,&val );
642 22500           i_gpix(wmark, vx, vy, &wval);
643            
644 90000 100         for(ch=0;chchannels;ch++)
645 67500           val.channel[ch] = saturate( val.channel[ch] + (pixdiff* (wval.channel[0]-128) )/128 );
646            
647 22500           i_ppix(im,tx+vx,ty+vy,&val);
648             }
649 1           }
650              
651             /*
652             =item i_autolevels_mono(im, lsat, usat)
653              
654             Do autolevels, but monochromatically.
655              
656             =cut
657             */
658              
659             void
660 3           i_autolevels_mono(i_img *im, float lsat, float usat) {
661             i_color val;
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;
665             i_color *row;
666 3           dIMCTXim(im);
667 3 50         int adapt_channels = im->channels == 4 ? 2 : 1;
668 3           int color_channels = i_img_color_channels(im);
669 3           i_img_dim color_samples = im->xsize * color_channels;
670            
671              
672 3           im_log((aIMCTX, 1,"i_autolevels_mono(im %p, lsat %f,usat %f)\n", im, lsat,usat));
673              
674             /* build the histogram in 8-bits, unless the image has a very small
675             range it should make little difference to the result */
676 3           sum_lum = 0;
677 771 100         for (i = 0; i < 256; i++)
678 768           hist[i] = 0;
679              
680 3           row = mymalloc(im->xsize * sizeof(i_color));
681             /* create histogram for each channel */
682 173 100         for (y = 0; y < im->ysize; y++) {
683 170           i_color *p = row;
684 170           i_glin(im, 0, im->xsize, y, row);
685 170 50         if (im->channels > 2)
686 170           i_adapt_colors(adapt_channels, im->channels, row, im->xsize);
687 22870 100         for (x = 0; x < im->xsize; x++) {
688 22700           hist[p->channel[0]]++;
689 22700           ++p;
690             }
691             }
692 3           myfree(row);
693              
694 771 100         for(i = 0; i < 256; i++) {
695 768           sum_lum += hist[i];
696             }
697            
698 3           min_lum = 0;
699 3           lower_accum = 0;
700 771 100         for (i = 0; i < 256; ++i) {
701 768 100         if (lower_accum < sum_lum * lsat)
702 131           min_lum = i;
703 768           lower_accum += hist[i];
704             }
705              
706 3           max_lum = 255;
707 3           upper_accum = 0;
708 771 100         for(i = 255; i >= 0; i--) {
709 768 100         if (upper_accum < sum_lum * usat)
710 205           max_lum = i;
711 768           upper_accum += hist[i];
712             }
713              
714 3 100         #code im->bits <= 8
715 3           IM_SAMPLE_T *srow = mymalloc(color_samples * sizeof(IM_SAMPLE_T));
716             #ifdef IM_EIGHT_BIT
717 2           IM_WORK_T low = min_lum;
718             i_sample_t lookup[256];
719             #else
720 1           IM_WORK_T low = min_lum / 255.0 * IM_SAMPLE_MAX;
721             #endif
722 3           double scale = 255.0 / (max_lum - min_lum);
723              
724             #ifdef IM_EIGHT_BIT
725 514 100         for (i = 0; i < 256; ++i) {
726 512           IM_WORK_T tmp = (i - low) * scale;
727 512 100         lookup[i] = IM_LIMIT(tmp);
728             }
729             #endif
730              
731 173 100         for(y = 0; y < im->ysize; y++) {
    100          
732 170           IM_GSAMP(im, 0, im->xsize, y, srow, NULL, color_channels);
733 68270 100         for(i = 0; i < color_samples; ++i) {
    100          
734             #ifdef IM_EIGHT_BIT
735 67800           srow[i] = lookup[srow[i]];
736             #else
737 300           IM_WORK_T tmp = (srow[i] - low) * scale;
738 300 50         srow[i] = IM_LIMIT(tmp);
    50          
739             #endif
740             }
741 170           IM_PSAMP(im, 0, im->xsize, y, srow, NULL, color_channels);
742             }
743 3           myfree(srow);
744             #/code
745 3           }
746              
747              
748             /*
749             =item i_autolevels(im, lsat, usat, skew)
750              
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.
754              
755             im - target image
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
758             skew - not used yet
759              
760             Note: this code calculates levels and adjusts each channel separately,
761             which will typically cause a color shift.
762              
763             =cut
764             */
765              
766             void
767 1           i_autolevels(i_img *im, float lsat, float usat, float skew) {
768             i_color val;
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;
774 1           dIMCTXim(im);
775              
776 1           im_log((aIMCTX, 1,"i_autolevels(im %p, lsat %f,usat %f,skew %f)\n", im, lsat,usat,skew));
777              
778 1           rsum=gsum=bsum=0;
779 257 100         for(i=0;i<256;i++) rhist[i]=ghist[i]=bhist[i] = 0;
780             /* create histogram for each channel */
781 22651 100         for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
    100          
782 22500           i_gpix(im, x, y, &val);
783 22500           rhist[val.channel[0]]++;
784 22500           ghist[val.channel[1]]++;
785 22500           bhist[val.channel[2]]++;
786             }
787              
788 257 100         for(i=0;i<256;i++) {
789 256           rsum+=rhist[i];
790 256           gsum+=ghist[i];
791 256           bsum+=bhist[i];
792             }
793            
794 1           rmin = gmin = bmin = 0;
795 1           rmax = gmax = bmax = 255;
796            
797 1           rcu = rcl = gcu = gcl = bcu = bcl = 0;
798            
799 257 100         for(i=0; i<256; i++) {
800 256 50         rcl += rhist[i]; if ( (rcl
801 256 100         rcu += rhist[255-i]; if ( (rcu
802              
803 256 50         gcl += ghist[i]; if ( (gcl
804 256 100         gcu += ghist[255-i]; if ( (gcu
805              
806 256 50         bcl += bhist[i]; if ( (bcl
807 256 100         bcu += bhist[255-i]; if ( (bcu
808             }
809              
810 22651 100         for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
    100          
811 22500           i_gpix(im, x, y, &val);
812 22500           val.channel[0]=saturate((val.channel[0]-rmin)*255/(rmax-rmin));
813 22500           val.channel[1]=saturate((val.channel[1]-gmin)*255/(gmax-gmin));
814 22500           val.channel[2]=saturate((val.channel[2]-bmin)*255/(bmax-bmin));
815 22500           i_ppix(im, x, y, &val);
816             }
817 1           }
818              
819             /*
820             =item Noise(x,y)
821              
822             Pseudo noise utility function used to generate perlin noise. (internal)
823              
824             x - x coordinate
825             y - y coordinate
826              
827             =cut
828             */
829              
830             static
831             double
832 8100000           Noise(i_img_dim x, i_img_dim y) {
833 8100000           i_img_dim n = x + y * 57;
834 8100000           n = (n<<13) ^ n;
835 8100000           return ( 1.0 - ( (n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff) / 1073741824.0);
836             }
837              
838             /*
839             =item SmoothedNoise1(x,y)
840              
841             Pseudo noise utility function used to generate perlin noise. (internal)
842              
843             x - x coordinate
844             y - y coordinate
845              
846             =cut
847             */
848              
849             static
850             double
851 900000           SmoothedNoise1(double x, double y) {
852 900000           double corners = ( Noise(x-1, y-1)+Noise(x+1, y-1)+Noise(x-1, y+1)+Noise(x+1, y+1) ) / 16;
853 900000           double sides = ( Noise(x-1, y) +Noise(x+1, y) +Noise(x, y-1) +Noise(x, y+1) ) / 8;
854 900000           double center = Noise(x, y) / 4;
855 900000           return corners + sides + center;
856             }
857              
858              
859             /*
860             =item G_Interpolate(a, b, x)
861              
862             Utility function used to generate perlin noise. (internal)
863              
864             =cut
865             */
866              
867             static
868             double
869 675000           C_Interpolate(double a, double b, double x) {
870             /* float ft = x * 3.1415927; */
871 675000           double ft = x * PI;
872 675000           double f = (1 - cos(ft)) * .5;
873 675000           return a*(1-f) + b*f;
874             }
875              
876              
877             /*
878             =item InterpolatedNoise(x, y)
879              
880             Utility function used to generate perlin noise. (internal)
881              
882             =cut
883             */
884              
885             static
886             double
887 225000           InterpolatedNoise(double x, double y) {
888              
889 225000           i_img_dim integer_X = x;
890 225000           double fractional_X = x - integer_X;
891 225000           i_img_dim integer_Y = y;
892 225000           double fractional_Y = y - integer_Y;
893              
894 225000           double v1 = SmoothedNoise1(integer_X, integer_Y);
895 225000           double v2 = SmoothedNoise1(integer_X + 1, integer_Y);
896 225000           double v3 = SmoothedNoise1(integer_X, integer_Y + 1);
897 225000           double v4 = SmoothedNoise1(integer_X + 1, integer_Y + 1);
898              
899 225000           double i1 = C_Interpolate(v1 , v2 , fractional_X);
900 225000           double i2 = C_Interpolate(v3 , v4 , fractional_X);
901              
902 225000           return C_Interpolate(i1 , i2 , fractional_Y);
903             }
904              
905              
906              
907             /*
908             =item PerlinNoise_2D(x, y)
909              
910             Utility function used to generate perlin noise. (internal)
911              
912             =cut
913             */
914              
915             static
916             float
917 45000           PerlinNoise_2D(float x, float y) {
918             int i;
919             double frequency;
920             double amplitude;
921 45000           double total = 0;
922 45000           int Number_Of_Octaves=6;
923 45000           int n = Number_Of_Octaves - 1;
924              
925 270000 100         for(i=0;i
926 225000           frequency = 2.0 * i;
927 225000           amplitude = PI;
928 225000           total = total + InterpolatedNoise(x * frequency, y * frequency) * amplitude;
929             }
930              
931 45000           return total;
932             }
933              
934              
935             /*
936             =item i_radnoise(im, xo, yo, rscale, ascale)
937              
938             Perlin-like radial noise.
939              
940             im - target image
941             xo - x coordinate of center
942             yo - y coordinate of center
943             rscale - radial scale
944             ascale - angular scale
945              
946             =cut
947             */
948              
949             void
950 1           i_radnoise(i_img *im, i_img_dim xo, i_img_dim yo, double rscale, double ascale) {
951             i_img_dim x, y;
952             int ch;
953             i_color val;
954             unsigned char v;
955             double xc, yc, r;
956             double a;
957            
958 22651 100         for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
    100          
959 22500           xc = (double)x-xo+0.5;
960 22500           yc = (double)y-yo+0.5;
961 22500           r = rscale*sqrt(xc*xc+yc*yc)+1.2;
962 22500           a = (PI+atan2(yc,xc))*ascale;
963 22500           v = saturate(128+100*(PerlinNoise_2D(a,r)));
964             /* v=saturate(120+12*PerlinNoise_2D(xo+(float)x/scale,yo+(float)y/scale)); Good soft marble */
965 90000 100         for(ch=0; chchannels; ch++) val.channel[ch]=v;
966 22500           i_ppix(im, x, y, &val);
967             }
968 1           }
969              
970              
971             /*
972             =item i_turbnoise(im, xo, yo, scale)
973              
974             Perlin-like 2d noise noise.
975              
976             im - target image
977             xo - x coordinate translation
978             yo - y coordinate translation
979             scale - scale of noise
980              
981             =cut
982             */
983              
984             void
985 1           i_turbnoise(i_img *im, double xo, double yo, double scale) {
986             i_img_dim x,y;
987             int ch;
988             unsigned char v;
989             i_color val;
990              
991 22651 100         for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
    100          
992             /* v=saturate(125*(1.0+PerlinNoise_2D(xo+(float)x/scale,yo+(float)y/scale))); */
993 22500           v = saturate(120*(1.0+sin(xo+(double)x/scale+PerlinNoise_2D(xo+(double)x/scale,yo+(float)y/scale))));
994 90000 100         for(ch=0; chchannels; ch++) val.channel[ch] = v;
995 22500           i_ppix(im, x, y, &val);
996             }
997 1           }
998              
999              
1000              
1001             /*
1002             =item i_gradgen(im, num, xo, yo, ival, dmeasure)
1003              
1004             Gradient generating function.
1005              
1006             im - target image
1007             num - number of points given
1008             xo - array of x coordinates
1009             yo - array of y coordinates
1010             ival - array of i_color objects
1011             dmeasure - distance measure to be used.
1012             0 = Euclidean
1013             1 = Euclidean squared
1014             2 = Manhattan distance
1015              
1016             =cut
1017             */
1018              
1019              
1020             void
1021 1           i_gradgen(i_img *im, int num, i_img_dim *xo, i_img_dim *yo, i_color *ival, int dmeasure) {
1022            
1023             i_color val;
1024             int p, ch;
1025             i_img_dim x, y;
1026 1           int channels = im->channels;
1027 1           i_img_dim xsize = im->xsize;
1028 1           i_img_dim ysize = im->ysize;
1029             size_t bytes;
1030              
1031             double *fdist;
1032 1           dIMCTXim(im);
1033              
1034 1           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            
1036 4 100         for(p = 0; p
1037 3           im_log((aIMCTX,1,"i_gradgen: p%d(" i_DFp ")\n", p, i_DFcp(xo[p], yo[p])));
1038 3           ICL_info(&ival[p]);
1039             }
1040              
1041             /* on the systems I have sizeof(float) == sizeof(int) and thus
1042             this would be same size as the arrays xo and yo point at, but this
1043             may not be true for other systems
1044              
1045             since the arrays here are caller controlled, I assume that on
1046             overflow is a programming error rather than an end-user error, so
1047             calling exit() is justified.
1048             */
1049 1           bytes = sizeof(double) * num;
1050 1 50         if (bytes / num != sizeof(double)) {
1051 0           fprintf(stderr, "integer overflow calculating memory allocation");
1052 0           exit(1);
1053             }
1054 1           fdist = mymalloc( bytes ); /* checked 14jul05 tonyc */
1055            
1056 22651 100         for(y = 0; y
    100          
1057 22500           double cs = 0;
1058 22500           double csd = 0;
1059 90000 100         for(p = 0; p
1060 67500           i_img_dim xd = x-xo[p];
1061 67500           i_img_dim yd = y-yo[p];
1062 67500           switch (dmeasure) {
1063             case 0: /* euclidean */
1064 0           fdist[p] = sqrt(xd*xd + yd*yd); /* euclidean distance */
1065 0           break;
1066             case 1: /* euclidean squared */
1067 67500           fdist[p] = xd*xd + yd*yd; /* euclidean distance */
1068 67500           break;
1069             case 2: /* euclidean squared */
1070 0           fdist[p] = i_max(xd*xd, yd*yd); /* manhattan distance */
1071 0           break;
1072             default:
1073 0           im_fatal(aIMCTX, 3,"i_gradgen: Unknown distance measure\n");
1074             }
1075 67500           cs += fdist[p];
1076             }
1077            
1078 22500           csd = 1/((num-1)*cs);
1079              
1080 90000 100         for(p = 0; p
1081            
1082 90000 100         for(ch = 0; ch
1083 67500           int tres = 0;
1084 270000 100         for(p = 0; p
1085 67500           val.channel[ch] = saturate(tres);
1086             }
1087 22500           i_ppix(im, x, y, &val);
1088             }
1089 1           myfree(fdist);
1090            
1091 1           }
1092              
1093             void
1094 1           i_nearest_color_foo(i_img *im, int num, i_img_dim *xo, i_img_dim *yo, i_color *ival, int dmeasure) {
1095              
1096             int p;
1097             i_img_dim x, y;
1098 1           i_img_dim xsize = im->xsize;
1099 1           i_img_dim ysize = im->ysize;
1100 1           dIMCTXim(im);
1101              
1102 1           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            
1104 4 100         for(p = 0; p
1105 3           im_log((aIMCTX, 1,"i_gradgen: p%d(" i_DFp ")\n", p, i_DFcp(xo[p], yo[p])));
1106 3           ICL_info(&ival[p]);
1107             }
1108              
1109 22651 100         for(y = 0; y
    100          
1110 22500           int midx = 0;
1111 22500           double mindist = 0;
1112 22500           double curdist = 0;
1113              
1114 22500           i_img_dim xd = x-xo[0];
1115 22500           i_img_dim yd = y-yo[0];
1116              
1117 22500           switch (dmeasure) {
1118             case 0: /* euclidean */
1119 0           mindist = sqrt(xd*xd + yd*yd); /* euclidean distance */
1120 0           break;
1121             case 1: /* euclidean squared */
1122 22500           mindist = xd*xd + yd*yd; /* euclidean distance */
1123 22500           break;
1124             case 2: /* euclidean squared */
1125 0           mindist = i_max(xd*xd, yd*yd); /* manhattan distance */
1126 0           break;
1127             default:
1128 0           im_fatal(aIMCTX, 3,"i_nearest_color: Unknown distance measure\n");
1129             }
1130              
1131 67500 100         for(p = 1; p
1132 45000           xd = x-xo[p];
1133 45000           yd = y-yo[p];
1134 45000           switch (dmeasure) {
1135             case 0: /* euclidean */
1136 0           curdist = sqrt(xd*xd + yd*yd); /* euclidean distance */
1137 0           break;
1138             case 1: /* euclidean squared */
1139 45000           curdist = xd*xd + yd*yd; /* euclidean distance */
1140 45000           break;
1141             case 2: /* euclidean squared */
1142 0           curdist = i_max(xd*xd, yd*yd); /* manhattan distance */
1143 0           break;
1144             default:
1145 0           im_fatal(aIMCTX, 3,"i_nearest_color: Unknown distance measure\n");
1146             }
1147 45000 100         if (curdist < mindist) {
1148 23182           mindist = curdist;
1149 23182           midx = p;
1150             }
1151             }
1152 22500           i_ppix(im, x, y, &ival[midx]);
1153             }
1154 1           }
1155              
1156             /*
1157             =item i_nearest_color(im, num, xo, yo, oval, dmeasure)
1158              
1159             This wasn't document - quoth Addi:
1160              
1161             An arty type of filter
1162              
1163             FIXME: check IRC logs for actual text.
1164              
1165             Inputs:
1166              
1167             =over
1168              
1169             =item *
1170              
1171             i_img *im - image to render on.
1172              
1173             =item *
1174              
1175             int num - number of points/colors in xo, yo, oval
1176              
1177             =item *
1178              
1179             i_img_dim *xo - array of I x positions
1180              
1181             =item *
1182              
1183             i_img_dim *yo - array of I y positions
1184              
1185             =item *
1186              
1187             i_color *oval - array of I colors
1188              
1189             xo, yo, oval correspond to each other, the point xo[i], yo[i] has a
1190             color something like oval[i], at least closer to that color than other
1191             points.
1192              
1193             =item *
1194              
1195             int dmeasure - how we measure the distance from some point P(x,y) to
1196             any (xo[i], yo[i]).
1197              
1198             Valid values are:
1199              
1200             =over
1201              
1202             =item 0
1203              
1204             euclidean distance: sqrt((x2-x1)**2 + (y2-y1)**2)
1205              
1206             =item 1
1207              
1208             square of euclidean distance: ((x2-x1)**2 + (y2-y1)**2)
1209              
1210             =item 2
1211              
1212             manhattan distance: max((y2-y1)**2, (x2-x1)**2)
1213              
1214             =back
1215              
1216             An invalid value causes an error exit (the program is aborted).
1217              
1218             =back
1219              
1220             =cut
1221             */
1222              
1223             int
1224 1           i_nearest_color(i_img *im, int num, i_img_dim *xo, i_img_dim *yo, i_color *oval, int dmeasure) {
1225             i_color *ival;
1226             float *tval;
1227             double c1, c2;
1228             i_color val;
1229             int p, ch;
1230             i_img_dim x, y;
1231 1           i_img_dim xsize = im->xsize;
1232 1           i_img_dim ysize = im->ysize;
1233             int *cmatch;
1234             size_t ival_bytes, tval_bytes;
1235 1           dIMCTXim(im);
1236              
1237 1           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));
1238              
1239 1           i_clear_error();
1240              
1241 1 50         if (num <= 0) {
1242 0           i_push_error(0, "no points supplied to nearest_color filter");
1243 0           return 0;
1244             }
1245              
1246 1 50         if (dmeasure < 0 || dmeasure > i_dmeasure_limit) {
    50          
1247 0           i_push_error(0, "distance measure invalid");
1248 0           return 0;
1249             }
1250              
1251 1           tval_bytes = sizeof(float)*num*im->channels;
1252 1 50         if (tval_bytes / num != sizeof(float) * im->channels) {
1253 0           i_push_error(0, "integer overflow calculating memory allocation");
1254 0           return 0;
1255             }
1256 1           ival_bytes = sizeof(i_color) * num;
1257 1 50         if (ival_bytes / sizeof(i_color) != num) {
1258 0           i_push_error(0, "integer overflow calculating memory allocation");
1259 0           return 0;
1260             }
1261 1           tval = mymalloc( tval_bytes ); /* checked 17feb2005 tonyc */
1262 1           ival = mymalloc( ival_bytes ); /* checked 17feb2005 tonyc */
1263 1           cmatch = mymalloc( sizeof(int)*num ); /* checked 17feb2005 tonyc */
1264              
1265 4 100         for(p = 0; p
1266 12 100         for(ch = 0; chchannels; ch++) tval[ p * im->channels + ch] = 0;
1267 3           cmatch[p] = 0;
1268             }
1269              
1270            
1271 22651 100         for(y = 0; y
    100          
1272 22500           int midx = 0;
1273 22500           double mindist = 0;
1274 22500           double curdist = 0;
1275            
1276 22500           i_img_dim xd = x-xo[0];
1277 22500           i_img_dim yd = y-yo[0];
1278              
1279 22500           switch (dmeasure) {
1280             case 0: /* euclidean */
1281 0           mindist = sqrt(xd*xd + yd*yd); /* euclidean distance */
1282 0           break;
1283             case 1: /* euclidean squared */
1284 22500           mindist = xd*xd + yd*yd; /* euclidean distance */
1285 22500           break;
1286             case 2: /* manhatten distance */
1287 0           mindist = i_max(xd*xd, yd*yd); /* manhattan distance */
1288 0           break;
1289             default:
1290 0           im_fatal(aIMCTX, 3,"i_nearest_color: Unknown distance measure\n");
1291             }
1292            
1293 67500 100         for(p = 1; p
1294 45000           xd = x-xo[p];
1295 45000           yd = y-yo[p];
1296 45000           switch (dmeasure) {
1297             case 0: /* euclidean */
1298 0           curdist = sqrt(xd*xd + yd*yd); /* euclidean distance */
1299 0           break;
1300             case 1: /* euclidean squared */
1301 45000           curdist = xd*xd + yd*yd; /* euclidean distance */
1302 45000           break;
1303             case 2: /* euclidean squared */
1304 0           curdist = i_max(xd*xd, yd*yd); /* manhattan distance */
1305 0           break;
1306             default:
1307 0           im_fatal(aIMCTX, 3,"i_nearest_color: Unknown distance measure\n");
1308             }
1309 45000 100         if (curdist < mindist) {
1310 23182           mindist = curdist;
1311 23182           midx = p;
1312             }
1313             }
1314              
1315 22500           cmatch[midx]++;
1316 22500           i_gpix(im, x, y, &val);
1317 22500           c2 = 1.0/(float)(cmatch[midx]);
1318 22500           c1 = 1.0-c2;
1319            
1320 90000 100         for(ch = 0; chchannels; ch++)
1321 135000           tval[midx*im->channels + ch] =
1322 67500           c1*tval[midx*im->channels + ch] + c2 * (float) val.channel[ch];
1323            
1324             }
1325              
1326 4 100         for(p = 0; p
1327 12 100         for(ch = 0; chchannels; ch++)
1328 9           ival[p].channel[ch] = tval[p*im->channels + ch];
1329              
1330             /* avoid uninitialized value messages from valgrind */
1331 6 100         while (ch < MAXCHANNELS)
1332 3           ival[p].channel[ch++] = 0;
1333             }
1334              
1335 1           i_nearest_color_foo(im, num, xo, yo, ival, dmeasure);
1336              
1337 1           myfree(cmatch);
1338 1           myfree(ival);
1339 1           myfree(tval);
1340              
1341 1           return 1;
1342             }
1343              
1344             /*
1345             =item i_unsharp_mask(im, stddev, scale)
1346              
1347             Perform an usharp mask, which is defined as subtracting the blurred
1348             image from double the original.
1349              
1350             =cut
1351             */
1352              
1353             void
1354 1           i_unsharp_mask(i_img *im, double stddev, double scale) {
1355             i_img *copy;
1356             i_img_dim x, y;
1357             int ch;
1358              
1359 1 50         if (scale < 0)
1360 0           return;
1361             /* it really shouldn't ever be more than 1.0, but maybe ... */
1362 1 50         if (scale > 100)
1363 0           scale = 100;
1364              
1365 1           copy = i_copy(im);
1366 1           i_gaussian(copy, stddev);
1367 1 50         if (im->bits == i_8_bits) {
1368 1           i_color *blur = mymalloc(im->xsize * sizeof(i_color)); /* checked 17feb2005 tonyc */
1369 1           i_color *out = mymalloc(im->xsize * sizeof(i_color)); /* checked 17feb2005 tonyc */
1370              
1371 151 100         for (y = 0; y < im->ysize; ++y) {
1372 150           i_glin(copy, 0, copy->xsize, y, blur);
1373 150           i_glin(im, 0, im->xsize, y, out);
1374 22650 100         for (x = 0; x < im->xsize; ++x) {
1375 90000 100         for (ch = 0; ch < im->channels; ++ch) {
1376             /*int temp = out[x].channel[ch] +
1377             scale * (out[x].channel[ch] - blur[x].channel[ch]);*/
1378 67500           int temp = out[x].channel[ch] * 2 - blur[x].channel[ch];
1379 67500 100         if (temp < 0)
1380 4602           temp = 0;
1381 62898 100         else if (temp > 255)
1382 3167           temp = 255;
1383 67500           out[x].channel[ch] = temp;
1384             }
1385             }
1386 150           i_plin(im, 0, im->xsize, y, out);
1387             }
1388              
1389 1           myfree(blur);
1390 1           myfree(out);
1391             }
1392             else {
1393 0           i_fcolor *blur = mymalloc(im->xsize * sizeof(i_fcolor)); /* checked 17feb2005 tonyc */
1394 0           i_fcolor *out = mymalloc(im->xsize * sizeof(i_fcolor)); /* checked 17feb2005 tonyc */
1395              
1396 0 0         for (y = 0; y < im->ysize; ++y) {
1397 0           i_glinf(copy, 0, copy->xsize, y, blur);
1398 0           i_glinf(im, 0, im->xsize, y, out);
1399 0 0         for (x = 0; x < im->xsize; ++x) {
1400 0 0         for (ch = 0; ch < im->channels; ++ch) {
1401 0           double temp = out[x].channel[ch] +
1402 0           scale * (out[x].channel[ch] - blur[x].channel[ch]);
1403 0 0         if (temp < 0)
1404 0           temp = 0;
1405 0 0         else if (temp > 1.0)
1406 0           temp = 1.0;
1407 0           out[x].channel[ch] = temp;
1408             }
1409             }
1410 0           i_plinf(im, 0, im->xsize, y, out);
1411             }
1412              
1413 0           myfree(blur);
1414 0           myfree(out);
1415             }
1416 1           i_img_destroy(copy);
1417             }
1418              
1419             /*
1420             =item i_diff_image(im1, im2, mindist)
1421              
1422             Creates a new image that is transparent, except where the pixel in im2
1423             is different from im1, where it is the pixel from im2.
1424              
1425             The samples must differ by at least mindiff to be considered different.
1426              
1427             =cut
1428             */
1429              
1430             i_img *
1431 5           i_diff_image(i_img *im1, i_img *im2, double mindist) {
1432             i_img *out;
1433             int outchans, diffchans;
1434             i_img_dim xsize, ysize;
1435 5           dIMCTXim(im1);
1436              
1437 5           i_clear_error();
1438 5 50         if (im1->channels != im2->channels) {
1439 0           i_push_error(0, "different number of channels");
1440 0           return NULL;
1441             }
1442              
1443 5           outchans = diffchans = im1->channels;
1444 5 50         if (outchans == 1 || outchans == 3)
    50          
1445 5           ++outchans;
1446              
1447 5           xsize = i_min(im1->xsize, im2->xsize);
1448 5           ysize = i_min(im1->ysize, im2->ysize);
1449              
1450 5           out = i_sametype_chans(im1, xsize, ysize, outchans);
1451              
1452 8 100         if (im1->bits == i_8_bits && im2->bits == i_8_bits) {
    50          
1453 3           i_color *line1 = mymalloc(xsize * sizeof(*line1)); /* checked 17feb2005 tonyc */
1454 3           i_color *line2 = mymalloc(xsize * sizeof(*line1)); /* checked 17feb2005 tonyc */
1455             i_color empty;
1456             i_img_dim x, y;
1457             int ch;
1458 3           int imindist = (int)mindist;
1459              
1460 15 100         for (ch = 0; ch < MAXCHANNELS; ++ch)
1461 12           empty.channel[ch] = 0;
1462              
1463 157 100         for (y = 0; y < ysize; ++y) {
1464 154           i_glin(im1, 0, xsize, y, line1);
1465 154           i_glin(im2, 0, xsize, y, line2);
1466 154 50         if (outchans != diffchans) {
1467             /* give the output an alpha channel since it doesn't have one */
1468 22666 100         for (x = 0; x < xsize; ++x)
1469 22512           line2[x].channel[diffchans] = 255;
1470             }
1471 22666 100         for (x = 0; x < xsize; ++x) {
1472 22512           int diff = 0;
1473 88719 100         for (ch = 0; ch < diffchans; ++ch) {
1474 66651 100         if (line1[x].channel[ch] != line2[x].channel[ch]
1475 445 100         && abs(line1[x].channel[ch] - line2[x].channel[ch]) > imindist) {
1476 444           diff = 1;
1477 444           break;
1478             }
1479             }
1480 22512 100         if (!diff)
1481 22068           line2[x] = empty;
1482             }
1483 154           i_plin(out, 0, xsize, y, line2);
1484             }
1485 3           myfree(line1);
1486 3           myfree(line2);
1487             }
1488             else {
1489 2           i_fcolor *line1 = mymalloc(xsize * sizeof(*line1)); /* checked 17feb2005 tonyc */
1490 2           i_fcolor *line2 = mymalloc(xsize * sizeof(*line2)); /* checked 17feb2005 tonyc */
1491             i_fcolor empty;
1492             i_img_dim x, y;
1493             int ch;
1494 2           double dist = mindist / 255.0;
1495              
1496 10 100         for (ch = 0; ch < MAXCHANNELS; ++ch)
1497 8           empty.channel[ch] = 0;
1498              
1499 6 100         for (y = 0; y < ysize; ++y) {
1500 4           i_glinf(im1, 0, xsize, y, line1);
1501 4           i_glinf(im2, 0, xsize, y, line2);
1502 4 50         if (outchans != diffchans) {
1503             /* give the output an alpha channel since it doesn't have one */
1504 16 100         for (x = 0; x < xsize; ++x)
1505 12           line2[x].channel[diffchans] = 1.0;
1506             }
1507 16 100         for (x = 0; x < xsize; ++x) {
1508 12           int diff = 0;
1509 42 100         for (ch = 0; ch < diffchans; ++ch) {
1510 33 100         if (line1[x].channel[ch] != line2[x].channel[ch]
1511 4 100         && fabs(line1[x].channel[ch] - line2[x].channel[ch]) > dist) {
1512 3           diff = 1;
1513 3           break;
1514             }
1515             }
1516 12 100         if (!diff)
1517 9           line2[x] = empty;
1518             }
1519 4           i_plinf(out, 0, xsize, y, line2);
1520             }
1521 2           myfree(line1);
1522 2           myfree(line2);
1523             }
1524              
1525 5           return out;
1526             }
1527              
1528             /*
1529             =item i_rgbdiff_image(im1, im2)
1530              
1531             Creates a new image that is black, except where the pixel in im2 is
1532             different from im1, where it is the arithmetical difference to im2 per
1533             color.
1534              
1535             =cut
1536             */
1537              
1538             i_img *
1539 1           i_rgbdiff_image(i_img *im1, i_img *im2) {
1540             i_img *out;
1541             int outchans, diffchans;
1542             i_img_dim xsize, ysize;
1543 1           dIMCTXim(im1);
1544              
1545 1           i_clear_error();
1546 1 50         if (im1->channels != im2->channels) {
1547 0           i_push_error(0, "different number of channels");
1548 0           return NULL;
1549             }
1550              
1551 1           outchans = diffchans = im1->channels;
1552 1 50         if (outchans == 2 || outchans == 4)
    50          
1553 1           --outchans;
1554              
1555 1           xsize = i_min(im1->xsize, im2->xsize);
1556 1           ysize = i_min(im1->ysize, im2->ysize);
1557              
1558 1           out = i_sametype_chans(im1, xsize, ysize, outchans);
1559              
1560 2 50         #code im1->bits == i_8_bits && im2->bits == i_8_bits
    50          
1561 1           IM_COLOR *line1 = mymalloc(xsize * sizeof(*line1));
1562 1           IM_COLOR *line2 = mymalloc(xsize * sizeof(*line1));
1563             i_img_dim x, y;
1564             int ch;
1565              
1566 3 100         for (y = 0; y < ysize; ++y) {
    0          
1567 2           IM_GLIN(im1, 0, xsize, y, line1);
1568 2           IM_GLIN(im2, 0, xsize, y, line2);
1569 8 100         for (x = 0; x < xsize; ++x) {
    0          
1570 24 100         for (ch = 0; ch < outchans; ++ch) {
    0          
1571 18           line2[x].channel[ch] = IM_ABS(line1[x].channel[ch] - line2[x].channel[ch]);
1572             }
1573             }
1574 2           IM_PLIN(out, 0, xsize, y, line2);
1575             }
1576 1           myfree(line1);
1577 1           myfree(line2);
1578             #/code
1579              
1580 1           return out;
1581             }
1582              
1583             struct fount_state;
1584             static double linear_fount_f(double x, double y, struct fount_state *state);
1585             static double bilinear_fount_f(double x, double y, struct fount_state *state);
1586             static double radial_fount_f(double x, double y, struct fount_state *state);
1587             static double square_fount_f(double x, double y, struct fount_state *state);
1588             static double revolution_fount_f(double x, double y,
1589             struct fount_state *state);
1590             static double conical_fount_f(double x, double y, struct fount_state *state);
1591              
1592             typedef double (*fount_func)(double, double, struct fount_state *);
1593             static fount_func fount_funcs[] =
1594             {
1595             linear_fount_f,
1596             bilinear_fount_f,
1597             radial_fount_f,
1598             square_fount_f,
1599             revolution_fount_f,
1600             conical_fount_f,
1601             };
1602              
1603             static double linear_interp(double pos, i_fountain_seg *seg);
1604             static double sine_interp(double pos, i_fountain_seg *seg);
1605             static double sphereup_interp(double pos, i_fountain_seg *seg);
1606             static double spheredown_interp(double pos, i_fountain_seg *seg);
1607             typedef double (*fount_interp)(double pos, i_fountain_seg *seg);
1608             static fount_interp fount_interps[] =
1609             {
1610             linear_interp,
1611             linear_interp,
1612             sine_interp,
1613             sphereup_interp,
1614             spheredown_interp,
1615             };
1616              
1617             static void direct_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg);
1618             static void hue_up_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg);
1619             static void hue_down_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg);
1620             typedef void (*fount_cinterp)(i_fcolor *out, double pos, i_fountain_seg *seg);
1621             static fount_cinterp fount_cinterps[] =
1622             {
1623             direct_cinterp,
1624             hue_up_cinterp,
1625             hue_down_cinterp,
1626             };
1627              
1628             typedef double (*fount_repeat)(double v);
1629             static double fount_r_none(double v);
1630             static double fount_r_sawtooth(double v);
1631             static double fount_r_triangle(double v);
1632             static double fount_r_saw_both(double v);
1633             static double fount_r_tri_both(double v);
1634             static fount_repeat fount_repeats[] =
1635             {
1636             fount_r_none,
1637             fount_r_sawtooth,
1638             fount_r_triangle,
1639             fount_r_saw_both,
1640             fount_r_tri_both,
1641             };
1642              
1643             static int simple_ssample(i_fcolor *out, double x, double y,
1644             struct fount_state *state);
1645             static int random_ssample(i_fcolor *out, double x, double y,
1646             struct fount_state *state);
1647             static int circle_ssample(i_fcolor *out, double x, double y,
1648             struct fount_state *state);
1649             typedef int (*fount_ssample)(i_fcolor *out, double x, double y,
1650             struct fount_state *state);
1651             static fount_ssample fount_ssamples[] =
1652             {
1653             NULL,
1654             simple_ssample,
1655             random_ssample,
1656             circle_ssample,
1657             };
1658              
1659             static int
1660             fount_getat(i_fcolor *out, double x, double y, struct fount_state *state);
1661              
1662             /*
1663             Keep state information used by each type of fountain fill
1664             */
1665             struct fount_state {
1666             /* precalculated for the equation of the line perpendicular to the line AB */
1667             double lA, lB, lC;
1668             double AB;
1669             double sqrtA2B2;
1670             double mult;
1671             double cos;
1672             double sin;
1673             double theta;
1674             i_img_dim xa, ya;
1675             void *ssample_data;
1676             fount_func ffunc;
1677             fount_repeat rpfunc;
1678             fount_ssample ssfunc;
1679             double parm;
1680             i_fountain_seg *segs;
1681             int count;
1682             };
1683              
1684             static void
1685             fount_init_state(struct fount_state *state, double xa, double ya,
1686             double xb, double yb, i_fountain_type type,
1687             i_fountain_repeat repeat, int combine, int super_sample,
1688             double ssample_param, int count, i_fountain_seg *segs);
1689              
1690             static void
1691             fount_finish_state(struct fount_state *state);
1692              
1693             #define EPSILON (1e-6)
1694              
1695             /*
1696             =item i_fountain(im, xa, ya, xb, yb, type, repeat, combine, super_sample, ssample_param, count, segs)
1697              
1698             Draws a fountain fill using A(xa, ya) and B(xb, yb) as reference points.
1699              
1700             I controls how the reference points are used:
1701              
1702             =over
1703              
1704             =item i_ft_linear
1705              
1706             linear, where A is 0 and B is 1.
1707              
1708             =item i_ft_bilinear
1709              
1710             linear in both directions from A.
1711              
1712             =item i_ft_radial
1713              
1714             circular, where A is the centre of the fill, and B is a point
1715             on the radius.
1716              
1717             =item i_ft_radial_square
1718              
1719             where A is the centre of the fill and B is the centre of
1720             one side of the square.
1721              
1722             =item i_ft_revolution
1723              
1724             where A is the centre of the fill and B defines the 0/1.0
1725             angle of the fill.
1726              
1727             =item i_ft_conical
1728              
1729             similar to i_ft_revolution, except that the revolution goes in both
1730             directions
1731              
1732             =back
1733              
1734             I can be one of:
1735              
1736             =over
1737              
1738             =item i_fr_none
1739              
1740             values < 0 are treated as zero, values > 1 are treated as 1.
1741              
1742             =item i_fr_sawtooth
1743              
1744             negative values are treated as 0, positive values are modulo 1.0
1745              
1746             =item i_fr_triangle
1747              
1748             negative values are treated as zero, if (int)value is odd then the value is treated as 1-(value
1749             mod 1.0), otherwise the same as for sawtooth.
1750              
1751             =item i_fr_saw_both
1752              
1753             like i_fr_sawtooth, except that the sawtooth pattern repeats into
1754             negative values.
1755              
1756             =item i_fr_tri_both
1757              
1758             Like i_fr_triangle, except that negative values are handled as their
1759             absolute values.
1760              
1761             =back
1762              
1763             If combine is non-zero then non-opaque values are combined with the
1764             underlying color.
1765              
1766             I controls super sampling, if any. At some point I'll
1767             probably add a adaptive super-sampler. Current possible values are:
1768              
1769             =over
1770              
1771             =item i_fts_none
1772              
1773             No super-sampling is done.
1774              
1775             =item i_fts_grid
1776              
1777             A square grid of points withing the pixel are sampled.
1778              
1779             =item i_fts_random
1780              
1781             Random points within the pixel are sampled.
1782              
1783             =item i_fts_circle
1784              
1785             Points on the radius of a circle are sampled. This produces fairly
1786             good results, but is fairly slow since sin() and cos() are evaluated
1787             for each point.
1788              
1789             =back
1790              
1791             I is intended to be roughly the number of points
1792             sampled within the pixel.
1793              
1794             I and I define the segments of the fill.
1795              
1796             =cut
1797              
1798             */
1799              
1800             int
1801 9           i_fountain(i_img *im, double xa, double ya, double xb, double yb,
1802             i_fountain_type type, i_fountain_repeat repeat,
1803             int combine, int super_sample, double ssample_param,
1804             int count, i_fountain_seg *segs) {
1805             struct fount_state state;
1806             i_img_dim x, y;
1807 9           i_fcolor *line = NULL;
1808 9           i_fcolor *work = NULL;
1809             size_t line_bytes;
1810 9           i_fill_combine_f combine_func = NULL;
1811 9           i_fill_combinef_f combinef_func = NULL;
1812 9           dIMCTXim(im);
1813              
1814 9           i_clear_error();
1815              
1816             /* i_fountain() allocates floating colors even for 8-bit images,
1817             so we need to do this check */
1818 9           line_bytes = sizeof(i_fcolor) * im->xsize;
1819 9 50         if (line_bytes / sizeof(i_fcolor) != im->xsize) {
1820 0           i_push_error(0, "integer overflow calculating memory allocation");
1821 0           return 0;
1822             }
1823            
1824 9           line = mymalloc(line_bytes); /* checked 17feb2005 tonyc */
1825              
1826 9           i_get_combine(combine, &combine_func, &combinef_func);
1827 9 100         if (combinef_func) {
1828 2           work = mymalloc(line_bytes); /* checked 17feb2005 tonyc */
1829             }
1830              
1831 9           fount_init_state(&state, xa, ya, xb, yb, type, repeat, combine,
1832             super_sample, ssample_param, count, segs);
1833              
1834 1109 100         for (y = 0; y < im->ysize; ++y) {
1835 1100           i_glinf(im, 0, im->xsize, y, line);
1836 146100 100         for (x = 0; x < im->xsize; ++x) {
1837             i_fcolor c;
1838             int got_one;
1839 145000 100         if (super_sample == i_fts_none)
1840 77500           got_one = fount_getat(&c, x, y, &state);
1841             else
1842 67500           got_one = state.ssfunc(&c, x, y, &state);
1843 145000 50         if (got_one) {
1844 145000 100         if (combinef_func)
1845 45000           work[x] = c;
1846             else
1847 100000           line[x] = c;
1848             }
1849             }
1850 1100 100         if (combinef_func)
1851 300           combinef_func(line, work, im->channels, im->xsize);
1852 1100           i_plinf(im, 0, im->xsize, y, line);
1853             }
1854 9           fount_finish_state(&state);
1855 9           myfree(work);
1856 9           myfree(line);
1857              
1858 9           return 1;
1859             }
1860              
1861             typedef struct {
1862             i_fill_t base;
1863             struct fount_state state;
1864             } i_fill_fountain_t;
1865              
1866             static void
1867             fill_fountf(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width, int channels,
1868             i_fcolor *data);
1869             static void
1870             fount_fill_destroy(i_fill_t *fill);
1871              
1872             static i_fill_fountain_t
1873             fount_fill_proto =
1874             {
1875             {
1876             NULL,
1877             fill_fountf,
1878             fount_fill_destroy
1879             }
1880             };
1881              
1882              
1883             /*
1884             =item i_new_fill_fount(C, C, C, C, C, C, C, C, C, C, C)
1885              
1886             =category Fills
1887             =synopsis fill = i_new_fill_fount(0, 0, 100, 100, i_ft_linear, i_ft_linear,
1888             =synopsis i_fr_triangle, 0, i_fts_grid, 9, 1, segs);
1889              
1890              
1891             Creates a new general fill which fills with a fountain fill.
1892              
1893             =cut
1894             */
1895              
1896             i_fill_t *
1897 5           i_new_fill_fount(double xa, double ya, double xb, double yb,
1898             i_fountain_type type, i_fountain_repeat repeat,
1899             int combine, int super_sample, double ssample_param,
1900             int count, i_fountain_seg *segs) {
1901 5           i_fill_fountain_t *fill = mymalloc(sizeof(i_fill_fountain_t));
1902            
1903 5           *fill = fount_fill_proto;
1904 5 50         if (combine)
1905 0           i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
1906             else {
1907 5           fill->base.combine = NULL;
1908 5           fill->base.combinef = NULL;
1909             }
1910 5           fount_init_state(&fill->state, xa, ya, xb, yb, type, repeat, combine,
1911             super_sample, ssample_param, count, segs);
1912              
1913 5           return &fill->base;
1914             }
1915              
1916             /*
1917             =back
1918              
1919             =head1 INTERNAL FUNCTIONS
1920              
1921             =over
1922              
1923             =item fount_init_state(...)
1924              
1925             Used by both the fountain fill filter and the fountain fill.
1926              
1927             =cut
1928             */
1929              
1930             static void
1931 14           fount_init_state(struct fount_state *state, double xa, double ya,
1932             double xb, double yb, i_fountain_type type,
1933             i_fountain_repeat repeat, int combine, int super_sample,
1934             double ssample_param, int count, i_fountain_seg *segs) {
1935             int i, j;
1936             size_t bytes;
1937 14           i_fountain_seg *my_segs = mymalloc(sizeof(i_fountain_seg) * count); /* checked 2jul06 - duplicating original */
1938             /*int have_alpha = im->channels == 2 || im->channels == 4;*/
1939            
1940 14           memset(state, 0, sizeof(*state));
1941             /* we keep a local copy that we can adjust for speed */
1942 31 100         for (i = 0; i < count; ++i) {
1943 17           i_fountain_seg *seg = my_segs + i;
1944              
1945 17           *seg = segs[i];
1946 17 100         if (seg->type < 0 || seg->type >= i_fst_end)
1947 1           seg->type = i_fst_linear;
1948 17 50         if (seg->color < 0 || seg->color >= i_fc_end)
1949 0           seg->color = i_fc_direct;
1950 17 100         if (seg->color == i_fc_hue_up || seg->color == i_fc_hue_down) {
    100          
1951             /* so we don't have to translate to HSV on each request, do it here */
1952 9 100         for (j = 0; j < 2; ++j) {
1953 6           i_rgb_to_hsvf(seg->c+j);
1954             }
1955 3 100         if (seg->color == i_fc_hue_up) {
1956 2 50         if (seg->c[1].channel[0] <= seg->c[0].channel[0])
1957 2           seg->c[1].channel[0] += 1.0;
1958             }
1959             else {
1960 1 50         if (seg->c[0].channel[0] <= seg->c[0].channel[1])
1961 1           seg->c[0].channel[0] += 1.0;
1962             }
1963             }
1964             /*printf("start %g mid %g end %g c0(%g,%g,%g,%g) c1(%g,%g,%g,%g) type %d color %d\n",
1965             seg->start, seg->middle, seg->end, seg->c[0].channel[0],
1966             seg->c[0].channel[1], seg->c[0].channel[2], seg->c[0].channel[3],
1967             seg->c[1].channel[0], seg->c[1].channel[1], seg->c[1].channel[2],
1968             seg->c[1].channel[3], seg->type, seg->color);*/
1969            
1970             }
1971              
1972             /* initialize each engine */
1973             /* these are so common ... */
1974 14           state->lA = xb - xa;
1975 14           state->lB = yb - ya;
1976 14           state->AB = sqrt(state->lA * state->lA + state->lB * state->lB);
1977 14           state->xa = xa;
1978 14           state->ya = ya;
1979 14           switch (type) {
1980             default:
1981 0           type = i_ft_linear; /* make the invalid value valid */
1982             case i_ft_linear:
1983             case i_ft_bilinear:
1984 10           state->lC = ya * ya - ya * yb + xa * xa - xa * xb;
1985 10           state->mult = 1;
1986 10           state->mult = 1/linear_fount_f(xb, yb, state);
1987 10           break;
1988              
1989             case i_ft_radial:
1990 4           state->mult = 1.0 / sqrt((double)(xb-xa)*(xb-xa)
1991 2           + (double)(yb-ya)*(yb-ya));
1992 2           break;
1993              
1994             case i_ft_radial_square:
1995 1           state->cos = state->lA / state->AB;
1996 1           state->sin = state->lB / state->AB;
1997 1           state->mult = 1.0 / state->AB;
1998 1           break;
1999              
2000             case i_ft_revolution:
2001 1           state->theta = atan2(yb-ya, xb-xa);
2002 1           state->mult = 1.0 / (PI * 2);
2003 1           break;
2004              
2005             case i_ft_conical:
2006 0           state->theta = atan2(yb-ya, xb-xa);
2007 0           state->mult = 1.0 / PI;
2008 0           break;
2009             }
2010 14           state->ffunc = fount_funcs[type];
2011 14 50         if (super_sample < 0
2012 14 50         || super_sample >= (int)(sizeof(fount_ssamples)/sizeof(*fount_ssamples))) {
2013 0           super_sample = 0;
2014             }
2015 14           state->ssample_data = NULL;
2016 14           switch (super_sample) {
2017             case i_fts_grid:
2018 2           ssample_param = floor(0.5 + sqrt(ssample_param));
2019 2 50         if (ssample_param > 1000) {
2020 0           ssample_param = 1000;
2021             }
2022 2           state->ssample_data = mymalloc(sizeof(i_fcolor) * ssample_param * ssample_param); /* checked 1jul06 tonyc */
2023 2           break;
2024              
2025             case i_fts_random:
2026             case i_fts_circle:
2027 1           ssample_param = floor(0.5+ssample_param);
2028 1 50         if (ssample_param > 1000) {
2029 0           ssample_param = 1000;
2030             }
2031 1           bytes = sizeof(i_fcolor) * ssample_param;
2032 1           state->ssample_data = mymalloc(bytes);
2033 1           break;
2034             }
2035 14           state->parm = ssample_param;
2036 14           state->ssfunc = fount_ssamples[super_sample];
2037 14 50         if (repeat < 0 || repeat >= (sizeof(fount_repeats)/sizeof(*fount_repeats)))
2038 0           repeat = 0;
2039 14           state->rpfunc = fount_repeats[repeat];
2040 14           state->segs = my_segs;
2041 14           state->count = count;
2042 14           }
2043              
2044             static void
2045 14           fount_finish_state(struct fount_state *state) {
2046 14 100         if (state->ssample_data)
2047 3           myfree(state->ssample_data);
2048 14           myfree(state->segs);
2049 14           }
2050              
2051              
2052             /*
2053             =item fount_getat(out, x, y, ffunc, rpfunc, state, segs, count)
2054              
2055             Evaluates the fountain fill at the given point.
2056              
2057             This is called by both the non-super-sampling and super-sampling code.
2058              
2059             You might think that it would make sense to sample the fill parameter
2060             instead, and combine those, but this breaks badly.
2061              
2062             =cut
2063             */
2064              
2065             static int
2066 635417           fount_getat(i_fcolor *out, double x, double y, struct fount_state *state) {
2067 635417           double v = (state->rpfunc)((state->ffunc)(x, y, state));
2068             int i;
2069              
2070 635417           i = 0;
2071 736658 50         while (i < state->count
2072 736658 50         && (v < state->segs[i].start || v > state->segs[i].end)) {
    100          
2073 101241           ++i;
2074             }
2075 635417 50         if (i < state->count) {
2076 635417           v = (fount_interps[state->segs[i].type])(v, state->segs+i);
2077 635417           (fount_cinterps[state->segs[i].color])(out, v, state->segs+i);
2078 635417           return 1;
2079             }
2080             else
2081 0           return 0;
2082             }
2083              
2084             /*
2085             =item linear_fount_f(x, y, state)
2086              
2087             Calculate the fill parameter for a linear fountain fill.
2088              
2089             Uses the point to line distance function, with some precalculation
2090             done in i_fountain().
2091              
2092             =cut
2093             */
2094             static double
2095 521941           linear_fount_f(double x, double y, struct fount_state *state) {
2096 521941           return (state->lA * x + state->lB * y + state->lC) / state->AB * state->mult;
2097             }
2098              
2099             /*
2100             =item bilinear_fount_f(x, y, state)
2101              
2102             Calculate the fill parameter for a bi-linear fountain fill.
2103              
2104             =cut
2105             */
2106             static double
2107 0           bilinear_fount_f(double x, double y, struct fount_state *state) {
2108 0           return fabs((state->lA * x + state->lB * y + state->lC) / state->AB * state->mult);
2109             }
2110              
2111             /*
2112             =item radial_fount_f(x, y, state)
2113              
2114             Calculate the fill parameter for a radial fountain fill.
2115              
2116             Simply uses the distance function.
2117              
2118             =cut
2119             */
2120             static double
2121 13486           radial_fount_f(double x, double y, struct fount_state *state) {
2122 13486           return sqrt((double)(state->xa-x)*(state->xa-x)
2123 26972           + (double)(state->ya-y)*(state->ya-y)) * state->mult;
2124             }
2125              
2126             /*
2127             =item square_fount_f(x, y, state)
2128              
2129             Calculate the fill parameter for a square fountain fill.
2130              
2131             Works by rotating the reference co-ordinate around the centre of the
2132             square.
2133              
2134             =cut
2135             */
2136             static double
2137 90000           square_fount_f(double x, double y, struct fount_state *state) {
2138             i_img_dim xc, yc; /* centred on A */
2139             double xt, yt; /* rotated by theta */
2140 90000           xc = x - state->xa;
2141 90000           yc = y - state->ya;
2142 90000           xt = fabs(xc * state->cos + yc * state->sin);
2143 90000           yt = fabs(-xc * state->sin + yc * state->cos);
2144 90000 100         return (xt > yt ? xt : yt) * state->mult;
2145             }
2146              
2147             /*
2148             =item revolution_fount_f(x, y, state)
2149              
2150             Calculates the fill parameter for the revolution fountain fill.
2151              
2152             =cut
2153             */
2154             static double
2155 10000           revolution_fount_f(double x, double y, struct fount_state *state) {
2156 10000           double angle = atan2(y - state->ya, x - state->xa);
2157            
2158 10000           angle -= state->theta;
2159 10000 100         if (angle < 0) {
2160 2500           angle = fmod(angle+ PI * 4, PI*2);
2161             }
2162              
2163 10000           return angle * state->mult;
2164             }
2165              
2166             /*
2167             =item conical_fount_f(x, y, state)
2168              
2169             Calculates the fill parameter for the conical fountain fill.
2170              
2171             =cut
2172             */
2173             static double
2174 0           conical_fount_f(double x, double y, struct fount_state *state) {
2175 0           double angle = atan2(y - state->ya, x - state->xa);
2176            
2177 0           angle -= state->theta;
2178 0 0         if (angle < -PI)
2179 0           angle += PI * 2;
2180 0 0         else if (angle > PI)
2181 0           angle -= PI * 2;
2182              
2183 0           return fabs(angle) * state->mult;
2184             }
2185              
2186             /*
2187             =item linear_interp(pos, seg)
2188              
2189             Calculates linear interpolation on the fill parameter. Breaks the
2190             segment into 2 regions based in the I value.
2191              
2192             =cut
2193             */
2194             static double
2195 635417           linear_interp(double pos, i_fountain_seg *seg) {
2196 635417 100         if (pos < seg->middle) {
2197 380737           double len = seg->middle - seg->start;
2198 380737 50         if (len < EPSILON)
2199 0           return 0.0;
2200             else
2201 380737           return (pos - seg->start) / len / 2;
2202             }
2203             else {
2204 254680           double len = seg->end - seg->middle;
2205 254680 50         if (len < EPSILON)
2206 0           return 1.0;
2207             else
2208 254680           return 0.5 + (pos - seg->middle) / len / 2;
2209             }
2210             }
2211              
2212             /*
2213             =item sine_interp(pos, seg)
2214              
2215             Calculates sine function interpolation on the fill parameter.
2216              
2217             =cut
2218             */
2219             static double
2220 0           sine_interp(double pos, i_fountain_seg *seg) {
2221             /* I wonder if there's a simple way to smooth the transition for this */
2222 0           double work = linear_interp(pos, seg);
2223              
2224 0           return (1-cos(work * PI))/2;
2225             }
2226              
2227             /*
2228             =item sphereup_interp(pos, seg)
2229              
2230             Calculates spherical interpolation on the fill parameter, with the cusp
2231             at the low-end.
2232              
2233             =cut
2234             */
2235             static double
2236 0           sphereup_interp(double pos, i_fountain_seg *seg) {
2237 0           double work = linear_interp(pos, seg);
2238              
2239 0           return sqrt(1.0 - (1-work) * (1-work));
2240             }
2241              
2242             /*
2243             =item spheredown_interp(pos, seg)
2244              
2245             Calculates spherical interpolation on the fill parameter, with the cusp
2246             at the high-end.
2247              
2248             =cut
2249             */
2250             static double
2251 18864           spheredown_interp(double pos, i_fountain_seg *seg) {
2252 18864           double work = linear_interp(pos, seg);
2253              
2254 18864           return 1-sqrt(1.0 - work * work);
2255             }
2256              
2257             /*
2258             =item direct_cinterp(out, pos, seg)
2259              
2260             Calculates the fountain color based on direct scaling of the channels
2261             of the color channels.
2262              
2263             =cut
2264             */
2265             static void
2266 594053           direct_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg) {
2267             int ch;
2268 2970265 100         for (ch = 0; ch < MAXCHANNELS; ++ch) {
2269 4752424           out->channel[ch] = seg->c[0].channel[ch] * (1 - pos)
2270 2376212           + seg->c[1].channel[ch] * pos;
2271             }
2272 594053           }
2273              
2274             /*
2275             =item hue_up_cinterp(put, pos, seg)
2276              
2277             Calculates the fountain color based on scaling a HSV value. The hue
2278             increases as the fill parameter increases.
2279              
2280             =cut
2281             */
2282             static void
2283 30189           hue_up_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg) {
2284             int ch;
2285 150945 100         for (ch = 0; ch < MAXCHANNELS; ++ch) {
2286 241512           out->channel[ch] = seg->c[0].channel[ch] * (1 - pos)
2287 120756           + seg->c[1].channel[ch] * pos;
2288             }
2289 30189           i_hsv_to_rgbf(out);
2290 30189           }
2291              
2292             /*
2293             =item hue_down_cinterp(put, pos, seg)
2294              
2295             Calculates the fountain color based on scaling a HSV value. The hue
2296             decreases as the fill parameter increases.
2297              
2298             =cut
2299             */
2300             static void
2301 11175           hue_down_cinterp(i_fcolor *out, double pos, i_fountain_seg *seg) {
2302             int ch;
2303 55875 100         for (ch = 0; ch < MAXCHANNELS; ++ch) {
2304 89400           out->channel[ch] = seg->c[0].channel[ch] * (1 - pos)
2305 44700           + seg->c[1].channel[ch] * pos;
2306             }
2307 11175           i_hsv_to_rgbf(out);
2308 11175           }
2309              
2310             /*
2311             =item simple_ssample(out, parm, x, y, state, ffunc, rpfunc, segs, count)
2312              
2313             Simple grid-based super-sampling.
2314              
2315             =cut
2316             */
2317             static int
2318 45000           simple_ssample(i_fcolor *out, double x, double y, struct fount_state *state) {
2319 45000           i_fcolor *work = state->ssample_data;
2320             i_img_dim dx, dy;
2321 45000           int grid = state->parm;
2322 45000           double base = -0.5 + 0.5 / grid;
2323 45000           double step = 1.0 / grid;
2324             int ch, i;
2325 45000           int samp_count = 0;
2326              
2327 135000 100         for (dx = 0; dx < grid; ++dx) {
2328 270000 100         for (dy = 0; dy < grid; ++dy) {
2329 180000 50         if (fount_getat(work+samp_count, x + base + step * dx,
2330 180000           y + base + step * dy, state)) {
2331 180000           ++samp_count;
2332             }
2333             }
2334             }
2335 225000 100         for (ch = 0; ch < MAXCHANNELS; ++ch) {
2336 180000           out->channel[ch] = 0;
2337 900000 100         for (i = 0; i < samp_count; ++i) {
2338 720000           out->channel[ch] += work[i].channel[ch];
2339             }
2340             /* we divide by 4 rather than samp_count since if there's only one valid
2341             sample it should be mostly transparent */
2342 180000           out->channel[ch] /= grid * grid;
2343             }
2344 45000           return samp_count;
2345             }
2346              
2347             /*
2348             =item random_ssample(out, parm, x, y, state, ffunc, rpfunc, segs, count)
2349              
2350             Random super-sampling.
2351              
2352             =cut
2353             */
2354             static int
2355 0           random_ssample(i_fcolor *out, double x, double y,
2356             struct fount_state *state) {
2357 0           i_fcolor *work = state->ssample_data;
2358             int i, ch;
2359 0           int maxsamples = state->parm;
2360 0           double rand_scale = 1.0 / RAND_MAX;
2361 0           int samp_count = 0;
2362 0 0         for (i = 0; i < maxsamples; ++i) {
2363 0 0         if (fount_getat(work+samp_count, x - 0.5 + rand() * rand_scale,
2364 0           y - 0.5 + rand() * rand_scale, state)) {
2365 0           ++samp_count;
2366             }
2367             }
2368 0 0         for (ch = 0; ch < MAXCHANNELS; ++ch) {
2369 0           out->channel[ch] = 0;
2370 0 0         for (i = 0; i < samp_count; ++i) {
2371 0           out->channel[ch] += work[i].channel[ch];
2372             }
2373             /* we divide by maxsamples rather than samp_count since if there's
2374             only one valid sample it should be mostly transparent */
2375 0           out->channel[ch] /= maxsamples;
2376             }
2377 0           return samp_count;
2378             }
2379              
2380             /*
2381             =item circle_ssample(out, parm, x, y, state, ffunc, rpfunc, segs, count)
2382              
2383             Super-sampling around the circumference of a circle.
2384              
2385             I considered saving the sin()/cos() values and transforming step-size
2386             around the circle, but that's inaccurate, though it may not matter
2387             much.
2388              
2389             =cut
2390             */
2391             static int
2392 22500           circle_ssample(i_fcolor *out, double x, double y,
2393             struct fount_state *state) {
2394 22500           i_fcolor *work = state->ssample_data;
2395             int i, ch;
2396 22500           int maxsamples = state->parm;
2397 22500           double angle = 2 * PI / maxsamples;
2398 22500           double radius = 0.3; /* semi-random */
2399 22500           int samp_count = 0;
2400 382500 100         for (i = 0; i < maxsamples; ++i) {
2401 360000 50         if (fount_getat(work+samp_count, x + radius * cos(angle * i),
2402 360000           y + radius * sin(angle * i), state)) {
2403 360000           ++samp_count;
2404             }
2405             }
2406 112500 100         for (ch = 0; ch < MAXCHANNELS; ++ch) {
2407 90000           out->channel[ch] = 0;
2408 1530000 100         for (i = 0; i < samp_count; ++i) {
2409 1440000           out->channel[ch] += work[i].channel[ch];
2410             }
2411             /* we divide by maxsamples rather than samp_count since if there's
2412             only one valid sample it should be mostly transparent */
2413 90000           out->channel[ch] /= maxsamples;
2414             }
2415 22500           return samp_count;
2416             }
2417              
2418             /*
2419             =item fount_r_none(v)
2420              
2421             Implements no repeats. Simply clamps the fill value.
2422              
2423             =cut
2424             */
2425             static double
2426 265417           fount_r_none(double v) {
2427 265417 100         return v < 0 ? 0 : v > 1 ? 1 : v;
    100          
2428             }
2429              
2430             /*
2431             =item fount_r_sawtooth(v)
2432              
2433             Implements sawtooth repeats. Clamps negative values and uses fmod()
2434             on others.
2435              
2436             =cut
2437             */
2438             static double
2439 10000           fount_r_sawtooth(double v) {
2440 10000 50         return v < 0 ? 0 : fmod(v, 1.0);
2441             }
2442              
2443             /*
2444             =item fount_r_triangle(v)
2445              
2446             Implements triangle repeats. Clamps negative values, uses fmod to get
2447             a range 0 through 2 and then adjusts values > 1.
2448              
2449             =cut
2450             */
2451             static double
2452 360000           fount_r_triangle(double v) {
2453 360000 100         if (v < 0)
2454 179064           return 0;
2455             else {
2456 180936           v = fmod(v, 2.0);
2457 180936 100         return v > 1.0 ? 2.0 - v : v;
2458             }
2459             }
2460              
2461             /*
2462             =item fount_r_saw_both(v)
2463              
2464             Implements sawtooth repeats in the both postive and negative directions.
2465              
2466             Adjusts the value to be postive and then just uses fmod().
2467              
2468             =cut
2469             */
2470             static double
2471 0           fount_r_saw_both(double v) {
2472 0 0         if (v < 0)
2473 0           v += 1+(int)(-v);
2474 0           return fmod(v, 1.0);
2475             }
2476              
2477             /*
2478             =item fount_r_tri_both(v)
2479              
2480             Implements triangle repeats in the both postive and negative directions.
2481              
2482             Uses fmod on the absolute value, and then adjusts values > 1.
2483              
2484             =cut
2485             */
2486             static double
2487 0           fount_r_tri_both(double v) {
2488 0           v = fmod(fabs(v), 2.0);
2489 0 0         return v > 1.0 ? 2.0 - v : v;
2490             }
2491              
2492             /*
2493             =item fill_fountf(fill, x, y, width, channels, data)
2494              
2495             The fill function for fountain fills.
2496              
2497             =cut
2498             */
2499             static void
2500 292           fill_fountf(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
2501             int channels, i_fcolor *data) {
2502 292           i_fill_fountain_t *f = (i_fill_fountain_t *)fill;
2503            
2504 18209 100         while (width--) {
2505             i_fcolor c;
2506             int got_one;
2507            
2508 17917 50         if (f->state.ssfunc)
2509 0           got_one = f->state.ssfunc(&c, x, y, &f->state);
2510             else
2511 17917           got_one = fount_getat(&c, x, y, &f->state);
2512              
2513 17917 50         if (got_one)
2514 17917           *data++ = c;
2515            
2516 17917           ++x;
2517             }
2518 292           }
2519              
2520             /*
2521             =item fount_fill_destroy(fill)
2522              
2523             =cut
2524             */
2525             static void
2526 5           fount_fill_destroy(i_fill_t *fill) {
2527 5           i_fill_fountain_t *f = (i_fill_fountain_t *)fill;
2528 5           fount_finish_state(&f->state);
2529 5           }
2530              
2531             /*
2532             =back
2533              
2534             =head1 AUTHOR
2535              
2536             Arnar M. Hrafnkelsson
2537              
2538             Tony Cook (i_fountain())
2539              
2540             =head1 SEE ALSO
2541              
2542             Imager(3)
2543              
2544             =cut
2545             */