X-Git-Url: http://git.imager.perl.org/imager.git/blobdiff_plain/6cfee9d1ec893f4947a6fd8c3472aad44b813ca8..3937f6cfeb29bc364fcb576f5319984c1e7a3c2a:/fills.c diff --git a/fills.c b/fills.c index 9bb2cb1f..ea586476 100644 --- a/fills.c +++ b/fills.c @@ -1,3 +1,4 @@ +#define IMAGER_NO_CONTEXT #include "imager.h" #include "imageri.h" @@ -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 @@ -162,10 +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(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 = { @@ -397,79 +399,83 @@ 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(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, - int dx, int dy); + 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 side of a filled area. =cut */ i_fill_t * i_new_fill_hatch(const i_color *fg, const i_color *bg, int combine, int hatch, - const unsigned char *cust_hatch, int dx, int dy) { + 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 side of a filled area. =cut */ i_fill_t * i_new_fill_hatchf(const i_fcolor *fg, const i_fcolor *bg, int combine, int hatch, - const unsigned char *cust_hatch, int dx, int dy) { + 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]; }; @@ -485,7 +491,7 @@ image_fill_proto = }; /* -=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); @@ -494,12 +500,12 @@ Create an image based fill. matrix is an array of 9 doubles representing a transformation matrix. -xoff and yoff are the offset into the image to start filling from. +C and C are the offset into the image to start filling from. =cut */ i_fill_t * -i_new_fill_image(i_img *im, const double *matrix, int xoff, int yoff, int combine) { +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 = image_fill_proto; @@ -528,6 +534,45 @@ i_new_fill_image(i_img *im, const double *matrix, int xoff, int yoff, int combin 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); + +struct i_fill_opacity_t { + i_fill_t base; + i_fill_t *other_fill; + double alpha_mult; +}; + +static struct i_fill_opacity_t +opacity_fill_proto = + { + { + fill_opacity, + fill_opacityf, + NULL + } + }; + +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; + + fill->base.combine = base_fill->combine; + fill->base.combinef = base_fill->combinef; + + fill->other_fill = base_fill; + fill->alpha_mult = alpha_mult; + + 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)) @@ -545,8 +590,8 @@ The 8-bit sample fill function for non-combining solid fills. =cut */ static void -fill_solid(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) { @@ -562,8 +607,8 @@ The floating sample fill function for non-combining solid fills. =cut */ static void -fill_solidf(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) { @@ -593,7 +638,7 @@ i_fill_t * 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, - int dx, int dy) { + 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; @@ -644,15 +689,15 @@ 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; - int want_channels = channels > 2 ? 4 : 2; if (channels < 3) { i_adapt_colors(2, 4, &fg, 1); @@ -675,10 +720,11 @@ static void fill_hatch(i_fill_t *fill, int x, int y, int width, int channels, The floating sample fill function for hatched fills. -=back +=cut */ -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; @@ -751,10 +797,11 @@ 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_img_dim i = 0; i_color *out = data; int want_channels = channels > 2 ? 4 : 2; @@ -767,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; @@ -781,12 +828,12 @@ 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); @@ -799,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; @@ -810,7 +857,7 @@ 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; @@ -828,10 +875,11 @@ static void fill_image(i_fill_t *fill, int x, int y, int width, int channels, =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_img_dim i = 0; int want_channels = channels > 2 ? 4 : 2; if (f->has_matrix) { @@ -844,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; @@ -858,12 +906,12 @@ 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); @@ -877,10 +925,10 @@ static void fill_imagef(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; @@ -901,6 +949,45 @@ static void fill_imagef(i_fill_t *fill, int x, int y, int width, int channels, i_adapt_fcolors(want_channels, f->src->channels, data, width); } +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; + + ++datap; + } +} /* =back