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