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(C<fg>, C<bg>, C<combine>, C<hatch>, C<cust_hatch>, C<dx>, C<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 C<fg> color used for the 1 bits in
421 the hatch and C<bg> for the 0 bits. If C<combine> is non-zero alpha
422 values will be combined.
424 If C<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 C<cust_hatch> is NULL then one of the standard hatches is used.
429 (C<dx>, C<dy>) are an offset into the hatch which can be used to hatch
430 adjoining areas out of alignment, or to align the origin of a hatch
431 with the the side of a filled area.
436 i_new_fill_hatch(const i_color *fg, const i_color *bg, int combine, int hatch,
437 const unsigned char *cust_hatch, int dx, int dy) {
438 return i_new_hatch_low(fg, bg, NULL, NULL, combine, hatch, cust_hatch,
443 =item i_new_fill_hatchf(C<fg>, C<bg>, C<combine>, C<hatch>, C<cust_hatch>, C<dx>, C<dy>)
446 =synopsis i_fill_t *fill = i_new_fill_hatchf(&fg_fcolor, &bg_fcolor, combine, hatch, custom_hatch, dx, dy);
448 Creates a new hatched fill with the C<fg> color used for the 1 bits in
449 the hatch and C<bg> for the 0 bits. If C<combine> is non-zero alpha
450 values will be combined.
452 If C<cust_hatch> is non-NULL it should be a pointer to 8 bytes of the
453 hash definition, with the high-bits to the left.
455 If C<cust_hatch> is NULL then one of the standard hatches is used.
457 (C<dx>, C<dy>) are an offset into the hatch which can be used to hatch
458 adjoining areas out of alignment, or to align the origin of a hatch
459 with the the side of a filled area.
464 i_new_fill_hatchf(const i_fcolor *fg, const i_fcolor *bg, int combine, int hatch,
465 const unsigned char *cust_hatch, int dx, int dy) {
466 return i_new_hatch_low(NULL, NULL, fg, bg, combine, hatch, cust_hatch,
470 static void fill_image(i_fill_t *fill, int x, int y, int width, int channels,
472 static void fill_imagef(i_fill_t *fill, int x, int y, int width, int channels,
474 struct i_fill_image_t {
482 static struct i_fill_image_t
493 =item i_new_fill_image(C<im>, C<matrix>, C<xoff>, C<yoff>, C<combine>)
496 =synopsis i_fill_t *fill = i_new_fill_image(src_img, matrix, x_offset, y_offset, combine);
498 Create an image based fill.
500 matrix is an array of 9 doubles representing a transformation matrix.
502 C<xoff> and C<yoff> are the offset into the image to start filling from.
507 i_new_fill_image(i_img *im, const double *matrix, int xoff, int yoff, int combine) {
508 struct i_fill_image_t *fill = mymalloc(sizeof(*fill)); /* checked 14jul05 tonyc */
510 *fill = image_fill_proto;
513 i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
516 fill->base.combine = NULL;
517 fill->base.combinef = NULL;
527 fill->has_matrix = 1;
528 memcpy(fill->matrix, matrix, sizeof(fill->matrix));
531 fill->has_matrix = 0;
536 static void fill_opacity(i_fill_t *fill, int x, int y, int width, int channels,
538 static void fill_opacityf(i_fill_t *fill, int x, int y, int width, int channels,
541 struct i_fill_opacity_t {
543 i_fill_t *other_fill;
547 static struct i_fill_opacity_t
556 i_new_fill_opacity(i_fill_t *base_fill, double alpha_mult) {
557 struct i_fill_opacity_t *fill = mymalloc(sizeof(*fill));
558 *fill = opacity_fill_proto;
560 fill->base.combine = base_fill->combine;
561 fill->base.combinef = base_fill->combinef;
563 fill->other_fill = base_fill;
564 fill->alpha_mult = alpha_mult;
566 if (!base_fill->f_fill_with_color) {
567 /* base fill only does floating, so we only do that too */
568 fill->base.f_fill_with_color = NULL;
574 #define T_SOLID_FILL(fill) ((i_fill_solid_t *)(fill))
579 =head1 INTERNAL FUNCTIONS
583 =item fill_solid(fill, x, y, width, channels, data)
585 The 8-bit sample fill function for non-combining solid fills.
590 fill_solid(i_fill_t *fill, int x, int y, int width, int channels,
592 i_color c = T_SOLID_FILL(fill)->c;
593 i_adapt_colors(channels > 2 ? 4 : 2, 4, &c, 1);
594 while (width-- > 0) {
600 =item fill_solid(fill, x, y, width, channels, data)
602 The floating sample fill function for non-combining solid fills.
607 fill_solidf(i_fill_t *fill, int x, int y, int width, int channels,
609 i_fcolor c = T_SOLID_FILL(fill)->fc;
610 i_adapt_fcolors(channels > 2 ? 4 : 2, 4, &c, 1);
611 while (width-- > 0) {
616 static i_fill_hatch_t
627 =item i_new_hatch_low(fg, bg, ffg, fbg, combine, hatch, cust_hatch, dx, dy)
629 Implements creation of hatch fill objects.
635 i_new_hatch_low(const i_color *fg, const i_color *bg,
636 const i_fcolor *ffg, const i_fcolor *fbg,
637 int combine, int hatch, const unsigned char *cust_hatch,
639 i_fill_hatch_t *fill = mymalloc(sizeof(i_fill_hatch_t)); /* checked 14jul05 tonyc */
641 *fill = hatch_fill_proto;
642 /* Some Sun C didn't like the condition expressions that were here.
643 See https://rt.cpan.org/Ticket/Display.html?id=21944
648 fill->fg = fcolor_to_color(ffg);
652 fill->bg = fcolor_to_color(fbg);
656 fill->ffg = color_to_fcolor(fg);
660 fill->fbg = color_to_fcolor(bg);
662 i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
665 fill->base.combine = NULL;
666 fill->base.combinef = NULL;
669 memcpy(fill->hatch, cust_hatch, 8);
672 if (hatch > sizeof(builtin_hatches)/sizeof(*builtin_hatches))
674 memcpy(fill->hatch, builtin_hatches[hatch], 8);
683 =item fill_hatch(fill, x, y, width, channels, data)
685 The 8-bit sample fill function for hatched fills.
689 static void fill_hatch(i_fill_t *fill, int x, int y, int width, int channels,
691 i_fill_hatch_t *f = (i_fill_hatch_t *)fill;
692 int byte = f->hatch[(y + f->dy) & 7];
693 int xpos = (x + f->dx) & 7;
694 int mask = 128 >> xpos;
697 int want_channels = channels > 2 ? 4 : 2;
700 i_adapt_colors(2, 4, &fg, 1);
701 i_adapt_colors(2, 4, &bg, 1);
704 while (width-- > 0) {
710 if ((mask >>= 1) == 0)
716 =item fill_hatchf(fill, x, y, width, channels, data)
718 The floating sample fill function for hatched fills.
722 static void fill_hatchf(i_fill_t *fill, int x, int y, int width, int channels,
724 i_fill_hatch_t *f = (i_fill_hatch_t *)fill;
725 int byte = f->hatch[(y + f->dy) & 7];
726 int xpos = (x + f->dx) & 7;
727 int mask = 128 >> xpos;
728 i_fcolor fg = f->ffg;
729 i_fcolor bg = f->fbg;
732 i_adapt_fcolors(2, 4, &fg, 1);
733 i_adapt_fcolors(2, 4, &bg, 1);
736 while (width-- > 0) {
742 if ((mask >>= 1) == 0)
747 /* hopefully this will be inlined (it is with -O3 with gcc 2.95.4) */
748 /* linear interpolation */
749 static i_color interp_i_color(i_color before, i_color after, double pos,
755 for (ch = 0; ch < channels; ++ch)
756 out.channel[ch] = (1-pos) * before.channel[ch] + pos * after.channel[ch];
757 if (channels > 3 && out.channel[3])
758 for (ch = 0; ch < channels; ++ch)
760 int temp = out.channel[ch] * 255 / out.channel[3];
763 out.channel[ch] = temp;
769 /* hopefully this will be inlined (it is with -O3 with gcc 2.95.4) */
770 /* linear interpolation */
771 static i_fcolor interp_i_fcolor(i_fcolor before, i_fcolor after, double pos,
777 for (ch = 0; ch < channels; ++ch)
778 out.channel[ch] = (1-pos) * before.channel[ch] + pos * after.channel[ch];
780 for (ch = 0; ch < channels; ++ch)
782 int temp = out.channel[ch] / out.channel[3];
785 out.channel[ch] = temp;
792 =item fill_image(fill, x, y, width, channels, data, work)
796 static void fill_image(i_fill_t *fill, int x, int y, int width, int channels,
798 struct i_fill_image_t *f = (struct i_fill_image_t *)fill;
801 int want_channels = channels > 2 ? 4 : 2;
806 double rx = f->matrix[0] * (x+i) + f->matrix[1] * y + f->matrix[2];
807 double ry = f->matrix[3] * (x+i) + f->matrix[4] * y + f->matrix[5];
808 double ix = floor(rx / f->src->xsize);
809 double iy = floor(ry / f->src->ysize);
816 ix = floor(rx / f->src->xsize);
820 iy = floor(ry / f->src->ysize);
822 rx -= ix * f->src->xsize;
823 ry -= iy * f->src->ysize;
825 for (dy = 0; dy < 2; ++dy) {
826 if ((int)rx == f->src->xsize-1) {
827 i_gpix(f->src, f->src->xsize-1, ((int)ry+dy) % f->src->ysize, &c[dy][0]);
828 i_gpix(f->src, 0, ((int)ry+dy) % f->src->xsize, &c[dy][1]);
831 i_glin(f->src, (int)rx, (int)rx+2, ((int)ry+dy) % f->src->ysize,
834 c2[dy] = interp_i_color(c[dy][0], c[dy][1], rx, f->src->channels);
836 *out++ = interp_i_color(c2[0], c2[1], ry, f->src->channels);
842 /* this should be possible to optimize to use i_glin() */
846 int ix = rx / f->src->xsize;
847 int iy = ry / f->src->ysize;
851 ix = rx / f->src->xsize;
855 iy = ry / f->src->xsize;
857 rx -= ix * f->src->xsize;
858 ry -= iy * f->src->ysize;
859 i_gpix(f->src, rx, ry, out);
864 if (f->src->channels != want_channels)
865 i_adapt_colors(want_channels, f->src->channels, data, width);
869 =item fill_imagef(fill, x, y, width, channels, data, work)
873 static void fill_imagef(i_fill_t *fill, int x, int y, int width, int channels,
875 struct i_fill_image_t *f = (struct i_fill_image_t *)fill;
877 int want_channels = channels > 2 ? 4 : 2;
880 i_fcolor *work_data = data;
883 double rx = f->matrix[0] * (x+i) + f->matrix[1] * y + f->matrix[2];
884 double ry = f->matrix[3] * (x+i) + f->matrix[4] * y + f->matrix[5];
885 double ix = floor(rx / f->src->xsize);
886 double iy = floor(ry / f->src->ysize);
893 ix = floor(rx / f->src->xsize);
897 iy = floor(ry / f->src->ysize);
899 rx -= ix * f->src->xsize;
900 ry -= iy * f->src->ysize;
902 for (dy = 0; dy < 2; ++dy) {
903 if ((int)rx == f->src->xsize-1) {
904 i_gpixf(f->src, f->src->xsize-1, ((int)ry+dy) % f->src->ysize, &c[dy][0]);
905 i_gpixf(f->src, 0, ((int)ry+dy) % f->src->xsize, &c[dy][1]);
908 i_glinf(f->src, (int)rx, (int)rx+2, ((int)ry+dy) % f->src->ysize,
911 c2[dy] = interp_i_fcolor(c[dy][0], c[dy][1], rx, f->src->channels);
913 *work_data++ = interp_i_fcolor(c2[0], c2[1], ry, f->src->channels);
918 i_fcolor *work_data = data;
920 /* this should be possible to optimize to use i_glin() */
924 int ix = rx / f->src->xsize;
925 int iy = ry / f->src->ysize;
929 ix = rx / f->src->xsize;
933 iy = ry / f->src->xsize;
935 rx -= ix * f->src->xsize;
936 ry -= iy * f->src->ysize;
937 i_gpixf(f->src, rx, ry, work_data);
942 if (f->src->channels != want_channels)
943 i_adapt_fcolors(want_channels, f->src->channels, data, width);
947 fill_opacity(i_fill_t *fill, int x, int y, int width, int channels,
949 struct i_fill_opacity_t *f = (struct i_fill_opacity_t *)fill;
950 int alpha_chan = channels > 2 ? 3 : 1;
951 i_color *datap = data;
953 (f->other_fill->f_fill_with_color)(f->other_fill, x, y, width, channels, data);
955 double new_alpha = datap->channel[alpha_chan] * f->alpha_mult;
957 datap->channel[alpha_chan] = 0;
958 else if (new_alpha > 255)
959 datap->channel[alpha_chan] = 255;
960 else datap->channel[alpha_chan] = (int)(new_alpha + 0.5);
966 fill_opacityf(i_fill_t *fill, int x, int y, int width, int channels,
968 struct i_fill_opacity_t *f = (struct i_fill_opacity_t *)fill;
969 int alpha_chan = channels > 2 ? 3 : 1;
970 i_fcolor *datap = data;
972 (f->other_fill->f_fill_with_fcolor)(f->other_fill, x, y, width, channels, data);
975 double new_alpha = datap->channel[alpha_chan] * f->alpha_mult;
977 datap->channel[alpha_chan] = 0;
978 else if (new_alpha > 1.0)
979 datap->channel[alpha_chan] = 1.0;
980 else datap->channel[alpha_chan] = new_alpha;
991 Tony Cook <tony@develop-help.com>