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 *, i_img_dim x, i_img_dim y, i_img_dim width,
167 int channels, i_color *);
168 static void fill_solidf(i_fill_t *, i_img_dim x, i_img_dim y, i_img_dim width,
169 int channels, i_fcolor *);
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, i_img_dim x, i_img_dim y,
405 i_img_dim width, int channels, i_color *data);
406 static void fill_hatchf(i_fill_t *fill, i_img_dim x, i_img_dim y,
407 i_img_dim width, int channels, i_fcolor *data);
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,
412 i_img_dim dx, i_img_dim dy);
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, i_img_dim dx, i_img_dim 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, i_img_dim dx, i_img_dim dy) {
466 return i_new_hatch_low(NULL, NULL, fg, bg, combine, hatch, cust_hatch,
470 static void fill_image(i_fill_t *fill, i_img_dim x, i_img_dim y,
471 i_img_dim width, int channels, i_color *data);
472 static void fill_imagef(i_fill_t *fill, i_img_dim x, i_img_dim y,
473 i_img_dim width, int channels, i_fcolor *data);
474 struct i_fill_image_t {
477 i_img_dim xoff, yoff;
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, i_img_dim xoff, i_img_dim 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, i_img_dim x, i_img_dim y,
537 i_img_dim width, int channels, i_color *data);
538 static void fill_opacityf(i_fill_t *fill, i_img_dim x, i_img_dim y,
539 i_img_dim width, int channels, i_fcolor *data);
541 struct i_fill_opacity_t {
543 i_fill_t *other_fill;
547 static struct i_fill_opacity_t
558 i_new_fill_opacity(i_fill_t *base_fill, double alpha_mult) {
559 struct i_fill_opacity_t *fill = mymalloc(sizeof(*fill));
560 *fill = opacity_fill_proto;
562 fill->base.combine = base_fill->combine;
563 fill->base.combinef = base_fill->combinef;
565 fill->other_fill = base_fill;
566 fill->alpha_mult = alpha_mult;
568 if (!base_fill->f_fill_with_color) {
569 /* base fill only does floating, so we only do that too */
570 fill->base.f_fill_with_color = NULL;
576 #define T_SOLID_FILL(fill) ((i_fill_solid_t *)(fill))
581 =head1 INTERNAL FUNCTIONS
585 =item fill_solid(fill, x, y, width, channels, data)
587 The 8-bit sample fill function for non-combining solid fills.
592 fill_solid(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
593 int channels, i_color *data) {
594 i_color c = T_SOLID_FILL(fill)->c;
595 i_adapt_colors(channels > 2 ? 4 : 2, 4, &c, 1);
596 while (width-- > 0) {
602 =item fill_solid(fill, x, y, width, channels, data)
604 The floating sample fill function for non-combining solid fills.
609 fill_solidf(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
610 int channels, i_fcolor *data) {
611 i_fcolor c = T_SOLID_FILL(fill)->fc;
612 i_adapt_fcolors(channels > 2 ? 4 : 2, 4, &c, 1);
613 while (width-- > 0) {
618 static i_fill_hatch_t
629 =item i_new_hatch_low(fg, bg, ffg, fbg, combine, hatch, cust_hatch, dx, dy)
631 Implements creation of hatch fill objects.
637 i_new_hatch_low(const i_color *fg, const i_color *bg,
638 const i_fcolor *ffg, const i_fcolor *fbg,
639 int combine, int hatch, const unsigned char *cust_hatch,
640 i_img_dim dx, i_img_dim dy) {
641 i_fill_hatch_t *fill = mymalloc(sizeof(i_fill_hatch_t)); /* checked 14jul05 tonyc */
643 *fill = hatch_fill_proto;
644 /* Some Sun C didn't like the condition expressions that were here.
645 See https://rt.cpan.org/Ticket/Display.html?id=21944
650 fill->fg = fcolor_to_color(ffg);
654 fill->bg = fcolor_to_color(fbg);
658 fill->ffg = color_to_fcolor(fg);
662 fill->fbg = color_to_fcolor(bg);
664 i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
667 fill->base.combine = NULL;
668 fill->base.combinef = NULL;
671 memcpy(fill->hatch, cust_hatch, 8);
674 if (hatch > sizeof(builtin_hatches)/sizeof(*builtin_hatches))
676 memcpy(fill->hatch, builtin_hatches[hatch], 8);
685 =item fill_hatch(fill, x, y, width, channels, data)
687 The 8-bit sample fill function for hatched fills.
692 fill_hatch(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
693 int channels, i_color *data) {
694 i_fill_hatch_t *f = (i_fill_hatch_t *)fill;
695 int byte = f->hatch[(y + f->dy) & 7];
696 int xpos = (x + f->dx) & 7;
697 int mask = 128 >> xpos;
702 i_adapt_colors(2, 4, &fg, 1);
703 i_adapt_colors(2, 4, &bg, 1);
706 while (width-- > 0) {
712 if ((mask >>= 1) == 0)
718 =item fill_hatchf(fill, x, y, width, channels, data)
720 The floating sample fill function for hatched fills.
725 fill_hatchf(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
726 int channels, i_fcolor *data) {
727 i_fill_hatch_t *f = (i_fill_hatch_t *)fill;
728 int byte = f->hatch[(y + f->dy) & 7];
729 int xpos = (x + f->dx) & 7;
730 int mask = 128 >> xpos;
731 i_fcolor fg = f->ffg;
732 i_fcolor bg = f->fbg;
735 i_adapt_fcolors(2, 4, &fg, 1);
736 i_adapt_fcolors(2, 4, &bg, 1);
739 while (width-- > 0) {
745 if ((mask >>= 1) == 0)
750 /* hopefully this will be inlined (it is with -O3 with gcc 2.95.4) */
751 /* linear interpolation */
752 static i_color interp_i_color(i_color before, i_color after, double pos,
758 for (ch = 0; ch < channels; ++ch)
759 out.channel[ch] = (1-pos) * before.channel[ch] + pos * after.channel[ch];
760 if (channels > 3 && out.channel[3])
761 for (ch = 0; ch < channels; ++ch)
763 int temp = out.channel[ch] * 255 / out.channel[3];
766 out.channel[ch] = temp;
772 /* hopefully this will be inlined (it is with -O3 with gcc 2.95.4) */
773 /* linear interpolation */
774 static i_fcolor interp_i_fcolor(i_fcolor before, i_fcolor after, double pos,
780 for (ch = 0; ch < channels; ++ch)
781 out.channel[ch] = (1-pos) * before.channel[ch] + pos * after.channel[ch];
783 for (ch = 0; ch < channels; ++ch)
785 int temp = out.channel[ch] / out.channel[3];
788 out.channel[ch] = temp;
795 =item fill_image(fill, x, y, width, channels, data, work)
800 fill_image(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
801 int channels, i_color *data) {
802 struct i_fill_image_t *f = (struct i_fill_image_t *)fill;
805 int want_channels = channels > 2 ? 4 : 2;
810 double rx = f->matrix[0] * (x+i) + f->matrix[1] * y + f->matrix[2];
811 double ry = f->matrix[3] * (x+i) + f->matrix[4] * y + f->matrix[5];
812 double ix = floor(rx / f->src->xsize);
813 double iy = floor(ry / f->src->ysize);
820 ix = floor(rx / f->src->xsize);
824 iy = floor(ry / f->src->ysize);
826 rx -= ix * f->src->xsize;
827 ry -= iy * f->src->ysize;
829 for (dy = 0; dy < 2; ++dy) {
830 if ((i_img_dim)rx == f->src->xsize-1) {
831 i_gpix(f->src, f->src->xsize-1, ((i_img_dim)ry+dy) % f->src->ysize, &c[dy][0]);
832 i_gpix(f->src, 0, ((i_img_dim)ry+dy) % f->src->xsize, &c[dy][1]);
835 i_glin(f->src, (i_img_dim)rx, (i_img_dim)rx+2, ((i_img_dim)ry+dy) % f->src->ysize,
838 c2[dy] = interp_i_color(c[dy][0], c[dy][1], rx, f->src->channels);
840 *out++ = interp_i_color(c2[0], c2[1], ry, f->src->channels);
846 /* this should be possible to optimize to use i_glin() */
850 i_img_dim ix = rx / f->src->xsize;
851 i_img_dim iy = ry / f->src->ysize;
855 ix = rx / f->src->xsize;
859 iy = ry / f->src->xsize;
861 rx -= ix * f->src->xsize;
862 ry -= iy * f->src->ysize;
863 i_gpix(f->src, rx, ry, out);
868 if (f->src->channels != want_channels)
869 i_adapt_colors(want_channels, f->src->channels, data, width);
873 =item fill_imagef(fill, x, y, width, channels, data, work)
878 fill_imagef(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
879 int channels, i_fcolor *data) {
880 struct i_fill_image_t *f = (struct i_fill_image_t *)fill;
882 int want_channels = channels > 2 ? 4 : 2;
885 i_fcolor *work_data = data;
888 double rx = f->matrix[0] * (x+i) + f->matrix[1] * y + f->matrix[2];
889 double ry = f->matrix[3] * (x+i) + f->matrix[4] * y + f->matrix[5];
890 double ix = floor(rx / f->src->xsize);
891 double iy = floor(ry / f->src->ysize);
898 ix = floor(rx / f->src->xsize);
902 iy = floor(ry / f->src->ysize);
904 rx -= ix * f->src->xsize;
905 ry -= iy * f->src->ysize;
907 for (dy = 0; dy < 2; ++dy) {
908 if ((i_img_dim)rx == f->src->xsize-1) {
909 i_gpixf(f->src, f->src->xsize-1, ((i_img_dim)ry+dy) % f->src->ysize, &c[dy][0]);
910 i_gpixf(f->src, 0, ((i_img_dim)ry+dy) % f->src->xsize, &c[dy][1]);
913 i_glinf(f->src, (i_img_dim)rx, (i_img_dim)rx+2, ((i_img_dim)ry+dy) % f->src->ysize,
916 c2[dy] = interp_i_fcolor(c[dy][0], c[dy][1], rx, f->src->channels);
918 *work_data++ = interp_i_fcolor(c2[0], c2[1], ry, f->src->channels);
923 i_fcolor *work_data = data;
925 /* this should be possible to optimize to use i_glin() */
929 i_img_dim ix = rx / f->src->xsize;
930 i_img_dim iy = ry / f->src->ysize;
934 ix = rx / f->src->xsize;
938 iy = ry / f->src->xsize;
940 rx -= ix * f->src->xsize;
941 ry -= iy * f->src->ysize;
942 i_gpixf(f->src, rx, ry, work_data);
947 if (f->src->channels != want_channels)
948 i_adapt_fcolors(want_channels, f->src->channels, data, width);
952 fill_opacity(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
953 int channels, i_color *data) {
954 struct i_fill_opacity_t *f = (struct i_fill_opacity_t *)fill;
955 int alpha_chan = channels > 2 ? 3 : 1;
956 i_color *datap = data;
958 (f->other_fill->f_fill_with_color)(f->other_fill, x, y, width, channels, data);
960 double new_alpha = datap->channel[alpha_chan] * f->alpha_mult;
962 datap->channel[alpha_chan] = 0;
963 else if (new_alpha > 255)
964 datap->channel[alpha_chan] = 255;
965 else datap->channel[alpha_chan] = (int)(new_alpha + 0.5);
971 fill_opacityf(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
972 int channels, i_fcolor *data) {
973 struct i_fill_opacity_t *f = (struct i_fill_opacity_t *)fill;
974 int alpha_chan = channels > 2 ? 3 : 1;
975 i_fcolor *datap = data;
977 (f->other_fill->f_fill_with_fcolor)(f->other_fill, x, y, width, channels, data);
980 double new_alpha = datap->channel[alpha_chan] * f->alpha_mult;
982 datap->channel[alpha_chan] = 0;
983 else if (new_alpha > 1.0)
984 datap->channel[alpha_chan] = 1.0;
985 else datap->channel[alpha_chan] = new_alpha;
996 Tony Cook <tony@develop-help.com>