]> git.imager.perl.org - imager.git/blob - fills.c
make dIMCTXio() public
[imager.git] / fills.c
1 #define IMAGER_NO_CONTEXT
2 #include "imager.h"
3 #include "imageri.h"
4
5 /*
6 =head1 NAME
7
8 fills.c - implements the basic general fills
9
10 =head1 SYNOPSIS
11
12   i_fill_t *fill;
13   i_color c1, c2;
14   i_fcolor fc1, fc2;
15   int combine;
16   fill = i_new_fill_solidf(&fc1, combine);
17   fill = i_new_fill_solid(&c1, combine);
18   fill = i_new_fill_hatchf(&fc1, &fc2, combine, hatch, cust_hash, dx, dy);
19   fill = i_new_fill_hatch(&c1, &c2, combine, hatch, cust_hash, dx, dy);
20   fill = i_new_fill_image(im, matrix, xoff, yoff, combine);
21   fill = i_new_fill_opacity(fill, alpha_mult);
22   i_fill_destroy(fill);
23
24 =head1 DESCRIPTION
25
26 Implements the basic general fills, which can be used for filling some
27 shapes and for flood fills.
28
29 Each fill can implement up to 3 functions:
30
31 =over
32
33 =item fill_with_color
34
35 called for fills on 8-bit images.  This can be NULL in which case the
36 fill_with_colorf function is called.
37
38 =item fill_with_fcolor
39
40 called for fills on non-8-bit images or when fill_with_color is NULL.
41
42 =item destroy
43
44 called by i_fill_destroy() if non-NULL, to release any extra resources
45 that the fill may need.
46
47 =back
48
49 fill_with_color and fill_with_fcolor are basically the same function
50 except that the first works with lines of i_color and the second with
51 lines of i_fcolor.
52
53 If the combines member if non-zero the line data is populated from the
54 target image before calling fill_with_*color.
55
56 fill_with_color needs to fill the I<data> parameter with the fill
57 pixels.  If combines is non-zero it the fill pixels should be combined
58 with the existing data.
59
60 The current fills are:
61
62 =over
63
64 =item *
65
66 solid fill
67
68 =item *
69
70 hatched fill
71
72 =item *
73
74 fountain fill
75
76 =back
77
78 Fountain fill is implemented by L<filters.c>.
79
80 Other fills that could be implemented include:
81
82 =over
83
84 =item *
85
86 image - an image tiled over the fill area, with an offset either
87 horizontally or vertically.
88
89 =item *
90
91 checkerboard - combine 2 fills in a checkerboard
92
93 =item *
94
95 combine - combine the levels of 2 other fills based in the levels of
96 an image
97
98 =item *
99
100 regmach - use the register machine to generate colors
101
102 =back
103
104 =over
105
106 =cut
107 */
108
109 static i_color fcolor_to_color(const i_fcolor *c) {
110   int ch;
111   i_color out;
112
113   for (ch = 0; ch < MAXCHANNELS; ++ch)
114     out.channel[ch] = SampleFTo8(c->channel[ch]);
115
116   return out;
117 }
118
119 static i_fcolor color_to_fcolor(const i_color *c) {
120   int ch;
121   i_fcolor out;
122
123   for (ch = 0; ch < MAXCHANNELS; ++ch)
124     out.channel[ch] = Sample8ToF(c->channel[ch]);
125
126   return out;
127 }
128
129 /* alpha combine in with out */
130 #define COMBINE(out, in, channels) \
131   { \
132     int ch; \
133     for (ch = 0; ch < (channels); ++ch) { \
134       (out).channel[ch] = ((out).channel[ch] * (255 - (in).channel[3]) \
135         + (in).channel[ch] * (in).channel[3]) / 255; \
136     } \
137   }
138
139 /* alpha combine in with out, in this case in is a simple array of
140    samples, potentially not integers - the mult combiner uses doubles
141    for accuracy */
142 #define COMBINEA(out, in, channels) \
143   { \
144     int ch; \
145     for (ch = 0; ch < (channels); ++ch) { \
146       (out).channel[ch] = ((out).channel[ch] * (255 - (in)[3]) \
147         + (in)[ch] * (in)[3]) / 255; \
148     } \
149   }
150
151 #define COMBINEF(out, in, channels) \
152   { \
153     int ch; \
154     for (ch = 0; ch < (channels); ++ch) { \
155       (out).channel[ch] = (out).channel[ch] * (1.0 - (in).channel[3]) \
156         + (in).channel[ch] * (in).channel[3]; \
157     } \
158   }
159
160 typedef struct
161 {
162   i_fill_t base;
163   i_color c;
164   i_fcolor fc;
165 } i_fill_solid_t;
166
167 static void fill_solid(i_fill_t *, i_img_dim x, i_img_dim y, i_img_dim width,
168                        int channels, i_color *);
169 static void fill_solidf(i_fill_t *, i_img_dim x, i_img_dim y, i_img_dim width,
170                         int channels, i_fcolor *);
171
172 static i_fill_solid_t base_solid_fill =
173 {
174   {
175     fill_solid,
176     fill_solidf,
177     NULL,
178     NULL,
179     NULL,
180   },
181 };
182
183 /*
184 =item i_fill_destroy(fill)
185 =order 90
186 =category Fills
187 =synopsis i_fill_destroy(fill);
188
189 Call to destroy any fill object.
190
191 =cut
192 */
193
194 void
195 i_fill_destroy(i_fill_t *fill) {
196   if (fill->destroy)
197     (fill->destroy)(fill);
198   myfree(fill);
199 }
200
201 /*
202 =item i_new_fill_solidf(color, combine)
203
204 =category Fills
205 =synopsis i_fill_t *fill = i_new_fill_solidf(&fcolor, combine);
206
207 Create a solid fill based on a float color.
208
209 If combine is non-zero then alpha values will be combined.
210
211 =cut
212 */
213
214 i_fill_t *
215 i_new_fill_solidf(const i_fcolor *c, int combine) {
216   int ch;
217   i_fill_solid_t *fill = mymalloc(sizeof(i_fill_solid_t)); /* checked 14jul05 tonyc */
218   
219   *fill = base_solid_fill;
220   if (combine) {
221     i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
222   }
223
224   fill->fc = *c;
225   for (ch = 0; ch < MAXCHANNELS; ++ch) {
226     fill->c.channel[ch] = SampleFTo8(c->channel[ch]);
227   }
228   
229   return &fill->base;
230 }
231
232 /*
233 =item i_new_fill_solid(color, combine)
234
235 =category Fills
236 =synopsis i_fill_t *fill = i_new_fill_solid(&color, combine);
237
238 Create a solid fill based on an 8-bit color.
239
240 If combine is non-zero then alpha values will be combined.
241
242 =cut
243 */
244
245 i_fill_t *
246 i_new_fill_solid(const i_color *c, int combine) {
247   int ch;
248   i_fill_solid_t *fill = mymalloc(sizeof(i_fill_solid_t)); /* checked 14jul05 tonyc */
249
250   *fill = base_solid_fill;
251   if (combine) {
252     i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
253   }
254
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   i_img_dim dx, dy;
403 } i_fill_hatch_t;
404
405 static void fill_hatch(i_fill_t *fill, i_img_dim x, i_img_dim y,
406                        i_img_dim width, int channels, i_color *data);
407 static void fill_hatchf(i_fill_t *fill, i_img_dim x, i_img_dim y,
408                         i_img_dim width, int channels, i_fcolor *data);
409 static
410 i_fill_t *
411 i_new_hatch_low(const i_color *fg, const i_color *bg, const i_fcolor *ffg, const i_fcolor *fbg, 
412                 int combine, int hatch, const unsigned char *cust_hatch,
413                 i_img_dim dx, i_img_dim dy);
414
415 /*
416 =item i_new_fill_hatch(C<fg>, C<bg>, C<combine>, C<hatch>, C<cust_hatch>, C<dx>, C<dy>)
417
418 =category Fills
419 =synopsis i_fill_t *fill = i_new_fill_hatch(&fg_color, &bg_color, combine, hatch, custom_hatch, dx, dy);
420
421 Creates a new hatched fill with the C<fg> color used for the 1 bits in
422 the hatch and C<bg> for the 0 bits.  If C<combine> is non-zero alpha
423 values will be combined.
424
425 If C<cust_hatch> is non-NULL it should be a pointer to 8 bytes of the
426 hash definition, with the high-bits to the left.
427
428 If C<cust_hatch> is NULL then one of the standard hatches is used.
429
430 (C<dx>, C<dy>) are an offset into the hatch which can be used to hatch
431 adjoining areas out of alignment, or to align the origin of a hatch
432 with the the side of a filled area.
433
434 =cut
435 */
436 i_fill_t *
437 i_new_fill_hatch(const i_color *fg, const i_color *bg, int combine, int hatch, 
438             const unsigned char *cust_hatch, i_img_dim dx, i_img_dim dy) {
439   return i_new_hatch_low(fg, bg, NULL, NULL, combine, hatch, cust_hatch, 
440                          dx, dy);
441 }
442
443 /*
444 =item i_new_fill_hatchf(C<fg>, C<bg>, C<combine>, C<hatch>, C<cust_hatch>, C<dx>, C<dy>)
445
446 =category Fills
447 =synopsis i_fill_t *fill = i_new_fill_hatchf(&fg_fcolor, &bg_fcolor, combine, hatch, custom_hatch, dx, dy);
448
449 Creates a new hatched fill with the C<fg> color used for the 1 bits in
450 the hatch and C<bg> for the 0 bits.  If C<combine> is non-zero alpha
451 values will be combined.
452
453 If C<cust_hatch> is non-NULL it should be a pointer to 8 bytes of the
454 hash definition, with the high-bits to the left.
455
456 If C<cust_hatch> is NULL then one of the standard hatches is used.
457
458 (C<dx>, C<dy>) are an offset into the hatch which can be used to hatch
459 adjoining areas out of alignment, or to align the origin of a hatch
460 with the the side of a filled area.
461
462 =cut
463 */
464 i_fill_t *
465 i_new_fill_hatchf(const i_fcolor *fg, const i_fcolor *bg, int combine, int hatch, 
466                   const unsigned char *cust_hatch, i_img_dim dx, i_img_dim dy) {
467   return i_new_hatch_low(NULL, NULL, fg, bg, combine, hatch, cust_hatch, 
468                          dx, dy);
469 }
470
471 static void fill_image(i_fill_t *fill, i_img_dim x, i_img_dim y,
472                        i_img_dim width, int channels, i_color *data);
473 static void fill_imagef(i_fill_t *fill, i_img_dim x, i_img_dim y,
474                         i_img_dim width, int channels, i_fcolor *data);
475 struct i_fill_image_t {
476   i_fill_t base;
477   i_img *src;
478   i_img_dim xoff, yoff;
479   int has_matrix;
480   double matrix[9];
481 };
482
483 static struct i_fill_image_t
484 image_fill_proto =
485   {
486     {
487       fill_image,
488       fill_imagef,
489       NULL
490     }
491   };
492
493 /*
494 =item i_new_fill_image(C<im>, C<matrix>, C<xoff>, C<yoff>, C<combine>)
495
496 =category Fills
497 =synopsis i_fill_t *fill = i_new_fill_image(src_img, matrix, x_offset, y_offset, combine);
498
499 Create an image based fill.
500
501 matrix is an array of 9 doubles representing a transformation matrix.
502
503 C<xoff> and C<yoff> are the offset into the image to start filling from.
504
505 =cut
506 */
507 i_fill_t *
508 i_new_fill_image(i_img *im, const double *matrix, i_img_dim xoff, i_img_dim yoff, int combine) {
509   struct i_fill_image_t *fill = mymalloc(sizeof(*fill)); /* checked 14jul05 tonyc */
510
511   *fill = image_fill_proto;
512
513   if (combine) {
514     i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
515   }
516   else {
517     fill->base.combine = NULL;
518     fill->base.combinef = NULL;
519   }
520   fill->src = im;
521   if (xoff < 0)
522     xoff += im->xsize;
523   fill->xoff = xoff;
524   if (yoff < 0)
525     yoff += im->ysize;
526   fill->yoff = yoff;
527   if (matrix) {
528     fill->has_matrix = 1;
529     memcpy(fill->matrix, matrix, sizeof(fill->matrix));
530   }
531   else
532     fill->has_matrix = 0;
533
534   return &fill->base;
535 }
536
537 static void fill_opacity(i_fill_t *fill, i_img_dim x, i_img_dim y,
538                          i_img_dim width, int channels, i_color *data);
539 static void fill_opacityf(i_fill_t *fill, i_img_dim x, i_img_dim y,
540                           i_img_dim width, int channels, i_fcolor *data);
541
542 struct i_fill_opacity_t {
543   i_fill_t base;
544   i_fill_t *other_fill;
545   double alpha_mult;
546 };
547
548 static struct i_fill_opacity_t
549 opacity_fill_proto =
550   {
551     {
552       fill_opacity,
553       fill_opacityf,
554       NULL
555     }
556   };
557
558 i_fill_t *
559 i_new_fill_opacity(i_fill_t *base_fill, double alpha_mult) {
560   struct i_fill_opacity_t *fill = mymalloc(sizeof(*fill));
561   *fill = opacity_fill_proto;
562
563   fill->base.combine = base_fill->combine;
564   fill->base.combinef = base_fill->combinef;
565
566   fill->other_fill = base_fill;
567   fill->alpha_mult = alpha_mult;
568
569   if (!base_fill->f_fill_with_color) {
570     /* base fill only does floating, so we only do that too */
571     fill->base.f_fill_with_color = NULL;
572   }
573
574   return &fill->base;
575 }
576
577 #define T_SOLID_FILL(fill) ((i_fill_solid_t *)(fill))
578
579 /*
580 =back
581
582 =head1 INTERNAL FUNCTIONS
583
584 =over
585
586 =item fill_solid(fill, x, y, width, channels, data)
587
588 The 8-bit sample fill function for non-combining solid fills.
589
590 =cut
591 */
592 static void
593 fill_solid(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
594            int channels, i_color *data) {
595   i_color c = T_SOLID_FILL(fill)->c;
596   i_adapt_colors(channels > 2 ? 4 : 2, 4, &c, 1);
597   while (width-- > 0) {
598     *data++ = c;
599   }
600 }
601
602 /*
603 =item fill_solid(fill, x, y, width, channels, data)
604
605 The floating sample fill function for non-combining solid fills.
606
607 =cut
608 */
609 static void
610 fill_solidf(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
611             int channels, i_fcolor *data) {
612   i_fcolor c = T_SOLID_FILL(fill)->fc;
613   i_adapt_fcolors(channels > 2 ? 4 : 2, 4, &c, 1);
614   while (width-- > 0) {
615     *data++ = c;
616   }
617 }
618
619 static i_fill_hatch_t
620 hatch_fill_proto =
621   {
622     {
623       fill_hatch,
624       fill_hatchf,
625       NULL
626     }
627   };
628
629 /*
630 =item i_new_hatch_low(fg, bg, ffg, fbg, combine, hatch, cust_hatch, dx, dy)
631
632 Implements creation of hatch fill objects.
633
634 =cut
635 */
636 static
637 i_fill_t *
638 i_new_hatch_low(const i_color *fg, const i_color *bg, 
639                 const i_fcolor *ffg, const i_fcolor *fbg, 
640                 int combine, int hatch, const unsigned char *cust_hatch,
641                 i_img_dim dx, i_img_dim dy) {
642   i_fill_hatch_t *fill = mymalloc(sizeof(i_fill_hatch_t)); /* checked 14jul05 tonyc */
643
644   *fill = hatch_fill_proto;
645   /* Some Sun C didn't like the condition expressions that were here.
646      See https://rt.cpan.org/Ticket/Display.html?id=21944
647    */
648   if (fg)
649     fill->fg = *fg;
650   else
651     fill->fg = fcolor_to_color(ffg);
652   if (bg)
653     fill->bg = *bg;
654   else
655     fill->bg = fcolor_to_color(fbg);
656   if (ffg) 
657     fill->ffg = *ffg;
658   else
659     fill->ffg = color_to_fcolor(fg);
660   if (fbg)
661     fill->fbg = *fbg;
662   else
663     fill->fbg = color_to_fcolor(bg);
664   if (combine) {
665     i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
666   }
667   else {
668     fill->base.combine = NULL;
669     fill->base.combinef = NULL;
670   }
671   if (cust_hatch) {
672     memcpy(fill->hatch, cust_hatch, 8);
673   }
674   else {
675     if (hatch > sizeof(builtin_hatches)/sizeof(*builtin_hatches)) 
676       hatch = 0;
677     memcpy(fill->hatch, builtin_hatches[hatch], 8);
678   }
679   fill->dx = dx & 7;
680   fill->dy = dy & 7;
681
682   return &fill->base;
683 }
684
685 /*
686 =item fill_hatch(fill, x, y, width, channels, data)
687
688 The 8-bit sample fill function for hatched fills.
689
690 =cut
691 */
692 static void 
693 fill_hatch(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
694            int channels, i_color *data) {
695   i_fill_hatch_t *f = (i_fill_hatch_t *)fill;
696   int byte = f->hatch[(y + f->dy) & 7];
697   int xpos = (x + f->dx) & 7;
698   int mask = 128 >> xpos;
699   i_color fg = f->fg;
700   i_color bg = f->bg;
701
702   if (channels < 3) {
703     i_adapt_colors(2, 4, &fg, 1);
704     i_adapt_colors(2, 4, &bg, 1);
705   }
706
707   while (width-- > 0) {
708     if (byte & mask)
709       *data++ = fg;
710     else
711       *data++ = bg;
712     
713     if ((mask >>= 1) == 0)
714       mask = 128;
715   }
716 }
717
718 /*
719 =item fill_hatchf(fill, x, y, width, channels, data)
720
721 The floating sample fill function for hatched fills.
722
723 =back
724 */
725 static void
726 fill_hatchf(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
727             int channels, i_fcolor *data) {
728   i_fill_hatch_t *f = (i_fill_hatch_t *)fill;
729   int byte = f->hatch[(y + f->dy) & 7];
730   int xpos = (x + f->dx) & 7;
731   int mask = 128 >> xpos;
732   i_fcolor fg = f->ffg;
733   i_fcolor bg = f->fbg;
734
735   if (channels < 3) {
736     i_adapt_fcolors(2, 4, &fg, 1);
737     i_adapt_fcolors(2, 4, &bg, 1);
738   }
739   
740   while (width-- > 0) {
741     if (byte & mask)
742       *data++ = fg;
743     else
744       *data++ = bg;
745     
746     if ((mask >>= 1) == 0)
747       mask = 128;
748   }
749 }
750
751 /* hopefully this will be inlined  (it is with -O3 with gcc 2.95.4) */
752 /* linear interpolation */
753 static i_color interp_i_color(i_color before, i_color after, double pos,
754                               int channels) {
755   i_color out;
756   int ch;
757
758   pos -= floor(pos);
759   for (ch = 0; ch < channels; ++ch)
760     out.channel[ch] = (1-pos) * before.channel[ch] + pos * after.channel[ch];
761   if (channels > 3 && out.channel[3])
762     for (ch = 0; ch < channels; ++ch)
763       if (ch != 3) {
764         int temp = out.channel[ch] * 255 / out.channel[3];
765         if (temp > 255)
766           temp = 255;
767         out.channel[ch] = temp;
768       }
769
770   return out;
771 }
772
773 /* hopefully this will be inlined  (it is with -O3 with gcc 2.95.4) */
774 /* linear interpolation */
775 static i_fcolor interp_i_fcolor(i_fcolor before, i_fcolor after, double pos,
776                                 int channels) {
777   i_fcolor out;
778   int ch;
779
780   pos -= floor(pos);
781   for (ch = 0; ch < channels; ++ch)
782     out.channel[ch] = (1-pos) * before.channel[ch] + pos * after.channel[ch];
783   if (out.channel[3])
784     for (ch = 0; ch < channels; ++ch)
785       if (ch != 3) {
786         int temp = out.channel[ch] / out.channel[3];
787         if (temp > 1.0)
788           temp = 1.0;
789         out.channel[ch] = temp;
790       }
791
792   return out;
793 }
794
795 /*
796 =item fill_image(fill, x, y, width, channels, data, work)
797
798 =cut
799 */
800 static void
801 fill_image(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
802            int channels, i_color *data) {
803   struct i_fill_image_t *f = (struct i_fill_image_t *)fill;
804   i_img_dim i = 0;
805   i_color *out = data;
806   int want_channels = channels > 2 ? 4 : 2;
807   
808   if (f->has_matrix) {
809     /* the hard way */
810     while (i < width) {
811       double rx = f->matrix[0] * (x+i) + f->matrix[1] * y + f->matrix[2];
812       double ry = f->matrix[3] * (x+i) + f->matrix[4] * y + f->matrix[5];
813       double ix = floor(rx / f->src->xsize);
814       double iy = floor(ry / f->src->ysize);
815       i_color c[2][2];
816       i_color c2[2];
817       i_img_dim dy;
818
819       if (f->xoff) {
820         rx += iy * f->xoff;
821         ix = floor(rx / f->src->xsize);
822       }
823       else if (f->yoff) {
824         ry += ix * f->yoff;
825         iy = floor(ry / f->src->ysize);
826       }
827       rx -= ix * f->src->xsize;
828       ry -= iy * f->src->ysize;
829
830       for (dy = 0; dy < 2; ++dy) {
831         if ((i_img_dim)rx == f->src->xsize-1) {
832           i_gpix(f->src, f->src->xsize-1, ((i_img_dim)ry+dy) % f->src->ysize, &c[dy][0]);
833           i_gpix(f->src, 0, ((i_img_dim)ry+dy) % f->src->xsize, &c[dy][1]);
834         }
835         else {
836           i_glin(f->src, (i_img_dim)rx, (i_img_dim)rx+2, ((i_img_dim)ry+dy) % f->src->ysize, 
837                  c[dy]);
838         }
839         c2[dy] = interp_i_color(c[dy][0], c[dy][1], rx, f->src->channels);
840       }
841       *out++ = interp_i_color(c2[0], c2[1], ry, f->src->channels);
842       ++i;
843     }
844   }
845   else {
846     /* the easy way */
847     /* this should be possible to optimize to use i_glin() */
848     while (i < width) {
849       i_img_dim rx = x+i;
850       i_img_dim ry = y;
851       i_img_dim ix = rx / f->src->xsize;
852       i_img_dim iy = ry / f->src->ysize;
853
854       if (f->xoff) {
855         rx += iy * f->xoff;
856         ix = rx / f->src->xsize;
857       }
858       else if (f->yoff) {
859         ry += ix * f->yoff;
860         iy = ry / f->src->ysize;
861       }
862       rx -= ix * f->src->xsize;
863       ry -= iy * f->src->ysize;
864       i_gpix(f->src, rx, ry, out);
865       ++out;
866       ++i;
867     }
868   }
869   if (f->src->channels != want_channels)
870     i_adapt_colors(want_channels, f->src->channels, data, width);
871 }
872
873 /*
874 =item fill_imagef(fill, x, y, width, channels, data, work)
875
876 =cut
877 */
878 static void
879 fill_imagef(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
880             int channels, i_fcolor *data) {
881   struct i_fill_image_t *f = (struct i_fill_image_t *)fill;
882   i_img_dim i = 0;
883   int want_channels = channels > 2 ? 4 : 2;
884   
885   if (f->has_matrix) {
886     i_fcolor *work_data = data;
887     /* the hard way */
888     while (i < width) {
889       double rx = f->matrix[0] * (x+i) + f->matrix[1] * y + f->matrix[2];
890       double ry = f->matrix[3] * (x+i) + f->matrix[4] * y + f->matrix[5];
891       double ix = floor(rx / f->src->xsize);
892       double iy = floor(ry / f->src->ysize);
893       i_fcolor c[2][2];
894       i_fcolor c2[2];
895       i_img_dim dy;
896
897       if (f->xoff) {
898         rx += iy * f->xoff;
899         ix = floor(rx / f->src->xsize);
900       }
901       else if (f->yoff) {
902         ry += ix * f->yoff;
903         iy = floor(ry / f->src->ysize);
904       }
905       rx -= ix * f->src->xsize;
906       ry -= iy * f->src->ysize;
907
908       for (dy = 0; dy < 2; ++dy) {
909         if ((i_img_dim)rx == f->src->xsize-1) {
910           i_gpixf(f->src, f->src->xsize-1, ((i_img_dim)ry+dy) % f->src->ysize, &c[dy][0]);
911           i_gpixf(f->src, 0, ((i_img_dim)ry+dy) % f->src->xsize, &c[dy][1]);
912         }
913         else {
914           i_glinf(f->src, (i_img_dim)rx, (i_img_dim)rx+2, ((i_img_dim)ry+dy) % f->src->ysize, 
915                  c[dy]);
916         }
917         c2[dy] = interp_i_fcolor(c[dy][0], c[dy][1], rx, f->src->channels);
918       }
919       *work_data++ = interp_i_fcolor(c2[0], c2[1], ry, f->src->channels);
920       ++i;
921     }
922   }
923   else {
924     i_fcolor *work_data = data;
925     /* the easy way */
926     /* this should be possible to optimize to use i_glin() */
927     while (i < width) {
928       i_img_dim rx = x+i;
929       i_img_dim ry = y;
930       i_img_dim ix = rx / f->src->xsize;
931       i_img_dim iy = ry / f->src->ysize;
932
933       if (f->xoff) {
934         rx += iy * f->xoff;
935         ix = rx / f->src->xsize;
936       }
937       else if (f->yoff) {
938         ry += ix * f->yoff;
939         iy = ry / f->src->xsize;
940       }
941       rx -= ix * f->src->xsize;
942       ry -= iy * f->src->ysize;
943       i_gpixf(f->src, rx, ry, work_data);
944       ++work_data;
945       ++i;
946     }
947   }
948   if (f->src->channels != want_channels)
949     i_adapt_fcolors(want_channels, f->src->channels, data, width);
950 }
951
952 static void 
953 fill_opacity(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
954              int channels, i_color *data) {
955   struct i_fill_opacity_t *f = (struct i_fill_opacity_t *)fill;
956   int alpha_chan = channels > 2 ? 3 : 1;
957   i_color *datap = data;
958   
959   (f->other_fill->f_fill_with_color)(f->other_fill, x, y, width, channels, data);
960   while (width--) {
961     double new_alpha = datap->channel[alpha_chan] * f->alpha_mult;
962     if (new_alpha < 0) 
963       datap->channel[alpha_chan] = 0;
964     else if (new_alpha > 255)
965       datap->channel[alpha_chan] = 255;
966     else datap->channel[alpha_chan] = (int)(new_alpha + 0.5);
967
968     ++datap;
969   }
970 }
971 static void 
972 fill_opacityf(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
973               int channels, i_fcolor *data) {
974   struct i_fill_opacity_t *f = (struct i_fill_opacity_t *)fill;
975   int alpha_chan = channels > 2 ? 3 : 1;
976   i_fcolor *datap = data;
977   
978   (f->other_fill->f_fill_with_fcolor)(f->other_fill, x, y, width, channels, data);
979   
980   while (width--) {
981     double new_alpha = datap->channel[alpha_chan] * f->alpha_mult;
982     if (new_alpha < 0) 
983       datap->channel[alpha_chan] = 0;
984     else if (new_alpha > 1.0)
985       datap->channel[alpha_chan] = 1.0;
986     else datap->channel[alpha_chan] = new_alpha;
987
988     ++datap;
989   }
990 }
991
992 /*
993 =back
994
995 =head1 AUTHOR
996
997 Tony Cook <tony@develop-help.com>
998
999 =head1 SEE ALSO
1000
1001 Imager(3)
1002
1003 =cut
1004 */