File Coverage

fills.c
Criterion Covered Total %
statement 236 286 82.5
branch 107 154 69.4
condition n/a
subroutine n/a
pod n/a
total 343 440 77.9


line stmt bran cond sub pod time code
1             #define IMAGER_NO_CONTEXT
2             #include "imager.h"
3             #include "imageri.h"
4             #include
5              
6             /*
7             =head1 NAME
8              
9             fills.c - implements the basic general fills
10              
11             =head1 SYNOPSIS
12              
13             i_fill_t *fill;
14             i_color c1, c2;
15             i_fcolor fc1, fc2;
16             int combine;
17             fill = i_new_fill_solidf(&fc1, combine);
18             fill = i_new_fill_solid(&c1, combine);
19             fill = i_new_fill_hatchf(&fc1, &fc2, combine, hatch, cust_hash, dx, dy);
20             fill = i_new_fill_hatch(&c1, &c2, combine, hatch, cust_hash, dx, dy);
21             fill = i_new_fill_image(im, matrix, xoff, yoff, combine);
22             fill = i_new_fill_opacity(fill, alpha_mult);
23             i_fill_destroy(fill);
24              
25             =head1 DESCRIPTION
26              
27             Implements the basic general fills, which can be used for filling some
28             shapes and for flood fills.
29              
30             Each fill can implement up to 3 functions:
31              
32             =over
33              
34             =item fill_with_color
35              
36             called for fills on 8-bit images. This can be NULL in which case the
37             fill_with_colorf function is called.
38              
39             =item fill_with_fcolor
40              
41             called for fills on non-8-bit images or when fill_with_color is NULL.
42              
43             =item destroy
44              
45             called by i_fill_destroy() if non-NULL, to release any extra resources
46             that the fill may need.
47              
48             =back
49              
50             fill_with_color and fill_with_fcolor are basically the same function
51             except that the first works with lines of i_color and the second with
52             lines of i_fcolor.
53              
54             If the combines member if non-zero the line data is populated from the
55             target image before calling fill_with_*color.
56              
57             fill_with_color needs to fill the I parameter with the fill
58             pixels. If combines is non-zero it the fill pixels should be combined
59             with the existing data.
60              
61             The current fills are:
62              
63             =over
64              
65             =item *
66              
67             solid fill
68              
69             =item *
70              
71             hatched fill
72              
73             =item *
74              
75             fountain fill
76              
77             =back
78              
79             Fountain fill is implemented by L.
80              
81             Other fills that could be implemented include:
82              
83             =over
84              
85             =item *
86              
87             image - an image tiled over the fill area, with an offset either
88             horizontally or vertically.
89              
90             =item *
91              
92             checkerboard - combine 2 fills in a checkerboard
93              
94             =item *
95              
96             combine - combine the levels of 2 other fills based in the levels of
97             an image
98              
99             =item *
100              
101             regmach - use the register machine to generate colors
102              
103             =back
104              
105             =over
106              
107             =cut
108             */
109              
110 4           static i_color fcolor_to_color(const i_fcolor *c) {
111             int ch;
112             i_color out;
113              
114 20 100         for (ch = 0; ch < MAXCHANNELS; ++ch)
115 16           out.channel[ch] = SampleFTo8(c->channel[ch]);
116              
117 4           return out;
118             }
119              
120 58           static i_fcolor color_to_fcolor(const i_color *c) {
121             int ch;
122             i_fcolor out;
123              
124 290 100         for (ch = 0; ch < MAXCHANNELS; ++ch)
125 232           out.channel[ch] = Sample8ToF(c->channel[ch]);
126              
127 58           return out;
128             }
129              
130             /* alpha combine in with out */
131             #define COMBINE(out, in, channels) \
132             { \
133             int ch; \
134             for (ch = 0; ch < (channels); ++ch) { \
135             (out).channel[ch] = ((out).channel[ch] * (255 - (in).channel[3]) \
136             + (in).channel[ch] * (in).channel[3]) / 255; \
137             } \
138             }
139              
140             /* alpha combine in with out, in this case in is a simple array of
141             samples, potentially not integers - the mult combiner uses doubles
142             for accuracy */
143             #define COMBINEA(out, in, channels) \
144             { \
145             int ch; \
146             for (ch = 0; ch < (channels); ++ch) { \
147             (out).channel[ch] = ((out).channel[ch] * (255 - (in)[3]) \
148             + (in)[ch] * (in)[3]) / 255; \
149             } \
150             }
151              
152             #define COMBINEF(out, in, channels) \
153             { \
154             int ch; \
155             for (ch = 0; ch < (channels); ++ch) { \
156             (out).channel[ch] = (out).channel[ch] * (1.0 - (in).channel[3]) \
157             + (in).channel[ch] * (in).channel[3]; \
158             } \
159             }
160              
161             typedef struct
162             {
163             i_fill_t base;
164             i_color c;
165             i_fcolor fc;
166             } i_fill_solid_t;
167              
168             static void fill_solid(i_fill_t *, i_img_dim x, i_img_dim y, i_img_dim width,
169             int channels, i_color *);
170             static void fill_solidf(i_fill_t *, i_img_dim x, i_img_dim y, i_img_dim width,
171             int channels, 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              
184             /*
185             =item i_fill_destroy(fill)
186             =order 90
187             =category Fills
188             =synopsis i_fill_destroy(fill);
189              
190             Call to destroy any fill object.
191              
192             =cut
193             */
194              
195             void
196 74           i_fill_destroy(i_fill_t *fill) {
197 74 100         if (fill->destroy)
198 5           (fill->destroy)(fill);
199 74           myfree(fill);
200 74           }
201              
202             /*
203             =item i_new_fill_solidf(color, combine)
204              
205             =category Fills
206             =synopsis i_fill_t *fill = i_new_fill_solidf(&fcolor, 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 1           i_new_fill_solidf(const i_fcolor *c, int combine) {
217             int ch;
218 1           i_fill_solid_t *fill = mymalloc(sizeof(i_fill_solid_t)); /* checked 14jul05 tonyc */
219            
220 1           *fill = base_solid_fill;
221 1 50         if (combine) {
222 0           i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
223             }
224              
225 1           fill->fc = *c;
226 5 100         for (ch = 0; ch < MAXCHANNELS; ++ch) {
227 4           fill->c.channel[ch] = SampleFTo8(c->channel[ch]);
228             }
229            
230 1           return &fill->base;
231             }
232              
233             /*
234             =item i_new_fill_solid(color, combine)
235              
236             =category Fills
237             =synopsis i_fill_t *fill = i_new_fill_solid(&color, combine);
238              
239             Create a solid fill based on an 8-bit color.
240              
241             If combine is non-zero then alpha values will be combined.
242              
243             =cut
244             */
245              
246             i_fill_t *
247 23           i_new_fill_solid(const i_color *c, int combine) {
248             int ch;
249 23           i_fill_solid_t *fill = mymalloc(sizeof(i_fill_solid_t)); /* checked 14jul05 tonyc */
250              
251 23           *fill = base_solid_fill;
252 23 100         if (combine) {
253 17           i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
254             }
255              
256 23           fill->c = *c;
257 115 100         for (ch = 0; ch < MAXCHANNELS; ++ch) {
258 92           fill->fc.channel[ch] = Sample8ToF(c->channel[ch]);
259             }
260            
261 23           return &fill->base;
262             }
263              
264             static unsigned char
265             builtin_hatches[][8] =
266             {
267             {
268             /* 1x1 checkerboard */
269             0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55,
270             },
271             {
272             /* 2x2 checkerboard */
273             0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33,
274             },
275             {
276             /* 4 x 4 checkerboard */
277             0xF0, 0xF0, 0xF0, 0xF0, 0x0F, 0x0F, 0x0F, 0x0F,
278             },
279             {
280             /* single vertical lines */
281             0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
282             },
283             {
284             /* double vertical lines */
285             0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
286             },
287             {
288             /* quad vertical lines */
289             0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
290             },
291             {
292             /* single hlines */
293             0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
294             },
295             {
296             /* double hlines */
297             0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,
298             },
299             {
300             /* quad hlines */
301             0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
302             },
303             {
304             /* single / */
305             0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80,
306             },
307             {
308             /* single \ */
309             0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01,
310             },
311             {
312             /* double / */
313             0x11, 0x22, 0x44, 0x88, 0x11, 0x22, 0x44, 0x88,
314             },
315             {
316             /* double \ */
317             0x88, 0x44, 0x22, 0x11, 0x88, 0x44, 0x22, 0x11,
318             },
319             {
320             /* single grid */
321             0xFF, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
322             },
323             {
324             /* double grid */
325             0xFF, 0x88, 0x88, 0x88, 0xFF, 0x88, 0x88, 0x88,
326             },
327             {
328             /* quad grid */
329             0xFF, 0xAA, 0xFF, 0xAA, 0xFF, 0xAA, 0xFF, 0xAA,
330             },
331             {
332             /* single dots */
333             0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
334             },
335             {
336             /* 4 dots */
337             0x88, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00,
338             },
339             {
340             /* 16 dots */
341             0xAA, 0x00, 0xAA, 0x00, 0xAA, 0x00, 0xAA, 0x00,
342             },
343             {
344             /* simple stipple */
345             0x48, 0x84, 0x00, 0x00, 0x84, 0x48, 0x00, 0x00,
346             },
347             {
348             /* weave */
349             0x55, 0xFD, 0x05, 0xFD, 0x55, 0xDF, 0x50, 0xDF,
350             },
351             {
352             /* single cross hatch */
353             0x82, 0x44, 0x28, 0x10, 0x28, 0x44, 0x82, 0x01,
354             },
355             {
356             /* double cross hatch */
357             0xAA, 0x44, 0xAA, 0x11, 0xAA, 0x44, 0xAA, 0x11,
358             },
359             {
360             /* vertical lozenge */
361             0x11, 0x11, 0x11, 0xAA, 0x44, 0x44, 0x44, 0xAA,
362             },
363             {
364             /* horizontal lozenge */
365             0x88, 0x70, 0x88, 0x07, 0x88, 0x70, 0x88, 0x07,
366             },
367             {
368             /* scales overlapping downwards */
369             0x80, 0x80, 0x41, 0x3E, 0x08, 0x08, 0x14, 0xE3,
370             },
371             {
372             /* scales overlapping upwards */
373             0xC7, 0x28, 0x10, 0x10, 0x7C, 0x82, 0x01, 0x01,
374             },
375             {
376             /* scales overlapping leftwards */
377             0x83, 0x84, 0x88, 0x48, 0x38, 0x48, 0x88, 0x84,
378             },
379             {
380             /* scales overlapping rightwards */
381             0x21, 0x11, 0x12, 0x1C, 0x12, 0x11, 0x21, 0xC1,
382             },
383             {
384             /* denser stipple */
385             0x44, 0x88, 0x22, 0x11, 0x44, 0x88, 0x22, 0x11,
386             },
387             {
388             /* L-shaped tiles */
389             0xFF, 0x84, 0x84, 0x9C, 0x94, 0x9C, 0x90, 0x90,
390             },
391             {
392             /* wider stipple */
393             0x80, 0x40, 0x20, 0x00, 0x02, 0x04, 0x08, 0x00,
394             },
395             };
396              
397             typedef struct
398             {
399             i_fill_t base;
400             i_color fg, bg;
401             i_fcolor ffg, fbg;
402             unsigned char hatch[8];
403             i_img_dim dx, dy;
404             } i_fill_hatch_t;
405              
406             static void fill_hatch(i_fill_t *fill, i_img_dim x, i_img_dim y,
407             i_img_dim width, int channels, i_color *data);
408             static void fill_hatchf(i_fill_t *fill, i_img_dim x, i_img_dim y,
409             i_img_dim width, int channels, i_fcolor *data);
410             static
411             i_fill_t *
412             i_new_hatch_low(const i_color *fg, const i_color *bg, const i_fcolor *ffg, const i_fcolor *fbg,
413             int combine, int hatch, const unsigned char *cust_hatch,
414             i_img_dim dx, i_img_dim dy);
415              
416             /*
417             =item i_new_fill_hatch(C, C, C, C, C, C, C)
418              
419             =category Fills
420             =synopsis i_fill_t *fill = i_new_fill_hatch(&fg_color, &bg_color, combine, hatch, custom_hatch, dx, dy);
421              
422             Creates a new hatched fill with the C color used for the 1 bits in
423             the hatch and C for the 0 bits. If C is non-zero alpha
424             values will be combined.
425              
426             If C 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 C is NULL then one of the standard hatches is used.
430              
431             (C, C) are an offset into the hatch which can be used to hatch
432             adjoining areas out of alignment, or to align the origin of a hatch
433             with the side of a filled area.
434              
435             =cut
436             */
437             i_fill_t *
438 29           i_new_fill_hatch(const i_color *fg, const i_color *bg, int combine, int hatch,
439             const unsigned char *cust_hatch, i_img_dim dx, i_img_dim dy) {
440 29 50         assert(fg);
441 29 50         assert(bg);
442 29           return i_new_hatch_low(fg, bg, NULL, NULL, combine, hatch, cust_hatch,
443             dx, dy);
444             }
445              
446             /*
447             =item i_new_fill_hatchf(C, C, C, C, C, C, C)
448              
449             =category Fills
450             =synopsis i_fill_t *fill = i_new_fill_hatchf(&fg_fcolor, &bg_fcolor, combine, hatch, custom_hatch, dx, dy);
451              
452             Creates a new hatched fill with the C color used for the 1 bits in
453             the hatch and C for the 0 bits. If C is non-zero alpha
454             values will be combined.
455              
456             If C is non-NULL it should be a pointer to 8 bytes of the
457             hash definition, with the high-bits to the left.
458              
459             If C is NULL then one of the standard hatches is used.
460              
461             (C, C) are an offset into the hatch which can be used to hatch
462             adjoining areas out of alignment, or to align the origin of a hatch
463             with the side of a filled area.
464              
465             =cut
466             */
467             i_fill_t *
468 2           i_new_fill_hatchf(const i_fcolor *fg, const i_fcolor *bg, int combine, int hatch,
469             const unsigned char *cust_hatch, i_img_dim dx, i_img_dim dy) {
470 2 50         assert(fg);
471 2 50         assert(bg);
472 2           return i_new_hatch_low(NULL, NULL, fg, bg, combine, hatch, cust_hatch,
473             dx, dy);
474             }
475              
476             static void fill_image(i_fill_t *fill, i_img_dim x, i_img_dim y,
477             i_img_dim width, int channels, i_color *data);
478             static void fill_imagef(i_fill_t *fill, i_img_dim x, i_img_dim y,
479             i_img_dim width, int channels, i_fcolor *data);
480             struct i_fill_image_t {
481             i_fill_t base;
482             i_img *src;
483             i_img_dim xoff, yoff;
484             int has_matrix;
485             double matrix[9];
486             };
487              
488             static struct i_fill_image_t
489             image_fill_proto =
490             {
491             {
492             fill_image,
493             fill_imagef,
494             NULL
495             }
496             };
497              
498             /*
499             =item i_new_fill_image(C, C, C, C, C)
500              
501             =category Fills
502             =synopsis i_fill_t *fill = i_new_fill_image(src_img, matrix, x_offset, y_offset, combine);
503              
504             Create an image based fill.
505              
506             matrix is an array of 9 doubles representing a transformation matrix.
507              
508             C and C are the offset into the image to start filling from.
509              
510             =cut
511             */
512             i_fill_t *
513 9           i_new_fill_image(i_img *im, const double *matrix, i_img_dim xoff, i_img_dim yoff, int combine) {
514 9           struct i_fill_image_t *fill = mymalloc(sizeof(*fill)); /* checked 14jul05 tonyc */
515              
516 9           *fill = image_fill_proto;
517              
518 9 100         if (combine) {
519 8           i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
520             }
521             else {
522 1           fill->base.combine = NULL;
523 1           fill->base.combinef = NULL;
524             }
525 9           fill->src = im;
526 9 50         if (xoff < 0)
527 0           xoff += im->xsize;
528 9           fill->xoff = xoff;
529 9 50         if (yoff < 0)
530 0           yoff += im->ysize;
531 9           fill->yoff = yoff;
532 9 100         if (matrix) {
533 1           fill->has_matrix = 1;
534 1           memcpy(fill->matrix, matrix, sizeof(fill->matrix));
535             }
536             else
537 8           fill->has_matrix = 0;
538              
539 9           return &fill->base;
540             }
541              
542             static void fill_opacity(i_fill_t *fill, i_img_dim x, i_img_dim y,
543             i_img_dim width, int channels, i_color *data);
544             static void fill_opacityf(i_fill_t *fill, i_img_dim x, i_img_dim y,
545             i_img_dim width, int channels, i_fcolor *data);
546              
547             struct i_fill_opacity_t {
548             i_fill_t base;
549             i_fill_t *other_fill;
550             double alpha_mult;
551             };
552              
553             static struct i_fill_opacity_t
554             opacity_fill_proto =
555             {
556             {
557             fill_opacity,
558             fill_opacityf,
559             NULL
560             }
561             };
562              
563             i_fill_t *
564 5           i_new_fill_opacity(i_fill_t *base_fill, double alpha_mult) {
565 5           struct i_fill_opacity_t *fill = mymalloc(sizeof(*fill));
566 5           *fill = opacity_fill_proto;
567              
568 5           fill->base.combine = base_fill->combine;
569 5           fill->base.combinef = base_fill->combinef;
570              
571 5           fill->other_fill = base_fill;
572 5           fill->alpha_mult = alpha_mult;
573              
574 5 100         if (!base_fill->f_fill_with_color) {
575             /* base fill only does floating, so we only do that too */
576 1           fill->base.f_fill_with_color = NULL;
577             }
578              
579 5           return &fill->base;
580             }
581              
582             #define T_SOLID_FILL(fill) ((i_fill_solid_t *)(fill))
583              
584             /*
585             =back
586              
587             =head1 INTERNAL FUNCTIONS
588              
589             =over
590              
591             =item fill_solid(fill, x, y, width, channels, data)
592              
593             The 8-bit sample fill function for non-combining solid fills.
594              
595             =cut
596             */
597             static void
598 729           fill_solid(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
599             int channels, i_color *data) {
600 729           i_color c = T_SOLID_FILL(fill)->c;
601 729 50         i_adapt_colors(channels > 2 ? 4 : 2, 4, &c, 1);
602 39919 100         while (width-- > 0) {
603 39190           *data++ = c;
604             }
605 729           }
606              
607             /*
608             =item fill_solid(fill, x, y, width, channels, data)
609              
610             The floating sample fill function for non-combining solid fills.
611              
612             =cut
613             */
614             static void
615 156           fill_solidf(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
616             int channels, i_fcolor *data) {
617 156           i_fcolor c = T_SOLID_FILL(fill)->fc;
618 156 50         i_adapt_fcolors(channels > 2 ? 4 : 2, 4, &c, 1);
619 780 100         while (width-- > 0) {
620 624           *data++ = c;
621             }
622 156           }
623              
624             static i_fill_hatch_t
625             hatch_fill_proto =
626             {
627             {
628             fill_hatch,
629             fill_hatchf,
630             NULL
631             }
632             };
633              
634             /*
635             =item i_new_hatch_low(fg, bg, ffg, fbg, combine, hatch, cust_hatch, dx, dy)
636              
637             Implements creation of hatch fill objects.
638              
639             =cut
640             */
641             static
642             i_fill_t *
643 31           i_new_hatch_low(const i_color *fg, const i_color *bg,
644             const i_fcolor *ffg, const i_fcolor *fbg,
645             int combine, int hatch, const unsigned char *cust_hatch,
646             i_img_dim dx, i_img_dim dy) {
647 31           i_fill_hatch_t *fill = mymalloc(sizeof(i_fill_hatch_t)); /* checked 14jul05 tonyc */
648              
649 31           *fill = hatch_fill_proto;
650 31 100         if (fg && bg) {
    50          
651 29           fill->fg = *fg;
652 29           fill->bg = *bg;
653 29           fill->ffg = color_to_fcolor(fg);
654 29           fill->fbg = color_to_fcolor(bg);
655             }
656 2 50         else if (ffg && fbg) {
    50          
657 2           fill->fg = fcolor_to_color(ffg);
658 2           fill->bg = fcolor_to_color(fbg);
659 2           fill->ffg = *ffg;
660 2           fill->fbg = *fbg;
661             }
662             else {
663 0           assert(0);
664             /* NOTREACHED */
665             }
666            
667 31 100         if (combine) {
668 3           i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
669             }
670             else {
671 28           fill->base.combine = NULL;
672 28           fill->base.combinef = NULL;
673             }
674 31 100         if (cust_hatch) {
675 1           memcpy(fill->hatch, cust_hatch, 8);
676             }
677             else {
678 30 50         if (hatch >= sizeof(builtin_hatches)/sizeof(*builtin_hatches)
679 30 50         || hatch < 0) {
680 0           hatch = 0;
681             }
682 30           memcpy(fill->hatch, builtin_hatches[hatch], 8);
683             }
684 31           fill->dx = dx & 7;
685 31           fill->dy = dy & 7;
686              
687 31           return &fill->base;
688             }
689              
690             /*
691             =item fill_hatch(fill, x, y, width, channels, data)
692              
693             The 8-bit sample fill function for hatched fills.
694              
695             =cut
696             */
697             static void
698 133458           fill_hatch(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
699             int channels, i_color *data) {
700 133458           i_fill_hatch_t *f = (i_fill_hatch_t *)fill;
701 133458           int byte = f->hatch[(y + f->dy) & 7];
702 133458           int xpos = (x + f->dx) & 7;
703 133458           int mask = 128 >> xpos;
704 133458           i_color fg = f->fg;
705 133458           i_color bg = f->bg;
706              
707 133458 100         if (channels < 3) {
708 50           i_adapt_colors(2, 4, &fg, 1);
709 50           i_adapt_colors(2, 4, &bg, 1);
710             }
711              
712 589752 100         while (width-- > 0) {
713 456294 100         if (byte & mask)
714 219546           *data++ = fg;
715             else
716 236748           *data++ = bg;
717            
718 456294 100         if ((mask >>= 1) == 0)
719 40181           mask = 128;
720             }
721 133458           }
722              
723             /*
724             =item fill_hatchf(fill, x, y, width, channels, data)
725              
726             The floating sample fill function for hatched fills.
727              
728             =cut
729             */
730             static void
731 488           fill_hatchf(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
732             int channels, i_fcolor *data) {
733 488           i_fill_hatch_t *f = (i_fill_hatch_t *)fill;
734 488           int byte = f->hatch[(y + f->dy) & 7];
735 488           int xpos = (x + f->dx) & 7;
736 488           int mask = 128 >> xpos;
737 488           i_fcolor fg = f->ffg;
738 488           i_fcolor bg = f->fbg;
739              
740 488 100         if (channels < 3) {
741 10           i_adapt_fcolors(2, 4, &fg, 1);
742 10           i_adapt_fcolors(2, 4, &bg, 1);
743             }
744            
745 50675 100         while (width-- > 0) {
746 50187 100         if (byte & mask)
747 16687           *data++ = fg;
748             else
749 33500           *data++ = bg;
750            
751 50187 100         if ((mask >>= 1) == 0)
752 6171           mask = 128;
753             }
754 488           }
755              
756             /* hopefully this will be inlined (it is with -O3 with gcc 2.95.4) */
757             /* linear interpolation */
758 15555           static i_color interp_i_color(i_color before, i_color after, double pos,
759             int channels) {
760             i_color out;
761             int ch;
762              
763 15555           pos -= floor(pos);
764 77775 100         for (ch = 0; ch < channels; ++ch)
765 62220           out.channel[ch] = (1-pos) * before.channel[ch] + pos * after.channel[ch];
766 15555 50         if (channels > 3 && out.channel[3]) {
    100          
767 48510 100         for (ch = 0; ch < channels; ++ch) {
768 38808 100         if (ch != 3) {
769 29106           int temp = out.channel[ch] * 255 / out.channel[3];
770 29106 100         if (temp > 255)
771 6953           temp = 255;
772 29106           out.channel[ch] = temp;
773             }
774             }
775             }
776              
777 15555           return out;
778             }
779              
780             /* hopefully this will be inlined (it is with -O3 with gcc 2.95.4) */
781             /* linear interpolation */
782 0           static i_fcolor interp_i_fcolor(i_fcolor before, i_fcolor after, double pos,
783             int channels) {
784             i_fcolor out;
785             int ch;
786              
787 0           pos -= floor(pos);
788 0 0         for (ch = 0; ch < channels; ++ch)
789 0           out.channel[ch] = (1-pos) * before.channel[ch] + pos * after.channel[ch];
790 0 0         if (out.channel[3]) {
791 0 0         for (ch = 0; ch < channels; ++ch) {
792 0 0         if (ch != 3) {
793 0           int temp = out.channel[ch] / out.channel[3];
794 0 0         if (temp > 1.0)
795 0           temp = 1.0;
796 0           out.channel[ch] = temp;
797             }
798             }
799             }
800              
801 0           return out;
802             }
803              
804             /*
805             =item fill_image(fill, x, y, width, channels, data, work)
806              
807             =cut
808             */
809             static void
810 372           fill_image(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
811             int channels, i_color *data) {
812 372           struct i_fill_image_t *f = (struct i_fill_image_t *)fill;
813 372           i_img_dim i = 0;
814 372           i_color *out = data;
815 372 100         int want_channels = channels > 2 ? 4 : 2;
816            
817 372 100         if (f->has_matrix) {
818             /* the hard way */
819 5266 100         while (i < width) {
820 5185           double rx = f->matrix[0] * (x+i) + f->matrix[1] * y + f->matrix[2];
821 5185           double ry = f->matrix[3] * (x+i) + f->matrix[4] * y + f->matrix[5];
822 5185           double ix = floor(rx / f->src->xsize);
823 5185           double iy = floor(ry / f->src->ysize);
824             i_color c[2][2];
825             i_color c2[2];
826             i_img_dim dy;
827              
828 5185 50         if (f->xoff) {
829 5185           rx += iy * f->xoff;
830 5185           ix = floor(rx / f->src->xsize);
831             }
832 0 0         else if (f->yoff) {
833 0           ry += ix * f->yoff;
834 0           iy = floor(ry / f->src->ysize);
835             }
836 5185           rx -= ix * f->src->xsize;
837 5185           ry -= iy * f->src->ysize;
838              
839 15555 100         for (dy = 0; dy < 2; ++dy) {
840 10370 100         if ((i_img_dim)rx == f->src->xsize-1) {
841 224           i_gpix(f->src, f->src->xsize-1, ((i_img_dim)ry+dy) % f->src->ysize, &c[dy][0]);
842 224           i_gpix(f->src, 0, ((i_img_dim)ry+dy) % f->src->xsize, &c[dy][1]);
843             }
844             else {
845 10146           i_glin(f->src, (i_img_dim)rx, (i_img_dim)rx+2, ((i_img_dim)ry+dy) % f->src->ysize,
846             c[dy]);
847             }
848 10370           c2[dy] = interp_i_color(c[dy][0], c[dy][1], rx, f->src->channels);
849             }
850 5185           *out++ = interp_i_color(c2[0], c2[1], ry, f->src->channels);
851 5185           ++i;
852             }
853             }
854             else {
855             /* the easy way */
856             /* this should be possible to optimize to use i_glin() */
857 17376 100         while (i < width) {
858 17085           i_img_dim rx = x+i;
859 17085           i_img_dim ry = y;
860 17085           i_img_dim ix = rx / f->src->xsize;
861 17085           i_img_dim iy = ry / f->src->ysize;
862              
863 17085 100         if (f->xoff) {
864 5185           rx += iy * f->xoff;
865 5185           ix = rx / f->src->xsize;
866             }
867 11900 100         else if (f->yoff) {
868 10000           ry += ix * f->yoff;
869 10000           iy = ry / f->src->ysize;
870             }
871 17085           rx -= ix * f->src->xsize;
872 17085           ry -= iy * f->src->ysize;
873 17085           i_gpix(f->src, rx, ry, out);
874 17085           ++out;
875 17085           ++i;
876             }
877             }
878 372 100         if (f->src->channels != want_channels)
879 180           i_adapt_colors(want_channels, f->src->channels, data, width);
880 372           }
881              
882             /*
883             =item fill_imagef(fill, x, y, width, channels, data, work)
884              
885             =cut
886             */
887             static void
888 100           fill_imagef(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
889             int channels, i_fcolor *data) {
890 100           struct i_fill_image_t *f = (struct i_fill_image_t *)fill;
891 100           i_img_dim i = 0;
892 100 100         int want_channels = channels > 2 ? 4 : 2;
893            
894 100 50         if (f->has_matrix) {
895 0           i_fcolor *work_data = data;
896             /* the hard way */
897 0 0         while (i < width) {
898 0           double rx = f->matrix[0] * (x+i) + f->matrix[1] * y + f->matrix[2];
899 0           double ry = f->matrix[3] * (x+i) + f->matrix[4] * y + f->matrix[5];
900 0           double ix = floor(rx / f->src->xsize);
901 0           double iy = floor(ry / f->src->ysize);
902             i_fcolor c[2][2];
903             i_fcolor c2[2];
904             i_img_dim dy;
905              
906 0 0         if (f->xoff) {
907 0           rx += iy * f->xoff;
908 0           ix = floor(rx / f->src->xsize);
909             }
910 0 0         else if (f->yoff) {
911 0           ry += ix * f->yoff;
912 0           iy = floor(ry / f->src->ysize);
913             }
914 0           rx -= ix * f->src->xsize;
915 0           ry -= iy * f->src->ysize;
916              
917 0 0         for (dy = 0; dy < 2; ++dy) {
918 0 0         if ((i_img_dim)rx == f->src->xsize-1) {
919 0           i_gpixf(f->src, f->src->xsize-1, ((i_img_dim)ry+dy) % f->src->ysize, &c[dy][0]);
920 0           i_gpixf(f->src, 0, ((i_img_dim)ry+dy) % f->src->xsize, &c[dy][1]);
921             }
922             else {
923 0           i_glinf(f->src, (i_img_dim)rx, (i_img_dim)rx+2, ((i_img_dim)ry+dy) % f->src->ysize,
924             c[dy]);
925             }
926 0           c2[dy] = interp_i_fcolor(c[dy][0], c[dy][1], rx, f->src->channels);
927             }
928 0           *work_data++ = interp_i_fcolor(c2[0], c2[1], ry, f->src->channels);
929 0           ++i;
930             }
931             }
932             else {
933 100           i_fcolor *work_data = data;
934             /* the easy way */
935             /* this should be possible to optimize to use i_glin() */
936 1900 100         while (i < width) {
937 1800           i_img_dim rx = x+i;
938 1800           i_img_dim ry = y;
939 1800           i_img_dim ix = rx / f->src->xsize;
940 1800           i_img_dim iy = ry / f->src->ysize;
941              
942 1800 50         if (f->xoff) {
943 0           rx += iy * f->xoff;
944 0           ix = rx / f->src->xsize;
945             }
946 1800 50         else if (f->yoff) {
947 0           ry += ix * f->yoff;
948 0           iy = ry / f->src->xsize;
949             }
950 1800           rx -= ix * f->src->xsize;
951 1800           ry -= iy * f->src->ysize;
952 1800           i_gpixf(f->src, rx, ry, work_data);
953 1800           ++work_data;
954 1800           ++i;
955             }
956             }
957 100 100         if (f->src->channels != want_channels)
958 80           i_adapt_fcolors(want_channels, f->src->channels, data, width);
959 100           }
960              
961             static void
962 31           fill_opacity(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
963             int channels, i_color *data) {
964 31           struct i_fill_opacity_t *f = (struct i_fill_opacity_t *)fill;
965 31 50         int alpha_chan = channels > 2 ? 3 : 1;
966 31           i_color *datap = data;
967            
968 31           (f->other_fill->f_fill_with_color)(f->other_fill, x, y, width, channels, data);
969 332 100         while (width--) {
970 301           double new_alpha = datap->channel[alpha_chan] * f->alpha_mult;
971 301 50         if (new_alpha < 0)
972 0           datap->channel[alpha_chan] = 0;
973 301 50         else if (new_alpha > 255)
974 0           datap->channel[alpha_chan] = 255;
975 301           else datap->channel[alpha_chan] = (int)(new_alpha + 0.5);
976              
977 301           ++datap;
978             }
979 31           }
980             static void
981 120           fill_opacityf(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
982             int channels, i_fcolor *data) {
983 120           struct i_fill_opacity_t *f = (struct i_fill_opacity_t *)fill;
984 120 50         int alpha_chan = channels > 2 ? 3 : 1;
985 120           i_fcolor *datap = data;
986            
987 120           (f->other_fill->f_fill_with_fcolor)(f->other_fill, x, y, width, channels, data);
988            
989 10320 100         while (width--) {
990 10200           double new_alpha = datap->channel[alpha_chan] * f->alpha_mult;
991 10200 50         if (new_alpha < 0)
992 0           datap->channel[alpha_chan] = 0;
993 10200 50         else if (new_alpha > 1.0)
994 0           datap->channel[alpha_chan] = 1.0;
995 10200           else datap->channel[alpha_chan] = new_alpha;
996              
997 10200           ++datap;
998             }
999 120           }
1000              
1001             /*
1002             =back
1003              
1004             =head1 AUTHOR
1005              
1006             Tony Cook
1007              
1008             =head1 SEE ALSO
1009              
1010             Imager(3)
1011              
1012             =cut
1013             */