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 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 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;
775 /* hopefully this will be inlined (it is with -O3 with gcc 2.95.4) */
776 /* linear interpolation */
777 static i_fcolor interp_i_fcolor(i_fcolor before, i_fcolor after, double pos,
783 for (ch = 0; ch < channels; ++ch)
784 out.channel[ch] = (1-pos) * before.channel[ch] + pos * after.channel[ch];
785 if (out.channel[3]) {
786 for (ch = 0; ch < channels; ++ch) {
788 int temp = out.channel[ch] / out.channel[3];
791 out.channel[ch] = temp;
800 =item fill_image(fill, x, y, width, channels, data, work)
805 fill_image(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
806 int channels, i_color *data) {
807 struct i_fill_image_t *f = (struct i_fill_image_t *)fill;
810 int want_channels = channels > 2 ? 4 : 2;
815 double rx = f->matrix[0] * (x+i) + f->matrix[1] * y + f->matrix[2];
816 double ry = f->matrix[3] * (x+i) + f->matrix[4] * y + f->matrix[5];
817 double ix = floor(rx / f->src->xsize);
818 double iy = floor(ry / f->src->ysize);
825 ix = floor(rx / f->src->xsize);
829 iy = floor(ry / f->src->ysize);
831 rx -= ix * f->src->xsize;
832 ry -= iy * f->src->ysize;
834 for (dy = 0; dy < 2; ++dy) {
835 if ((i_img_dim)rx == f->src->xsize-1) {
836 i_gpix(f->src, f->src->xsize-1, ((i_img_dim)ry+dy) % f->src->ysize, &c[dy][0]);
837 i_gpix(f->src, 0, ((i_img_dim)ry+dy) % f->src->xsize, &c[dy][1]);
840 i_glin(f->src, (i_img_dim)rx, (i_img_dim)rx+2, ((i_img_dim)ry+dy) % f->src->ysize,
843 c2[dy] = interp_i_color(c[dy][0], c[dy][1], rx, f->src->channels);
845 *out++ = interp_i_color(c2[0], c2[1], ry, f->src->channels);
851 /* this should be possible to optimize to use i_glin() */
855 i_img_dim ix = rx / f->src->xsize;
856 i_img_dim iy = ry / f->src->ysize;
860 ix = rx / f->src->xsize;
864 iy = ry / f->src->ysize;
866 rx -= ix * f->src->xsize;
867 ry -= iy * f->src->ysize;
868 i_gpix(f->src, rx, ry, out);
873 if (f->src->channels != want_channels)
874 i_adapt_colors(want_channels, f->src->channels, data, width);
878 =item fill_imagef(fill, x, y, width, channels, data, work)
883 fill_imagef(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
884 int channels, i_fcolor *data) {
885 struct i_fill_image_t *f = (struct i_fill_image_t *)fill;
887 int want_channels = channels > 2 ? 4 : 2;
890 i_fcolor *work_data = data;
893 double rx = f->matrix[0] * (x+i) + f->matrix[1] * y + f->matrix[2];
894 double ry = f->matrix[3] * (x+i) + f->matrix[4] * y + f->matrix[5];
895 double ix = floor(rx / f->src->xsize);
896 double iy = floor(ry / f->src->ysize);
903 ix = floor(rx / f->src->xsize);
907 iy = floor(ry / f->src->ysize);
909 rx -= ix * f->src->xsize;
910 ry -= iy * f->src->ysize;
912 for (dy = 0; dy < 2; ++dy) {
913 if ((i_img_dim)rx == f->src->xsize-1) {
914 i_gpixf(f->src, f->src->xsize-1, ((i_img_dim)ry+dy) % f->src->ysize, &c[dy][0]);
915 i_gpixf(f->src, 0, ((i_img_dim)ry+dy) % f->src->xsize, &c[dy][1]);
918 i_glinf(f->src, (i_img_dim)rx, (i_img_dim)rx+2, ((i_img_dim)ry+dy) % f->src->ysize,
921 c2[dy] = interp_i_fcolor(c[dy][0], c[dy][1], rx, f->src->channels);
923 *work_data++ = interp_i_fcolor(c2[0], c2[1], ry, f->src->channels);
928 i_fcolor *work_data = data;
930 /* this should be possible to optimize to use i_glin() */
934 i_img_dim ix = rx / f->src->xsize;
935 i_img_dim iy = ry / f->src->ysize;
939 ix = rx / f->src->xsize;
943 iy = ry / f->src->xsize;
945 rx -= ix * f->src->xsize;
946 ry -= iy * f->src->ysize;
947 i_gpixf(f->src, rx, ry, work_data);
952 if (f->src->channels != want_channels)
953 i_adapt_fcolors(want_channels, f->src->channels, data, width);
957 fill_opacity(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
958 int channels, i_color *data) {
959 struct i_fill_opacity_t *f = (struct i_fill_opacity_t *)fill;
960 int alpha_chan = channels > 2 ? 3 : 1;
961 i_color *datap = data;
963 (f->other_fill->f_fill_with_color)(f->other_fill, x, y, width, channels, data);
965 double new_alpha = datap->channel[alpha_chan] * f->alpha_mult;
967 datap->channel[alpha_chan] = 0;
968 else if (new_alpha > 255)
969 datap->channel[alpha_chan] = 255;
970 else datap->channel[alpha_chan] = (int)(new_alpha + 0.5);
976 fill_opacityf(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
977 int channels, i_fcolor *data) {
978 struct i_fill_opacity_t *f = (struct i_fill_opacity_t *)fill;
979 int alpha_chan = channels > 2 ? 3 : 1;
980 i_fcolor *datap = data;
982 (f->other_fill->f_fill_with_fcolor)(f->other_fill, x, y, width, channels, data);
985 double new_alpha = datap->channel[alpha_chan] * f->alpha_mult;
987 datap->channel[alpha_chan] = 0;
988 else if (new_alpha > 1.0)
989 datap->channel[alpha_chan] = 1.0;
990 else datap->channel[alpha_chan] = new_alpha;
1001 Tony Cook <tony@develop-help.com>