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;
569 #define T_SOLID_FILL(fill) ((i_fill_solid_t *)(fill))
574 =head1 INTERNAL FUNCTIONS
578 =item fill_solid(fill, x, y, width, channels, data)
580 The 8-bit sample fill function for non-combining solid fills.
585 fill_solid(i_fill_t *fill, int x, int y, int width, int channels,
587 i_color c = T_SOLID_FILL(fill)->c;
588 i_adapt_colors(channels > 2 ? 4 : 2, 4, &c, 1);
589 while (width-- > 0) {
595 =item fill_solid(fill, x, y, width, channels, data)
597 The floating sample fill function for non-combining solid fills.
602 fill_solidf(i_fill_t *fill, int x, int y, int width, int channels,
604 i_fcolor c = T_SOLID_FILL(fill)->fc;
605 i_adapt_fcolors(channels > 2 ? 4 : 2, 4, &c, 1);
606 while (width-- > 0) {
611 static i_fill_hatch_t
622 =item i_new_hatch_low(fg, bg, ffg, fbg, combine, hatch, cust_hatch, dx, dy)
624 Implements creation of hatch fill objects.
630 i_new_hatch_low(const i_color *fg, const i_color *bg,
631 const i_fcolor *ffg, const i_fcolor *fbg,
632 int combine, int hatch, const unsigned char *cust_hatch,
634 i_fill_hatch_t *fill = mymalloc(sizeof(i_fill_hatch_t)); /* checked 14jul05 tonyc */
636 *fill = hatch_fill_proto;
637 /* Some Sun C didn't like the condition expressions that were here.
638 See https://rt.cpan.org/Ticket/Display.html?id=21944
643 fill->fg = fcolor_to_color(ffg);
647 fill->bg = fcolor_to_color(fbg);
651 fill->ffg = color_to_fcolor(fg);
655 fill->fbg = color_to_fcolor(bg);
657 i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
660 fill->base.combine = NULL;
661 fill->base.combinef = NULL;
664 memcpy(fill->hatch, cust_hatch, 8);
667 if (hatch > sizeof(builtin_hatches)/sizeof(*builtin_hatches))
669 memcpy(fill->hatch, builtin_hatches[hatch], 8);
678 =item fill_hatch(fill, x, y, width, channels, data)
680 The 8-bit sample fill function for hatched fills.
684 static void fill_hatch(i_fill_t *fill, int x, int y, int width, int channels,
686 i_fill_hatch_t *f = (i_fill_hatch_t *)fill;
687 int byte = f->hatch[(y + f->dy) & 7];
688 int xpos = (x + f->dx) & 7;
689 int mask = 128 >> xpos;
692 int want_channels = channels > 2 ? 4 : 2;
695 i_adapt_colors(2, 4, &fg, 1);
696 i_adapt_colors(2, 4, &bg, 1);
699 while (width-- > 0) {
705 if ((mask >>= 1) == 0)
711 =item fill_hatchf(fill, x, y, width, channels, data)
713 The floating sample fill function for hatched fills.
717 static void fill_hatchf(i_fill_t *fill, int x, int y, int width, int channels,
719 i_fill_hatch_t *f = (i_fill_hatch_t *)fill;
720 int byte = f->hatch[(y + f->dy) & 7];
721 int xpos = (x + f->dx) & 7;
722 int mask = 128 >> xpos;
723 i_fcolor fg = f->ffg;
724 i_fcolor bg = f->fbg;
727 i_adapt_fcolors(2, 4, &fg, 1);
728 i_adapt_fcolors(2, 4, &bg, 1);
731 while (width-- > 0) {
737 if ((mask >>= 1) == 0)
742 /* hopefully this will be inlined (it is with -O3 with gcc 2.95.4) */
743 /* linear interpolation */
744 static i_color interp_i_color(i_color before, i_color after, double pos,
750 for (ch = 0; ch < channels; ++ch)
751 out.channel[ch] = (1-pos) * before.channel[ch] + pos * after.channel[ch];
752 if (channels > 3 && out.channel[3])
753 for (ch = 0; ch < channels; ++ch)
755 int temp = out.channel[ch] * 255 / out.channel[3];
758 out.channel[ch] = temp;
764 /* hopefully this will be inlined (it is with -O3 with gcc 2.95.4) */
765 /* linear interpolation */
766 static i_fcolor interp_i_fcolor(i_fcolor before, i_fcolor after, double pos,
772 for (ch = 0; ch < channels; ++ch)
773 out.channel[ch] = (1-pos) * before.channel[ch] + pos * after.channel[ch];
775 for (ch = 0; ch < channels; ++ch)
777 int temp = out.channel[ch] / out.channel[3];
780 out.channel[ch] = temp;
787 =item fill_image(fill, x, y, width, channels, data, work)
791 static void fill_image(i_fill_t *fill, int x, int y, int width, int channels,
793 struct i_fill_image_t *f = (struct i_fill_image_t *)fill;
796 int want_channels = channels > 2 ? 4 : 2;
801 double rx = f->matrix[0] * (x+i) + f->matrix[1] * y + f->matrix[2];
802 double ry = f->matrix[3] * (x+i) + f->matrix[4] * y + f->matrix[5];
803 double ix = floor(rx / f->src->xsize);
804 double iy = floor(ry / f->src->ysize);
811 ix = floor(rx / f->src->xsize);
815 iy = floor(ry / f->src->ysize);
817 rx -= ix * f->src->xsize;
818 ry -= iy * f->src->ysize;
820 for (dy = 0; dy < 2; ++dy) {
821 if ((int)rx == f->src->xsize-1) {
822 i_gpix(f->src, f->src->xsize-1, ((int)ry+dy) % f->src->ysize, &c[dy][0]);
823 i_gpix(f->src, 0, ((int)ry+dy) % f->src->xsize, &c[dy][1]);
826 i_glin(f->src, (int)rx, (int)rx+2, ((int)ry+dy) % f->src->ysize,
829 c2[dy] = interp_i_color(c[dy][0], c[dy][1], rx, f->src->channels);
831 *out++ = interp_i_color(c2[0], c2[1], ry, f->src->channels);
837 /* this should be possible to optimize to use i_glin() */
841 int ix = rx / f->src->xsize;
842 int iy = ry / f->src->ysize;
846 ix = rx / f->src->xsize;
850 iy = ry / f->src->xsize;
852 rx -= ix * f->src->xsize;
853 ry -= iy * f->src->ysize;
854 i_gpix(f->src, rx, ry, out);
859 if (f->src->channels != want_channels)
860 i_adapt_colors(want_channels, f->src->channels, data, width);
864 =item fill_imagef(fill, x, y, width, channels, data, work)
868 static void fill_imagef(i_fill_t *fill, int x, int y, int width, int channels,
870 struct i_fill_image_t *f = (struct i_fill_image_t *)fill;
872 int want_channels = channels > 2 ? 4 : 2;
875 i_fcolor *work_data = data;
878 double rx = f->matrix[0] * (x+i) + f->matrix[1] * y + f->matrix[2];
879 double ry = f->matrix[3] * (x+i) + f->matrix[4] * y + f->matrix[5];
880 double ix = floor(rx / f->src->xsize);
881 double iy = floor(ry / f->src->ysize);
888 ix = floor(rx / f->src->xsize);
892 iy = floor(ry / f->src->ysize);
894 rx -= ix * f->src->xsize;
895 ry -= iy * f->src->ysize;
897 for (dy = 0; dy < 2; ++dy) {
898 if ((int)rx == f->src->xsize-1) {
899 i_gpixf(f->src, f->src->xsize-1, ((int)ry+dy) % f->src->ysize, &c[dy][0]);
900 i_gpixf(f->src, 0, ((int)ry+dy) % f->src->xsize, &c[dy][1]);
903 i_glinf(f->src, (int)rx, (int)rx+2, ((int)ry+dy) % f->src->ysize,
906 c2[dy] = interp_i_fcolor(c[dy][0], c[dy][1], rx, f->src->channels);
908 *work_data++ = interp_i_fcolor(c2[0], c2[1], ry, f->src->channels);
913 i_fcolor *work_data = data;
915 /* this should be possible to optimize to use i_glin() */
919 int ix = rx / f->src->xsize;
920 int iy = ry / f->src->ysize;
924 ix = rx / f->src->xsize;
928 iy = ry / f->src->xsize;
930 rx -= ix * f->src->xsize;
931 ry -= iy * f->src->ysize;
932 i_gpixf(f->src, rx, ry, work_data);
937 if (f->src->channels != want_channels)
938 i_adapt_fcolors(want_channels, f->src->channels, data, width);
942 fill_opacity(i_fill_t *fill, int x, int y, int width, int channels,
944 struct i_fill_opacity_t *f = (struct i_fill_opacity_t *)fill;
945 int alpha_chan = channels > 2 ? 3 : 1;
946 i_color *datap = data;
948 (f->other_fill->f_fill_with_color)(f->other_fill, x, y, width, channels, data);
950 double new_alpha = datap->channel[alpha_chan] * f->alpha_mult;
952 datap->channel[alpha_chan] = 0;
953 else if (new_alpha > 255)
954 datap->channel[alpha_chan] = 255;
955 else datap->channel[alpha_chan] = (int)(new_alpha + 0.5);
961 fill_opacityf(i_fill_t *fill, int x, int y, int width, int channels,
963 struct i_fill_opacity_t *f = (struct i_fill_opacity_t *)fill;
964 int alpha_chan = channels > 2 ? 3 : 1;
965 i_fcolor *datap = data;
967 (f->other_fill->f_fill_with_fcolor)(f->other_fill, x, y, width, channels, data);
970 double new_alpha = datap->channel[alpha_chan] * f->alpha_mult;
972 datap->channel[alpha_chan] = 0;
973 else if (new_alpha > 1.0)
974 datap->channel[alpha_chan] = 1.0;
975 else datap->channel[alpha_chan] = new_alpha;
986 Tony Cook <tony@develop-help.com>