1 #define IMAGER_NO_CONTEXT
8 fills.c - implements the basic general fills
16 fill = i_new_fill_solidf(&fc1, combine);
17 fill = i_new_fill_solid(&c1, combine);
18 fill = i_new_fill_hatchf(&fc1, &fc2, combine, hatch, cust_hash, dx, dy);
19 fill = i_new_fill_hatch(&c1, &c2, combine, hatch, cust_hash, dx, dy);
20 fill = i_new_fill_image(im, matrix, xoff, yoff, combine);
21 fill = i_new_fill_opacity(fill, alpha_mult);
26 Implements the basic general fills, which can be used for filling some
27 shapes and for flood fills.
29 Each fill can implement up to 3 functions:
35 called for fills on 8-bit images. This can be NULL in which case the
36 fill_with_colorf function is called.
38 =item fill_with_fcolor
40 called for fills on non-8-bit images or when fill_with_color is NULL.
44 called by i_fill_destroy() if non-NULL, to release any extra resources
45 that the fill may need.
49 fill_with_color and fill_with_fcolor are basically the same function
50 except that the first works with lines of i_color and the second with
53 If the combines member if non-zero the line data is populated from the
54 target image before calling fill_with_*color.
56 fill_with_color needs to fill the I<data> parameter with the fill
57 pixels. If combines is non-zero it the fill pixels should be combined
58 with the existing data.
60 The current fills are:
78 Fountain fill is implemented by L<filters.c>.
80 Other fills that could be implemented include:
86 image - an image tiled over the fill area, with an offset either
87 horizontally or vertically.
91 checkerboard - combine 2 fills in a checkerboard
95 combine - combine the levels of 2 other fills based in the levels of
100 regmach - use the register machine to generate colors
109 static i_color fcolor_to_color(const i_fcolor *c) {
113 for (ch = 0; ch < MAXCHANNELS; ++ch)
114 out.channel[ch] = SampleFTo8(c->channel[ch]);
119 static i_fcolor color_to_fcolor(const i_color *c) {
123 for (ch = 0; ch < MAXCHANNELS; ++ch)
124 out.channel[ch] = Sample8ToF(c->channel[ch]);
129 /* alpha combine in with out */
130 #define COMBINE(out, in, channels) \
133 for (ch = 0; ch < (channels); ++ch) { \
134 (out).channel[ch] = ((out).channel[ch] * (255 - (in).channel[3]) \
135 + (in).channel[ch] * (in).channel[3]) / 255; \
139 /* alpha combine in with out, in this case in is a simple array of
140 samples, potentially not integers - the mult combiner uses doubles
142 #define COMBINEA(out, in, channels) \
145 for (ch = 0; ch < (channels); ++ch) { \
146 (out).channel[ch] = ((out).channel[ch] * (255 - (in)[3]) \
147 + (in)[ch] * (in)[3]) / 255; \
151 #define COMBINEF(out, in, channels) \
154 for (ch = 0; ch < (channels); ++ch) { \
155 (out).channel[ch] = (out).channel[ch] * (1.0 - (in).channel[3]) \
156 + (in).channel[ch] * (in).channel[3]; \
167 static void fill_solid(i_fill_t *, i_img_dim x, i_img_dim y, i_img_dim width,
168 int channels, i_color *);
169 static void fill_solidf(i_fill_t *, i_img_dim x, i_img_dim y, i_img_dim width,
170 int channels, i_fcolor *);
172 static i_fill_solid_t base_solid_fill =
184 =item i_fill_destroy(fill)
187 =synopsis i_fill_destroy(fill);
189 Call to destroy any fill object.
195 i_fill_destroy(i_fill_t *fill) {
197 (fill->destroy)(fill);
202 =item i_new_fill_solidf(color, combine)
205 =synopsis i_fill_t *fill = i_new_fill_solidf(&fcolor, combine);
207 Create a solid fill based on a float color.
209 If combine is non-zero then alpha values will be combined.
215 i_new_fill_solidf(const i_fcolor *c, int combine) {
217 i_fill_solid_t *fill = mymalloc(sizeof(i_fill_solid_t)); /* checked 14jul05 tonyc */
219 *fill = base_solid_fill;
221 i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
225 for (ch = 0; ch < MAXCHANNELS; ++ch) {
226 fill->c.channel[ch] = SampleFTo8(c->channel[ch]);
233 =item i_new_fill_solid(color, combine)
236 =synopsis i_fill_t *fill = i_new_fill_solid(&color, combine);
238 Create a solid fill based on an 8-bit color.
240 If combine is non-zero then alpha values will be combined.
246 i_new_fill_solid(const i_color *c, int combine) {
248 i_fill_solid_t *fill = mymalloc(sizeof(i_fill_solid_t)); /* checked 14jul05 tonyc */
250 *fill = base_solid_fill;
252 i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
256 for (ch = 0; ch < MAXCHANNELS; ++ch) {
257 fill->fc.channel[ch] = Sample8ToF(c->channel[ch]);
264 builtin_hatches[][8] =
267 /* 1x1 checkerboard */
268 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55,
271 /* 2x2 checkerboard */
272 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33,
275 /* 4 x 4 checkerboard */
276 0xF0, 0xF0, 0xF0, 0xF0, 0x0F, 0x0F, 0x0F, 0x0F,
279 /* single vertical lines */
280 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
283 /* double vertical lines */
284 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
287 /* quad vertical lines */
288 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
292 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
296 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,
300 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
304 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80,
308 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01,
312 0x11, 0x22, 0x44, 0x88, 0x11, 0x22, 0x44, 0x88,
316 0x88, 0x44, 0x22, 0x11, 0x88, 0x44, 0x22, 0x11,
320 0xFF, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
324 0xFF, 0x88, 0x88, 0x88, 0xFF, 0x88, 0x88, 0x88,
328 0xFF, 0xAA, 0xFF, 0xAA, 0xFF, 0xAA, 0xFF, 0xAA,
332 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
336 0x88, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00,
340 0xAA, 0x00, 0xAA, 0x00, 0xAA, 0x00, 0xAA, 0x00,
344 0x48, 0x84, 0x00, 0x00, 0x84, 0x48, 0x00, 0x00,
348 0x55, 0xFD, 0x05, 0xFD, 0x55, 0xDF, 0x50, 0xDF,
351 /* single cross hatch */
352 0x82, 0x44, 0x28, 0x10, 0x28, 0x44, 0x82, 0x01,
355 /* double cross hatch */
356 0xAA, 0x44, 0xAA, 0x11, 0xAA, 0x44, 0xAA, 0x11,
359 /* vertical lozenge */
360 0x11, 0x11, 0x11, 0xAA, 0x44, 0x44, 0x44, 0xAA,
363 /* horizontal lozenge */
364 0x88, 0x70, 0x88, 0x07, 0x88, 0x70, 0x88, 0x07,
367 /* scales overlapping downwards */
368 0x80, 0x80, 0x41, 0x3E, 0x08, 0x08, 0x14, 0xE3,
371 /* scales overlapping upwards */
372 0xC7, 0x28, 0x10, 0x10, 0x7C, 0x82, 0x01, 0x01,
375 /* scales overlapping leftwards */
376 0x83, 0x84, 0x88, 0x48, 0x38, 0x48, 0x88, 0x84,
379 /* scales overlapping rightwards */
380 0x21, 0x11, 0x12, 0x1C, 0x12, 0x11, 0x21, 0xC1,
384 0x44, 0x88, 0x22, 0x11, 0x44, 0x88, 0x22, 0x11,
388 0xFF, 0x84, 0x84, 0x9C, 0x94, 0x9C, 0x90, 0x90,
392 0x80, 0x40, 0x20, 0x00, 0x02, 0x04, 0x08, 0x00,
401 unsigned char hatch[8];
405 static void fill_hatch(i_fill_t *fill, i_img_dim x, i_img_dim y,
406 i_img_dim width, int channels, i_color *data);
407 static void fill_hatchf(i_fill_t *fill, i_img_dim x, i_img_dim y,
408 i_img_dim width, int channels, i_fcolor *data);
411 i_new_hatch_low(const i_color *fg, const i_color *bg, const i_fcolor *ffg, const i_fcolor *fbg,
412 int combine, int hatch, const unsigned char *cust_hatch,
413 i_img_dim dx, i_img_dim dy);
416 =item i_new_fill_hatch(C<fg>, C<bg>, C<combine>, C<hatch>, C<cust_hatch>, C<dx>, C<dy>)
419 =synopsis i_fill_t *fill = i_new_fill_hatch(&fg_color, &bg_color, combine, hatch, custom_hatch, dx, dy);
421 Creates a new hatched fill with the C<fg> color used for the 1 bits in
422 the hatch and C<bg> for the 0 bits. If C<combine> is non-zero alpha
423 values will be combined.
425 If C<cust_hatch> is non-NULL it should be a pointer to 8 bytes of the
426 hash definition, with the high-bits to the left.
428 If C<cust_hatch> is NULL then one of the standard hatches is used.
430 (C<dx>, C<dy>) are an offset into the hatch which can be used to hatch
431 adjoining areas out of alignment, or to align the origin of a hatch
432 with the the side of a filled area.
437 i_new_fill_hatch(const i_color *fg, const i_color *bg, int combine, int hatch,
438 const unsigned char *cust_hatch, i_img_dim dx, i_img_dim dy) {
439 return i_new_hatch_low(fg, bg, NULL, NULL, combine, hatch, cust_hatch,
444 =item i_new_fill_hatchf(C<fg>, C<bg>, C<combine>, C<hatch>, C<cust_hatch>, C<dx>, C<dy>)
447 =synopsis i_fill_t *fill = i_new_fill_hatchf(&fg_fcolor, &bg_fcolor, combine, hatch, custom_hatch, dx, dy);
449 Creates a new hatched fill with the C<fg> color used for the 1 bits in
450 the hatch and C<bg> for the 0 bits. If C<combine> is non-zero alpha
451 values will be combined.
453 If C<cust_hatch> is non-NULL it should be a pointer to 8 bytes of the
454 hash definition, with the high-bits to the left.
456 If C<cust_hatch> is NULL then one of the standard hatches is used.
458 (C<dx>, C<dy>) are an offset into the hatch which can be used to hatch
459 adjoining areas out of alignment, or to align the origin of a hatch
460 with the the side of a filled area.
465 i_new_fill_hatchf(const i_fcolor *fg, const i_fcolor *bg, int combine, int hatch,
466 const unsigned char *cust_hatch, i_img_dim dx, i_img_dim dy) {
467 return i_new_hatch_low(NULL, NULL, fg, bg, combine, hatch, cust_hatch,
471 static void fill_image(i_fill_t *fill, i_img_dim x, i_img_dim y,
472 i_img_dim width, int channels, i_color *data);
473 static void fill_imagef(i_fill_t *fill, i_img_dim x, i_img_dim y,
474 i_img_dim width, int channels, i_fcolor *data);
475 struct i_fill_image_t {
478 i_img_dim xoff, yoff;
483 static struct i_fill_image_t
494 =item i_new_fill_image(C<im>, C<matrix>, C<xoff>, C<yoff>, C<combine>)
497 =synopsis i_fill_t *fill = i_new_fill_image(src_img, matrix, x_offset, y_offset, combine);
499 Create an image based fill.
501 matrix is an array of 9 doubles representing a transformation matrix.
503 C<xoff> and C<yoff> are the offset into the image to start filling from.
508 i_new_fill_image(i_img *im, const double *matrix, i_img_dim xoff, i_img_dim yoff, int combine) {
509 struct i_fill_image_t *fill = mymalloc(sizeof(*fill)); /* checked 14jul05 tonyc */
511 *fill = image_fill_proto;
514 i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
517 fill->base.combine = NULL;
518 fill->base.combinef = NULL;
528 fill->has_matrix = 1;
529 memcpy(fill->matrix, matrix, sizeof(fill->matrix));
532 fill->has_matrix = 0;
537 static void fill_opacity(i_fill_t *fill, i_img_dim x, i_img_dim y,
538 i_img_dim width, int channels, i_color *data);
539 static void fill_opacityf(i_fill_t *fill, i_img_dim x, i_img_dim y,
540 i_img_dim width, int channels, i_fcolor *data);
542 struct i_fill_opacity_t {
544 i_fill_t *other_fill;
548 static struct i_fill_opacity_t
559 i_new_fill_opacity(i_fill_t *base_fill, double alpha_mult) {
560 struct i_fill_opacity_t *fill = mymalloc(sizeof(*fill));
561 *fill = opacity_fill_proto;
563 fill->base.combine = base_fill->combine;
564 fill->base.combinef = base_fill->combinef;
566 fill->other_fill = base_fill;
567 fill->alpha_mult = alpha_mult;
569 if (!base_fill->f_fill_with_color) {
570 /* base fill only does floating, so we only do that too */
571 fill->base.f_fill_with_color = NULL;
577 #define T_SOLID_FILL(fill) ((i_fill_solid_t *)(fill))
582 =head1 INTERNAL FUNCTIONS
586 =item fill_solid(fill, x, y, width, channels, data)
588 The 8-bit sample fill function for non-combining solid fills.
593 fill_solid(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
594 int channels, i_color *data) {
595 i_color c = T_SOLID_FILL(fill)->c;
596 i_adapt_colors(channels > 2 ? 4 : 2, 4, &c, 1);
597 while (width-- > 0) {
603 =item fill_solid(fill, x, y, width, channels, data)
605 The floating sample fill function for non-combining solid fills.
610 fill_solidf(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
611 int channels, i_fcolor *data) {
612 i_fcolor c = T_SOLID_FILL(fill)->fc;
613 i_adapt_fcolors(channels > 2 ? 4 : 2, 4, &c, 1);
614 while (width-- > 0) {
619 static i_fill_hatch_t
630 =item i_new_hatch_low(fg, bg, ffg, fbg, combine, hatch, cust_hatch, dx, dy)
632 Implements creation of hatch fill objects.
638 i_new_hatch_low(const i_color *fg, const i_color *bg,
639 const i_fcolor *ffg, const i_fcolor *fbg,
640 int combine, int hatch, const unsigned char *cust_hatch,
641 i_img_dim dx, i_img_dim dy) {
642 i_fill_hatch_t *fill = mymalloc(sizeof(i_fill_hatch_t)); /* checked 14jul05 tonyc */
644 *fill = hatch_fill_proto;
645 /* Some Sun C didn't like the condition expressions that were here.
646 See https://rt.cpan.org/Ticket/Display.html?id=21944
651 fill->fg = fcolor_to_color(ffg);
655 fill->bg = fcolor_to_color(fbg);
659 fill->ffg = color_to_fcolor(fg);
663 fill->fbg = color_to_fcolor(bg);
665 i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
668 fill->base.combine = NULL;
669 fill->base.combinef = NULL;
672 memcpy(fill->hatch, cust_hatch, 8);
675 if (hatch > sizeof(builtin_hatches)/sizeof(*builtin_hatches))
677 memcpy(fill->hatch, builtin_hatches[hatch], 8);
686 =item fill_hatch(fill, x, y, width, channels, data)
688 The 8-bit sample fill function for hatched fills.
693 fill_hatch(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
694 int channels, i_color *data) {
695 i_fill_hatch_t *f = (i_fill_hatch_t *)fill;
696 int byte = f->hatch[(y + f->dy) & 7];
697 int xpos = (x + f->dx) & 7;
698 int mask = 128 >> xpos;
703 i_adapt_colors(2, 4, &fg, 1);
704 i_adapt_colors(2, 4, &bg, 1);
707 while (width-- > 0) {
713 if ((mask >>= 1) == 0)
719 =item fill_hatchf(fill, x, y, width, channels, data)
721 The floating sample fill function for hatched fills.
726 fill_hatchf(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
727 int channels, i_fcolor *data) {
728 i_fill_hatch_t *f = (i_fill_hatch_t *)fill;
729 int byte = f->hatch[(y + f->dy) & 7];
730 int xpos = (x + f->dx) & 7;
731 int mask = 128 >> xpos;
732 i_fcolor fg = f->ffg;
733 i_fcolor bg = f->fbg;
736 i_adapt_fcolors(2, 4, &fg, 1);
737 i_adapt_fcolors(2, 4, &bg, 1);
740 while (width-- > 0) {
746 if ((mask >>= 1) == 0)
751 /* hopefully this will be inlined (it is with -O3 with gcc 2.95.4) */
752 /* linear interpolation */
753 static i_color interp_i_color(i_color before, i_color after, double pos,
759 for (ch = 0; ch < channels; ++ch)
760 out.channel[ch] = (1-pos) * before.channel[ch] + pos * after.channel[ch];
761 if (channels > 3 && out.channel[3])
762 for (ch = 0; ch < channels; ++ch)
764 int temp = out.channel[ch] * 255 / out.channel[3];
767 out.channel[ch] = temp;
773 /* hopefully this will be inlined (it is with -O3 with gcc 2.95.4) */
774 /* linear interpolation */
775 static i_fcolor interp_i_fcolor(i_fcolor before, i_fcolor after, double pos,
781 for (ch = 0; ch < channels; ++ch)
782 out.channel[ch] = (1-pos) * before.channel[ch] + pos * after.channel[ch];
784 for (ch = 0; ch < channels; ++ch)
786 int temp = out.channel[ch] / out.channel[3];
789 out.channel[ch] = temp;
796 =item fill_image(fill, x, y, width, channels, data, work)
801 fill_image(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
802 int channels, i_color *data) {
803 struct i_fill_image_t *f = (struct i_fill_image_t *)fill;
806 int want_channels = channels > 2 ? 4 : 2;
811 double rx = f->matrix[0] * (x+i) + f->matrix[1] * y + f->matrix[2];
812 double ry = f->matrix[3] * (x+i) + f->matrix[4] * y + f->matrix[5];
813 double ix = floor(rx / f->src->xsize);
814 double iy = floor(ry / f->src->ysize);
821 ix = floor(rx / f->src->xsize);
825 iy = floor(ry / f->src->ysize);
827 rx -= ix * f->src->xsize;
828 ry -= iy * f->src->ysize;
830 for (dy = 0; dy < 2; ++dy) {
831 if ((i_img_dim)rx == f->src->xsize-1) {
832 i_gpix(f->src, f->src->xsize-1, ((i_img_dim)ry+dy) % f->src->ysize, &c[dy][0]);
833 i_gpix(f->src, 0, ((i_img_dim)ry+dy) % f->src->xsize, &c[dy][1]);
836 i_glin(f->src, (i_img_dim)rx, (i_img_dim)rx+2, ((i_img_dim)ry+dy) % f->src->ysize,
839 c2[dy] = interp_i_color(c[dy][0], c[dy][1], rx, f->src->channels);
841 *out++ = interp_i_color(c2[0], c2[1], ry, f->src->channels);
847 /* this should be possible to optimize to use i_glin() */
851 i_img_dim ix = rx / f->src->xsize;
852 i_img_dim iy = ry / f->src->ysize;
856 ix = rx / f->src->xsize;
860 iy = ry / f->src->xsize;
862 rx -= ix * f->src->xsize;
863 ry -= iy * f->src->ysize;
864 i_gpix(f->src, rx, ry, out);
869 if (f->src->channels != want_channels)
870 i_adapt_colors(want_channels, f->src->channels, data, width);
874 =item fill_imagef(fill, x, y, width, channels, data, work)
879 fill_imagef(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
880 int channels, i_fcolor *data) {
881 struct i_fill_image_t *f = (struct i_fill_image_t *)fill;
883 int want_channels = channels > 2 ? 4 : 2;
886 i_fcolor *work_data = data;
889 double rx = f->matrix[0] * (x+i) + f->matrix[1] * y + f->matrix[2];
890 double ry = f->matrix[3] * (x+i) + f->matrix[4] * y + f->matrix[5];
891 double ix = floor(rx / f->src->xsize);
892 double iy = floor(ry / f->src->ysize);
899 ix = floor(rx / f->src->xsize);
903 iy = floor(ry / f->src->ysize);
905 rx -= ix * f->src->xsize;
906 ry -= iy * f->src->ysize;
908 for (dy = 0; dy < 2; ++dy) {
909 if ((i_img_dim)rx == f->src->xsize-1) {
910 i_gpixf(f->src, f->src->xsize-1, ((i_img_dim)ry+dy) % f->src->ysize, &c[dy][0]);
911 i_gpixf(f->src, 0, ((i_img_dim)ry+dy) % f->src->xsize, &c[dy][1]);
914 i_glinf(f->src, (i_img_dim)rx, (i_img_dim)rx+2, ((i_img_dim)ry+dy) % f->src->ysize,
917 c2[dy] = interp_i_fcolor(c[dy][0], c[dy][1], rx, f->src->channels);
919 *work_data++ = interp_i_fcolor(c2[0], c2[1], ry, f->src->channels);
924 i_fcolor *work_data = data;
926 /* this should be possible to optimize to use i_glin() */
930 i_img_dim ix = rx / f->src->xsize;
931 i_img_dim iy = ry / f->src->ysize;
935 ix = rx / f->src->xsize;
939 iy = ry / f->src->xsize;
941 rx -= ix * f->src->xsize;
942 ry -= iy * f->src->ysize;
943 i_gpixf(f->src, rx, ry, work_data);
948 if (f->src->channels != want_channels)
949 i_adapt_fcolors(want_channels, f->src->channels, data, width);
953 fill_opacity(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
954 int channels, i_color *data) {
955 struct i_fill_opacity_t *f = (struct i_fill_opacity_t *)fill;
956 int alpha_chan = channels > 2 ? 3 : 1;
957 i_color *datap = data;
959 (f->other_fill->f_fill_with_color)(f->other_fill, x, y, width, channels, data);
961 double new_alpha = datap->channel[alpha_chan] * f->alpha_mult;
963 datap->channel[alpha_chan] = 0;
964 else if (new_alpha > 255)
965 datap->channel[alpha_chan] = 255;
966 else datap->channel[alpha_chan] = (int)(new_alpha + 0.5);
972 fill_opacityf(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
973 int channels, i_fcolor *data) {
974 struct i_fill_opacity_t *f = (struct i_fill_opacity_t *)fill;
975 int alpha_chan = channels > 2 ? 3 : 1;
976 i_fcolor *datap = data;
978 (f->other_fill->f_fill_with_fcolor)(f->other_fill, x, y, width, channels, data);
981 double new_alpha = datap->channel[alpha_chan] * f->alpha_mult;
983 datap->channel[alpha_chan] = 0;
984 else if (new_alpha > 1.0)
985 datap->channel[alpha_chan] = 1.0;
986 else datap->channel[alpha_chan] = new_alpha;
997 Tony Cook <tony@develop-help.com>