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);
20 fill = i_new_fill_opacity(fill, alpha_mult);
25 Implements the basic general fills, which can be used for filling some
26 shapes and for flood fills.
28 Each fill can implement up to 3 functions:
34 called for fills on 8-bit images. This can be NULL in which case the
35 fill_with_colorf function is called.
37 =item fill_with_fcolor
39 called for fills on non-8-bit images or when fill_with_color is NULL.
43 called by i_fill_destroy() if non-NULL, to release any extra resources
44 that the fill may need.
48 fill_with_color and fill_with_fcolor are basically the same function
49 except that the first works with lines of i_color and the second with
52 If the combines member if non-zero the line data is populated from the
53 target image before calling fill_with_*color.
55 fill_with_color needs to fill the I<data> parameter with the fill
56 pixels. If combines is non-zero it the fill pixels should be combined
57 with the existing data.
59 The current fills are:
77 Fountain fill is implemented by L<filters.c>.
79 Other fills that could be implemented include:
85 image - an image tiled over the fill area, with an offset either
86 horizontally or vertically.
90 checkerboard - combine 2 fills in a checkerboard
94 combine - combine the levels of 2 other fills based in the levels of
99 regmach - use the register machine to generate colors
108 static i_color fcolor_to_color(const i_fcolor *c) {
112 for (ch = 0; ch < MAXCHANNELS; ++ch)
113 out.channel[ch] = SampleFTo8(c->channel[ch]);
118 static i_fcolor color_to_fcolor(const i_color *c) {
122 for (ch = 0; ch < MAXCHANNELS; ++ch)
123 out.channel[ch] = Sample8ToF(c->channel[ch]);
128 /* alpha combine in with out */
129 #define COMBINE(out, in, channels) \
132 for (ch = 0; ch < (channels); ++ch) { \
133 (out).channel[ch] = ((out).channel[ch] * (255 - (in).channel[3]) \
134 + (in).channel[ch] * (in).channel[3]) / 255; \
138 /* alpha combine in with out, in this case in is a simple array of
139 samples, potentially not integers - the mult combiner uses doubles
141 #define COMBINEA(out, in, channels) \
144 for (ch = 0; ch < (channels); ++ch) { \
145 (out).channel[ch] = ((out).channel[ch] * (255 - (in)[3]) \
146 + (in)[ch] * (in)[3]) / 255; \
150 #define COMBINEF(out, in, channels) \
153 for (ch = 0; ch < (channels); ++ch) { \
154 (out).channel[ch] = (out).channel[ch] * (1.0 - (in).channel[3]) \
155 + (in).channel[ch] * (in).channel[3]; \
166 static void fill_solid(i_fill_t *, int x, int y, int width, int channels,
168 static void fill_solidf(i_fill_t *, int x, int y, int width, int channels,
171 static i_fill_solid_t base_solid_fill =
183 =item i_fill_destroy(fill)
186 =synopsis i_fill_destroy(fill);
188 Call to destroy any fill object.
194 i_fill_destroy(i_fill_t *fill) {
196 (fill->destroy)(fill);
201 =item i_new_fill_solidf(color, combine)
204 =synopsis i_fill_t *fill = i_new_fill_solidf(&fcolor, combine);
206 Create a solid fill based on a float color.
208 If combine is non-zero then alpha values will be combined.
214 i_new_fill_solidf(const i_fcolor *c, int combine) {
216 i_fill_solid_t *fill = mymalloc(sizeof(i_fill_solid_t)); /* checked 14jul05 tonyc */
218 *fill = base_solid_fill;
220 i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
224 for (ch = 0; ch < MAXCHANNELS; ++ch) {
225 fill->c.channel[ch] = SampleFTo8(c->channel[ch]);
232 =item i_new_fill_solid(color, combine)
235 =synopsis i_fill_t *fill = i_new_fill_solid(&color, combine);
237 Create a solid fill based on an 8-bit color.
239 If combine is non-zero then alpha values will be combined.
245 i_new_fill_solid(const i_color *c, int combine) {
247 i_fill_solid_t *fill = mymalloc(sizeof(i_fill_solid_t)); /* checked 14jul05 tonyc */
249 *fill = base_solid_fill;
251 i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
255 for (ch = 0; ch < MAXCHANNELS; ++ch) {
256 fill->fc.channel[ch] = Sample8ToF(c->channel[ch]);
263 builtin_hatches[][8] =
266 /* 1x1 checkerboard */
267 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55,
270 /* 2x2 checkerboard */
271 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33,
274 /* 4 x 4 checkerboard */
275 0xF0, 0xF0, 0xF0, 0xF0, 0x0F, 0x0F, 0x0F, 0x0F,
278 /* single vertical lines */
279 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
282 /* double vertical lines */
283 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
286 /* quad vertical lines */
287 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
291 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
295 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,
299 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
303 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80,
307 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01,
311 0x11, 0x22, 0x44, 0x88, 0x11, 0x22, 0x44, 0x88,
315 0x88, 0x44, 0x22, 0x11, 0x88, 0x44, 0x22, 0x11,
319 0xFF, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
323 0xFF, 0x88, 0x88, 0x88, 0xFF, 0x88, 0x88, 0x88,
327 0xFF, 0xAA, 0xFF, 0xAA, 0xFF, 0xAA, 0xFF, 0xAA,
331 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
335 0x88, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00,
339 0xAA, 0x00, 0xAA, 0x00, 0xAA, 0x00, 0xAA, 0x00,
343 0x48, 0x84, 0x00, 0x00, 0x84, 0x48, 0x00, 0x00,
347 0x55, 0xFD, 0x05, 0xFD, 0x55, 0xDF, 0x50, 0xDF,
350 /* single cross hatch */
351 0x82, 0x44, 0x28, 0x10, 0x28, 0x44, 0x82, 0x01,
354 /* double cross hatch */
355 0xAA, 0x44, 0xAA, 0x11, 0xAA, 0x44, 0xAA, 0x11,
358 /* vertical lozenge */
359 0x11, 0x11, 0x11, 0xAA, 0x44, 0x44, 0x44, 0xAA,
362 /* horizontal lozenge */
363 0x88, 0x70, 0x88, 0x07, 0x88, 0x70, 0x88, 0x07,
366 /* scales overlapping downwards */
367 0x80, 0x80, 0x41, 0x3E, 0x08, 0x08, 0x14, 0xE3,
370 /* scales overlapping upwards */
371 0xC7, 0x28, 0x10, 0x10, 0x7C, 0x82, 0x01, 0x01,
374 /* scales overlapping leftwards */
375 0x83, 0x84, 0x88, 0x48, 0x38, 0x48, 0x88, 0x84,
378 /* scales overlapping rightwards */
379 0x21, 0x11, 0x12, 0x1C, 0x12, 0x11, 0x21, 0xC1,
383 0x44, 0x88, 0x22, 0x11, 0x44, 0x88, 0x22, 0x11,
387 0xFF, 0x84, 0x84, 0x9C, 0x94, 0x9C, 0x90, 0x90,
391 0x80, 0x40, 0x20, 0x00, 0x02, 0x04, 0x08, 0x00,
400 unsigned char hatch[8];
404 static void fill_hatch(i_fill_t *fill, int x, int y, int width, int channels,
406 static void fill_hatchf(i_fill_t *fill, int x, int y, int width, int channels,
410 i_new_hatch_low(const i_color *fg, const i_color *bg, const i_fcolor *ffg, const i_fcolor *fbg,
411 int combine, int hatch, const unsigned char *cust_hatch,
415 =item i_new_fill_hatch(fg, bg, combine, hatch, cust_hatch, dx, dy)
418 =synopsis i_fill_t *fill = i_new_fill_hatch(&fg_color, &bg_color, combine, hatch, custom_hatch, dx, dy);
420 Creates a new hatched fill with the fg color used for the 1 bits in
421 the hatch and bg for the 0 bits. If combine is non-zero alpha values
424 If cust_hatch is non-NULL it should be a pointer to 8 bytes of the
425 hash definition, with the high-bits to the left.
427 If cust_hatch is NULL then one of the standard hatches is used.
429 (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.
434 i_new_fill_hatch(const i_color *fg, const i_color *bg, int combine, int hatch,
435 const unsigned char *cust_hatch, int dx, int dy) {
436 return i_new_hatch_low(fg, bg, NULL, NULL, combine, hatch, cust_hatch,
441 =item i_new_fill_hatchf(fg, bg, combine, hatch, cust_hatch, dx, dy)
444 =synopsis i_fill_t *fill = i_new_fill_hatchf(&fg_fcolor, &bg_fcolor, combine, hatch, custom_hatch, dx, dy);
446 Creates a new hatched fill with the fg color used for the 1 bits in
447 the hatch and bg for the 0 bits. If combine is non-zero alpha values
450 If cust_hatch is non-NULL it should be a pointer to 8 bytes of the
451 hash definition, with the high-bits to the left.
453 If cust_hatch is NULL then one of the standard hatches is used.
455 (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.
460 i_new_fill_hatchf(const i_fcolor *fg, const i_fcolor *bg, int combine, int hatch,
461 const unsigned char *cust_hatch, int dx, int dy) {
462 return i_new_hatch_low(NULL, NULL, fg, bg, combine, hatch, cust_hatch,
466 static void fill_image(i_fill_t *fill, int x, int y, int width, int channels,
468 static void fill_imagef(i_fill_t *fill, int x, int y, int width, int channels,
470 struct i_fill_image_t {
478 static struct i_fill_image_t
489 =item i_new_fill_image(im, matrix, xoff, yoff, combine)
492 =synopsis i_fill_t *fill = i_new_fill_image(src_img, matrix, x_offset, y_offset, combine);
494 Create an image based fill.
496 matrix is an array of 9 doubles representing a transformation matrix.
498 xoff and yoff are the offset into the image to start filling from.
503 i_new_fill_image(i_img *im, const double *matrix, int xoff, int yoff, int combine) {
504 struct i_fill_image_t *fill = mymalloc(sizeof(*fill)); /* checked 14jul05 tonyc */
506 *fill = image_fill_proto;
509 i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
512 fill->base.combine = NULL;
513 fill->base.combinef = NULL;
523 fill->has_matrix = 1;
524 memcpy(fill->matrix, matrix, sizeof(fill->matrix));
527 fill->has_matrix = 0;
532 static void fill_opacity(i_fill_t *fill, int x, int y, int width, int channels,
534 static void fill_opacityf(i_fill_t *fill, int x, int y, int width, int channels,
537 struct i_fill_opacity_t {
539 i_fill_t *other_fill;
543 static struct i_fill_opacity_t
552 i_new_fill_opacity(i_fill_t *base_fill, double alpha_mult) {
553 struct i_fill_opacity_t *fill = mymalloc(sizeof(*fill));
554 *fill = opacity_fill_proto;
556 fill->base.combine = base_fill->combine;
557 fill->base.combinef = base_fill->combinef;
559 fill->other_fill = base_fill;
560 fill->alpha_mult = alpha_mult;
565 #define T_SOLID_FILL(fill) ((i_fill_solid_t *)(fill))
570 =head1 INTERNAL FUNCTIONS
574 =item fill_solid(fill, x, y, width, channels, data)
576 The 8-bit sample fill function for non-combining solid fills.
581 fill_solid(i_fill_t *fill, int x, int y, int width, int channels,
583 i_color c = T_SOLID_FILL(fill)->c;
584 i_adapt_colors(channels > 2 ? 4 : 2, 4, &c, 1);
585 while (width-- > 0) {
591 =item fill_solid(fill, x, y, width, channels, data)
593 The floating sample fill function for non-combining solid fills.
598 fill_solidf(i_fill_t *fill, int x, int y, int width, int channels,
600 i_fcolor c = T_SOLID_FILL(fill)->fc;
601 i_adapt_fcolors(channels > 2 ? 4 : 2, 4, &c, 1);
602 while (width-- > 0) {
607 static i_fill_hatch_t
618 =item i_new_hatch_low(fg, bg, ffg, fbg, combine, hatch, cust_hatch, dx, dy)
620 Implements creation of hatch fill objects.
626 i_new_hatch_low(const i_color *fg, const i_color *bg,
627 const i_fcolor *ffg, const i_fcolor *fbg,
628 int combine, int hatch, const unsigned char *cust_hatch,
630 i_fill_hatch_t *fill = mymalloc(sizeof(i_fill_hatch_t)); /* checked 14jul05 tonyc */
632 *fill = hatch_fill_proto;
633 /* Some Sun C didn't like the condition expressions that were here.
634 See https://rt.cpan.org/Ticket/Display.html?id=21944
639 fill->fg = fcolor_to_color(ffg);
643 fill->bg = fcolor_to_color(fbg);
647 fill->ffg = color_to_fcolor(fg);
651 fill->fbg = color_to_fcolor(bg);
653 i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
656 fill->base.combine = NULL;
657 fill->base.combinef = NULL;
660 memcpy(fill->hatch, cust_hatch, 8);
663 if (hatch > sizeof(builtin_hatches)/sizeof(*builtin_hatches))
665 memcpy(fill->hatch, builtin_hatches[hatch], 8);
674 =item fill_hatch(fill, x, y, width, channels, data)
676 The 8-bit sample fill function for hatched fills.
680 static void fill_hatch(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;
688 int want_channels = channels > 2 ? 4 : 2;
691 i_adapt_colors(2, 4, &fg, 1);
692 i_adapt_colors(2, 4, &bg, 1);
695 while (width-- > 0) {
701 if ((mask >>= 1) == 0)
707 =item fill_hatchf(fill, x, y, width, channels, data)
709 The floating sample fill function for hatched fills.
713 static void fill_hatchf(i_fill_t *fill, int x, int y, int width, int channels,
715 i_fill_hatch_t *f = (i_fill_hatch_t *)fill;
716 int byte = f->hatch[(y + f->dy) & 7];
717 int xpos = (x + f->dx) & 7;
718 int mask = 128 >> xpos;
719 i_fcolor fg = f->ffg;
720 i_fcolor bg = f->fbg;
723 i_adapt_fcolors(2, 4, &fg, 1);
724 i_adapt_fcolors(2, 4, &bg, 1);
727 while (width-- > 0) {
733 if ((mask >>= 1) == 0)
738 /* hopefully this will be inlined (it is with -O3 with gcc 2.95.4) */
739 /* linear interpolation */
740 static i_color interp_i_color(i_color before, i_color after, double pos,
746 for (ch = 0; ch < channels; ++ch)
747 out.channel[ch] = (1-pos) * before.channel[ch] + pos * after.channel[ch];
748 if (channels > 3 && out.channel[3])
749 for (ch = 0; ch < channels; ++ch)
751 int temp = out.channel[ch] * 255 / out.channel[3];
754 out.channel[ch] = temp;
760 /* hopefully this will be inlined (it is with -O3 with gcc 2.95.4) */
761 /* linear interpolation */
762 static i_fcolor interp_i_fcolor(i_fcolor before, i_fcolor after, double pos,
768 for (ch = 0; ch < channels; ++ch)
769 out.channel[ch] = (1-pos) * before.channel[ch] + pos * after.channel[ch];
771 for (ch = 0; ch < channels; ++ch)
773 int temp = out.channel[ch] / out.channel[3];
776 out.channel[ch] = temp;
783 =item fill_image(fill, x, y, width, channels, data, work)
787 static void fill_image(i_fill_t *fill, int x, int y, int width, int channels,
789 struct i_fill_image_t *f = (struct i_fill_image_t *)fill;
792 int want_channels = channels > 2 ? 4 : 2;
797 double rx = f->matrix[0] * (x+i) + f->matrix[1] * y + f->matrix[2];
798 double ry = f->matrix[3] * (x+i) + f->matrix[4] * y + f->matrix[5];
799 double ix = floor(rx / f->src->xsize);
800 double iy = floor(ry / f->src->ysize);
807 ix = floor(rx / f->src->xsize);
811 iy = floor(ry / f->src->ysize);
813 rx -= ix * f->src->xsize;
814 ry -= iy * f->src->ysize;
816 for (dy = 0; dy < 2; ++dy) {
817 if ((int)rx == f->src->xsize-1) {
818 i_gpix(f->src, f->src->xsize-1, ((int)ry+dy) % f->src->ysize, &c[dy][0]);
819 i_gpix(f->src, 0, ((int)ry+dy) % f->src->xsize, &c[dy][1]);
822 i_glin(f->src, (int)rx, (int)rx+2, ((int)ry+dy) % f->src->ysize,
825 c2[dy] = interp_i_color(c[dy][0], c[dy][1], rx, f->src->channels);
827 *out++ = interp_i_color(c2[0], c2[1], ry, f->src->channels);
833 /* this should be possible to optimize to use i_glin() */
837 int ix = rx / f->src->xsize;
838 int iy = ry / f->src->ysize;
842 ix = rx / f->src->xsize;
846 iy = ry / f->src->xsize;
848 rx -= ix * f->src->xsize;
849 ry -= iy * f->src->ysize;
850 i_gpix(f->src, rx, ry, out);
855 if (f->src->channels != want_channels)
856 i_adapt_colors(want_channels, f->src->channels, data, width);
860 =item fill_imagef(fill, x, y, width, channels, data, work)
864 static void fill_imagef(i_fill_t *fill, int x, int y, int width, int channels,
866 struct i_fill_image_t *f = (struct i_fill_image_t *)fill;
868 int want_channels = channels > 2 ? 4 : 2;
871 i_fcolor *work_data = data;
874 double rx = f->matrix[0] * (x+i) + f->matrix[1] * y + f->matrix[2];
875 double ry = f->matrix[3] * (x+i) + f->matrix[4] * y + f->matrix[5];
876 double ix = floor(rx / f->src->xsize);
877 double iy = floor(ry / f->src->ysize);
884 ix = floor(rx / f->src->xsize);
888 iy = floor(ry / f->src->ysize);
890 rx -= ix * f->src->xsize;
891 ry -= iy * f->src->ysize;
893 for (dy = 0; dy < 2; ++dy) {
894 if ((int)rx == f->src->xsize-1) {
895 i_gpixf(f->src, f->src->xsize-1, ((int)ry+dy) % f->src->ysize, &c[dy][0]);
896 i_gpixf(f->src, 0, ((int)ry+dy) % f->src->xsize, &c[dy][1]);
899 i_glinf(f->src, (int)rx, (int)rx+2, ((int)ry+dy) % f->src->ysize,
902 c2[dy] = interp_i_fcolor(c[dy][0], c[dy][1], rx, f->src->channels);
904 *work_data++ = interp_i_fcolor(c2[0], c2[1], ry, f->src->channels);
909 i_fcolor *work_data = data;
911 /* this should be possible to optimize to use i_glin() */
915 int ix = rx / f->src->xsize;
916 int iy = ry / f->src->ysize;
920 ix = rx / f->src->xsize;
924 iy = ry / f->src->xsize;
926 rx -= ix * f->src->xsize;
927 ry -= iy * f->src->ysize;
928 i_gpixf(f->src, rx, ry, work_data);
933 if (f->src->channels != want_channels)
934 i_adapt_fcolors(want_channels, f->src->channels, data, width);
938 fill_opacity(i_fill_t *fill, int x, int y, int width, int channels,
940 struct i_fill_opacity_t *f = (struct i_fill_opacity_t *)fill;
941 int alpha_chan = channels-1; /* channels is always 2 or 4 */
942 i_color *datap = data;
944 (f->other_fill->f_fill_with_color)(f->other_fill, x, y, width, channels, data);
946 double new_alpha = datap->channel[alpha_chan] * f->alpha_mult;
948 datap->channel[alpha_chan] = 0;
949 else if (new_alpha > 255)
950 datap->channel[alpha_chan] = 255;
951 else datap->channel[alpha_chan] = (int)(new_alpha + 0.5);
957 fill_opacityf(i_fill_t *fill, int x, int y, int width, int channels,
959 struct i_fill_opacity_t *f = (struct i_fill_opacity_t *)fill;
960 int alpha_chan = channels-1; /* channels is always 2 or 4 */
961 i_fcolor *datap = data;
963 (f->other_fill->f_fill_with_fcolor)(f->other_fill, x, y, width, channels, data);
966 double new_alpha = datap->channel[alpha_chan] * f->alpha_mult;
968 datap->channel[alpha_chan] = 0;
969 else if (new_alpha > 1.0)
970 datap->channel[alpha_chan] = 1.0;
971 else datap->channel[alpha_chan] = new_alpha;
982 Tony Cook <tony@develop-help.com>