| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package Imager::Tiler; | 
| 2 |  |  |  |  |  |  |  | 
| 3 | 1 |  |  | 1 |  | 2574 | use Imager; | 
|  | 1 |  |  |  |  | 82740 |  | 
|  | 1 |  |  |  |  | 7 |  | 
| 4 | 1 |  |  | 1 |  | 60 | use Exporter; | 
|  | 1 |  |  |  |  | 3 |  | 
|  | 1 |  |  |  |  | 60 |  | 
| 5 |  |  |  |  |  |  |  | 
| 6 |  |  |  |  |  |  | our @ISA = qw(Exporter); | 
| 7 |  |  |  |  |  |  |  | 
| 8 |  |  |  |  |  |  | our @EXPORT = (); | 
| 9 |  |  |  |  |  |  | our @EXPORT_OK = qw(tile); | 
| 10 |  |  |  |  |  |  |  | 
| 11 | 1 |  |  | 1 |  | 5 | use strict; | 
|  | 1 |  |  |  |  | 6 |  | 
|  | 1 |  |  |  |  | 23 |  | 
| 12 | 1 |  |  | 1 |  | 4 | use warnings; | 
|  | 1 |  |  |  |  | 1 |  | 
|  | 1 |  |  |  |  | 1309 |  | 
| 13 |  |  |  |  |  |  |  | 
| 14 |  |  |  |  |  |  | our $VERSION = '1.01'; | 
| 15 |  |  |  |  |  |  |  | 
| 16 |  |  |  |  |  |  | =pod | 
| 17 |  |  |  |  |  |  |  | 
| 18 |  |  |  |  |  |  | =head1 NAME | 
| 19 |  |  |  |  |  |  |  | 
| 20 |  |  |  |  |  |  | Imager::Tiler - package to aggregate images into a single tiled image via Imager | 
| 21 |  |  |  |  |  |  |  | 
| 22 |  |  |  |  |  |  | =head1 SYNOPSIS | 
| 23 |  |  |  |  |  |  |  | 
| 24 |  |  |  |  |  |  | use Imager::Tiler qw(tile); | 
| 25 |  |  |  |  |  |  | # | 
| 26 |  |  |  |  |  |  | #	use computed coordinates for layout, and retrieve the | 
| 27 |  |  |  |  |  |  | #	coordinates for later use (as imported method) | 
| 28 |  |  |  |  |  |  | # | 
| 29 |  |  |  |  |  |  | my ($img, @coords) = tile( | 
| 30 |  |  |  |  |  |  | Images => [ 'chart1.png', 'chart2.png', 'chart3.png', 'chart4.png'], | 
| 31 |  |  |  |  |  |  | Background => 'lgray', | 
| 32 |  |  |  |  |  |  | Center => 1, | 
| 33 |  |  |  |  |  |  | VEdgeMargin => 10, | 
| 34 |  |  |  |  |  |  | HEdgeMargin => 10, | 
| 35 |  |  |  |  |  |  | VTileMargin => 5, | 
| 36 |  |  |  |  |  |  | HTileMargin => 5); | 
| 37 |  |  |  |  |  |  | # | 
| 38 |  |  |  |  |  |  | #	use explicit coordinates for layout (as class method) | 
| 39 |  |  |  |  |  |  | # | 
| 40 |  |  |  |  |  |  | my $explimg = Imager::Tiler->tile( | 
| 41 |  |  |  |  |  |  | Images => [ 'chart1.png', 'chart2.png', 'chart3.png', 'chart4.png'], | 
| 42 |  |  |  |  |  |  | Background => 'lgray', | 
| 43 |  |  |  |  |  |  | Width => 500, | 
| 44 |  |  |  |  |  |  | Height => 500, | 
| 45 |  |  |  |  |  |  | Coordinates => [ | 
| 46 |  |  |  |  |  |  | 10, 10, | 
| 47 |  |  |  |  |  |  | 120, 10, | 
| 48 |  |  |  |  |  |  | 10, 120, | 
| 49 |  |  |  |  |  |  | 120, 120 ]); | 
| 50 |  |  |  |  |  |  |  | 
| 51 |  |  |  |  |  |  | =head1 DESCRIPTION | 
| 52 |  |  |  |  |  |  |  | 
| 53 |  |  |  |  |  |  | Creates a new tiled image from a set of input images. Various arguments | 
| 54 |  |  |  |  |  |  | may be specified to position individual images, or the default | 
| 55 |  |  |  |  |  |  | behaviors can be used to create an reasonable placement to fill a | 
| 56 |  |  |  |  |  |  | square image. | 
| 57 |  |  |  |  |  |  |  | 
| 58 |  |  |  |  |  |  | =head1 METHODS | 
| 59 |  |  |  |  |  |  |  | 
| 60 |  |  |  |  |  |  | Only a single method is provided: | 
| 61 |  |  |  |  |  |  |  | 
| 62 |  |  |  |  |  |  | =head4 $image = Imager::Tiler->tile( %args ) | 
| 63 |  |  |  |  |  |  |  | 
| 64 |  |  |  |  |  |  | =head4 ($image, @coords) = Imager::Tiler->tile( %args ) | 
| 65 |  |  |  |  |  |  |  | 
| 66 |  |  |  |  |  |  | Returns a Imager::Image object of the images specified in %args, | 
| 67 |  |  |  |  |  |  | positioned according to the directives in %arg. In array context, | 
| 68 |  |  |  |  |  |  | also returns the list of upper left corner coordinates of each image, | 
| 69 |  |  |  |  |  |  | so e.g., an application can adjust the image map coordinate values | 
| 70 |  |  |  |  |  |  | for individual images. | 
| 71 |  |  |  |  |  |  |  | 
| 72 |  |  |  |  |  |  | Valid %args are: | 
| 73 |  |  |  |  |  |  |  | 
| 74 |  |  |  |  |  |  | =over 4 | 
| 75 |  |  |  |  |  |  |  | 
| 76 |  |  |  |  |  |  | =item B> C<$color> I<(optional)> | 
| 77 |  |  |  |  |  |  |  | 
| 78 |  |  |  |  |  |  | specifies a color to be used as the tiled image background. Must be a string | 
| 79 |  |  |  |  |  |  | of either hexadecimal RGB values, I B<'#FFAC24'>, or a name from | 
| 80 |  |  |  |  |  |  | the following list of supported colors: | 
| 81 |  |  |  |  |  |  |  | 
| 82 |  |  |  |  |  |  | white     lyellow     lpurple     lbrown | 
| 83 |  |  |  |  |  |  | lgray     yellow      purple      dbrown | 
| 84 |  |  |  |  |  |  | gray      dyellow     dpurple     transparent | 
| 85 |  |  |  |  |  |  | dgray     lgreen      lorange | 
| 86 |  |  |  |  |  |  | black     green       orange | 
| 87 |  |  |  |  |  |  | lblue     dgreen      pink | 
| 88 |  |  |  |  |  |  | blue      lred        dpink | 
| 89 |  |  |  |  |  |  | dblue     red         marine | 
| 90 |  |  |  |  |  |  | gold      dred        cyan | 
| 91 |  |  |  |  |  |  |  | 
| 92 |  |  |  |  |  |  | Default is white. | 
| 93 |  |  |  |  |  |  |  | 
| 94 |  |  |  |  |  |  | =item B> C<$boolean> I<(optional)> | 
| 95 |  |  |  |  |  |  |  | 
| 96 |  |  |  |  |  |  | If set to a "true" value, causes images to be centered within | 
| 97 |  |  |  |  |  |  | their computed tile location; ignored if B is specified. | 
| 98 |  |  |  |  |  |  | Default is false, which causes images to be anchored to the | 
| 99 |  |  |  |  |  |  | upper left corner of their tile. | 
| 100 |  |  |  |  |  |  |  | 
| 101 |  |  |  |  |  |  | =item B> C<\@coords> I<(optional)> | 
| 102 |  |  |  |  |  |  |  | 
| 103 |  |  |  |  |  |  | arrayref of (X, Y) coordinates of the upper left corner of each tiled image; | 
| 104 |  |  |  |  |  |  | must have an (X, Y) element for each input image. If not provided, | 
| 105 |  |  |  |  |  |  | the default is a computed layout to fit images into an equal (or nearly equal) | 
| 106 |  |  |  |  |  |  | number of rows and columns, in a left to right, top to bottom mapping in the | 
| 107 |  |  |  |  |  |  | order specified in B. B. | 
| 108 |  |  |  |  |  |  |  | 
| 109 |  |  |  |  |  |  | If B is specified, then B and B must also be | 
| 110 |  |  |  |  |  |  | specified, and any margin values are ignored. | 
| 111 |  |  |  |  |  |  |  | 
| 112 |  |  |  |  |  |  | =item B> C<$pixels> I<(optional)> | 
| 113 |  |  |  |  |  |  |  | 
| 114 |  |  |  |  |  |  | outer edge margin for both top and bottom; | 
| 115 |  |  |  |  |  |  | If either HEdgeMargin or VEdgeMargin, they override this value. | 
| 116 |  |  |  |  |  |  |  | 
| 117 |  |  |  |  |  |  | =item B> C<$format> I<(optional)> | 
| 118 |  |  |  |  |  |  |  | 
| 119 |  |  |  |  |  |  | Output image format; default is 'PNG'; valid values depend on the | 
| 120 |  |  |  |  |  |  | Imager installations; see L for details. | 
| 121 |  |  |  |  |  |  |  | 
| 122 |  |  |  |  |  |  | =item B> C<$pixels> I<(optional)> | 
| 123 |  |  |  |  |  |  |  | 
| 124 |  |  |  |  |  |  | horizontal edge margin; space in pixels at left and right of output image; | 
| 125 |  |  |  |  |  |  | default zero. | 
| 126 |  |  |  |  |  |  |  | 
| 127 |  |  |  |  |  |  | =item B> C<$height> I<(optional)> | 
| 128 |  |  |  |  |  |  |  | 
| 129 |  |  |  |  |  |  | total height of output image; if not specified, defaults to | 
| 130 |  |  |  |  |  |  | minimum height needed to contain the images | 
| 131 |  |  |  |  |  |  |  | 
| 132 |  |  |  |  |  |  | =item B> C<$pixels> I<(optional)> | 
| 133 |  |  |  |  |  |  |  | 
| 134 |  |  |  |  |  |  | horizontal margin between tile images; | 
| 135 |  |  |  |  |  |  | default zero. | 
| 136 |  |  |  |  |  |  |  | 
| 137 |  |  |  |  |  |  | =item B> C<\@images> I<(required)> | 
| 138 |  |  |  |  |  |  |  | 
| 139 |  |  |  |  |  |  | arrayref of images to be tiled; may be either Imager::Image objects, | 
| 140 |  |  |  |  |  |  | or filenames; if the latter, the format is derived from | 
| 141 |  |  |  |  |  |  | the file qualifier | 
| 142 |  |  |  |  |  |  |  | 
| 143 |  |  |  |  |  |  | =item B> C<$count> I<(optional)> | 
| 144 |  |  |  |  |  |  |  | 
| 145 |  |  |  |  |  |  | Specifies the number of images per row in the layout; ignored if | 
| 146 |  |  |  |  |  |  | B is also specified. Permits an alternate layout to | 
| 147 |  |  |  |  |  |  | the default approximate square layout. | 
| 148 |  |  |  |  |  |  |  | 
| 149 |  |  |  |  |  |  | =item B> C I<(optional)> | 
| 150 |  |  |  |  |  |  |  | 
| 151 |  |  |  |  |  |  | When set to a true value, causes tiled image to have a small | 
| 152 |  |  |  |  |  |  | drop shadow behind them (10 pixels along the right and lower edges). | 
| 153 |  |  |  |  |  |  | Default false. | 
| 154 |  |  |  |  |  |  |  | 
| 155 |  |  |  |  |  |  | =item B> C<$pixels> I<(optional)> | 
| 156 |  |  |  |  |  |  |  | 
| 157 |  |  |  |  |  |  | tile image margin, both top and bottom; if either | 
| 158 |  |  |  |  |  |  | HTileMargin or VTileMargin are specified, they override this value. | 
| 159 |  |  |  |  |  |  |  | 
| 160 |  |  |  |  |  |  | =item B> C<$pixels> I<(optional)> | 
| 161 |  |  |  |  |  |  |  | 
| 162 |  |  |  |  |  |  | vertical edge margin; space in pixels at top and bottom of output image; | 
| 163 |  |  |  |  |  |  | default zero. | 
| 164 |  |  |  |  |  |  |  | 
| 165 |  |  |  |  |  |  | =item B> C<$pixels> I<(optional)> | 
| 166 |  |  |  |  |  |  |  | 
| 167 |  |  |  |  |  |  | vertical margin between tile images; | 
| 168 |  |  |  |  |  |  | default zero. | 
| 169 |  |  |  |  |  |  |  | 
| 170 |  |  |  |  |  |  | =item B> C<$width> I<(optional)> | 
| 171 |  |  |  |  |  |  |  | 
| 172 |  |  |  |  |  |  | total width of output image; if not specified, defaults to | 
| 173 |  |  |  |  |  |  | minimum width needed to contain the images | 
| 174 |  |  |  |  |  |  |  | 
| 175 |  |  |  |  |  |  | =back | 
| 176 |  |  |  |  |  |  |  | 
| 177 |  |  |  |  |  |  | =head1 SEE ALSO | 
| 178 |  |  |  |  |  |  |  | 
| 179 |  |  |  |  |  |  | L | 
| 180 |  |  |  |  |  |  |  | 
| 181 |  |  |  |  |  |  | =head1 AUTHOR, COPYRIGHT, and LICENSE | 
| 182 |  |  |  |  |  |  |  | 
| 183 |  |  |  |  |  |  | Dean Arnold L | 
| 184 |  |  |  |  |  |  |  | 
| 185 |  |  |  |  |  |  | Copyright(C) 2007, 2008, Dean Arnold, Presicient Corp., USA. | 
| 186 |  |  |  |  |  |  |  | 
| 187 |  |  |  |  |  |  | Permission is granted to use, copy, modify, and redistribute this | 
| 188 |  |  |  |  |  |  | software under the terms of the Academic Free License version 3.0, as specified at the | 
| 189 |  |  |  |  |  |  | Open Source Initiative website L. | 
| 190 |  |  |  |  |  |  |  | 
| 191 |  |  |  |  |  |  | =cut | 
| 192 |  |  |  |  |  |  |  | 
| 193 |  |  |  |  |  |  | my %colors = ( | 
| 194 |  |  |  |  |  |  | white    => [255,255,255], | 
| 195 |  |  |  |  |  |  | lgray    => [191,191,191], | 
| 196 |  |  |  |  |  |  | gray    => [127,127,127], | 
| 197 |  |  |  |  |  |  | dgray    => [63,63,63], | 
| 198 |  |  |  |  |  |  | black    => [0,0,0], | 
| 199 |  |  |  |  |  |  | lblue    => [0,0,255], | 
| 200 |  |  |  |  |  |  | blue    => [0,0,191], | 
| 201 |  |  |  |  |  |  | dblue    => [0,0,127], | 
| 202 |  |  |  |  |  |  | gold    => [255,215,0], | 
| 203 |  |  |  |  |  |  | lyellow    => [255,255,125], | 
| 204 |  |  |  |  |  |  | yellow    => [255,255,0], | 
| 205 |  |  |  |  |  |  | dyellow    => [127,127,0], | 
| 206 |  |  |  |  |  |  | lgreen    => [0,255,0], | 
| 207 |  |  |  |  |  |  | green    => [0,191,0], | 
| 208 |  |  |  |  |  |  | dgreen    => [0,127,0], | 
| 209 |  |  |  |  |  |  | lred    => [255,0,0], | 
| 210 |  |  |  |  |  |  | red        => [191,0,0], | 
| 211 |  |  |  |  |  |  | dred    => [127,0,0], | 
| 212 |  |  |  |  |  |  | lpurple    => [255,0,255], | 
| 213 |  |  |  |  |  |  | purple    => [191,0,191], | 
| 214 |  |  |  |  |  |  | dpurple    => [127,0,127], | 
| 215 |  |  |  |  |  |  | lorange    => [255,183,0], | 
| 216 |  |  |  |  |  |  | orange    => [255,127,0], | 
| 217 |  |  |  |  |  |  | pink    => [255,183,193], | 
| 218 |  |  |  |  |  |  | dpink    => [255,105,180], | 
| 219 |  |  |  |  |  |  | marine    => [127,127,255], | 
| 220 |  |  |  |  |  |  | cyan    => [0,255,255], | 
| 221 |  |  |  |  |  |  | lbrown    => [210,180,140], | 
| 222 |  |  |  |  |  |  | dbrown    => [165,42,42], | 
| 223 |  |  |  |  |  |  | transparent => [1,1,1, 0] | 
| 224 |  |  |  |  |  |  | ); | 
| 225 |  |  |  |  |  |  | # | 
| 226 |  |  |  |  |  |  | #	compute coordinates for tiled images | 
| 227 |  |  |  |  |  |  | # | 
| 228 |  |  |  |  |  |  | sub _layout { | 
| 229 | 0 |  |  | 0 |  |  | my ($center, $vedge, $hedge, $vtile, $htile, $imgsperrow, $shadow, @images) = @_; | 
| 230 | 0 |  |  |  |  |  | my ($rows, $cols); | 
| 231 |  |  |  |  |  |  |  | 
| 232 | 0 |  |  |  |  |  | my $imgcnt = scalar @images; | 
| 233 | 0 | 0 |  |  |  |  | if (defined($imgsperrow)) { | 
| 234 | 0 |  |  |  |  |  | $cols = $imgsperrow; | 
| 235 | 0 |  |  |  |  |  | $rows = int($imgcnt/$cols); | 
| 236 | 0 | 0 |  |  |  |  | $rows++ | 
| 237 |  |  |  |  |  |  | unless (($rows * $cols) >= $imgcnt); | 
| 238 |  |  |  |  |  |  | } | 
| 239 |  |  |  |  |  |  | else { | 
| 240 | 0 |  |  |  |  |  | $rows = $cols = int(sqrt($imgcnt)); | 
| 241 | 0 | 0 |  |  |  |  | unless (($rows * $cols) == $imgcnt) { | 
| 242 | 0 |  |  |  |  |  | $cols++; | 
| 243 | 0 | 0 |  |  |  |  | $rows++ | 
| 244 |  |  |  |  |  |  | unless (($rows * $cols) >= $imgcnt); | 
| 245 |  |  |  |  |  |  | } | 
| 246 |  |  |  |  |  |  | } | 
| 247 |  |  |  |  |  |  | # | 
| 248 |  |  |  |  |  |  | #	compute width and height based on input images | 
| 249 |  |  |  |  |  |  | # | 
| 250 | 0 |  |  |  |  |  | my @rowh = ( (0) x $rows ); | 
| 251 | 0 |  |  |  |  |  | my @colw = ( (0) x $cols ); | 
| 252 | 0 |  |  |  |  |  | my @coords = (); | 
| 253 | 0 | 0 |  |  |  |  | $shadow = $shadow ? 10 : 0; | 
| 254 | 0 |  |  |  |  |  | foreach my $r (0..$rows-1) { | 
| 255 | 0 |  |  |  |  |  | $rowh[$r] = 0; | 
| 256 | 0 |  |  |  |  |  | foreach my $c (0..$cols - 1) { | 
| 257 | 0 |  |  |  |  |  | my $img = ($r * $cols) + $c; | 
| 258 | 0 | 0 |  |  |  |  | last unless $images[$img]; | 
| 259 |  |  |  |  |  |  |  | 
| 260 | 0 | 0 | 0 |  |  |  | my $w = $images[$img]->getwidth() + $shadow + | 
| 261 |  |  |  |  |  |  | ((($r == 0) || ($r == $rows - 1)) ? (($vtile >> 1) + $vedge) : $vtile); | 
| 262 | 0 | 0 | 0 |  |  |  | my $h = $images[$img]->getheight() + $shadow + | 
| 263 |  |  |  |  |  |  | ((($c == 0) || ($c == $cols - 1)) ? (($htile >> 1) + $hedge) : $htile); | 
| 264 |  |  |  |  |  |  |  | 
| 265 | 0 | 0 |  |  |  |  | $colw[$c] = $w | 
| 266 |  |  |  |  |  |  | if ($colw[$c] < $w); | 
| 267 | 0 | 0 |  |  |  |  | $rowh[$r] = $h | 
| 268 |  |  |  |  |  |  | if ($rowh[$r] < $h); | 
| 269 |  |  |  |  |  |  | } | 
| 270 |  |  |  |  |  |  | } | 
| 271 |  |  |  |  |  |  | # | 
| 272 |  |  |  |  |  |  | #	compute total image size | 
| 273 |  |  |  |  |  |  | # | 
| 274 | 0 |  |  |  |  |  | my ($totalw, $totalh) = ($vedge * 2, $hedge * 2); | 
| 275 | 0 |  |  |  |  |  | map $totalw += $_, @colw; | 
| 276 | 0 |  |  |  |  |  | map $totalh += $_, @rowh; | 
| 277 |  |  |  |  |  |  | # | 
| 278 |  |  |  |  |  |  | #	now compute placement coords | 
| 279 |  |  |  |  |  |  | # | 
| 280 | 0 |  |  |  |  |  | my ($left, $top) = ($vedge, $hedge); | 
| 281 | 0 |  |  |  |  |  | foreach my $r (0..$#rowh) { | 
| 282 | 0 |  |  |  |  |  | foreach my $c (0..$#colw) { | 
| 283 | 0 |  |  |  |  |  | my $img = ($r * $cols) + $c; | 
| 284 | 0 | 0 |  |  |  |  | last unless $images[$img]; | 
| 285 |  |  |  |  |  |  |  | 
| 286 | 0 | 0 |  |  |  |  | if ($center) { | 
| 287 | 0 |  |  |  |  |  | push @coords, | 
| 288 |  |  |  |  |  |  | $left + (($colw[$c] - $images[$img]->getwidth() - $shadow) >> 1), | 
| 289 |  |  |  |  |  |  | $top  + (($rowh[$r] - $images[$img]->getheight() - $shadow) >> 1); | 
| 290 |  |  |  |  |  |  | } | 
| 291 |  |  |  |  |  |  | else { | 
| 292 | 0 |  |  |  |  |  | push @coords, $left, $top; | 
| 293 |  |  |  |  |  |  | } | 
| 294 | 0 |  |  |  |  |  | $left += $colw[$c]; | 
| 295 |  |  |  |  |  |  | } | 
| 296 |  |  |  |  |  |  |  | 
| 297 | 0 |  |  |  |  |  | $top += $rowh[$r]; | 
| 298 | 0 |  |  |  |  |  | $left = $vedge; | 
| 299 |  |  |  |  |  |  | } | 
| 300 | 0 |  |  |  |  |  | return ($totalw, $totalh, @coords); | 
| 301 |  |  |  |  |  |  | } | 
| 302 |  |  |  |  |  |  |  | 
| 303 |  |  |  |  |  |  | sub tile { | 
| 304 | 0 | 0 |  | 0 | 1 |  | shift if ($_[0] eq 'Imager::Tiler');	# if called as a object, not class, method | 
| 305 | 0 |  |  |  |  |  | my %args = @_; | 
| 306 |  |  |  |  |  |  |  | 
| 307 | 0 | 0 | 0 |  |  |  | die 'No images specified.' | 
|  |  |  | 0 |  |  |  |  | 
| 308 |  |  |  |  |  |  | unless $args{Images} && ref $args{Images} && | 
| 309 |  |  |  |  |  |  | (ref $args{Images} eq 'ARRAY'); | 
| 310 |  |  |  |  |  |  |  | 
| 311 | 0 |  |  |  |  |  | my $imgcnt = 0; | 
| 312 | 0 |  |  |  |  |  | foreach (@{$args{Images}}) { | 
|  | 0 |  |  |  |  |  |  | 
| 313 | 0 | 0 | 0 |  |  |  | next if (ref $_ && $_->isa('Imager')); | 
| 314 | 0 |  |  |  |  |  | my $img = Imager->new(channels => 4); | 
| 315 | 0 | 0 |  |  |  |  | die 'Cannot load image $_:' . $img->errstr() | 
| 316 |  |  |  |  |  |  | unless $img->read(file => $_); | 
| 317 | 0 |  |  |  |  |  | $_ = $img; | 
| 318 |  |  |  |  |  |  | } | 
| 319 |  |  |  |  |  |  |  | 
| 320 | 0 | 0 |  |  |  |  | $args{TileMargin} = 0 | 
| 321 |  |  |  |  |  |  | unless exists $args{TileMargin}; | 
| 322 |  |  |  |  |  |  |  | 
| 323 | 0 | 0 |  |  |  |  | $args{EdgeMargin} = 0 | 
| 324 |  |  |  |  |  |  | unless exists $args{EdgeMargin}; | 
| 325 |  |  |  |  |  |  |  | 
| 326 | 0 | 0 |  |  |  |  | $args{VEdgeMargin} = $args{EdgeMargin} | 
| 327 |  |  |  |  |  |  | unless exists $args{VEdgeMargin}; | 
| 328 |  |  |  |  |  |  |  | 
| 329 | 0 | 0 |  |  |  |  | $args{HEdgeMargin} = $args{EdgeMargin} | 
| 330 |  |  |  |  |  |  | unless exists $args{HEdgeMargin}; | 
| 331 |  |  |  |  |  |  |  | 
| 332 | 0 | 0 |  |  |  |  | $args{VTileMargin} = $args{TileMargin} | 
| 333 |  |  |  |  |  |  | unless exists $args{VTileMargin}; | 
| 334 |  |  |  |  |  |  |  | 
| 335 | 0 | 0 |  |  |  |  | $args{HTileMargin} = $args{TileMargin} | 
| 336 |  |  |  |  |  |  | unless exists $args{HTileMargin}; | 
| 337 |  |  |  |  |  |  |  | 
| 338 | 0 |  |  |  |  |  | my $background = $colors{white}; | 
| 339 | 0 | 0 |  |  |  |  | if (exists $args{Background}) { | 
| 340 | 0 | 0 | 0 |  |  |  | die "Invalid Background $args{Background}." | 
| 341 |  |  |  |  |  |  | unless exists $colors{$args{Background}} || | 
| 342 |  |  |  |  |  |  | ($args{Background}=~/^#[0-9a-fA-F]+$/); | 
| 343 | 0 |  | 0 |  |  |  | $background = $colors{$args{Background}} || $args{Background}; | 
| 344 |  |  |  |  |  |  | } | 
| 345 |  |  |  |  |  |  |  | 
| 346 | 0 | 0 |  |  |  |  | $args{Format} = 'png' | 
| 347 |  |  |  |  |  |  | unless exists $args{Format}; | 
| 348 |  |  |  |  |  |  |  | 
| 349 | 0 |  |  |  |  |  | my $format = lc $args{Format}; | 
| 350 |  |  |  |  |  |  |  | 
| 351 | 0 |  |  |  |  |  | my ($w, $h) = ($args{Width}, $args{Height}); | 
| 352 |  |  |  |  |  |  |  | 
| 353 | 0 |  |  |  |  |  | my @coords; | 
| 354 | 0 | 0 |  |  |  |  | if (exists $args{Coordinates}) { | 
| 355 | 0 | 0 |  |  |  |  | die "Width not specified for explicit placement." | 
| 356 |  |  |  |  |  |  | unless exists $args{Width}; | 
| 357 |  |  |  |  |  |  |  | 
| 358 | 0 | 0 |  |  |  |  | die "Height not specified for explicit placement." | 
| 359 |  |  |  |  |  |  | unless exists $args{Height}; | 
| 360 |  |  |  |  |  |  |  | 
| 361 | 0 |  |  |  |  |  | @coords = @{$args{Coordinates}}; | 
|  | 0 |  |  |  |  |  |  | 
| 362 | 0 |  |  |  |  |  | my $imgcnt = scalar @{$args{Images}}; | 
|  | 0 |  |  |  |  |  |  | 
| 363 |  |  |  |  |  |  |  | 
| 364 | 0 | 0 |  |  |  |  | die "$imgcnt images require " . ($imgcnt * 2) . " coordinates, but only" . scalar @coords . " specified." | 
| 365 |  |  |  |  |  |  | if ($imgcnt * 2) > scalar @coords; | 
| 366 |  |  |  |  |  |  | # | 
| 367 |  |  |  |  |  |  | #	we'll permit more coords than images; | 
| 368 |  |  |  |  |  |  | #	we also permit coords to place images outside the Width/Height | 
| 369 |  |  |  |  |  |  | # | 
| 370 |  |  |  |  |  |  | } | 
| 371 |  |  |  |  |  |  | else { | 
| 372 | 0 |  |  |  |  |  | ($w, $h, @coords) = _layout( | 
| 373 |  |  |  |  |  |  | $args{Center}, | 
| 374 |  |  |  |  |  |  | $args{VEdgeMargin}, | 
| 375 |  |  |  |  |  |  | $args{HEdgeMargin}, | 
| 376 |  |  |  |  |  |  | $args{VTileMargin}, | 
| 377 |  |  |  |  |  |  | $args{HTileMargin}, | 
| 378 |  |  |  |  |  |  | $args{ImagesPerRow}, | 
| 379 |  |  |  |  |  |  | $args{Shadow}, | 
| 380 | 0 |  |  |  |  |  | @{$args{Images}}); | 
| 381 |  |  |  |  |  |  |  | 
| 382 | 0 | 0 | 0 |  |  |  | die "Specified Width $args{Width} less than computed width of $w." | 
| 383 |  |  |  |  |  |  | if (exists $args{Width}) && ($args{Width} < $w); | 
| 384 |  |  |  |  |  |  |  | 
| 385 | 0 | 0 | 0 |  |  |  | die "Specified Height $args{Height} less than computed height of $h." | 
| 386 |  |  |  |  |  |  | if (exists $args{Height}) && ($args{Height} < $h); | 
| 387 |  |  |  |  |  |  | } | 
| 388 |  |  |  |  |  |  | # | 
| 389 |  |  |  |  |  |  | #	now create and populate the image | 
| 390 |  |  |  |  |  |  | #	(need a way to support truecolor ?) | 
| 391 |  |  |  |  |  |  | # | 
| 392 | 0 | 0 |  |  |  |  | my $tiled = Imager->new(xsize => $w, ysize => $h, channels => 4) | 
| 393 |  |  |  |  |  |  | or die "Unable to create image."; | 
| 394 |  |  |  |  |  |  |  | 
| 395 | 0 | 0 |  |  |  |  | $background = ref $background | 
| 396 |  |  |  |  |  |  | ? Imager::Color->new(@$background) | 
| 397 |  |  |  |  |  |  | : Imager::Color->new($background); | 
| 398 | 0 | 0 |  |  |  |  | die "Unable to create background color." | 
| 399 |  |  |  |  |  |  | unless defined $background; | 
| 400 |  |  |  |  |  |  |  | 
| 401 | 0 | 0 |  |  |  |  | my $shadow = $args{Shadow} | 
| 402 |  |  |  |  |  |  | ? Imager::Color->new(120, 120, 120, 80) | 
| 403 |  |  |  |  |  |  | : undef; | 
| 404 | 0 | 0 |  |  |  |  | $tiled->box(box => [ 0,0, $w - 1, $h - 1], color => $background, filled => 1) | 
| 405 |  |  |  |  |  |  | or die $tiled->errstr(); | 
| 406 |  |  |  |  |  |  |  | 
| 407 | 0 |  |  |  |  |  | my $x = 0; | 
| 408 | 0 |  |  |  |  |  | foreach (@{$args{Images}}) { | 
|  | 0 |  |  |  |  |  |  | 
| 409 | 0 |  |  |  |  |  | $_ = $_->convert(preset => 'addalpha'); | 
| 410 | 0 |  |  |  |  |  | $w = $coords[$x++]; | 
| 411 | 0 |  |  |  |  |  | $h = $coords[$x++]; | 
| 412 | 0 | 0 |  |  |  |  | $tiled->box(box => [ $w + 9, $h + 9, $w + $_->getwidth() + 9, $h + $_->getheight() + 9], | 
| 413 |  |  |  |  |  |  | color => $shadow, filled => 1) | 
| 414 |  |  |  |  |  |  | if $shadow; | 
| 415 | 0 | 0 |  |  |  |  | $tiled->rubthrough(src => $_, tx => $w, ty => $h) or die $tiled->errstr(); | 
| 416 |  |  |  |  |  |  | } | 
| 417 |  |  |  |  |  |  | # | 
| 418 |  |  |  |  |  |  | #	in array context, returns the coordinates so e.g. any image maps | 
| 419 |  |  |  |  |  |  | #	can be adjusted to the tiled image's newl location | 
| 420 |  |  |  |  |  |  | # | 
| 421 | 0 |  |  |  |  |  | my $imgdata; | 
| 422 | 0 | 0 |  |  |  |  | $tiled->write(data => \$imgdata, type => $format) or | 
| 423 |  |  |  |  |  |  | die $tiled->errstr(); | 
| 424 | 0 | 0 |  |  |  |  | return wantarray ? ($imgdata, @coords) : $imgdata; | 
| 425 |  |  |  |  |  |  | } | 
| 426 |  |  |  |  |  |  |  | 
| 427 |  |  |  |  |  |  | 1; |