OUTPUT:
RETVAL
+Imager::FillHandle
+i_new_fill_opacity(other_fill, alpha_mult)
+ Imager::FillHandle other_fill
+ double alpha_mult
+
void
i_errors()
PREINIT:
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
return &fill->base;
}
+static void fill_opacity(i_fill_t *fill, int x, int y, int width, int channels,
+ i_color *data);
+static void fill_opacityf(i_fill_t *fill, int x, int y, int 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;
+
+ return &fill->base;
+}
#define T_SOLID_FILL(fill) ((i_fill_solid_t *)(fill))
i_adapt_fcolors(want_channels, f->src->channels, data, width);
}
+static void
+fill_opacity(i_fill_t *fill, int x, int y, int width, int channels,
+ i_color *data) {
+ struct i_fill_opacity_t *f = (struct i_fill_opacity_t *)fill;
+ int alpha_chan = channels-1; /* channels is always 2 or 4 */
+ 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, int x, int y, int width, int channels,
+ i_fcolor *data) {
+ struct i_fill_opacity_t *f = (struct i_fill_alpha_t *)fill;
+ int alpha_chan = channels-1; /* channels is always 2 or 4 */
+ 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
const unsigned char *cust_hatch, int dx, int dy);
extern i_fill_t *
i_new_fill_image(i_img *im, const double *matrix, int xoff, int yoff, int combine);
+extern i_fill_t *i_new_fill_opacity(i_fill_t *, double alpha_mult);
extern void i_fill_destroy(i_fill_t *fill);
float i_gpix_pch(i_img *im,int x,int y,int ch);
$hsh{yoff}, $hsh{combine});
$self->{DEPS} = [ $hsh{image}{IMG} ];
}
+ elsif (defined $hsh{type} && $hsh{type} eq "opacity") {
+ my $other_fill = delete $hsh{other};
+ unless (defined $other_fill) {
+ Imager->_set_error("'other' parameter required to create alpha fill");
+ return;
+ }
+ unless (eval { $other_fill->isa("Imager::Fill") }) {
+ Imager->_set_error("'other' parameter must be an Imager::Fill object to create an alpha fill");
+ return;
+ }
+
+ my $raw_fill = $other_fill->{fill};
+ my $opacity = delete $hsh{opacity};
+ defined $opacity or $opacity = 0.5; # some sort of default
+ $self->{fill} =
+ Imager::i_new_fill_opacity($raw_fill, $opacity);
+ $self->{DEPS} = [ $other_fill ]; # keep reference to old fill and its deps
+ }
else {
$Imager::ERRSTR = "No fill type specified";
warn "No fill type!";
dx=>$dx, dy=>$dy);
my $fill3 = Imager::Fill->new(fountain=>$type, ...);
my $fill4 = Imager::Fill->new(image=>$img, ...);
+ my $fill5 = Imager::Fill->new(type => "alpha", other => $fill, alpha => ...);
=head1 DESCRIPTION
The matrix parameter will significantly slow down the fill.
+=head2 Opacity modification fill
+
+ my $fill = Imager::Fill->new(type => "opacity"
+
+This can be used to make a fill that is a more translucent of opaque
+version of an existing fill. This is intended for use where you
+receive a fill object as a parameter and need to change the opacity.
+
+Parameters:
+
+=over
+
+=item *
+
+type => "alpha" - Required
+
+=item *
+
+other - the fill to produce a modified version of. This must be an
+Imager::Fill object. Required.
+
+=item *
+
+opacity - multiplier for the source fill opacity. Default: 0.5.
+
+=back
+
+The source fill's combine mode is used.
+
=head1 OTHER METHODS
=over
&& $ca == $alpha, $comment)) {
$builder->diag(<<END_DIAG);
Color mismatch:
- Red: $red vs $cr
-Green: $green vs $cg
- Blue: $blue vs $cb
-Alpha: $alpha vs $ca
+ Red: $cr vs $red
+Green: $cg vs $green
+ Blue: $cb vs $blue
+Alpha: $ca vs $alpha
END_DIAG
return;
}
&& abs($ca - $alpha) <= $mindiff, $comment)) {
$builder->diag(<<END_DIAG);
Color mismatch:
- Red: $red vs $cr
-Green: $green vs $cg
- Blue: $blue vs $cb
-Alpha: $alpha vs $ca
+ Red: $cr vs $red
+Green: $cg vs $green
+ Blue: $cb vs $blue
+Alpha: $ca vs $alpha
END_DIAG
return;
}
#!perl -w
use strict;
-use Test::More tests => 129;
+use Test::More tests => 143;
use Imager ':handy';
use Imager::Fill;
use Imager::Color::Float;
-use Imager::Test qw(is_image);
+use Imager::Test qw(is_image is_color4 is_fcolor4);
use Config;
Imager::init_log("testout/t20fill.log", 1);
}
}
+{ # alpha modifying fills
+ { # 8-bit/sample
+ my $base_img = Imager->new(xsize => 4, ysize => 2, channels => 4);
+ $base_img->setscanline
+ (
+ x => 0,
+ y => 0,
+ pixels =>
+ [
+ map Imager::Color->new($_),
+ qw/FF000020 00FF0080 00008040 FFFF00FF/,
+ ],
+ );
+ $base_img->setscanline
+ (
+ x => 0,
+ y => 1,
+ pixels =>
+ [
+ map Imager::Color->new($_),
+ qw/FFFF00FF FF000000 00FF0080 00008040/
+ ]
+ );
+ my $base_fill = Imager::Fill->new
+ (
+ image => $base_img,
+ combine => "normal",
+ );
+ ok($base_fill, "make the base image fill");
+ my $fill50 = Imager::Fill->new(type => "opacity", opacity => 0.5, other => $base_fill)
+ or print "# ", Imager->errstr, "\n";
+ ok($fill50, "make 50% alpha translation fill");
+ my $out = Imager->new(xsize => 10, ysize => 10, channels => 4);
+ $out->box(fill => $fill50);
+ is_color4($out->getpixel(x => 0, y => 0),
+ 255, 0, 0, 16, "check alpha output");
+ is_color4($out->getpixel(x => 2, y => 1),
+ 0, 255, 0, 64, "check alpha output");
+ $out->box(filled => 1, color => "000000");
+ is_color4($out->getpixel(x => 0, y => 0),
+ 0, 0, 0, 255, "check after clear");
+ $out->box(fill => $fill50);
+ is_color4($out->getpixel(x => 4, y => 2),
+ 16, 0, 0, 255, "check drawn against background");
+ is_color4($out->getpixel(x => 6, y => 3),
+ 0, 64, 0, 255, "check drawn against background");
+ }
+ { # double/sample
+ use Imager::Color::Float;
+ my $base_img = Imager->new(xsize => 4, ysize => 2, channels => 4, bits => "double");
+ $base_img->setscanline
+ (
+ x => 0,
+ y => 0,
+ pixels =>
+ [
+ map Imager::Color::Float->new(@$_),
+ [ 1, 0, 0, 0.125 ],
+ [ 0, 1, 0, 0.5 ],
+ [ 0, 0, 0.5, 0.25 ],
+ [ 1, 1, 0, 1 ],
+ ],
+ );
+ $base_img->setscanline
+ (
+ x => 0,
+ y => 1,
+ pixels =>
+ [
+ map Imager::Color::Float->new(@$_),
+ [ 1, 1, 0, 1 ],
+ [ 1, 0, 0, 0 ],
+ [ 0, 1, 0, 0.5 ],
+ [ 0, 0, 0.5, 0.25 ],
+ ]
+ );
+ my $base_fill = Imager::Fill->new
+ (
+ image => $base_img,
+ combine => "normal",
+ );
+ ok($base_fill, "make the base image fill");
+ my $fill50 = Imager::Fill->new(type => "opacity", opacity => 0.5, other => $base_fill)
+ or print "# ", Imager->errstr, "\n";
+ ok($fill50, "make 50% alpha translation fill");
+ my $out = Imager->new(xsize => 10, ysize => 10, channels => 4, bits => "double");
+ $out->box(fill => $fill50);
+ is_fcolor4($out->getpixel(x => 0, y => 0, type => "float"),
+ 1, 0, 0, 0.0625, "check alpha output at 0,0");
+ is_fcolor4($out->getpixel(x => 2, y => 1, type => "float"),
+ 0, 1, 0, 0.25, "check alpha output at 2,1");
+ $out->box(filled => 1, color => "000000");
+ is_fcolor4($out->getpixel(x => 0, y => 0, type => "float"),
+ 0, 0, 0, 1, "check after clear");
+ $out->box(fill => $fill50);
+ is_fcolor4($out->getpixel(x => 4, y => 2, type => "float"),
+ 0.0625, 0, 0, 1, "check drawn against background at 4,2");
+ is_fcolor4($out->getpixel(x => 6, y => 3, type => "float"),
+ 0, 0.25, 0, 1, "check drawn against background at 6,3");
+ }
+}
+
sub color_close {
my ($c1, $c2) = @_;