X-Git-Url: http://git.imager.perl.org/imager.git/blobdiff_plain/43c5dacbc0c703d1eee26a0eb93adf6db6a1e247..81b6f49945e4d1676fcbdf7cd8974c84e0aa31d1:/fills.c diff --git a/fills.c b/fills.c index bcd06049..6b464823 100644 --- a/fills.c +++ b/fills.c @@ -1,5 +1,6 @@ -#include "image.h" -#include "imagei.h" +#define IMAGER_NO_CONTEXT +#include "imager.h" +#include "imageri.h" /* =head1 NAME @@ -17,6 +18,7 @@ fills.c - implements the basic general fills fill = i_new_fill_hatchf(&fc1, &fc2, combine, hatch, cust_hash, dx, dy); fill = i_new_fill_hatch(&c1, &c2, combine, hatch, cust_hash, dx, dy); fill = i_new_fill_image(im, matrix, xoff, yoff, combine); + fill = i_new_fill_opacity(fill, alpha_mult); i_fill_destroy(fill); =head1 DESCRIPTION @@ -104,7 +106,7 @@ regmach - use the register machine to generate colors =cut */ -static i_color fcolor_to_color(i_fcolor *c) { +static i_color fcolor_to_color(const i_fcolor *c) { int ch; i_color out; @@ -114,7 +116,7 @@ static i_color fcolor_to_color(i_fcolor *c) { return out; } -static i_fcolor color_to_fcolor(i_color *c) { +static i_fcolor color_to_fcolor(const i_color *c) { int ch; i_fcolor out; @@ -162,14 +164,10 @@ typedef struct i_fcolor fc; } i_fill_solid_t; -static void fill_solid(i_fill_t *, int x, int y, int width, int channels, - i_color *); -static void fill_solidf(i_fill_t *, int x, int y, int width, int channels, - i_fcolor *); -static void fill_solid_comb(i_fill_t *, int x, int y, int width, int channels, - i_color *); -static void fill_solidf_comb(i_fill_t *, int x, int y, int width, - int channels, i_fcolor *); +static void fill_solid(i_fill_t *, i_img_dim x, i_img_dim y, i_img_dim width, + int channels, i_color *); +static void fill_solidf(i_fill_t *, i_img_dim x, i_img_dim y, i_img_dim width, + int channels, i_fcolor *); static i_fill_solid_t base_solid_fill = { @@ -181,19 +179,12 @@ static i_fill_solid_t base_solid_fill = NULL, }, }; -static i_fill_solid_t base_solid_fill_comb = -{ - { - fill_solid_comb, - fill_solidf_comb, - NULL, - NULL, - NULL, - }, -}; /* =item i_fill_destroy(fill) +=order 90 +=category Fills +=synopsis i_fill_destroy(fill); Call to destroy any fill object. @@ -210,6 +201,9 @@ i_fill_destroy(i_fill_t *fill) { /* =item i_new_fill_solidf(color, combine) +=category Fills +=synopsis i_fill_t *fill = i_new_fill_solidf(&fcolor, combine); + Create a solid fill based on a float color. If combine is non-zero then alpha values will be combined. @@ -218,16 +212,15 @@ If combine is non-zero then alpha values will be combined. */ i_fill_t * -i_new_fill_solidf(i_fcolor *c, int combine) { +i_new_fill_solidf(const i_fcolor *c, int combine) { int ch; - i_fill_solid_t *fill = mymalloc(sizeof(i_fill_solid_t)); + i_fill_solid_t *fill = mymalloc(sizeof(i_fill_solid_t)); /* checked 14jul05 tonyc */ + *fill = base_solid_fill; if (combine) { - *fill = base_solid_fill_comb; i_get_combine(combine, &fill->base.combine, &fill->base.combinef); } - else - *fill = base_solid_fill; + fill->fc = *c; for (ch = 0; ch < MAXCHANNELS; ++ch) { fill->c.channel[ch] = SampleFTo8(c->channel[ch]); @@ -239,7 +232,10 @@ i_new_fill_solidf(i_fcolor *c, int combine) { /* =item i_new_fill_solid(color, combine) -Create a solid fill based. +=category Fills +=synopsis i_fill_t *fill = i_new_fill_solid(&color, combine); + +Create a solid fill based on an 8-bit color. If combine is non-zero then alpha values will be combined. @@ -247,16 +243,15 @@ If combine is non-zero then alpha values will be combined. */ i_fill_t * -i_new_fill_solid(i_color *c, int combine) { +i_new_fill_solid(const i_color *c, int combine) { int ch; - i_fill_solid_t *fill = mymalloc(sizeof(i_fill_solid_t)); + i_fill_solid_t *fill = mymalloc(sizeof(i_fill_solid_t)); /* checked 14jul05 tonyc */ + *fill = base_solid_fill; if (combine) { - *fill = base_solid_fill_comb; i_get_combine(combine, &fill->base.combine, &fill->base.combinef); } - else - *fill = base_solid_fill; + fill->c = *c; for (ch = 0; ch < MAXCHANNELS; ++ch) { fill->fc.channel[ch] = Sample8ToF(c->channel[ch]); @@ -404,91 +399,116 @@ typedef struct i_color fg, bg; i_fcolor ffg, fbg; unsigned char hatch[8]; - int dx, dy; + i_img_dim dx, dy; } i_fill_hatch_t; -static void fill_hatch(i_fill_t *fill, int x, int y, int width, int channels, - i_color *data); -static void fill_hatchf(i_fill_t *fill, int x, int y, int width, int channels, - i_fcolor *data); +static void fill_hatch(i_fill_t *fill, i_img_dim x, i_img_dim y, + i_img_dim width, int channels, i_color *data); +static void fill_hatchf(i_fill_t *fill, i_img_dim x, i_img_dim y, + i_img_dim width, int channels, i_fcolor *data); static i_fill_t * -i_new_hatch_low(i_color *fg, i_color *bg, i_fcolor *ffg, i_fcolor *fbg, - int combine, int hatch, unsigned char *cust_hatch, - int dx, int dy); +i_new_hatch_low(const i_color *fg, const i_color *bg, const i_fcolor *ffg, const i_fcolor *fbg, + int combine, int hatch, const unsigned char *cust_hatch, + i_img_dim dx, i_img_dim dy); /* -=item i_new_fill_hatch(fg, bg, combine, hatch, cust_hatch, dx, dy) +=item i_new_fill_hatch(C, C, C, C, C, C, C) + +=category Fills +=synopsis i_fill_t *fill = i_new_fill_hatch(&fg_color, &bg_color, combine, hatch, custom_hatch, dx, dy); -Creates a new hatched fill with the fg color used for the 1 bits in -the hatch and bg for the 0 bits. If combine is non-zero alpha values -will be combined. +Creates a new hatched fill with the C color used for the 1 bits in +the hatch and C for the 0 bits. If C is non-zero alpha +values will be combined. -If cust_hatch is non-NULL it should be a pointer to 8 bytes of the +If C is non-NULL it should be a pointer to 8 bytes of the hash definition, with the high-bits to the left. -If cust_hatch is NULL then one of the standard hatches is used. +If C is NULL then one of the standard hatches is used. -(dx, dy) are an offset into the hatch which can be used to unalign adjoining areas, or to align the origin of a hatch with the the side of a filled area. +(C, C) are an offset into the hatch which can be used to hatch +adjoining areas out of alignment, or to align the origin of a hatch +with the the side of a filled area. =cut */ i_fill_t * -i_new_fill_hatch(i_color *fg, i_color *bg, int combine, int hatch, - unsigned char *cust_hatch, int dx, int dy) { +i_new_fill_hatch(const i_color *fg, const i_color *bg, int combine, int hatch, + const unsigned char *cust_hatch, i_img_dim dx, i_img_dim dy) { return i_new_hatch_low(fg, bg, NULL, NULL, combine, hatch, cust_hatch, dx, dy); } /* -=item i_new_fill_hatchf(fg, bg, combine, hatch, cust_hatch, dx, dy) +=item i_new_fill_hatchf(C, C, C, C, C, C, C) + +=category Fills +=synopsis i_fill_t *fill = i_new_fill_hatchf(&fg_fcolor, &bg_fcolor, combine, hatch, custom_hatch, dx, dy); -Creates a new hatched fill with the fg color used for the 1 bits in -the hatch and bg for the 0 bits. If combine is non-zero alpha values -will be combined. +Creates a new hatched fill with the C color used for the 1 bits in +the hatch and C for the 0 bits. If C is non-zero alpha +values will be combined. -If cust_hatch is non-NULL it should be a pointer to 8 bytes of the +If C is non-NULL it should be a pointer to 8 bytes of the hash definition, with the high-bits to the left. -If cust_hatch is NULL then one of the standard hatches is used. +If C is NULL then one of the standard hatches is used. -(dx, dy) are an offset into the hatch which can be used to unalign adjoining areas, or to align the origin of a hatch with the the side of a filled area. +(C, C) are an offset into the hatch which can be used to hatch +adjoining areas out of alignment, or to align the origin of a hatch +with the the side of a filled area. =cut */ i_fill_t * -i_new_fill_hatchf(i_fcolor *fg, i_fcolor *bg, int combine, int hatch, - unsigned char *cust_hatch, int dx, int dy) { +i_new_fill_hatchf(const i_fcolor *fg, const i_fcolor *bg, int combine, int hatch, + const unsigned char *cust_hatch, i_img_dim dx, i_img_dim dy) { return i_new_hatch_low(NULL, NULL, fg, bg, combine, hatch, cust_hatch, dx, dy); } -static void fill_image(i_fill_t *fill, int x, int y, int width, int channels, - i_color *data); -static void fill_imagef(i_fill_t *fill, int x, int y, int width, int channels, - i_fcolor *data); +static void fill_image(i_fill_t *fill, i_img_dim x, i_img_dim y, + i_img_dim width, int channels, i_color *data); +static void fill_imagef(i_fill_t *fill, i_img_dim x, i_img_dim y, + i_img_dim width, int channels, i_fcolor *data); struct i_fill_image_t { i_fill_t base; i_img *src; - int xoff, yoff; + i_img_dim xoff, yoff; int has_matrix; double matrix[9]; }; +static struct i_fill_image_t +image_fill_proto = + { + { + fill_image, + fill_imagef, + NULL + } + }; + /* -=item i_new_fill_image(im, matrix, xoff, yoff, combine) +=item i_new_fill_image(C, C, C, C, C) + +=category Fills +=synopsis i_fill_t *fill = i_new_fill_image(src_img, matrix, x_offset, y_offset, combine); Create an image based fill. +matrix is an array of 9 doubles representing a transformation matrix. + +C and C are the offset into the image to start filling from. + =cut */ i_fill_t * -i_new_fill_image(i_img *im, double *matrix, int xoff, int yoff, int combine) { - struct i_fill_image_t *fill = mymalloc(sizeof(*fill)); +i_new_fill_image(i_img *im, const double *matrix, i_img_dim xoff, i_img_dim yoff, int combine) { + struct i_fill_image_t *fill = mymalloc(sizeof(*fill)); /* checked 14jul05 tonyc */ - fill->base.fill_with_color = fill_image; - fill->base.fill_with_fcolor = fill_imagef; - fill->base.destroy = NULL; + *fill = image_fill_proto; if (combine) { i_get_combine(combine, &fill->base.combine, &fill->base.combinef); @@ -514,79 +534,98 @@ i_new_fill_image(i_img *im, double *matrix, int xoff, int yoff, int combine) { return &fill->base; } +static void fill_opacity(i_fill_t *fill, i_img_dim x, i_img_dim y, + i_img_dim width, int channels, i_color *data); +static void fill_opacityf(i_fill_t *fill, i_img_dim x, i_img_dim y, + i_img_dim width, int channels, i_fcolor *data); -#define T_SOLID_FILL(fill) ((i_fill_solid_t *)(fill)) - -/* -=back +struct i_fill_opacity_t { + i_fill_t base; + i_fill_t *other_fill; + double alpha_mult; +}; -=head1 INTERNAL FUNCTIONS +static struct i_fill_opacity_t +opacity_fill_proto = + { + { + fill_opacity, + fill_opacityf, + NULL + } + }; -=over +i_fill_t * +i_new_fill_opacity(i_fill_t *base_fill, double alpha_mult) { + struct i_fill_opacity_t *fill = mymalloc(sizeof(*fill)); + *fill = opacity_fill_proto; -=item fill_solid(fill, x, y, width, channels, data) + fill->base.combine = base_fill->combine; + fill->base.combinef = base_fill->combinef; -The 8-bit sample fill function for non-combining solid fills. + fill->other_fill = base_fill; + fill->alpha_mult = alpha_mult; -=cut -*/ -static void -fill_solid(i_fill_t *fill, int x, int y, int width, int channels, - i_color *data) { - while (width-- > 0) { - *data++ = T_SOLID_FILL(fill)->c; + if (!base_fill->f_fill_with_color) { + /* base fill only does floating, so we only do that too */ + fill->base.f_fill_with_color = NULL; } + + return &fill->base; } +#define T_SOLID_FILL(fill) ((i_fill_solid_t *)(fill)) + /* -=item fill_solid(fill, x, y, width, channels, data) +=back -The floating sample fill function for non-combining solid fills. +=head1 INTERNAL FUNCTIONS -=cut -*/ -static void -fill_solidf(i_fill_t *fill, int x, int y, int width, int channels, - i_fcolor *data) { - while (width-- > 0) { - *data++ = T_SOLID_FILL(fill)->fc; - } -} +=over -/* -=item fill_solid_comb(fill, x, y, width, channels, data) +=item fill_solid(fill, x, y, width, channels, data) -The 8-bit sample fill function for combining solid fills. +The 8-bit sample fill function for non-combining solid fills. =cut */ static void -fill_solid_comb(i_fill_t *fill, int x, int y, int width, int channels, - i_color *data) { +fill_solid(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width, + int channels, i_color *data) { i_color c = T_SOLID_FILL(fill)->c; - + i_adapt_colors(channels > 2 ? 4 : 2, 4, &c, 1); while (width-- > 0) { *data++ = c; } } /* -=item fill_solidf_comb(fill, x, y, width, channels, data) +=item fill_solid(fill, x, y, width, channels, data) -The floating sample fill function for combining solid fills. +The floating sample fill function for non-combining solid fills. =cut */ static void -fill_solidf_comb(i_fill_t *fill, int x, int y, int width, int channels, - i_fcolor *data) { +fill_solidf(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width, + int channels, i_fcolor *data) { i_fcolor c = T_SOLID_FILL(fill)->fc; - + i_adapt_fcolors(channels > 2 ? 4 : 2, 4, &c, 1); while (width-- > 0) { *data++ = c; } } +static i_fill_hatch_t +hatch_fill_proto = + { + { + fill_hatch, + fill_hatchf, + NULL + } + }; + /* =item i_new_hatch_low(fg, bg, ffg, fbg, combine, hatch, cust_hatch, dx, dy) @@ -596,18 +635,32 @@ Implements creation of hatch fill objects. */ static i_fill_t * -i_new_hatch_low(i_color *fg, i_color *bg, i_fcolor *ffg, i_fcolor *fbg, - int combine, int hatch, unsigned char *cust_hatch, - int dx, int dy) { - i_fill_hatch_t *fill = mymalloc(sizeof(i_fill_hatch_t)); - - fill->base.fill_with_color = fill_hatch; - fill->base.fill_with_fcolor = fill_hatchf; - fill->base.destroy = NULL; - fill->fg = fg ? *fg : fcolor_to_color(ffg); - fill->bg = bg ? *bg : fcolor_to_color(fbg); - fill->ffg = ffg ? *ffg : color_to_fcolor(fg); - fill->fbg = fbg ? *fbg : color_to_fcolor(bg); +i_new_hatch_low(const i_color *fg, const i_color *bg, + const i_fcolor *ffg, const i_fcolor *fbg, + int combine, int hatch, const unsigned char *cust_hatch, + i_img_dim dx, i_img_dim dy) { + i_fill_hatch_t *fill = mymalloc(sizeof(i_fill_hatch_t)); /* checked 14jul05 tonyc */ + + *fill = hatch_fill_proto; + /* Some Sun C didn't like the condition expressions that were here. + See https://rt.cpan.org/Ticket/Display.html?id=21944 + */ + if (fg) + fill->fg = *fg; + else + fill->fg = fcolor_to_color(ffg); + if (bg) + fill->bg = *bg; + else + fill->bg = fcolor_to_color(fbg); + if (ffg) + fill->ffg = *ffg; + else + fill->ffg = color_to_fcolor(fg); + if (fbg) + fill->fbg = *fbg; + else + fill->fbg = color_to_fcolor(bg); if (combine) { i_get_combine(combine, &fill->base.combine, &fill->base.combinef); } @@ -636,15 +689,26 @@ The 8-bit sample fill function for hatched fills. =cut */ -static void fill_hatch(i_fill_t *fill, int x, int y, int width, int channels, - i_color *data) { +static void +fill_hatch(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width, + int channels, i_color *data) { i_fill_hatch_t *f = (i_fill_hatch_t *)fill; int byte = f->hatch[(y + f->dy) & 7]; int xpos = (x + f->dx) & 7; int mask = 128 >> xpos; + i_color fg = f->fg; + i_color bg = f->bg; + + if (channels < 3) { + i_adapt_colors(2, 4, &fg, 1); + i_adapt_colors(2, 4, &bg, 1); + } while (width-- > 0) { - *data++ = (byte & mask) ? f->fg : f->bg; + if (byte & mask) + *data++ = fg; + else + *data++ = bg; if ((mask >>= 1) == 0) mask = 128; @@ -658,15 +722,26 @@ The floating sample fill function for hatched fills. =back */ -static void fill_hatchf(i_fill_t *fill, int x, int y, int width, int channels, - i_fcolor *data) { +static void +fill_hatchf(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width, + int channels, i_fcolor *data) { i_fill_hatch_t *f = (i_fill_hatch_t *)fill; int byte = f->hatch[(y + f->dy) & 7]; int xpos = (x + f->dx) & 7; int mask = 128 >> xpos; + i_fcolor fg = f->ffg; + i_fcolor bg = f->fbg; + + if (channels < 3) { + i_adapt_fcolors(2, 4, &fg, 1); + i_adapt_fcolors(2, 4, &bg, 1); + } while (width-- > 0) { - *data++ = (byte & mask) ? f->ffg : f->fbg; + if (byte & mask) + *data++ = fg; + else + *data++ = bg; if ((mask >>= 1) == 0) mask = 128; @@ -683,7 +758,7 @@ static i_color interp_i_color(i_color before, i_color after, double pos, pos -= floor(pos); for (ch = 0; ch < channels; ++ch) out.channel[ch] = (1-pos) * before.channel[ch] + pos * after.channel[ch]; - if (out.channel[3]) + if (channels > 3 && out.channel[3]) for (ch = 0; ch < channels; ++ch) if (ch != 3) { int temp = out.channel[ch] * 255 / out.channel[3]; @@ -722,11 +797,13 @@ static i_fcolor interp_i_fcolor(i_fcolor before, i_fcolor after, double pos, =cut */ -static void fill_image(i_fill_t *fill, int x, int y, int width, int channels, - i_color *data) { +static void +fill_image(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width, + int channels, i_color *data) { struct i_fill_image_t *f = (struct i_fill_image_t *)fill; - int i = 0; - i_color c; + i_img_dim i = 0; + i_color *out = data; + int want_channels = channels > 2 ? 4 : 2; if (f->has_matrix) { /* the hard way */ @@ -737,7 +814,7 @@ static void fill_image(i_fill_t *fill, int x, int y, int width, int channels, double iy = floor(ry / f->src->ysize); i_color c[2][2]; i_color c2[2]; - int dy; + i_img_dim dy; if (f->xoff) { rx += iy * f->xoff; @@ -751,17 +828,17 @@ static void fill_image(i_fill_t *fill, int x, int y, int width, int channels, ry -= iy * f->src->ysize; for (dy = 0; dy < 2; ++dy) { - if ((int)rx == f->src->xsize-1) { - i_gpix(f->src, f->src->xsize-1, ((int)ry+dy) % f->src->ysize, &c[dy][0]); - i_gpix(f->src, 0, ((int)ry+dy) % f->src->xsize, &c[dy][1]); + if ((i_img_dim)rx == f->src->xsize-1) { + i_gpix(f->src, f->src->xsize-1, ((i_img_dim)ry+dy) % f->src->ysize, &c[dy][0]); + i_gpix(f->src, 0, ((i_img_dim)ry+dy) % f->src->xsize, &c[dy][1]); } else { - i_glin(f->src, (int)rx, (int)rx+2, ((int)ry+dy) % f->src->ysize, + i_glin(f->src, (i_img_dim)rx, (i_img_dim)rx+2, ((i_img_dim)ry+dy) % f->src->ysize, c[dy]); } c2[dy] = interp_i_color(c[dy][0], c[dy][1], rx, f->src->channels); } - *data++ = interp_i_color(c2[0], c2[1], ry, f->src->channels); + *out++ = interp_i_color(c2[0], c2[1], ry, f->src->channels); ++i; } } @@ -769,10 +846,10 @@ static void fill_image(i_fill_t *fill, int x, int y, int width, int channels, /* the easy way */ /* this should be possible to optimize to use i_glin() */ while (i < width) { - int rx = x+i; - int ry = y; - int ix = rx / f->src->xsize; - int iy = ry / f->src->ysize; + i_img_dim rx = x+i; + i_img_dim ry = y; + i_img_dim ix = rx / f->src->xsize; + i_img_dim iy = ry / f->src->ysize; if (f->xoff) { rx += iy * f->xoff; @@ -780,29 +857,33 @@ static void fill_image(i_fill_t *fill, int x, int y, int width, int channels, } else if (f->yoff) { ry += ix * f->yoff; - iy = ry / f->src->xsize; + iy = ry / f->src->ysize; } rx -= ix * f->src->xsize; ry -= iy * f->src->ysize; - i_gpix(f->src, rx, ry, data); - ++data; + i_gpix(f->src, rx, ry, out); + ++out; ++i; } } + if (f->src->channels != want_channels) + i_adapt_colors(want_channels, f->src->channels, data, width); } /* -=item fill_image(fill, x, y, width, channels, data, work) +=item fill_imagef(fill, x, y, width, channels, data, work) =cut */ -static void fill_imagef(i_fill_t *fill, int x, int y, int width, int channels, - i_fcolor *data) { +static void +fill_imagef(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width, + int channels, i_fcolor *data) { struct i_fill_image_t *f = (struct i_fill_image_t *)fill; - int i = 0; - i_fcolor c; + i_img_dim i = 0; + int want_channels = channels > 2 ? 4 : 2; if (f->has_matrix) { + i_fcolor *work_data = data; /* the hard way */ while (i < width) { double rx = f->matrix[0] * (x+i) + f->matrix[1] * y + f->matrix[2]; @@ -811,7 +892,7 @@ static void fill_imagef(i_fill_t *fill, int x, int y, int width, int channels, double iy = floor(ry / f->src->ysize); i_fcolor c[2][2]; i_fcolor c2[2]; - int dy; + i_img_dim dy; if (f->xoff) { rx += iy * f->xoff; @@ -825,28 +906,29 @@ static void fill_imagef(i_fill_t *fill, int x, int y, int width, int channels, ry -= iy * f->src->ysize; for (dy = 0; dy < 2; ++dy) { - if ((int)rx == f->src->xsize-1) { - i_gpixf(f->src, f->src->xsize-1, ((int)ry+dy) % f->src->ysize, &c[dy][0]); - i_gpixf(f->src, 0, ((int)ry+dy) % f->src->xsize, &c[dy][1]); + if ((i_img_dim)rx == f->src->xsize-1) { + i_gpixf(f->src, f->src->xsize-1, ((i_img_dim)ry+dy) % f->src->ysize, &c[dy][0]); + i_gpixf(f->src, 0, ((i_img_dim)ry+dy) % f->src->xsize, &c[dy][1]); } else { - i_glinf(f->src, (int)rx, (int)rx+2, ((int)ry+dy) % f->src->ysize, + i_glinf(f->src, (i_img_dim)rx, (i_img_dim)rx+2, ((i_img_dim)ry+dy) % f->src->ysize, c[dy]); } c2[dy] = interp_i_fcolor(c[dy][0], c[dy][1], rx, f->src->channels); } - *data++ = interp_i_fcolor(c2[0], c2[1], ry, f->src->channels); + *work_data++ = interp_i_fcolor(c2[0], c2[1], ry, f->src->channels); ++i; } } else { + i_fcolor *work_data = data; /* the easy way */ /* this should be possible to optimize to use i_glin() */ while (i < width) { - int rx = x+i; - int ry = y; - int ix = rx / f->src->xsize; - int iy = ry / f->src->ysize; + i_img_dim rx = x+i; + i_img_dim ry = y; + i_img_dim ix = rx / f->src->xsize; + i_img_dim iy = ry / f->src->ysize; if (f->xoff) { rx += iy * f->xoff; @@ -858,480 +940,55 @@ static void fill_imagef(i_fill_t *fill, int x, int y, int width, int channels, } rx -= ix * f->src->xsize; ry -= iy * f->src->ysize; - i_gpixf(f->src, rx, ry, data); - ++data; + i_gpixf(f->src, rx, ry, work_data); + ++work_data; ++i; } } + if (f->src->channels != want_channels) + i_adapt_fcolors(want_channels, f->src->channels, data, width); } -static void combine_replace(i_color *, i_color *, int, int); -static void combine_replacef(i_fcolor *, i_fcolor *, int, int); -static void combine_alphablend(i_color *, i_color *, int, int); -static void combine_alphablendf(i_fcolor *, i_fcolor *, int, int); -static void combine_mult(i_color *, i_color *, int, int); -static void combine_multf(i_fcolor *, i_fcolor *, int, int); -static void combine_dissolve(i_color *, i_color *, int, int); -static void combine_dissolvef(i_fcolor *, i_fcolor *, int, int); -static void combine_add(i_color *, i_color *, int, int); -static void combine_addf(i_fcolor *, i_fcolor *, int, int); -static void combine_subtract(i_color *, i_color *, int, int); -static void combine_subtractf(i_fcolor *, i_fcolor *, int, int); -static void combine_diff(i_color *, i_color *, int, int); -static void combine_difff(i_fcolor *, i_fcolor *, int, int); -static void combine_darken(i_color *, i_color *, int, int); -static void combine_darkenf(i_fcolor *, i_fcolor *, int, int); -static void combine_lighten(i_color *, i_color *, int, int); -static void combine_lightenf(i_fcolor *, i_fcolor *, int, int); -static void combine_hue(i_color *, i_color *, int, int); -static void combine_huef(i_fcolor *, i_fcolor *, int, int); -static void combine_sat(i_color *, i_color *, int, int); -static void combine_satf(i_fcolor *, i_fcolor *, int, int); -static void combine_value(i_color *, i_color *, int, int); -static void combine_valuef(i_fcolor *, i_fcolor *, int, int); -static void combine_color(i_color *, i_color *, int, int); -static void combine_colorf(i_fcolor *, i_fcolor *, int, int); - -struct i_combines { - i_fill_combine_f combine; - i_fill_combinef_f combinef; -} combines[] = -{ - { /* replace */ - combine_replace, - combine_replacef, - }, - { /* alpha blend */ - combine_alphablend, - combine_alphablendf, - }, - { - /* multiply */ - combine_mult, - combine_multf, - }, - { - /* dissolve */ - combine_dissolve, - combine_dissolvef, - }, - { - /* add */ - combine_add, - combine_addf, - }, - { - /* subtract */ - combine_subtract, - combine_subtractf, - }, - { - /* diff */ - combine_diff, - combine_difff, - }, - { - combine_lighten, - combine_lightenf, - }, - { - combine_darken, - combine_darkenf, - }, - { - combine_hue, - combine_huef, - }, - { - combine_sat, - combine_satf, - }, - { - combine_value, - combine_valuef, - }, - { - combine_color, - combine_colorf, - }, -}; - -/* -=item i_get_combine(combine, color_func, fcolor_func) - -=cut -*/ - -void i_get_combine(int combine, i_fill_combine_f *color_func, - i_fill_combinef_f *fcolor_func) { - if (combine < 0 || combine > sizeof(combines) / sizeof(*combines)) - combine = 0; - - *color_func = combines[combine].combine; - *fcolor_func = combines[combine].combinef; -} - -static void combine_replace(i_color *out, i_color *in, int channels, int count) { - while (count--) { - *out++ = *in++; - } -} - -static void combine_replacef(i_fcolor *out, i_fcolor *in, int channels, int count) { - while (count--) { - *out++ = *in++; - } -} - -static void combine_alphablend(i_color *out, i_color *in, int channels, int count) { - while (count--) { - COMBINE(*out, *in, channels); - ++out; - ++in; - } -} - -static void combine_alphablendf(i_fcolor *out, i_fcolor *in, int channels, int count) { - while (count--) { - COMBINEF(*out, *in, channels); - ++out; - ++in; - } -} - -static void combine_mult(i_color *out, i_color *in, int channels, int count) { - int ch; - - while (count--) { - i_color c = *in; - double mult[MAXCHANNELS]; - mult[3] = in->channel[3]; - for (ch = 0; ch < (channels); ++ch) { - if (ch != 3) - mult[ch] = (out->channel[ch] * in->channel[ch]) * (1.0 / 255); - } - COMBINEA(*out, mult, channels); - ++out; - ++in; - } -} - -static void combine_multf(i_fcolor *out, i_fcolor *in, int channels, int count) { - int ch; - - while (count--) { - i_fcolor c = *in; - for (ch = 0; ch < channels; ++ch) { - if (ch != 3) - c.channel[ch] = out->channel[ch] * in->channel[ch]; - } - COMBINEF(*out, c, channels); - ++out; - ++in; - } -} - -static void combine_dissolve(i_color *out, i_color *in, int channels, int count) { - int ch; - - while (count--) { - if (in->channel[3] > rand() * (255.0 / RAND_MAX)) - COMBINE(*out, *in, channels); - ++out; - ++in; - } -} - -static void combine_dissolvef(i_fcolor *out, i_fcolor *in, int channels, int count) { - int ch; - - while (count--) { - if (in->channel[3] > rand() * (1.0 / RAND_MAX)) - COMBINEF(*out, *in, channels); - ++out; - ++in; - } -} - -static void combine_add(i_color *out, i_color *in, int channels, int count) { - int ch; - - while (count--) { - i_color c = *in; - for (ch = 0; ch < (channels); ++ch) { - if (ch != 3) { - int total = out->channel[ch] + in->channel[ch]; - if (total > 255) - total = 255; - c.channel[ch] = total; - } - } - COMBINE(*out, c, channels); - ++out; - ++in; - } -} - -static void combine_addf(i_fcolor *out, i_fcolor *in, int channels, int count) { - int ch; - - while (count--) { - i_fcolor c = *in; - for (ch = 0; ch < (channels); ++ch) { - if (ch != 3) { - double total = out->channel[ch] + in->channel[ch]; - if (total > 1.0) - total = 1.0; - out->channel[ch] = total; - } - } - COMBINEF(*out, c, channels); - ++out; - ++in; - } -} - -static void combine_subtract(i_color *out, i_color *in, int channels, int count) { - int ch; - - while (count--) { - i_color c = *in; - for (ch = 0; ch < (channels); ++ch) { - if (ch != 3) { - int total = out->channel[ch] - in->channel[ch]; - if (total < 0) - total = 0; - c.channel[ch] = total; - } - } - COMBINE(*out, c, channels); - ++out; - ++in; - } -} - -static void combine_subtractf(i_fcolor *out, i_fcolor *in, int channels, int count) { - int ch; - - while (count--) { - i_fcolor c = *in; - for (ch = 0; ch < channels; ++ch) { - if (ch != 3) { - double total = out->channel[ch] - in->channel[ch]; - if (total < 0) - total = 0; - c.channel[ch] = total; - } - } - COMBINEF(*out, c, channels); - ++out; - ++in; - } -} - -static void combine_diff(i_color *out, i_color *in, int channels, int count) { - int ch; - - while (count--) { - i_color c = *in; - for (ch = 0; ch < (channels); ++ch) { - if (ch != 3) - c.channel[ch] = abs(out->channel[ch] - in->channel[ch]); - } - COMBINE(*out, c, channels) - ++out; - ++in; - } -} - -static void combine_difff(i_fcolor *out, i_fcolor *in, int channels, int count) { - int ch; - - while (count--) { - i_fcolor c = *in; - for (ch = 0; ch < (channels); ++ch) { - if (ch != 3) - c.channel[ch] = fabs(out->channel[ch] - in->channel[ch]); - } - COMBINEF(*out, c, channels); - ++out; - ++in; - } -} - -static void combine_darken(i_color *out, i_color *in, int channels, int count) { - int ch; - - while (count--) { - for (ch = 0; ch < channels; ++ch) { - if (ch != 3 && out->channel[ch] < in->channel[ch]) - in->channel[ch] = out->channel[ch]; - } - COMBINE(*out, *in, channels); - ++out; - ++in; - } -} - -static void combine_darkenf(i_fcolor *out, i_fcolor *in, int channels, int count) { - int ch; - - while (count--) { - for (ch = 0; ch < channels; ++ch) { - if (ch != 3 && out->channel[ch] < in->channel[ch]) - in->channel[ch] = out->channel[ch]; - } - COMBINEF(*out, *in, channels); - ++out; - ++in; - } -} - -static void combine_lighten(i_color *out, i_color *in, int channels, int count) { - int ch; - - while (count--) { - for (ch = 0; ch < channels; ++ch) { - if (ch != 3 && out->channel[ch] > in->channel[ch]) - in->channel[ch] = out->channel[ch]; - } - COMBINE(*out, *in, channels); - ++out; - ++in; - } -} - -static void combine_lightenf(i_fcolor *out, i_fcolor *in, int channels, int count) { - int ch; - - while (count--) { - for (ch = 0; ch < channels; ++ch) { - if (ch != 3 && out->channel[ch] > in->channel[ch]) - in->channel[ch] = out->channel[ch]; - } - COMBINEF(*out, *in, channels); - ++out; - ++in; - } -} - -static void combine_hue(i_color *out, i_color *in, int channels, int count) { - while (count--) { - i_color c = *out; - i_rgb_to_hsv(&c); - i_rgb_to_hsv(in); - c.channel[0] = in->channel[0]; - i_hsv_to_rgb(&c); - c.channel[3] = in->channel[3]; - COMBINE(*out, c, channels); - ++out; - ++in; - } -} - -static void combine_huef(i_fcolor *out, i_fcolor *in, int channels, int count) { - while (count--) { - i_fcolor c = *out; - i_rgb_to_hsvf(&c); - i_rgb_to_hsvf(in); - c.channel[0] = in->channel[0]; - i_hsv_to_rgbf(&c); - c.channel[3] = in->channel[3]; - COMBINEF(*out, c, channels); - ++out; - ++in; - } -} - -static void combine_sat(i_color *out, i_color *in, int channels, int count) { - while (count--) { - i_color c = *out; - i_rgb_to_hsv(&c); - i_rgb_to_hsv(in); - c.channel[1] = in->channel[1]; - i_hsv_to_rgb(&c); - c.channel[3] = in->channel[3]; - COMBINE(*out, c, channels); - ++out; - ++in; - } -} - -static void combine_satf(i_fcolor *out, i_fcolor *in, int channels, int count) { - while (count--) { - i_fcolor c = *out; - i_rgb_to_hsvf(&c); - i_rgb_to_hsvf(in); - c.channel[1] = in->channel[1]; - i_hsv_to_rgbf(&c); - c.channel[3] = in->channel[3]; - COMBINEF(*out, c, channels); - ++out; - ++in; - } -} - -static void combine_value(i_color *out, i_color *in, int channels, int count) { - while (count--) { - i_color c = *out; - i_rgb_to_hsv(&c); - i_rgb_to_hsv(in); - c.channel[2] = in->channel[2]; - i_hsv_to_rgb(&c); - c.channel[3] = in->channel[3]; - COMBINE(*out, c, channels); - ++out; - ++in; - } -} - -static void combine_valuef(i_fcolor *out, i_fcolor *in, int channels, - int count) { - while (count--) { - i_fcolor c = *out; - i_rgb_to_hsvf(&c); - i_rgb_to_hsvf(in); - c.channel[2] = in->channel[2]; - i_hsv_to_rgbf(&c); - c.channel[3] = in->channel[3]; - COMBINEF(*out, c, channels); - ++out; - ++in; - } -} - -static void combine_color(i_color *out, i_color *in, int channels, int count) { - while (count--) { - i_color c = *out; - i_rgb_to_hsv(&c); - i_rgb_to_hsv(in); - c.channel[0] = in->channel[0]; - c.channel[1] = in->channel[1]; - i_hsv_to_rgb(&c); - c.channel[3] = in->channel[3]; - COMBINE(*out, c, channels); - ++out; - ++in; - } -} +static void +fill_opacity(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width, + int channels, i_color *data) { + struct i_fill_opacity_t *f = (struct i_fill_opacity_t *)fill; + int alpha_chan = channels > 2 ? 3 : 1; + i_color *datap = data; + + (f->other_fill->f_fill_with_color)(f->other_fill, x, y, width, channels, data); + while (width--) { + double new_alpha = datap->channel[alpha_chan] * f->alpha_mult; + if (new_alpha < 0) + datap->channel[alpha_chan] = 0; + else if (new_alpha > 255) + datap->channel[alpha_chan] = 255; + else datap->channel[alpha_chan] = (int)(new_alpha + 0.5); + + ++datap; + } +} +static void +fill_opacityf(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width, + int channels, i_fcolor *data) { + struct i_fill_opacity_t *f = (struct i_fill_opacity_t *)fill; + int alpha_chan = channels > 2 ? 3 : 1; + i_fcolor *datap = data; + + (f->other_fill->f_fill_with_fcolor)(f->other_fill, x, y, width, channels, data); + + while (width--) { + double new_alpha = datap->channel[alpha_chan] * f->alpha_mult; + if (new_alpha < 0) + datap->channel[alpha_chan] = 0; + else if (new_alpha > 1.0) + datap->channel[alpha_chan] = 1.0; + else datap->channel[alpha_chan] = new_alpha; -static void combine_colorf(i_fcolor *out, i_fcolor *in, int channels, - int count) { - while (count--) { - i_fcolor c = *out; - i_rgb_to_hsvf(&c); - i_rgb_to_hsvf(in); - c.channel[0] = in->channel[0]; - c.channel[1] = in->channel[1]; - i_hsv_to_rgbf(&c); - c.channel[3] = in->channel[3]; - COMBINEF(*out, c, channels); - ++out; - ++in; + ++datap; } } - /* =back