7 fills.c - implements the basic general fills
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 fill = i_new_fill_image(im, matrix, xoff, yoff, combine);
24 Implements the basic general fills, which can be used for filling some
25 shapes and for flood fills.
27 Each fill can implement up to 3 functions:
33 called for fills on 8-bit images. This can be NULL in which case the
34 fill_with_colorf function is called.
36 =item fill_with_fcolor
38 called for fills on non-8-bit images or when fill_with_color is NULL.
42 called by i_fill_destroy() if non-NULL, to release any extra resources
43 that the fill may need.
47 fill_with_color and fill_with_fcolor are basically the same function
48 except that the first works with lines of i_color and the second with
51 If the combines member if non-zero the line data is populated from the
52 target image before calling fill_with_*color.
54 fill_with_color needs to fill the I<data> parameter with the fill
55 pixels. If combines is non-zero it the fill pixels should be combined
56 with the existing data.
58 The current fills are:
76 Fountain fill is implemented by L<filters.c>.
78 Other fills that could be implemented include:
84 image - an image tiled over the fill area, with an offset either
85 horizontally or vertically.
89 checkerboard - combine 2 fills in a checkerboard
93 combine - combine the levels of 2 other fills based in the levels of
98 regmach - use the register machine to generate colors
107 static i_color fcolor_to_color(const i_fcolor *c) {
111 for (ch = 0; ch < MAXCHANNELS; ++ch)
112 out.channel[ch] = SampleFTo8(c->channel[ch]);
117 static i_fcolor color_to_fcolor(const i_color *c) {
121 for (ch = 0; ch < MAXCHANNELS; ++ch)
122 out.channel[ch] = Sample8ToF(c->channel[ch]);
127 /* alpha combine in with out */
128 #define COMBINE(out, in, channels) \
131 for (ch = 0; ch < (channels); ++ch) { \
132 (out).channel[ch] = ((out).channel[ch] * (255 - (in).channel[3]) \
133 + (in).channel[ch] * (in).channel[3]) / 255; \
137 /* alpha combine in with out, in this case in is a simple array of
138 samples, potentially not integers - the mult combiner uses doubles
140 #define COMBINEA(out, in, channels) \
143 for (ch = 0; ch < (channels); ++ch) { \
144 (out).channel[ch] = ((out).channel[ch] * (255 - (in)[3]) \
145 + (in)[ch] * (in)[3]) / 255; \
149 #define COMBINEF(out, in, channels) \
152 for (ch = 0; ch < (channels); ++ch) { \
153 (out).channel[ch] = (out).channel[ch] * (1.0 - (in).channel[3]) \
154 + (in).channel[ch] * (in).channel[3]; \
165 static void fill_solid(i_fill_t *, int x, int y, int width, int channels,
167 static void fill_solidf(i_fill_t *, int x, int y, int width, int channels,
170 static i_fill_solid_t base_solid_fill =
182 =item i_fill_destroy(fill)
185 =synopsis i_fill_destroy(fill);
187 Call to destroy any fill object.
193 i_fill_destroy(i_fill_t *fill) {
195 (fill->destroy)(fill);
200 =item i_new_fill_solidf(color, combine)
203 =synopsis i_fill_t *fill = i_new_fill_solidf(&fcolor, combine);
205 Create a solid fill based on a float color.
207 If combine is non-zero then alpha values will be combined.
213 i_new_fill_solidf(const i_fcolor *c, int combine) {
215 i_fill_solid_t *fill = mymalloc(sizeof(i_fill_solid_t)); /* checked 14jul05 tonyc */
217 *fill = base_solid_fill;
219 i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
223 for (ch = 0; ch < MAXCHANNELS; ++ch) {
224 fill->c.channel[ch] = SampleFTo8(c->channel[ch]);
231 =item i_new_fill_solid(color, combine)
234 =synopsis i_fill_t *fill = i_new_fill_solid(&color, combine);
236 Create a solid fill based on an 8-bit color.
238 If combine is non-zero then alpha values will be combined.
244 i_new_fill_solid(const i_color *c, int combine) {
246 i_fill_solid_t *fill = mymalloc(sizeof(i_fill_solid_t)); /* checked 14jul05 tonyc */
248 *fill = base_solid_fill;
250 i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
254 for (ch = 0; ch < MAXCHANNELS; ++ch) {
255 fill->fc.channel[ch] = Sample8ToF(c->channel[ch]);
262 builtin_hatches[][8] =
265 /* 1x1 checkerboard */
266 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55,
269 /* 2x2 checkerboard */
270 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33,
273 /* 4 x 4 checkerboard */
274 0xF0, 0xF0, 0xF0, 0xF0, 0x0F, 0x0F, 0x0F, 0x0F,
277 /* single vertical lines */
278 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
281 /* double vertical lines */
282 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
285 /* quad vertical lines */
286 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
290 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
294 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,
298 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
302 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80,
306 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01,
310 0x11, 0x22, 0x44, 0x88, 0x11, 0x22, 0x44, 0x88,
314 0x88, 0x44, 0x22, 0x11, 0x88, 0x44, 0x22, 0x11,
318 0xFF, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
322 0xFF, 0x88, 0x88, 0x88, 0xFF, 0x88, 0x88, 0x88,
326 0xFF, 0xAA, 0xFF, 0xAA, 0xFF, 0xAA, 0xFF, 0xAA,
330 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
334 0x88, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00,
338 0xAA, 0x00, 0xAA, 0x00, 0xAA, 0x00, 0xAA, 0x00,
342 0x48, 0x84, 0x00, 0x00, 0x84, 0x48, 0x00, 0x00,
346 0x55, 0xFD, 0x05, 0xFD, 0x55, 0xDF, 0x50, 0xDF,
349 /* single cross hatch */
350 0x82, 0x44, 0x28, 0x10, 0x28, 0x44, 0x82, 0x01,
353 /* double cross hatch */
354 0xAA, 0x44, 0xAA, 0x11, 0xAA, 0x44, 0xAA, 0x11,
357 /* vertical lozenge */
358 0x11, 0x11, 0x11, 0xAA, 0x44, 0x44, 0x44, 0xAA,
361 /* horizontal lozenge */
362 0x88, 0x70, 0x88, 0x07, 0x88, 0x70, 0x88, 0x07,
365 /* scales overlapping downwards */
366 0x80, 0x80, 0x41, 0x3E, 0x08, 0x08, 0x14, 0xE3,
369 /* scales overlapping upwards */
370 0xC7, 0x28, 0x10, 0x10, 0x7C, 0x82, 0x01, 0x01,
373 /* scales overlapping leftwards */
374 0x83, 0x84, 0x88, 0x48, 0x38, 0x48, 0x88, 0x84,
377 /* scales overlapping rightwards */
378 0x21, 0x11, 0x12, 0x1C, 0x12, 0x11, 0x21, 0xC1,
382 0x44, 0x88, 0x22, 0x11, 0x44, 0x88, 0x22, 0x11,
386 0xFF, 0x84, 0x84, 0x9C, 0x94, 0x9C, 0x90, 0x90,
390 0x80, 0x40, 0x20, 0x00, 0x02, 0x04, 0x08, 0x00,
399 unsigned char hatch[8];
403 static void fill_hatch(i_fill_t *fill, int x, int y, int width, int channels,
405 static void fill_hatchf(i_fill_t *fill, int x, int y, int width, int channels,
409 i_new_hatch_low(const i_color *fg, const i_color *bg, const i_fcolor *ffg, const i_fcolor *fbg,
410 int combine, int hatch, const unsigned char *cust_hatch,
414 =item i_new_fill_hatch(fg, bg, combine, hatch, cust_hatch, dx, dy)
417 =synopsis i_fill_t *fill = i_new_fill_hatch(&fg_color, &bg_color, combine, hatch, custom_hatch, dx, dy);
419 Creates a new hatched fill with the fg color used for the 1 bits in
420 the hatch and bg for the 0 bits. If combine is non-zero alpha values
423 If cust_hatch is non-NULL it should be a pointer to 8 bytes of the
424 hash definition, with the high-bits to the left.
426 If cust_hatch is NULL then one of the standard hatches is used.
428 (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.
433 i_new_fill_hatch(const i_color *fg, const i_color *bg, int combine, int hatch,
434 const unsigned char *cust_hatch, int dx, int dy) {
435 return i_new_hatch_low(fg, bg, NULL, NULL, combine, hatch, cust_hatch,
440 =item i_new_fill_hatchf(fg, bg, combine, hatch, cust_hatch, dx, dy)
443 =synopsis i_fill_t *fill = i_new_fill_hatchf(&fg_fcolor, &bg_fcolor, combine, hatch, custom_hatch, dx, dy);
445 Creates a new hatched fill with the fg color used for the 1 bits in
446 the hatch and bg for the 0 bits. If combine is non-zero alpha values
449 If cust_hatch is non-NULL it should be a pointer to 8 bytes of the
450 hash definition, with the high-bits to the left.
452 If cust_hatch is NULL then one of the standard hatches is used.
454 (dx, dy) are an offset into the hatch which can be used to unalign adjoining areas, or to align the origin of a hatch with the the side of a filled area.
459 i_new_fill_hatchf(const i_fcolor *fg, const i_fcolor *bg, int combine, int hatch,
460 const unsigned char *cust_hatch, int dx, int dy) {
461 return i_new_hatch_low(NULL, NULL, fg, bg, combine, hatch, cust_hatch,
465 static void fill_image(i_fill_t *fill, int x, int y, int width, int channels,
467 static void fill_imagef(i_fill_t *fill, int x, int y, int width, int channels,
469 struct i_fill_image_t {
477 static struct i_fill_image_t
488 =item i_new_fill_image(im, matrix, xoff, yoff, combine)
491 =synopsis i_fill_t *fill = i_new_fill_image(src_img, matrix, x_offset, y_offset, combine);
493 Create an image based fill.
495 matrix is an array of 9 doubles representing a transformation matrix.
497 xoff and yoff are the offset into the image to start filling from.
502 i_new_fill_image(i_img *im, const double *matrix, int xoff, int yoff, int combine) {
503 struct i_fill_image_t *fill = mymalloc(sizeof(*fill)); /* checked 14jul05 tonyc */
505 *fill = image_fill_proto;
508 i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
511 fill->base.combine = NULL;
512 fill->base.combinef = NULL;
522 fill->has_matrix = 1;
523 memcpy(fill->matrix, matrix, sizeof(fill->matrix));
526 fill->has_matrix = 0;
532 #define T_SOLID_FILL(fill) ((i_fill_solid_t *)(fill))
537 =head1 INTERNAL FUNCTIONS
541 =item fill_solid(fill, x, y, width, channels, data)
543 The 8-bit sample fill function for non-combining solid fills.
548 fill_solid(i_fill_t *fill, int x, int y, int width, int channels,
550 i_color c = T_SOLID_FILL(fill)->c;
551 i_adapt_colors(channels > 2 ? 4 : 2, 4, &c, 1);
552 while (width-- > 0) {
558 =item fill_solid(fill, x, y, width, channels, data)
560 The floating sample fill function for non-combining solid fills.
565 fill_solidf(i_fill_t *fill, int x, int y, int width, int channels,
567 i_fcolor c = T_SOLID_FILL(fill)->fc;
568 i_adapt_fcolors(channels > 2 ? 4 : 2, 4, &c, 1);
569 while (width-- > 0) {
574 static i_fill_hatch_t
585 =item i_new_hatch_low(fg, bg, ffg, fbg, combine, hatch, cust_hatch, dx, dy)
587 Implements creation of hatch fill objects.
593 i_new_hatch_low(const i_color *fg, const i_color *bg,
594 const i_fcolor *ffg, const i_fcolor *fbg,
595 int combine, int hatch, const unsigned char *cust_hatch,
597 i_fill_hatch_t *fill = mymalloc(sizeof(i_fill_hatch_t)); /* checked 14jul05 tonyc */
599 *fill = hatch_fill_proto;
600 /* Some Sun C didn't like the condition expressions that were here.
601 See https://rt.cpan.org/Ticket/Display.html?id=21944
606 fill->fg = fcolor_to_color(ffg);
610 fill->bg = fcolor_to_color(fbg);
614 fill->ffg = color_to_fcolor(fg);
618 fill->fbg = color_to_fcolor(bg);
620 i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
623 fill->base.combine = NULL;
624 fill->base.combinef = NULL;
627 memcpy(fill->hatch, cust_hatch, 8);
630 if (hatch > sizeof(builtin_hatches)/sizeof(*builtin_hatches))
632 memcpy(fill->hatch, builtin_hatches[hatch], 8);
641 =item fill_hatch(fill, x, y, width, channels, data)
643 The 8-bit sample fill function for hatched fills.
647 static void fill_hatch(i_fill_t *fill, int x, int y, int width, int channels,
649 i_fill_hatch_t *f = (i_fill_hatch_t *)fill;
650 int byte = f->hatch[(y + f->dy) & 7];
651 int xpos = (x + f->dx) & 7;
652 int mask = 128 >> xpos;
655 int want_channels = channels > 2 ? 4 : 2;
658 i_adapt_colors(2, 4, &fg, 1);
659 i_adapt_colors(2, 4, &bg, 1);
662 while (width-- > 0) {
668 if ((mask >>= 1) == 0)
674 =item fill_hatchf(fill, x, y, width, channels, data)
676 The floating sample fill function for hatched fills.
680 static void fill_hatchf(i_fill_t *fill, int x, int y, int width, int channels,
682 i_fill_hatch_t *f = (i_fill_hatch_t *)fill;
683 int byte = f->hatch[(y + f->dy) & 7];
684 int xpos = (x + f->dx) & 7;
685 int mask = 128 >> xpos;
686 i_fcolor fg = f->ffg;
687 i_fcolor bg = f->fbg;
690 i_adapt_fcolors(2, 4, &fg, 1);
691 i_adapt_fcolors(2, 4, &bg, 1);
694 while (width-- > 0) {
700 if ((mask >>= 1) == 0)
705 /* hopefully this will be inlined (it is with -O3 with gcc 2.95.4) */
706 /* linear interpolation */
707 static i_color interp_i_color(i_color before, i_color after, double pos,
713 for (ch = 0; ch < channels; ++ch)
714 out.channel[ch] = (1-pos) * before.channel[ch] + pos * after.channel[ch];
715 if (channels > 3 && out.channel[3])
716 for (ch = 0; ch < channels; ++ch)
718 int temp = out.channel[ch] * 255 / out.channel[3];
721 out.channel[ch] = temp;
727 /* hopefully this will be inlined (it is with -O3 with gcc 2.95.4) */
728 /* linear interpolation */
729 static i_fcolor interp_i_fcolor(i_fcolor before, i_fcolor after, double pos,
735 for (ch = 0; ch < channels; ++ch)
736 out.channel[ch] = (1-pos) * before.channel[ch] + pos * after.channel[ch];
738 for (ch = 0; ch < channels; ++ch)
740 int temp = out.channel[ch] / out.channel[3];
743 out.channel[ch] = temp;
750 =item fill_image(fill, x, y, width, channels, data, work)
754 static void fill_image(i_fill_t *fill, int x, int y, int width, int channels,
756 struct i_fill_image_t *f = (struct i_fill_image_t *)fill;
759 int want_channels = channels > 2 ? 4 : 2;
764 double rx = f->matrix[0] * (x+i) + f->matrix[1] * y + f->matrix[2];
765 double ry = f->matrix[3] * (x+i) + f->matrix[4] * y + f->matrix[5];
766 double ix = floor(rx / f->src->xsize);
767 double iy = floor(ry / f->src->ysize);
774 ix = floor(rx / f->src->xsize);
778 iy = floor(ry / f->src->ysize);
780 rx -= ix * f->src->xsize;
781 ry -= iy * f->src->ysize;
783 for (dy = 0; dy < 2; ++dy) {
784 if ((int)rx == f->src->xsize-1) {
785 i_gpix(f->src, f->src->xsize-1, ((int)ry+dy) % f->src->ysize, &c[dy][0]);
786 i_gpix(f->src, 0, ((int)ry+dy) % f->src->xsize, &c[dy][1]);
789 i_glin(f->src, (int)rx, (int)rx+2, ((int)ry+dy) % f->src->ysize,
792 c2[dy] = interp_i_color(c[dy][0], c[dy][1], rx, f->src->channels);
794 *out++ = interp_i_color(c2[0], c2[1], ry, f->src->channels);
800 /* this should be possible to optimize to use i_glin() */
804 int ix = rx / f->src->xsize;
805 int iy = ry / f->src->ysize;
809 ix = rx / f->src->xsize;
813 iy = ry / f->src->xsize;
815 rx -= ix * f->src->xsize;
816 ry -= iy * f->src->ysize;
817 i_gpix(f->src, rx, ry, out);
822 if (f->src->channels != want_channels)
823 i_adapt_colors(want_channels, f->src->channels, data, width);
827 =item fill_imagef(fill, x, y, width, channels, data, work)
831 static void fill_imagef(i_fill_t *fill, int x, int y, int width, int channels,
833 struct i_fill_image_t *f = (struct i_fill_image_t *)fill;
835 int want_channels = channels > 2 ? 4 : 2;
838 i_fcolor *work_data = data;
841 double rx = f->matrix[0] * (x+i) + f->matrix[1] * y + f->matrix[2];
842 double ry = f->matrix[3] * (x+i) + f->matrix[4] * y + f->matrix[5];
843 double ix = floor(rx / f->src->xsize);
844 double iy = floor(ry / f->src->ysize);
851 ix = floor(rx / f->src->xsize);
855 iy = floor(ry / f->src->ysize);
857 rx -= ix * f->src->xsize;
858 ry -= iy * f->src->ysize;
860 for (dy = 0; dy < 2; ++dy) {
861 if ((int)rx == f->src->xsize-1) {
862 i_gpixf(f->src, f->src->xsize-1, ((int)ry+dy) % f->src->ysize, &c[dy][0]);
863 i_gpixf(f->src, 0, ((int)ry+dy) % f->src->xsize, &c[dy][1]);
866 i_glinf(f->src, (int)rx, (int)rx+2, ((int)ry+dy) % f->src->ysize,
869 c2[dy] = interp_i_fcolor(c[dy][0], c[dy][1], rx, f->src->channels);
871 *work_data++ = interp_i_fcolor(c2[0], c2[1], ry, f->src->channels);
876 i_fcolor *work_data = data;
878 /* this should be possible to optimize to use i_glin() */
882 int ix = rx / f->src->xsize;
883 int iy = ry / f->src->ysize;
887 ix = rx / f->src->xsize;
891 iy = ry / f->src->xsize;
893 rx -= ix * f->src->xsize;
894 ry -= iy * f->src->ysize;
895 i_gpixf(f->src, rx, ry, work_data);
900 if (f->src->channels != want_channels)
901 i_adapt_fcolors(want_channels, f->src->channels, data, width);
910 Tony Cook <tony@develop-help.com>