1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
|
#!perl
use strict;
use Imager;
use Getopt::Long;
my $bg;
my $shadow_size = "10%";
my $offset = "0x0";
my $shadow_color = "#404040";
GetOptions(
"bg=s" => \$bg,
"size|s=s" => \$shadow_size,
"o|offset=s" => \$offset,
"s|shadow=s" => \$shadow_color,
);
my $infile = shift;
my $outfile = shift
or die <<EOS;
Usage: $0 [options] infile outfile
Options can be any or all of:
-bg color - fill the background with a color instead of using
transparency, this can be a translucent color.
-size size - size of the shadow in pixels, or percent of min dimension
-offset <xsize>x<ysize> - offset of the original image within the shadow
-shadow color - color of the shadow
EOS
my $src = Imager->new(file => $infile)
or die "Cannot read image file '$infile': ", Imager->errstr, "\n";
# simplify things by always working in RGB rather than grey
$src = $src->convert(preset => "rgb");
if ($shadow_size =~ /^([0-9]+)%$/) {
my $dim = $src->getwidth < $src->getheight ? $src->getwidth : $src->getheight;
$shadow_size = int($1 * $dim / 100 + 0.5);
}
my ($x_offset, $y_offset) = $offset =~ /^([+-]?[0-9]+)x([+-]?[0-9]+)$/
or die "$0: invalid offset\n";
my $shc = Imager::Color->new($shadow_color)
or die "$0: invalid shadow color: ", Imager->errstr, "\n";
my ($red, $green, $blue) = $shc->rgba;
# First create a new image, either with an alpha channel (if you want
# transparency behind the shadow) or without, if you want a background
# colour:
my $out = Imager->new
(
xsize => $shadow_size * 2 + $src->getwidth,
ysize => $shadow_size * 2 + $src->getheight,
channels => 4,
);
if ($bg) {
# fill it with your background color, if you want one
my $bgc = Imager::Color->new($bg)
or die "$0: invalid color '$bg'\n";
$out->box(filled => 1, color => $bgc);
}
# Make a work image to render the shadow on:
my $shadow_work = Imager->new
(
xsize => $out->getwidth,
ysize => $out->getheight,
channels => 1,
);
if ($src->getchannels == 4) {
# Extract the alpha channel from the source image, if the image has no
# alpha, then a solid box then it's simpler, first the alpha version:
my $alpha = $src->convert(preset => "alpha");
# and draw that on the work shadow:
$shadow_work->paste
(
src => $alpha,
left => $shadow_size,
top => $shadow_size,
);
}
else {
# otherwise just draw a box for the non-alpha source:
$shadow_work->box
(
filled => 1,
color => [ 255 ],
xmin => $shadow_size,
ymin => $shadow_size,
xmax => $shadow_size + $src->getwidth() - 1,
ymax => $shadow_size + $src->getheight() - 1,
);
}
# Blur the work shadow:
$shadow_work->filter(type => "gaussian", stddev => $shadow_size);
# Convert it to an RGB image with alpha:
$shadow_work = $shadow_work->convert
(
matrix => [ [ 0, $red / 255 ],
[ 0, $green / 255 ],
[ 0, $blue / 255 ],
[ 1 ] ]
) or die $shadow_work->errstr;
# Draw that on the output image:
$out->rubthrough(src => $shadow_work);
# Draw our original image on the output image, perhaps with an offset:
$out->rubthrough
(
src => $src,
tx => $shadow_size + $x_offset,
ty => $shadow_size + $y_offset,
);
$out->write(file => $outfile)
or die "Cannot write to '$outfile': ", $out->errstr, "\n";
|