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,
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, 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 {
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, 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
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, i_img_dim x, i_img_dim y, i_img_dim width,
591 int channels, i_color *data) {
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, i_img_dim x, i_img_dim y, i_img_dim width,
608 int channels, i_fcolor *data) {
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.
690 fill_hatch(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
691 int channels, i_color *data) {
692 i_fill_hatch_t *f = (i_fill_hatch_t *)fill;
693 int byte = f->hatch[(y + f->dy) & 7];
694 int xpos = (x + f->dx) & 7;
695 int mask = 128 >> xpos;
698 int want_channels = channels > 2 ? 4 : 2;
701 i_adapt_colors(2, 4, &fg, 1);
702 i_adapt_colors(2, 4, &bg, 1);
705 while (width-- > 0) {
711 if ((mask >>= 1) == 0)
717 =item fill_hatchf(fill, x, y, width, channels, data)
719 The floating sample fill function for hatched fills.
724 fill_hatchf(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
725 int channels, i_fcolor *data) {
726 i_fill_hatch_t *f = (i_fill_hatch_t *)fill;
727 int byte = f->hatch[(y + f->dy) & 7];
728 int xpos = (x + f->dx) & 7;
729 int mask = 128 >> xpos;
730 i_fcolor fg = f->ffg;
731 i_fcolor bg = f->fbg;
734 i_adapt_fcolors(2, 4, &fg, 1);
735 i_adapt_fcolors(2, 4, &bg, 1);
738 while (width-- > 0) {
744 if ((mask >>= 1) == 0)
749 /* hopefully this will be inlined (it is with -O3 with gcc 2.95.4) */
750 /* linear interpolation */
751 static i_color interp_i_color(i_color before, i_color after, double pos,
757 for (ch = 0; ch < channels; ++ch)
758 out.channel[ch] = (1-pos) * before.channel[ch] + pos * after.channel[ch];
759 if (channels > 3 && out.channel[3])
760 for (ch = 0; ch < channels; ++ch)
762 int temp = out.channel[ch] * 255 / out.channel[3];
765 out.channel[ch] = temp;
771 /* hopefully this will be inlined (it is with -O3 with gcc 2.95.4) */
772 /* linear interpolation */
773 static i_fcolor interp_i_fcolor(i_fcolor before, i_fcolor after, double pos,
779 for (ch = 0; ch < channels; ++ch)
780 out.channel[ch] = (1-pos) * before.channel[ch] + pos * after.channel[ch];
782 for (ch = 0; ch < channels; ++ch)
784 int temp = out.channel[ch] / out.channel[3];
787 out.channel[ch] = temp;
794 =item fill_image(fill, x, y, width, channels, data, work)
799 fill_image(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
800 int channels, i_color *data) {
801 struct i_fill_image_t *f = (struct i_fill_image_t *)fill;
804 int want_channels = channels > 2 ? 4 : 2;
809 double rx = f->matrix[0] * (x+i) + f->matrix[1] * y + f->matrix[2];
810 double ry = f->matrix[3] * (x+i) + f->matrix[4] * y + f->matrix[5];
811 double ix = floor(rx / f->src->xsize);
812 double iy = floor(ry / f->src->ysize);
819 ix = floor(rx / f->src->xsize);
823 iy = floor(ry / f->src->ysize);
825 rx -= ix * f->src->xsize;
826 ry -= iy * f->src->ysize;
828 for (dy = 0; dy < 2; ++dy) {
829 if ((int)rx == f->src->xsize-1) {
830 i_gpix(f->src, f->src->xsize-1, ((int)ry+dy) % f->src->ysize, &c[dy][0]);
831 i_gpix(f->src, 0, ((int)ry+dy) % f->src->xsize, &c[dy][1]);
834 i_glin(f->src, (int)rx, (int)rx+2, ((int)ry+dy) % f->src->ysize,
837 c2[dy] = interp_i_color(c[dy][0], c[dy][1], rx, f->src->channels);
839 *out++ = interp_i_color(c2[0], c2[1], ry, f->src->channels);
845 /* this should be possible to optimize to use i_glin() */
849 i_img_dim ix = rx / f->src->xsize;
850 i_img_dim iy = ry / f->src->ysize;
854 ix = rx / f->src->xsize;
858 iy = ry / f->src->xsize;
860 rx -= ix * f->src->xsize;
861 ry -= iy * f->src->ysize;
862 i_gpix(f->src, rx, ry, out);
867 if (f->src->channels != want_channels)
868 i_adapt_colors(want_channels, f->src->channels, data, width);
872 =item fill_imagef(fill, x, y, width, channels, data, work)
877 fill_imagef(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
878 int channels, i_fcolor *data) {
879 struct i_fill_image_t *f = (struct i_fill_image_t *)fill;
881 int want_channels = channels > 2 ? 4 : 2;
884 i_fcolor *work_data = data;
887 double rx = f->matrix[0] * (x+i) + f->matrix[1] * y + f->matrix[2];
888 double ry = f->matrix[3] * (x+i) + f->matrix[4] * y + f->matrix[5];
889 double ix = floor(rx / f->src->xsize);
890 double iy = floor(ry / f->src->ysize);
897 ix = floor(rx / f->src->xsize);
901 iy = floor(ry / f->src->ysize);
903 rx -= ix * f->src->xsize;
904 ry -= iy * f->src->ysize;
906 for (dy = 0; dy < 2; ++dy) {
907 if ((int)rx == f->src->xsize-1) {
908 i_gpixf(f->src, f->src->xsize-1, ((int)ry+dy) % f->src->ysize, &c[dy][0]);
909 i_gpixf(f->src, 0, ((int)ry+dy) % f->src->xsize, &c[dy][1]);
912 i_glinf(f->src, (int)rx, (int)rx+2, ((int)ry+dy) % f->src->ysize,
915 c2[dy] = interp_i_fcolor(c[dy][0], c[dy][1], rx, f->src->channels);
917 *work_data++ = interp_i_fcolor(c2[0], c2[1], ry, f->src->channels);
922 i_fcolor *work_data = data;
924 /* this should be possible to optimize to use i_glin() */
928 i_img_dim ix = rx / f->src->xsize;
929 i_img_dim iy = ry / f->src->ysize;
933 ix = rx / f->src->xsize;
937 iy = ry / f->src->xsize;
939 rx -= ix * f->src->xsize;
940 ry -= iy * f->src->ysize;
941 i_gpixf(f->src, rx, ry, work_data);
946 if (f->src->channels != want_channels)
947 i_adapt_fcolors(want_channels, f->src->channels, data, width);
951 fill_opacity(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
952 int channels, i_color *data) {
953 struct i_fill_opacity_t *f = (struct i_fill_opacity_t *)fill;
954 int alpha_chan = channels > 2 ? 3 : 1;
955 i_color *datap = data;
957 (f->other_fill->f_fill_with_color)(f->other_fill, x, y, width, channels, data);
959 double new_alpha = datap->channel[alpha_chan] * f->alpha_mult;
961 datap->channel[alpha_chan] = 0;
962 else if (new_alpha > 255)
963 datap->channel[alpha_chan] = 255;
964 else datap->channel[alpha_chan] = (int)(new_alpha + 0.5);
970 fill_opacityf(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
971 int channels, i_fcolor *data) {
972 struct i_fill_opacity_t *f = (struct i_fill_opacity_t *)fill;
973 int alpha_chan = channels > 2 ? 3 : 1;
974 i_fcolor *datap = data;
976 (f->other_fill->f_fill_with_fcolor)(f->other_fill, x, y, width, channels, data);
979 double new_alpha = datap->channel[alpha_chan] * f->alpha_mult;
981 datap->channel[alpha_chan] = 0;
982 else if (new_alpha > 1.0)
983 datap->channel[alpha_chan] = 1.0;
984 else datap->channel[alpha_chan] = new_alpha;
995 Tony Cook <tony@develop-help.com>