]> git.imager.perl.org - imager.git/blob - fills.c
d91fb9804c86edc65d5e220d8c86217f35664dd0
[imager.git] / fills.c
1 #include "image.h"
2 #include "imagei.h"
3
4 /*
5 =head1 NAME
6
7 fills.c - implements the basic general fills
8
9 =head1 SYNOPSIS
10
11   i_fill_t *fill;
12   i_color c1, c2;
13   i_fcolor fc1, fc2;
14   int combine;
15   fill = i_new_fill_solidf(&fc1, combine);
16   fill = i_new_fill_solid(&c1, combine);
17   fill = i_new_fill_hatchf(&fc1, &fc2, combine, hatch, cust_hash, dx, dy);
18   fill = i_new_fill_hatch(&c1, &c2, combine, hatch, cust_hash, dx, dy);
19   i_fill_destroy(fill);
20
21 =head1 DESCRIPTION
22
23 Implements the basic general fills, which can be used for filling some
24 shapes and for flood fills.
25
26 Each fill can implement up to 3 functions:
27
28 =over
29
30 =item fill_with_color
31
32 called for fills on 8-bit images.  This can be NULL in which case the
33 fill_with_colorf function is called.
34
35 =item fill_with_fcolor
36
37 called for fills on non-8-bit images or when fill_with_color is NULL.
38
39 =item destroy
40
41 called by i_fill_destroy() if non-NULL, to release any extra resources
42 that the fill may need.
43
44 =back
45
46 fill_with_color and fill_with_fcolor are basically the same function
47 except that the first works with lines of i_color and the second with
48 lines of i_fcolor.
49
50 If the combines member if non-zero the line data is populated from the
51 target image before calling fill_with_*color.
52
53 fill_with_color needs to fill the I<data> parameter with the fill
54 pixels.  If combines is non-zero it the fill pixels should be combined
55 with the existing data.
56
57 The current fills are:
58
59 =over
60
61 =item *
62
63 solid fill
64
65 =item *
66
67 hatched fill
68
69 =item *
70
71 fountain fill
72
73 =back
74
75 Fountain fill is implemented by L<filters.c>.
76
77 Other fills that could be implemented include:
78
79 =over
80
81 =item *
82
83 image - an image tiled over the fill area, with an offset either
84 horizontally or vertically.
85
86 =item *
87
88 checkerboard - combine 2 fills in a checkerboard
89
90 =item *
91
92 combine - combine the levels of 2 other fills based in the levels of
93 an image
94
95 =item *
96
97 regmach - use the register machine to generate colors
98
99 =back
100
101 =over
102
103 =cut
104 */
105
106 static i_color fcolor_to_color(i_fcolor *c) {
107   int ch;
108   i_color out;
109
110   for (ch = 0; ch < MAXCHANNELS; ++ch)
111     out.channel[ch] = SampleFTo8(c->channel[ch]);
112
113   return out;
114 }
115
116 static i_fcolor color_to_fcolor(i_color *c) {
117   int ch;
118   i_fcolor out;
119
120   for (ch = 0; ch < MAXCHANNELS; ++ch)
121     out.channel[ch] = Sample8ToF(c->channel[ch]);
122
123   return out;
124 }
125
126 /* alpha combine in with out */
127 #define COMBINE(out, in, channels) \
128   { \
129     int ch; \
130     for (ch = 0; ch < (channels); ++ch) { \
131       (out).channel[ch] = ((out).channel[ch] * (255 - (in).channel[3]) \
132         + (in).channel[ch] * (in).channel[3]) / 255; \
133     } \
134   }
135
136 /* alpha combine in with out, in this case in is a simple array of
137    samples, potentially not integers - the mult combiner uses doubles
138    for accuracy */
139 #define COMBINEA(out, in, channels) \
140   { \
141     int ch; \
142     for (ch = 0; ch < (channels); ++ch) { \
143       (out).channel[ch] = ((out).channel[ch] * (255 - (in)[3]) \
144         + (in)[ch] * (in)[3]) / 255; \
145     } \
146   }
147
148 #define COMBINEF(out, in, channels) \
149   { \
150     int ch; \
151     for (ch = 0; ch < (channels); ++ch) { \
152       (out).channel[ch] = (out).channel[ch] * (1.0 - (in).channel[3]) \
153         + (in).channel[ch] * (in).channel[3]; \
154     } \
155   }
156
157 typedef struct
158 {
159   i_fill_t base;
160   i_color c;
161   i_fcolor fc;
162 } i_fill_solid_t;
163
164 static void fill_solid(i_fill_t *, int x, int y, int width, int channels, 
165                        i_color *, i_color *);
166 static void fill_solidf(i_fill_t *, int x, int y, int width, int channels, 
167                         i_fcolor *, i_fcolor *);
168 static void fill_solid_comb(i_fill_t *, int x, int y, int width, int channels, 
169                             i_color *, i_color *);
170 static void fill_solidf_comb(i_fill_t *, int x, int y, int width, 
171                              int channels, i_fcolor *, i_fcolor *);
172
173 static i_fill_solid_t base_solid_fill =
174 {
175   {
176     fill_solid,
177     fill_solidf,
178     NULL,
179     NULL,
180     NULL,
181   },
182 };
183 static i_fill_solid_t base_solid_fill_comb =
184 {
185   {
186     fill_solid_comb,
187     fill_solidf_comb,
188     NULL,
189     NULL,
190     NULL,
191   },
192 };
193
194 /*
195 =item i_fill_destroy(fill)
196
197 Call to destroy any fill object.
198
199 =cut
200 */
201
202 void
203 i_fill_destroy(i_fill_t *fill) {
204   if (fill->destroy)
205     (fill->destroy)(fill);
206   myfree(fill);
207 }
208
209 /*
210 =item i_new_fill_solidf(color, combine)
211
212 Create a solid fill based on a float color.
213
214 If combine is non-zero then alpha values will be combined.
215
216 =cut
217 */
218
219 i_fill_t *
220 i_new_fill_solidf(i_fcolor *c, int combine) {
221   int ch;
222   i_fill_solid_t *fill = mymalloc(sizeof(i_fill_solid_t));
223   
224   if (combine) {
225     *fill = base_solid_fill_comb;
226     i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
227   }
228   else
229     *fill = base_solid_fill;
230   fill->fc = *c;
231   for (ch = 0; ch < MAXCHANNELS; ++ch) {
232     fill->c.channel[ch] = SampleFTo8(c->channel[ch]);
233   }
234   
235   return &fill->base;
236 }
237
238 /*
239 =item i_new_fill_solid(color, combine)
240
241 Create a solid fill based.
242
243 If combine is non-zero then alpha values will be combined.
244
245 =cut
246 */
247
248 i_fill_t *
249 i_new_fill_solid(i_color *c, int combine) {
250   int ch;
251   i_fill_solid_t *fill = mymalloc(sizeof(i_fill_solid_t));
252
253   if (combine) {
254     *fill = base_solid_fill_comb;
255     i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
256   }
257   else
258     *fill = base_solid_fill;
259   fill->c = *c;
260   for (ch = 0; ch < MAXCHANNELS; ++ch) {
261     fill->fc.channel[ch] = Sample8ToF(c->channel[ch]);
262   }
263   
264   return &fill->base;
265 }
266
267 static unsigned char
268 builtin_hatches[][8] =
269 {
270   {
271     /* 1x1 checkerboard */
272     0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55,
273   },
274   {
275     /* 2x2 checkerboard */
276     0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33,
277   },
278   {
279     /* 4 x 4 checkerboard */
280     0xF0, 0xF0, 0xF0, 0xF0, 0x0F, 0x0F, 0x0F, 0x0F,
281   },
282   {
283     /* single vertical lines */
284     0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
285   },
286   {
287     /* double vertical lines */
288     0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 
289   },
290   {
291     /* quad vertical lines */
292     0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
293   },
294   {
295     /* single hlines */
296     0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
297   },
298   {
299     /* double hlines */
300     0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,
301   },
302   {
303     /* quad hlines */
304     0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
305   },
306   {
307     /* single / */
308     0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80,
309   },
310   {
311     /* single \ */
312     0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01,
313   },
314   {
315     /* double / */
316     0x11, 0x22, 0x44, 0x88, 0x11, 0x22, 0x44, 0x88,
317   },
318   {
319     /* double \ */
320     0x88, 0x44, 0x22, 0x11, 0x88, 0x44, 0x22, 0x11,
321   },
322   {
323     /* single grid */
324     0xFF, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
325   },
326   {
327     /* double grid */
328     0xFF, 0x88, 0x88, 0x88, 0xFF, 0x88, 0x88, 0x88,
329   },
330   {
331     /* quad grid */
332     0xFF, 0xAA, 0xFF, 0xAA, 0xFF, 0xAA, 0xFF, 0xAA,
333   },
334   {
335     /* single dots */
336     0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
337   },
338   {
339     /* 4 dots */
340     0x88, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00,
341   },
342   {
343     /* 16 dots */
344     0xAA, 0x00, 0xAA, 0x00, 0xAA, 0x00, 0xAA, 0x00,
345   },
346   {
347     /* simple stipple */
348     0x48, 0x84, 0x00, 0x00, 0x84, 0x48, 0x00, 0x00,
349   },
350   {
351     /* weave */
352     0x55, 0xFD, 0x05, 0xFD, 0x55, 0xDF, 0x50, 0xDF,
353   },
354   {
355     /* single cross hatch */
356     0x82, 0x44, 0x28, 0x10, 0x28, 0x44, 0x82, 0x01,
357   },
358   {
359     /* double cross hatch */
360     0xAA, 0x44, 0xAA, 0x11, 0xAA, 0x44, 0xAA, 0x11,
361   },
362   {
363     /* vertical lozenge */
364     0x11, 0x11, 0x11, 0xAA, 0x44, 0x44, 0x44, 0xAA,
365   },
366   {
367     /* horizontal lozenge */
368     0x88, 0x70, 0x88, 0x07, 0x88, 0x70, 0x88, 0x07,
369   },
370   {
371     /* scales overlapping downwards */
372     0x80, 0x80, 0x41, 0x3E, 0x08, 0x08, 0x14, 0xE3,
373   },
374   {
375     /* scales overlapping upwards */
376     0xC7, 0x28, 0x10, 0x10, 0x7C, 0x82, 0x01, 0x01,
377   },
378   {
379     /* scales overlapping leftwards */
380     0x83, 0x84, 0x88, 0x48, 0x38, 0x48, 0x88, 0x84,
381   },
382   {
383     /* scales overlapping rightwards */
384     0x21, 0x11, 0x12, 0x1C, 0x12, 0x11, 0x21, 0xC1,
385   },
386   {
387     /* denser stipple */
388     0x44, 0x88, 0x22, 0x11, 0x44, 0x88, 0x22, 0x11,
389   },
390   {
391     /* L-shaped tiles */
392     0xFF, 0x84, 0x84, 0x9C, 0x94, 0x9C, 0x90, 0x90,
393   },
394   {
395     /* wider stipple */
396     0x80, 0x40, 0x20, 0x00, 0x02, 0x04, 0x08, 0x00,
397   },
398 };
399
400 typedef struct
401 {
402   i_fill_t base;
403   i_color fg, bg;
404   i_fcolor ffg, fbg;
405   unsigned char hatch[8];
406   int dx, dy;
407 } i_fill_hatch_t;
408
409 static void fill_hatch(i_fill_t *fill, int x, int y, int width, int channels, 
410                        i_color *data, i_color *work);
411 static void fill_hatchf(i_fill_t *fill, int x, int y, int width, int channels, 
412                         i_fcolor *data, i_fcolor *work);
413 static
414 i_fill_t *
415 i_new_hatch_low(i_color *fg, i_color *bg, i_fcolor *ffg, i_fcolor *fbg, 
416                 int combine, int hatch, unsigned char *cust_hatch,
417                 int dx, int dy);
418
419 /*
420 =item i_new_fill_hatch(fg, bg, combine, hatch, cust_hatch, dx, dy)
421
422 Creates a new hatched fill with the fg color used for the 1 bits in
423 the hatch and bg for the 0 bits.  If combine is non-zero alpha values
424 will be combined.
425
426 If cust_hatch is non-NULL it should be a pointer to 8 bytes of the
427 hash definition, with the high-bits to the left.
428
429 If cust_hatch is NULL then one of the standard hatches is used.
430
431 (dx, dy) are an offset into the hatch which can be used to unalign adjoining areas, or to align the origin of a hatch with the the side of a filled area.
432
433 =cut
434 */
435 i_fill_t *
436 i_new_fill_hatch(i_color *fg, i_color *bg, int combine, int hatch, 
437             unsigned char *cust_hatch, int dx, int dy) {
438   return i_new_hatch_low(fg, bg, NULL, NULL, combine, hatch, cust_hatch, 
439                          dx, dy);
440 }
441
442 /*
443 =item i_new_fill_hatchf(fg, bg, combine, hatch, cust_hatch, dx, dy)
444
445 Creates a new hatched fill with the fg color used for the 1 bits in
446 the hatch and bg for the 0 bits.  If combine is non-zero alpha values
447 will be combined.
448
449 If cust_hatch is non-NULL it should be a pointer to 8 bytes of the
450 hash definition, with the high-bits to the left.
451
452 If cust_hatch is NULL then one of the standard hatches is used.
453
454 (dx, dy) are an offset into the hatch which can be used to unalign adjoining areas, or to align the origin of a hatch with the the side of a filled area.
455
456 =cut
457 */
458 i_fill_t *
459 i_new_fill_hatchf(i_fcolor *fg, i_fcolor *bg, int combine, int hatch, 
460             unsigned char *cust_hatch, int dx, int dy) {
461   return i_new_hatch_low(NULL, NULL, fg, bg, combine, hatch, cust_hatch, 
462                          dx, dy);
463 }
464
465 #define T_SOLID_FILL(fill) ((i_fill_solid_t *)(fill))
466
467 /*
468 =back
469
470 =head1 INTERNAL FUNCTIONS
471
472 =over
473
474 =item fill_solid(fill, x, y, width, channels, data)
475
476 The 8-bit sample fill function for non-combining solid fills.
477
478 =cut
479 */
480 static void
481 fill_solid(i_fill_t *fill, int x, int y, int width, int channels, 
482            i_color *data, i_color *work) {
483   while (width-- > 0) {
484     *data++ = T_SOLID_FILL(fill)->c;
485   }
486 }
487
488 /*
489 =item fill_solid(fill, x, y, width, channels, data)
490
491 The floating sample fill function for non-combining solid fills.
492
493 =cut
494 */
495 static void
496 fill_solidf(i_fill_t *fill, int x, int y, int width, int channels, 
497            i_fcolor *data, i_fcolor *work) {
498   while (width-- > 0) {
499     *data++ = T_SOLID_FILL(fill)->fc;
500   }
501 }
502
503 /*
504 =item fill_solid_comb(fill, x, y, width, channels, data)
505
506 The 8-bit sample fill function for combining solid fills.
507
508 =cut
509 */
510 static void
511 fill_solid_comb(i_fill_t *fill, int x, int y, int width, int channels, 
512                 i_color *data, i_color *work) {
513   i_color c = T_SOLID_FILL(fill)->c;
514   int count = width;
515   i_color *wstart = work;
516
517   while (width-- > 0) {
518     *work++ = c;
519   }
520   (fill->combine)(data, wstart, channels, count);
521 }
522
523 /*
524 =item fill_solidf_comb(fill, x, y, width, channels, data)
525
526 The floating sample fill function for combining solid fills.
527
528 =cut
529 */
530 static void
531 fill_solidf_comb(i_fill_t *fill, int x, int y, int width, int channels, 
532            i_fcolor *data, i_fcolor *work) {
533   i_fcolor c = T_SOLID_FILL(fill)->fc;
534   int count = width;
535   i_fcolor *wstart = work;
536
537   while (width-- > 0) {
538     *work++ = c;
539   }
540   (fill->combinef)(data, wstart, channels, count);
541 }
542
543 /*
544 =item i_new_hatch_low(fg, bg, ffg, fbg, combine, hatch, cust_hatch, dx, dy)
545
546 Implements creation of hatch fill objects.
547
548 =cut
549 */
550 static
551 i_fill_t *
552 i_new_hatch_low(i_color *fg, i_color *bg, i_fcolor *ffg, i_fcolor *fbg, 
553                 int combine, int hatch, unsigned char *cust_hatch,
554                 int dx, int dy) {
555   i_fill_hatch_t *fill = mymalloc(sizeof(i_fill_hatch_t));
556
557   fill->base.fill_with_color = fill_hatch;
558   fill->base.fill_with_fcolor = fill_hatchf;
559   fill->base.destroy = NULL;
560   fill->fg = fg ? *fg : fcolor_to_color(ffg);
561   fill->bg = bg ? *bg : fcolor_to_color(fbg);
562   fill->ffg = ffg ? *ffg : color_to_fcolor(fg);
563   fill->fbg = fbg ? *fbg : color_to_fcolor(bg);
564   if (combine) {
565     i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
566   }
567   else {
568     fill->base.combine = NULL;
569     fill->base.combinef = NULL;
570   }
571   if (cust_hatch) {
572     memcpy(fill->hatch, cust_hatch, 8);
573   }
574   else {
575     if (hatch > sizeof(builtin_hatches)/sizeof(*builtin_hatches)) 
576       hatch = 0;
577     memcpy(fill->hatch, builtin_hatches[hatch], 8);
578   }
579   fill->dx = dx & 7;
580   fill->dy = dy & 7;
581
582   return &fill->base;
583 }
584
585 /*
586 =item fill_hatch(fill, x, y, width, channels, data)
587
588 The 8-bit sample fill function for hatched fills.
589
590 =back
591 */
592 static void fill_hatch(i_fill_t *fill, int x, int y, int width, int channels, 
593                        i_color *data, i_color *work) {
594   i_fill_hatch_t *f = (i_fill_hatch_t *)fill;
595   int byte = f->hatch[(y + f->dy) & 7];
596   int xpos = (x + f->dx) & 7;
597   int mask = 128 >> xpos;
598
599   if (fill->combine) {
600     int count = width;
601     i_color *wstart = work;
602
603     while (count-- > 0) {
604       *work++ = (byte & mask) ? f->fg : f->bg;
605       
606       if ((mask >>= 1) == 0)
607         mask = 128;
608     }
609     (fill->combine)(data, wstart, channels, width);
610   }
611   else {
612     while (width-- > 0) {
613       *data++ = (byte & mask) ? f->fg : f->bg;
614
615       if ((mask >>= 1) == 0)
616         mask = 128;
617     }
618   }
619 }
620
621 /*
622 =item fill_hatchf(fill, x, y, width, channels, data)
623
624 The floating sample fill function for hatched fills.
625
626 =back
627 */
628 static void fill_hatchf(i_fill_t *fill, int x, int y, int width, int channels, 
629                         i_fcolor *data, i_fcolor *work) {
630   i_fill_hatch_t *f = (i_fill_hatch_t *)fill;
631   int byte = f->hatch[(y + f->dy) & 7];
632   int xpos = (x + f->dx) & 7;
633   int mask = 128 >> xpos;
634   
635   if (fill->combinef) {
636     int count = width;
637     i_fcolor *wstart = work;
638
639     while (count-- > 0) {
640       *work++ = (byte & mask) ? f->ffg : f->fbg;
641       
642       if ((mask >>= 1) == 0)
643         mask = 128;
644     }
645     (fill->combinef)(data, wstart, channels, width);
646   }
647   else {
648     while (width-- > 0) {
649       *data++ = (byte & mask) ? f->ffg : f->fbg;
650
651       if ((mask >>= 1) == 0)
652         mask = 128;
653     }
654   }
655 }
656
657 static void combine_replace(i_color *, i_color *, int, int);
658 static void combine_replacef(i_fcolor *, i_fcolor *, int, int);
659 static void combine_alphablend(i_color *, i_color *, int, int);
660 static void combine_alphablendf(i_fcolor *, i_fcolor *, int, int);
661 static void combine_mult(i_color *, i_color *, int, int);
662 static void combine_multf(i_fcolor *, i_fcolor *, int, int);
663 static void combine_dissolve(i_color *, i_color *, int, int);
664 static void combine_dissolvef(i_fcolor *, i_fcolor *, int, int);
665 static void combine_add(i_color *, i_color *, int, int);
666 static void combine_addf(i_fcolor *, i_fcolor *, int, int);
667 static void combine_subtract(i_color *, i_color *, int, int);
668 static void combine_subtractf(i_fcolor *, i_fcolor *, int, int);
669 static void combine_diff(i_color *, i_color *, int, int);
670 static void combine_difff(i_fcolor *, i_fcolor *, int, int);
671 static void combine_darken(i_color *, i_color *, int, int);
672 static void combine_darkenf(i_fcolor *, i_fcolor *, int, int);
673 static void combine_lighten(i_color *, i_color *, int, int);
674 static void combine_lightenf(i_fcolor *, i_fcolor *, int, int);
675 static void combine_hue(i_color *, i_color *, int, int);
676 static void combine_huef(i_fcolor *, i_fcolor *, int, int);
677 static void combine_sat(i_color *, i_color *, int, int);
678 static void combine_satf(i_fcolor *, i_fcolor *, int, int);
679 static void combine_value(i_color *, i_color *, int, int);
680 static void combine_valuef(i_fcolor *, i_fcolor *, int, int);
681 static void combine_color(i_color *, i_color *, int, int);
682 static void combine_colorf(i_fcolor *, i_fcolor *, int, int);
683
684 struct i_combines {
685   i_fill_combine_f combine;
686   i_fill_combinef_f combinef;
687 } combines[] =
688 {
689   { /* replace */
690     combine_replace,
691     combine_replacef,
692   },
693   { /* alpha blend */
694     combine_alphablend,
695     combine_alphablendf,
696   },
697   {
698     /* multiply */
699     combine_mult,
700     combine_multf,
701   },
702   {
703     /* dissolve */
704     combine_dissolve,
705     combine_dissolvef,
706   },
707   {
708     /* add */
709     combine_add,
710     combine_addf,
711   },
712   {
713     /* subtract */
714     combine_subtract,
715     combine_subtractf,
716   },
717   {
718     /* diff */
719     combine_diff,
720     combine_difff,
721   },
722   {
723     combine_lighten,
724     combine_lightenf,
725   },
726   {
727     combine_darken,
728     combine_darkenf,
729   },
730   {
731     combine_hue,
732     combine_huef,
733   },
734   {
735     combine_sat,
736     combine_satf,
737   },
738   {
739     combine_value,
740     combine_valuef,
741   },
742   {
743     combine_color,
744     combine_colorf,
745   },
746 };
747
748 /*
749 =item i_get_combine(combine, color_func, fcolor_func)
750
751 =cut
752 */
753
754 void i_get_combine(int combine, i_fill_combine_f *color_func, 
755                    i_fill_combinef_f *fcolor_func) {
756   if (combine < 0 || combine > sizeof(combines) / sizeof(*combines))
757     combine = 0;
758
759   *color_func = combines[combine].combine;
760   *fcolor_func = combines[combine].combinef;
761 }
762
763 static void combine_replace(i_color *out, i_color *in, int channels, int count) {
764   while (count--) {
765     *out++ = *in++;
766   }
767 }
768
769 static void combine_replacef(i_fcolor *out, i_fcolor *in, int channels, int count) {
770   while (count--) {
771     *out++ = *in++;
772   }
773 }
774
775 static void combine_alphablend(i_color *out, i_color *in, int channels, int count) {
776   while (count--) {
777     COMBINE(*out, *in, channels);
778     ++out;
779     ++in;
780   }
781 }
782
783 static void combine_alphablendf(i_fcolor *out, i_fcolor *in, int channels, int count) {
784   while (count--) {
785     COMBINEF(*out, *in, channels);
786     ++out;
787     ++in;
788   }
789 }
790
791 static void combine_mult(i_color *out, i_color *in, int channels, int count) {
792   int ch;
793
794   while (count--) {
795     i_color c = *in;
796     double mult[MAXCHANNELS];
797     mult[3] = in->channel[3];
798     for (ch = 0; ch < (channels); ++ch) { 
799       if (ch != 3)
800         mult[ch] = (out->channel[ch] * in->channel[ch]) * (1.0 / 255);
801     } 
802     COMBINEA(*out, mult, channels);
803     ++out;
804     ++in;
805   }
806 }
807
808 static void combine_multf(i_fcolor *out, i_fcolor *in, int channels, int count) {
809   int ch;
810
811   while (count--) {
812     i_fcolor c = *in;
813     for (ch = 0; ch < channels; ++ch) { 
814       if (ch != 3)
815         c.channel[ch] = out->channel[ch] * in->channel[ch];
816     } 
817     COMBINEF(*out, c, channels);
818     ++out;
819     ++in;
820   }
821 }
822
823 static void combine_dissolve(i_color *out, i_color *in, int channels, int count) {
824   int ch;
825
826   while (count--) {
827     if (in->channel[3] > rand() * (255.0 / RAND_MAX))
828       COMBINE(*out, *in, channels);
829     ++out;
830     ++in;
831   }
832 }
833
834 static void combine_dissolvef(i_fcolor *out, i_fcolor *in, int channels, int count) {
835   int ch;
836
837   while (count--) {
838     if (in->channel[3] > rand() * (1.0 / RAND_MAX))
839       COMBINEF(*out, *in, channels);
840     ++out;
841     ++in;
842   }
843 }
844
845 static void combine_add(i_color *out, i_color *in, int channels, int count) {
846   int ch;
847
848   while (count--) {
849     i_color c = *in;
850     for (ch = 0; ch < (channels); ++ch) { 
851       if (ch != 3) {
852         int total = out->channel[ch] + in->channel[ch];
853         if (total > 255)
854           total = 255;
855         c.channel[ch] = total;
856       }
857     } 
858     COMBINE(*out, c, channels);
859     ++out;
860     ++in;
861   }
862 }
863
864 static void combine_addf(i_fcolor *out, i_fcolor *in, int channels, int count) {
865   int ch;
866
867   while (count--) {
868     i_fcolor c = *in;
869     for (ch = 0; ch < (channels); ++ch) { 
870       if (ch != 3) {
871         double total = out->channel[ch] + in->channel[ch];
872         if (total > 1.0)
873           total = 1.0;
874         out->channel[ch] = total;
875       }
876     } 
877     COMBINEF(*out, c, channels);
878     ++out;
879     ++in;
880   }
881 }
882
883 static void combine_subtract(i_color *out, i_color *in, int channels, int count) {
884   int ch;
885
886   while (count--) {
887     i_color c = *in;
888     for (ch = 0; ch < (channels); ++ch) { 
889       if (ch != 3) {
890         int total = out->channel[ch] - in->channel[ch];
891         if (total < 0)
892           total = 0;
893         c.channel[ch] = total;
894       }
895     } 
896     COMBINE(*out, c, channels);
897     ++out;
898     ++in;
899   }
900 }
901
902 static void combine_subtractf(i_fcolor *out, i_fcolor *in, int channels, int count) {
903   int ch;
904
905   while (count--) {
906     i_fcolor c = *in;
907     for (ch = 0; ch < channels; ++ch) { 
908       if (ch != 3) {
909         double total = out->channel[ch] - in->channel[ch];
910         if (total < 0)
911           total = 0;
912         c.channel[ch] = total;
913       }
914     } 
915     COMBINEF(*out, c, channels);
916     ++out;
917     ++in;
918   }
919 }
920
921 static void combine_diff(i_color *out, i_color *in, int channels, int count) {
922   int ch;
923
924   while (count--) {
925     i_color c = *in;
926     for (ch = 0; ch < (channels); ++ch) { 
927       if (ch != 3) 
928         c.channel[ch] = abs(out->channel[ch] - in->channel[ch]);
929     } 
930     COMBINE(*out, c, channels)
931     ++out;
932     ++in;
933   }
934 }
935
936 static void combine_difff(i_fcolor *out, i_fcolor *in, int channels, int count) {
937   int ch;
938
939   while (count--) {
940     i_fcolor c = *in;
941     for (ch = 0; ch < (channels); ++ch) { 
942       if (ch != 3)
943         c.channel[ch] = fabs(out->channel[ch] - in->channel[ch]);
944     }
945     COMBINEF(*out, c, channels);
946     ++out;
947     ++in;
948   }
949 }
950
951 static void combine_darken(i_color *out, i_color *in, int channels, int count) {
952   int ch;
953
954   while (count--) {
955     for (ch = 0; ch < channels; ++ch) { 
956       if (ch != 3 && out->channel[ch] < in->channel[ch])
957         in->channel[ch] = out->channel[ch];
958     } 
959     COMBINE(*out, *in, channels);
960     ++out;
961     ++in;
962   }
963 }
964
965 static void combine_darkenf(i_fcolor *out, i_fcolor *in, int channels, int count) {
966   int ch;
967
968   while (count--) {
969     for (ch = 0; ch < channels; ++ch) { 
970       if (ch != 3 && out->channel[ch] < in->channel[ch])
971         in->channel[ch] = out->channel[ch];
972     } 
973     COMBINEF(*out, *in, channels);
974     ++out;
975     ++in;
976   }
977 }
978
979 static void combine_lighten(i_color *out, i_color *in, int channels, int count) {
980   int ch;
981
982   while (count--) {
983     for (ch = 0; ch < channels; ++ch) { 
984       if (ch != 3 && out->channel[ch] > in->channel[ch])
985         in->channel[ch] = out->channel[ch];
986     } 
987     COMBINE(*out, *in, channels);
988     ++out;
989     ++in;
990   }
991 }
992
993 static void combine_lightenf(i_fcolor *out, i_fcolor *in, int channels, int count) {
994   int ch;
995
996   while (count--) {
997     for (ch = 0; ch < channels; ++ch) { 
998       if (ch != 3 && out->channel[ch] > in->channel[ch])
999         in->channel[ch] = out->channel[ch];
1000     } 
1001     COMBINEF(*out, *in, channels);
1002     ++out;
1003     ++in;
1004   }
1005 }
1006
1007 static void combine_hue(i_color *out, i_color *in, int channels, int count) {
1008   while (count--) {
1009     i_color c = *out;
1010     i_rgb_to_hsv(&c);
1011     i_rgb_to_hsv(in);
1012     c.channel[0] = in->channel[0];
1013     i_hsv_to_rgb(&c);
1014     c.channel[3] = in->channel[3];
1015     COMBINE(*out, c, channels);
1016     ++out;
1017     ++in;
1018   }
1019 }
1020
1021 static void combine_huef(i_fcolor *out, i_fcolor *in, int channels, int count) {
1022   while (count--) {
1023     i_fcolor c = *out;
1024     i_rgb_to_hsvf(&c);
1025     i_rgb_to_hsvf(in);
1026     c.channel[0] = in->channel[0];
1027     i_hsv_to_rgbf(&c);
1028     c.channel[3] = in->channel[3];
1029     COMBINEF(*out, c, channels);
1030     ++out;
1031     ++in;
1032   }
1033 }
1034
1035 static void combine_sat(i_color *out, i_color *in, int channels, int count) {
1036   while (count--) {
1037     i_color c = *out;
1038     i_rgb_to_hsv(&c);
1039     i_rgb_to_hsv(in);
1040     c.channel[1] = in->channel[1];
1041     i_hsv_to_rgb(&c);
1042     c.channel[3] = in->channel[3];
1043     COMBINE(*out, c, channels);
1044     ++out;
1045     ++in;
1046   }
1047 }
1048
1049 static void combine_satf(i_fcolor *out, i_fcolor *in, int channels, int count) {
1050   while (count--) {
1051     i_fcolor c = *out;
1052     i_rgb_to_hsvf(&c);
1053     i_rgb_to_hsvf(in);
1054     c.channel[1] = in->channel[1];
1055     i_hsv_to_rgbf(&c);
1056     c.channel[3] = in->channel[3];
1057     COMBINEF(*out, c, channels);
1058     ++out;
1059     ++in;
1060   }
1061 }
1062
1063 static void combine_value(i_color *out, i_color *in, int channels, int count) {
1064   while (count--) {
1065     i_color c = *out;
1066     i_rgb_to_hsv(&c);
1067     i_rgb_to_hsv(in);
1068     c.channel[2] = in->channel[2];
1069     i_hsv_to_rgb(&c);
1070     c.channel[3] = in->channel[3];
1071     COMBINE(*out, c, channels);
1072     ++out;
1073     ++in;
1074   }
1075 }
1076
1077 static void combine_valuef(i_fcolor *out, i_fcolor *in, int channels, 
1078                            int count) {
1079   while (count--) {
1080     i_fcolor c = *out;
1081     i_rgb_to_hsvf(&c);
1082     i_rgb_to_hsvf(in);
1083     c.channel[2] = in->channel[2];
1084     i_hsv_to_rgbf(&c);
1085     c.channel[3] = in->channel[3];
1086     COMBINEF(*out, c, channels);
1087     ++out;
1088     ++in;
1089   }
1090 }
1091
1092 static void combine_color(i_color *out, i_color *in, int channels, int count) {
1093   while (count--) {
1094     i_color c = *out;
1095     i_rgb_to_hsv(&c);
1096     i_rgb_to_hsv(in);
1097     c.channel[0] = in->channel[0];
1098     c.channel[1] = in->channel[1];
1099     i_hsv_to_rgb(&c);
1100     c.channel[3] = in->channel[3];
1101     COMBINE(*out, c, channels);
1102     ++out;
1103     ++in;
1104   }
1105 }
1106
1107 static void combine_colorf(i_fcolor *out, i_fcolor *in, int channels, 
1108                            int count) {
1109   while (count--) {
1110     i_fcolor c = *out;
1111     i_rgb_to_hsvf(&c);
1112     i_rgb_to_hsvf(in);
1113     c.channel[0] = in->channel[0];
1114     c.channel[1] = in->channel[1];
1115     i_hsv_to_rgbf(&c);
1116     c.channel[3] = in->channel[3];
1117     COMBINEF(*out, c, channels);
1118     ++out;
1119     ++in;
1120   }
1121 }
1122
1123
1124 /*
1125 =back
1126
1127 =head1 AUTHOR
1128
1129 Tony Cook <tony@develop-help.com>
1130
1131 =head1 SEE ALSO
1132
1133 Imager(3)
1134
1135 =cut
1136 */