1 #define IMAGER_NO_CONTEXT
9 fills.c - implements the basic general fills
17 fill = i_new_fill_solidf(&fc1, combine);
18 fill = i_new_fill_solid(&c1, combine);
19 fill = i_new_fill_hatchf(&fc1, &fc2, combine, hatch, cust_hash, dx, dy);
20 fill = i_new_fill_hatch(&c1, &c2, combine, hatch, cust_hash, dx, dy);
21 fill = i_new_fill_image(im, matrix, xoff, yoff, combine);
22 fill = i_new_fill_opacity(fill, alpha_mult);
27 Implements the basic general fills, which can be used for filling some
28 shapes and for flood fills.
30 Each fill can implement up to 3 functions:
36 called for fills on 8-bit images. This can be NULL in which case the
37 fill_with_colorf function is called.
39 =item fill_with_fcolor
41 called for fills on non-8-bit images or when fill_with_color is NULL.
45 called by i_fill_destroy() if non-NULL, to release any extra resources
46 that the fill may need.
50 fill_with_color and fill_with_fcolor are basically the same function
51 except that the first works with lines of i_color and the second with
54 If the combines member if non-zero the line data is populated from the
55 target image before calling fill_with_*color.
57 fill_with_color needs to fill the I<data> parameter with the fill
58 pixels. If combines is non-zero it the fill pixels should be combined
59 with the existing data.
61 The current fills are:
79 Fountain fill is implemented by L<filters.c>.
81 Other fills that could be implemented include:
87 image - an image tiled over the fill area, with an offset either
88 horizontally or vertically.
92 checkerboard - combine 2 fills in a checkerboard
96 combine - combine the levels of 2 other fills based in the levels of
101 regmach - use the register machine to generate colors
110 static i_color fcolor_to_color(const i_fcolor *c) {
114 for (ch = 0; ch < MAXCHANNELS; ++ch)
115 out.channel[ch] = SampleFTo8(c->channel[ch]);
120 static i_fcolor color_to_fcolor(const i_color *c) {
124 for (ch = 0; ch < MAXCHANNELS; ++ch)
125 out.channel[ch] = Sample8ToF(c->channel[ch]);
130 /* alpha combine in with out */
131 #define COMBINE(out, in, channels) \
134 for (ch = 0; ch < (channels); ++ch) { \
135 (out).channel[ch] = ((out).channel[ch] * (255 - (in).channel[3]) \
136 + (in).channel[ch] * (in).channel[3]) / 255; \
140 /* alpha combine in with out, in this case in is a simple array of
141 samples, potentially not integers - the mult combiner uses doubles
143 #define COMBINEA(out, in, channels) \
146 for (ch = 0; ch < (channels); ++ch) { \
147 (out).channel[ch] = ((out).channel[ch] * (255 - (in)[3]) \
148 + (in)[ch] * (in)[3]) / 255; \
152 #define COMBINEF(out, in, channels) \
155 for (ch = 0; ch < (channels); ++ch) { \
156 (out).channel[ch] = (out).channel[ch] * (1.0 - (in).channel[3]) \
157 + (in).channel[ch] * (in).channel[3]; \
168 static void fill_solid(i_fill_t *, i_img_dim x, i_img_dim y, i_img_dim width,
169 int channels, i_color *);
170 static void fill_solidf(i_fill_t *, i_img_dim x, i_img_dim y, i_img_dim width,
171 int channels, i_fcolor *);
173 static i_fill_solid_t base_solid_fill =
185 =item i_fill_destroy(fill)
188 =synopsis i_fill_destroy(fill);
190 Call to destroy any fill object.
196 i_fill_destroy(i_fill_t *fill) {
198 (fill->destroy)(fill);
203 =item i_new_fill_solidf(color, combine)
206 =synopsis i_fill_t *fill = i_new_fill_solidf(&fcolor, combine);
208 Create a solid fill based on a float color.
210 If combine is non-zero then alpha values will be combined.
216 i_new_fill_solidf(const i_fcolor *c, int combine) {
218 i_fill_solid_t *fill = mymalloc(sizeof(i_fill_solid_t)); /* checked 14jul05 tonyc */
220 *fill = base_solid_fill;
222 i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
226 for (ch = 0; ch < MAXCHANNELS; ++ch) {
227 fill->c.channel[ch] = SampleFTo8(c->channel[ch]);
234 =item i_new_fill_solid(color, combine)
237 =synopsis i_fill_t *fill = i_new_fill_solid(&color, combine);
239 Create a solid fill based on an 8-bit color.
241 If combine is non-zero then alpha values will be combined.
247 i_new_fill_solid(const i_color *c, int combine) {
249 i_fill_solid_t *fill = mymalloc(sizeof(i_fill_solid_t)); /* checked 14jul05 tonyc */
251 *fill = base_solid_fill;
253 i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
257 for (ch = 0; ch < MAXCHANNELS; ++ch) {
258 fill->fc.channel[ch] = Sample8ToF(c->channel[ch]);
265 builtin_hatches[][8] =
268 /* 1x1 checkerboard */
269 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55,
272 /* 2x2 checkerboard */
273 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33,
276 /* 4 x 4 checkerboard */
277 0xF0, 0xF0, 0xF0, 0xF0, 0x0F, 0x0F, 0x0F, 0x0F,
280 /* single vertical lines */
281 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
284 /* double vertical lines */
285 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
288 /* quad vertical lines */
289 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
293 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
297 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,
301 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
305 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80,
309 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01,
313 0x11, 0x22, 0x44, 0x88, 0x11, 0x22, 0x44, 0x88,
317 0x88, 0x44, 0x22, 0x11, 0x88, 0x44, 0x22, 0x11,
321 0xFF, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
325 0xFF, 0x88, 0x88, 0x88, 0xFF, 0x88, 0x88, 0x88,
329 0xFF, 0xAA, 0xFF, 0xAA, 0xFF, 0xAA, 0xFF, 0xAA,
333 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
337 0x88, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00,
341 0xAA, 0x00, 0xAA, 0x00, 0xAA, 0x00, 0xAA, 0x00,
345 0x48, 0x84, 0x00, 0x00, 0x84, 0x48, 0x00, 0x00,
349 0x55, 0xFD, 0x05, 0xFD, 0x55, 0xDF, 0x50, 0xDF,
352 /* single cross hatch */
353 0x82, 0x44, 0x28, 0x10, 0x28, 0x44, 0x82, 0x01,
356 /* double cross hatch */
357 0xAA, 0x44, 0xAA, 0x11, 0xAA, 0x44, 0xAA, 0x11,
360 /* vertical lozenge */
361 0x11, 0x11, 0x11, 0xAA, 0x44, 0x44, 0x44, 0xAA,
364 /* horizontal lozenge */
365 0x88, 0x70, 0x88, 0x07, 0x88, 0x70, 0x88, 0x07,
368 /* scales overlapping downwards */
369 0x80, 0x80, 0x41, 0x3E, 0x08, 0x08, 0x14, 0xE3,
372 /* scales overlapping upwards */
373 0xC7, 0x28, 0x10, 0x10, 0x7C, 0x82, 0x01, 0x01,
376 /* scales overlapping leftwards */
377 0x83, 0x84, 0x88, 0x48, 0x38, 0x48, 0x88, 0x84,
380 /* scales overlapping rightwards */
381 0x21, 0x11, 0x12, 0x1C, 0x12, 0x11, 0x21, 0xC1,
385 0x44, 0x88, 0x22, 0x11, 0x44, 0x88, 0x22, 0x11,
389 0xFF, 0x84, 0x84, 0x9C, 0x94, 0x9C, 0x90, 0x90,
393 0x80, 0x40, 0x20, 0x00, 0x02, 0x04, 0x08, 0x00,
402 unsigned char hatch[8];
406 static void fill_hatch(i_fill_t *fill, i_img_dim x, i_img_dim y,
407 i_img_dim width, int channels, i_color *data);
408 static void fill_hatchf(i_fill_t *fill, i_img_dim x, i_img_dim y,
409 i_img_dim width, int channels, i_fcolor *data);
412 i_new_hatch_low(const i_color *fg, const i_color *bg, const i_fcolor *ffg, const i_fcolor *fbg,
413 int combine, int hatch, const unsigned char *cust_hatch,
414 i_img_dim dx, i_img_dim dy);
417 =item i_new_fill_hatch(C<fg>, C<bg>, C<combine>, C<hatch>, C<cust_hatch>, C<dx>, C<dy>)
420 =synopsis i_fill_t *fill = i_new_fill_hatch(&fg_color, &bg_color, combine, hatch, custom_hatch, dx, dy);
422 Creates a new hatched fill with the C<fg> color used for the 1 bits in
423 the hatch and C<bg> for the 0 bits. If C<combine> is non-zero alpha
424 values will be combined.
426 If C<cust_hatch> is non-NULL it should be a pointer to 8 bytes of the
427 hash definition, with the high-bits to the left.
429 If C<cust_hatch> is NULL then one of the standard hatches is used.
431 (C<dx>, C<dy>) are an offset into the hatch which can be used to hatch
432 adjoining areas out of alignment, or to align the origin of a hatch
433 with the side of a filled area.
438 i_new_fill_hatch(const i_color *fg, const i_color *bg, int combine, int hatch,
439 const unsigned char *cust_hatch, i_img_dim dx, i_img_dim dy) {
442 return i_new_hatch_low(fg, bg, NULL, NULL, combine, hatch, cust_hatch,
447 =item i_new_fill_hatchf(C<fg>, C<bg>, C<combine>, C<hatch>, C<cust_hatch>, C<dx>, C<dy>)
450 =synopsis i_fill_t *fill = i_new_fill_hatchf(&fg_fcolor, &bg_fcolor, combine, hatch, custom_hatch, dx, dy);
452 Creates a new hatched fill with the C<fg> color used for the 1 bits in
453 the hatch and C<bg> for the 0 bits. If C<combine> is non-zero alpha
454 values will be combined.
456 If C<cust_hatch> is non-NULL it should be a pointer to 8 bytes of the
457 hash definition, with the high-bits to the left.
459 If C<cust_hatch> is NULL then one of the standard hatches is used.
461 (C<dx>, C<dy>) are an offset into the hatch which can be used to hatch
462 adjoining areas out of alignment, or to align the origin of a hatch
463 with the side of a filled area.
468 i_new_fill_hatchf(const i_fcolor *fg, const i_fcolor *bg, int combine, int hatch,
469 const unsigned char *cust_hatch, i_img_dim dx, i_img_dim dy) {
472 return i_new_hatch_low(NULL, NULL, fg, bg, combine, hatch, cust_hatch,
476 static void fill_image(i_fill_t *fill, i_img_dim x, i_img_dim y,
477 i_img_dim width, int channels, i_color *data);
478 static void fill_imagef(i_fill_t *fill, i_img_dim x, i_img_dim y,
479 i_img_dim width, int channels, i_fcolor *data);
480 struct i_fill_image_t {
483 i_img_dim xoff, yoff;
488 static struct i_fill_image_t
499 =item i_new_fill_image(C<im>, C<matrix>, C<xoff>, C<yoff>, C<combine>)
502 =synopsis i_fill_t *fill = i_new_fill_image(src_img, matrix, x_offset, y_offset, combine);
504 Create an image based fill.
506 matrix is an array of 9 doubles representing a transformation matrix.
508 C<xoff> and C<yoff> are the offset into the image to start filling from.
513 i_new_fill_image(i_img *im, const double *matrix, i_img_dim xoff, i_img_dim yoff, int combine) {
514 struct i_fill_image_t *fill = mymalloc(sizeof(*fill)); /* checked 14jul05 tonyc */
516 *fill = image_fill_proto;
519 i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
522 fill->base.combine = NULL;
523 fill->base.combinef = NULL;
533 fill->has_matrix = 1;
534 memcpy(fill->matrix, matrix, sizeof(fill->matrix));
537 fill->has_matrix = 0;
542 static void fill_opacity(i_fill_t *fill, i_img_dim x, i_img_dim y,
543 i_img_dim width, int channels, i_color *data);
544 static void fill_opacityf(i_fill_t *fill, i_img_dim x, i_img_dim y,
545 i_img_dim width, int channels, i_fcolor *data);
547 struct i_fill_opacity_t {
549 i_fill_t *other_fill;
553 static struct i_fill_opacity_t
564 i_new_fill_opacity(i_fill_t *base_fill, double alpha_mult) {
565 struct i_fill_opacity_t *fill = mymalloc(sizeof(*fill));
566 *fill = opacity_fill_proto;
568 fill->base.combine = base_fill->combine;
569 fill->base.combinef = base_fill->combinef;
571 fill->other_fill = base_fill;
572 fill->alpha_mult = alpha_mult;
574 if (!base_fill->f_fill_with_color) {
575 /* base fill only does floating, so we only do that too */
576 fill->base.f_fill_with_color = NULL;
582 #define T_SOLID_FILL(fill) ((i_fill_solid_t *)(fill))
587 =head1 INTERNAL FUNCTIONS
591 =item fill_solid(fill, x, y, width, channels, data)
593 The 8-bit sample fill function for non-combining solid fills.
598 fill_solid(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
599 int channels, i_color *data) {
600 i_color c = T_SOLID_FILL(fill)->c;
601 i_adapt_colors(channels > 2 ? 4 : 2, 4, &c, 1);
602 while (width-- > 0) {
608 =item fill_solid(fill, x, y, width, channels, data)
610 The floating sample fill function for non-combining solid fills.
615 fill_solidf(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
616 int channels, i_fcolor *data) {
617 i_fcolor c = T_SOLID_FILL(fill)->fc;
618 i_adapt_fcolors(channels > 2 ? 4 : 2, 4, &c, 1);
619 while (width-- > 0) {
624 static i_fill_hatch_t
635 =item i_new_hatch_low(fg, bg, ffg, fbg, combine, hatch, cust_hatch, dx, dy)
637 Implements creation of hatch fill objects.
643 i_new_hatch_low(const i_color *fg, const i_color *bg,
644 const i_fcolor *ffg, const i_fcolor *fbg,
645 int combine, int hatch, const unsigned char *cust_hatch,
646 i_img_dim dx, i_img_dim dy) {
647 i_fill_hatch_t *fill = mymalloc(sizeof(i_fill_hatch_t)); /* checked 14jul05 tonyc */
649 *fill = hatch_fill_proto;
653 fill->ffg = color_to_fcolor(fg);
654 fill->fbg = color_to_fcolor(bg);
656 else if (ffg && fbg) {
657 fill->fg = fcolor_to_color(ffg);
658 fill->bg = fcolor_to_color(fbg);
668 i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
671 fill->base.combine = NULL;
672 fill->base.combinef = NULL;
675 memcpy(fill->hatch, cust_hatch, 8);
678 if (hatch >= sizeof(builtin_hatches)/sizeof(*builtin_hatches)
682 memcpy(fill->hatch, builtin_hatches[hatch], 8);
691 =item fill_hatch(fill, x, y, width, channels, data)
693 The 8-bit sample fill function for hatched fills.
698 fill_hatch(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
699 int channels, i_color *data) {
700 i_fill_hatch_t *f = (i_fill_hatch_t *)fill;
701 int byte = f->hatch[(y + f->dy) & 7];
702 int xpos = (x + f->dx) & 7;
703 int mask = 128 >> xpos;
708 i_adapt_colors(2, 4, &fg, 1);
709 i_adapt_colors(2, 4, &bg, 1);
712 while (width-- > 0) {
718 if ((mask >>= 1) == 0)
724 =item fill_hatchf(fill, x, y, width, channels, data)
726 The floating sample fill function for hatched fills.
731 fill_hatchf(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
732 int channels, i_fcolor *data) {
733 i_fill_hatch_t *f = (i_fill_hatch_t *)fill;
734 int byte = f->hatch[(y + f->dy) & 7];
735 int xpos = (x + f->dx) & 7;
736 int mask = 128 >> xpos;
737 i_fcolor fg = f->ffg;
738 i_fcolor bg = f->fbg;
741 i_adapt_fcolors(2, 4, &fg, 1);
742 i_adapt_fcolors(2, 4, &bg, 1);
745 while (width-- > 0) {
751 if ((mask >>= 1) == 0)
756 /* hopefully this will be inlined (it is with -O3 with gcc 2.95.4) */
757 /* linear interpolation */
758 static i_color interp_i_color(i_color before, i_color after, double pos,
764 for (ch = 0; ch < channels; ++ch)
765 out.channel[ch] = (1-pos) * before.channel[ch] + pos * after.channel[ch];
766 if (channels > 3 && out.channel[3]) {
767 for (ch = 0; ch < channels; ++ch) {
769 int temp = out.channel[ch] * 255 / out.channel[3];
772 out.channel[ch] = temp;
780 /* hopefully this will be inlined (it is with -O3 with gcc 2.95.4) */
781 /* linear interpolation */
782 static i_fcolor interp_i_fcolor(i_fcolor before, i_fcolor after, double pos,
788 for (ch = 0; ch < channels; ++ch)
789 out.channel[ch] = (1-pos) * before.channel[ch] + pos * after.channel[ch];
790 if (out.channel[3]) {
791 for (ch = 0; ch < channels; ++ch) {
793 int temp = out.channel[ch] / out.channel[3];
796 out.channel[ch] = temp;
805 =item fill_image(fill, x, y, width, channels, data, work)
810 fill_image(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
811 int channels, i_color *data) {
812 struct i_fill_image_t *f = (struct i_fill_image_t *)fill;
815 int want_channels = channels > 2 ? 4 : 2;
820 double rx = f->matrix[0] * (x+i) + f->matrix[1] * y + f->matrix[2];
821 double ry = f->matrix[3] * (x+i) + f->matrix[4] * y + f->matrix[5];
822 double ix = floor(rx / f->src->xsize);
823 double iy = floor(ry / f->src->ysize);
830 ix = floor(rx / f->src->xsize);
834 iy = floor(ry / f->src->ysize);
836 rx -= ix * f->src->xsize;
837 ry -= iy * f->src->ysize;
839 for (dy = 0; dy < 2; ++dy) {
840 if ((i_img_dim)rx == f->src->xsize-1) {
841 i_gpix(f->src, f->src->xsize-1, ((i_img_dim)ry+dy) % f->src->ysize, &c[dy][0]);
842 i_gpix(f->src, 0, ((i_img_dim)ry+dy) % f->src->xsize, &c[dy][1]);
845 i_glin(f->src, (i_img_dim)rx, (i_img_dim)rx+2, ((i_img_dim)ry+dy) % f->src->ysize,
848 c2[dy] = interp_i_color(c[dy][0], c[dy][1], rx, f->src->channels);
850 *out++ = interp_i_color(c2[0], c2[1], ry, f->src->channels);
856 /* this should be possible to optimize to use i_glin() */
860 i_img_dim ix = rx / f->src->xsize;
861 i_img_dim iy = ry / f->src->ysize;
865 ix = rx / f->src->xsize;
869 iy = ry / f->src->ysize;
871 rx -= ix * f->src->xsize;
872 ry -= iy * f->src->ysize;
873 i_gpix(f->src, rx, ry, out);
878 if (f->src->channels != want_channels)
879 i_adapt_colors(want_channels, f->src->channels, data, width);
883 =item fill_imagef(fill, x, y, width, channels, data, work)
888 fill_imagef(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
889 int channels, i_fcolor *data) {
890 struct i_fill_image_t *f = (struct i_fill_image_t *)fill;
892 int want_channels = channels > 2 ? 4 : 2;
895 i_fcolor *work_data = data;
898 double rx = f->matrix[0] * (x+i) + f->matrix[1] * y + f->matrix[2];
899 double ry = f->matrix[3] * (x+i) + f->matrix[4] * y + f->matrix[5];
900 double ix = floor(rx / f->src->xsize);
901 double iy = floor(ry / f->src->ysize);
908 ix = floor(rx / f->src->xsize);
912 iy = floor(ry / f->src->ysize);
914 rx -= ix * f->src->xsize;
915 ry -= iy * f->src->ysize;
917 for (dy = 0; dy < 2; ++dy) {
918 if ((i_img_dim)rx == f->src->xsize-1) {
919 i_gpixf(f->src, f->src->xsize-1, ((i_img_dim)ry+dy) % f->src->ysize, &c[dy][0]);
920 i_gpixf(f->src, 0, ((i_img_dim)ry+dy) % f->src->xsize, &c[dy][1]);
923 i_glinf(f->src, (i_img_dim)rx, (i_img_dim)rx+2, ((i_img_dim)ry+dy) % f->src->ysize,
926 c2[dy] = interp_i_fcolor(c[dy][0], c[dy][1], rx, f->src->channels);
928 *work_data++ = interp_i_fcolor(c2[0], c2[1], ry, f->src->channels);
933 i_fcolor *work_data = data;
935 /* this should be possible to optimize to use i_glin() */
939 i_img_dim ix = rx / f->src->xsize;
940 i_img_dim iy = ry / f->src->ysize;
944 ix = rx / f->src->xsize;
948 iy = ry / f->src->xsize;
950 rx -= ix * f->src->xsize;
951 ry -= iy * f->src->ysize;
952 i_gpixf(f->src, rx, ry, work_data);
957 if (f->src->channels != want_channels)
958 i_adapt_fcolors(want_channels, f->src->channels, data, width);
962 fill_opacity(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
963 int channels, i_color *data) {
964 struct i_fill_opacity_t *f = (struct i_fill_opacity_t *)fill;
965 int alpha_chan = channels > 2 ? 3 : 1;
966 i_color *datap = data;
968 (f->other_fill->f_fill_with_color)(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 > 255)
974 datap->channel[alpha_chan] = 255;
975 else datap->channel[alpha_chan] = (int)(new_alpha + 0.5);
981 fill_opacityf(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
982 int channels, i_fcolor *data) {
983 struct i_fill_opacity_t *f = (struct i_fill_opacity_t *)fill;
984 int alpha_chan = channels > 2 ? 3 : 1;
985 i_fcolor *datap = data;
987 (f->other_fill->f_fill_with_fcolor)(f->other_fill, x, y, width, channels, data);
990 double new_alpha = datap->channel[alpha_chan] * f->alpha_mult;
992 datap->channel[alpha_chan] = 0;
993 else if (new_alpha > 1.0)
994 datap->channel[alpha_chan] = 1.0;
995 else datap->channel[alpha_chan] = new_alpha;
1006 Tony Cook <tony@develop-help.com>