File: drop_shadow.pl

package info (click to toggle)
libimager-perl 1.005%2Bdfsg-2
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 6,308 kB
  • ctags: 4,067
  • sloc: perl: 30,915; ansic: 27,680; makefile: 55; cpp: 4
file content (132 lines) | stat: -rw-r--r-- 3,293 bytes parent folder | download | duplicates (6)
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";