| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package CSS::SpriteBuilder::Sprite; |
|
2
|
|
|
|
|
|
|
|
|
3
|
4
|
|
|
4
|
|
33
|
use warnings; |
|
|
4
|
|
|
|
|
8
|
|
|
|
4
|
|
|
|
|
112
|
|
|
4
|
4
|
|
|
4
|
|
21
|
use strict; |
|
|
4
|
|
|
|
|
7
|
|
|
|
4
|
|
|
|
|
123
|
|
|
5
|
4
|
|
|
4
|
|
21
|
use File::Glob ":glob"; |
|
|
4
|
|
|
|
|
7
|
|
|
|
4
|
|
|
|
|
2158
|
|
|
6
|
4
|
|
|
4
|
|
23
|
use File::Spec; |
|
|
4
|
|
|
|
|
7
|
|
|
|
4
|
|
|
|
|
86
|
|
|
7
|
4
|
|
|
4
|
|
17
|
use Cwd (); |
|
|
4
|
|
|
|
|
7
|
|
|
|
4
|
|
|
|
|
54
|
|
|
8
|
4
|
|
|
4
|
|
17
|
use CSS::SpriteBuilder::Constants; |
|
|
4
|
|
|
|
|
5
|
|
|
|
4
|
|
|
|
|
342
|
|
|
9
|
4
|
|
|
4
|
|
1622
|
use CSS::SpriteBuilder::SpriteItem; |
|
|
4
|
|
|
|
|
10
|
|
|
|
4
|
|
|
|
|
140
|
|
|
10
|
4
|
|
|
4
|
|
26
|
use base 'CSS::SpriteBuilder::ImageDriver::Auto'; |
|
|
4
|
|
|
|
|
6
|
|
|
|
4
|
|
|
|
|
7668
|
|
|
11
|
|
|
|
|
|
|
|
|
12
|
0
|
|
|
0
|
0
|
0
|
sub max { $_[ $_[0] < $_[1] ] } |
|
13
|
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
sub new { |
|
15
|
3
|
|
|
3
|
1
|
18
|
my ($class, @args) = @_; |
|
16
|
|
|
|
|
|
|
|
|
17
|
3
|
|
|
|
|
42
|
my $self = $class->SUPER::new( |
|
18
|
|
|
|
|
|
|
source_dir => undef, |
|
19
|
|
|
|
|
|
|
source_images => undef, |
|
20
|
|
|
|
|
|
|
target_file => undef, |
|
21
|
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
image_quality => DEF_IMAGE_QUALITY, |
|
23
|
|
|
|
|
|
|
max_image_size => DEF_MAX_IMAGE_SIZE, |
|
24
|
|
|
|
|
|
|
max_image_width => DEF_MAX_IMAGE_WIDTH, |
|
25
|
|
|
|
|
|
|
max_image_height => DEF_MAX_IMAGE_HEIGHT, |
|
26
|
|
|
|
|
|
|
max_sprite_width => DEF_MAX_SPRITE_WIDTH, |
|
27
|
|
|
|
|
|
|
max_sprite_height => DEF_MAX_SPRITE_HEIGHT, |
|
28
|
|
|
|
|
|
|
margin => DEF_MARGIN, |
|
29
|
|
|
|
|
|
|
transparent_color => undef, |
|
30
|
|
|
|
|
|
|
is_background => 0, |
|
31
|
|
|
|
|
|
|
layout => DEF_LAYOUT, |
|
32
|
|
|
|
|
|
|
css_selector_prefix => DEF_CSS_SELECTOR_PREFIX, |
|
33
|
|
|
|
|
|
|
css_url_prefix => '', |
|
34
|
|
|
|
|
|
|
is_add_timestamp => 1, |
|
35
|
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
_sprite_no => 1, |
|
37
|
|
|
|
|
|
|
_repeated_images => [], |
|
38
|
|
|
|
|
|
|
_sprites => {}, |
|
39
|
|
|
|
|
|
|
_x => 0, |
|
40
|
|
|
|
|
|
|
_y => 0, |
|
41
|
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
@args, |
|
43
|
|
|
|
|
|
|
); |
|
44
|
|
|
|
|
|
|
|
|
45
|
3
|
50
|
|
|
|
7
|
unless ( grep { $_ eq $self->{layout} } @{ LAYOUT_LIST() } ) { |
|
|
9
|
|
|
|
|
26
|
|
|
|
3
|
|
|
|
|
8
|
|
|
46
|
0
|
|
|
|
|
0
|
die "Invalid 'layout' parameter: $self->{layout}"; |
|
47
|
|
|
|
|
|
|
} |
|
48
|
|
|
|
|
|
|
|
|
49
|
3
|
|
|
|
|
10
|
return $self; |
|
50
|
|
|
|
|
|
|
} |
|
51
|
|
|
|
|
|
|
|
|
52
|
6
|
|
|
6
|
0
|
114
|
sub target_file { sprintf( $_[0]->{target_file}, $_[0]->{_sprite_no} ) } |
|
53
|
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
sub _init { |
|
55
|
0
|
|
|
0
|
|
0
|
my ($self, $image) = @_; |
|
56
|
|
|
|
|
|
|
|
|
57
|
0
|
0
|
|
|
|
0
|
die "The 'target_file' parameter is not defined" unless $self->{target_file}; |
|
58
|
0
|
0
|
|
|
|
0
|
die "The 'source_images' parameter is not defined" unless $self->{source_images}; |
|
59
|
|
|
|
|
|
|
|
|
60
|
0
|
|
|
|
|
0
|
$self->SUPER::_init($image); |
|
61
|
|
|
|
|
|
|
|
|
62
|
0
|
|
|
|
|
0
|
$self->{_x} = $self->{_y} = 0; |
|
63
|
|
|
|
|
|
|
|
|
64
|
0
|
|
|
|
|
0
|
return; |
|
65
|
|
|
|
|
|
|
} |
|
66
|
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
sub build { |
|
68
|
3
|
|
|
3
|
0
|
6
|
my ($self) = @_; |
|
69
|
|
|
|
|
|
|
|
|
70
|
3
|
|
|
|
|
8
|
my $images = $self->search_images(); |
|
71
|
3
|
|
|
|
|
6
|
foreach my $image (@$images) { |
|
72
|
3
|
|
|
|
|
9
|
$self->process_image($image); |
|
73
|
|
|
|
|
|
|
} |
|
74
|
|
|
|
|
|
|
|
|
75
|
3
|
|
|
|
|
10
|
$self->write(); |
|
76
|
|
|
|
|
|
|
|
|
77
|
3
|
|
|
|
|
50
|
return $self->{_sprites}; |
|
78
|
|
|
|
|
|
|
} |
|
79
|
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
sub search_images { |
|
81
|
3
|
|
|
3
|
0
|
4
|
my ($self) = @_; |
|
82
|
|
|
|
|
|
|
|
|
83
|
3
|
|
|
|
|
5
|
my $save_dir; |
|
84
|
3
|
50
|
|
|
|
17
|
if ( $self->{source_dir} ) { |
|
85
|
3
|
|
|
|
|
27
|
$save_dir = Cwd::getcwd(); |
|
86
|
3
|
50
|
|
|
|
89
|
chdir $self->{source_dir} or die "Cannot chdir to $self->{source_dir}: $!\n"; |
|
87
|
|
|
|
|
|
|
} |
|
88
|
|
|
|
|
|
|
|
|
89
|
3
|
50
|
33
|
|
|
23
|
my @images = grep { |
|
|
|
|
50
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
90
|
3
|
|
|
|
|
5
|
( !$self->{max_image_size} || -s $_->source_file() <= $self->{max_image_size} ) |
|
91
|
|
|
|
|
|
|
&& ( !$self->{max_image_width} || $_->width() <= $self->{max_image_width} ) |
|
92
|
|
|
|
|
|
|
&& ( !$self->{max_image_height} || $_->height() <= $self->{max_image_height} ) |
|
93
|
|
|
|
|
|
|
&& ( $_->width() <= $self->{max_sprite_width} && $_->height <= $self->{max_sprite_height} |
|
94
|
|
|
|
|
|
|
or die "The image resolution is bigger than maximum configured value for '". $_->source_file() ."'" |
|
95
|
|
|
|
|
|
|
) |
|
96
|
|
|
|
|
|
|
} map { |
|
97
|
3
|
|
|
|
|
7
|
my $image_opts = $_; |
|
98
|
3
|
|
|
|
|
17
|
map { |
|
99
|
3
|
|
|
|
|
100
|
CSS::SpriteBuilder::SpriteItem->new( |
|
100
|
|
|
|
|
|
|
%$image_opts, |
|
101
|
|
|
|
|
|
|
source_file => $_, |
|
102
|
|
|
|
|
|
|
) |
|
103
|
|
|
|
|
|
|
} bsd_glob( $image_opts->{file}, File::Glob::GLOB_ERR ); |
|
104
|
3
|
|
|
|
|
5
|
} @{ $self->{source_images} }; |
|
105
|
|
|
|
|
|
|
|
|
106
|
3
|
50
|
|
|
|
14
|
if ($save_dir) { |
|
107
|
3
|
50
|
|
|
|
64
|
chdir $save_dir or die "Cannot chdir to $save_dir: $!\n"; |
|
108
|
|
|
|
|
|
|
} |
|
109
|
|
|
|
|
|
|
|
|
110
|
3
|
50
|
|
|
|
13
|
return wantarray ? @images: \@images; |
|
111
|
|
|
|
|
|
|
} |
|
112
|
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
sub process_image { |
|
114
|
3
|
|
|
3
|
0
|
4
|
my ($self, $image) = @_; |
|
115
|
|
|
|
|
|
|
|
|
116
|
3
|
|
|
|
|
10
|
$self->allocate_space($image); |
|
117
|
|
|
|
|
|
|
|
|
118
|
3
|
|
|
|
|
8
|
$self->align_image($image); |
|
119
|
|
|
|
|
|
|
|
|
120
|
3
|
|
|
|
|
8
|
$self->save_info($image); |
|
121
|
|
|
|
|
|
|
|
|
122
|
3
|
50
|
33
|
|
|
18
|
$self->save_repeated_images($image) |
|
123
|
|
|
|
|
|
|
if $self->{layout} ne PACKED_LAYOUT && $image->{is_repeat}; |
|
124
|
|
|
|
|
|
|
|
|
125
|
3
|
|
|
|
|
9
|
$self->post_process($image); |
|
126
|
|
|
|
|
|
|
} |
|
127
|
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
sub align_image { |
|
129
|
3
|
|
|
3
|
0
|
4
|
my ($self, $image) = @_; |
|
130
|
|
|
|
|
|
|
|
|
131
|
3
|
50
|
|
|
|
10
|
if ( $self->is_blank() ) { |
|
132
|
3
|
|
|
|
|
9
|
$self->reset($image); |
|
133
|
|
|
|
|
|
|
} |
|
134
|
|
|
|
|
|
|
else { |
|
135
|
0
|
0
|
|
|
|
0
|
$self->{_x} += $self->{margin} if $self->{_x}; |
|
136
|
|
|
|
|
|
|
|
|
137
|
0
|
|
|
|
|
0
|
$self->extent( |
|
138
|
|
|
|
|
|
|
max($self->width(), $self->{_x} + $image->width() ), |
|
139
|
|
|
|
|
|
|
max($self->height(), $self->{_y} + $image->height()), |
|
140
|
|
|
|
|
|
|
); |
|
141
|
|
|
|
|
|
|
|
|
142
|
0
|
|
|
|
|
0
|
$self->composite( $image, $self->{_x}, $self->{_y} ); |
|
143
|
|
|
|
|
|
|
} |
|
144
|
|
|
|
|
|
|
|
|
145
|
3
|
|
|
|
|
6
|
return; |
|
146
|
|
|
|
|
|
|
} |
|
147
|
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
sub allocate_space { |
|
149
|
3
|
|
|
3
|
0
|
4
|
my ($self, $image) = @_; |
|
150
|
|
|
|
|
|
|
|
|
151
|
3
|
50
|
|
|
|
25
|
return if $self->is_blank(); |
|
152
|
|
|
|
|
|
|
|
|
153
|
0
|
0
|
|
|
|
0
|
my $x_margin = $self->{_x} == 0 ? 0 : $self->{margin}; |
|
154
|
|
|
|
|
|
|
|
|
155
|
0
|
0
|
0
|
|
|
0
|
if ( |
|
156
|
|
|
|
|
|
|
$self->{layout} eq VERTICAL_LAYOUT |
|
157
|
|
|
|
|
|
|
|| ($self->{_x} + $image->width() + $x_margin) > $self->{max_sprite_width} |
|
158
|
|
|
|
|
|
|
) { |
|
159
|
0
|
|
|
|
|
0
|
$self->{_x} = 0; |
|
160
|
0
|
|
|
|
|
0
|
$self->{_y} = $self->height() + $self->{margin}; |
|
161
|
|
|
|
|
|
|
} |
|
162
|
|
|
|
|
|
|
|
|
163
|
0
|
0
|
0
|
|
|
0
|
if ( |
|
|
|
|
0
|
|
|
|
|
|
164
|
|
|
|
|
|
|
$self->{_y} > 0 && ( |
|
165
|
|
|
|
|
|
|
$self->{layout} eq HORIZONTAL_LAYOUT |
|
166
|
|
|
|
|
|
|
|| ($self->{_y} + $image->height() + $self->{margin}) > $self->{max_sprite_height} |
|
167
|
|
|
|
|
|
|
) |
|
168
|
|
|
|
|
|
|
) { |
|
169
|
0
|
|
|
|
|
0
|
$self->write(); |
|
170
|
|
|
|
|
|
|
} |
|
171
|
|
|
|
|
|
|
|
|
172
|
0
|
|
|
|
|
0
|
return; |
|
173
|
|
|
|
|
|
|
} |
|
174
|
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
sub save_info { |
|
176
|
3
|
|
|
3
|
0
|
5
|
my ($self, $image) = @_; |
|
177
|
|
|
|
|
|
|
|
|
178
|
3
|
|
|
|
|
7
|
my (undef, undef, $filename) = File::Spec->splitpath( $self->target_file() ); |
|
179
|
3
|
|
|
|
|
9
|
my $sprite_image = $self->{css_url_prefix} . $filename; |
|
180
|
|
|
|
|
|
|
|
|
181
|
3
|
50
|
|
|
|
14
|
$sprite_image .= '?' . time() if $self->{is_add_timestamp}; |
|
182
|
|
|
|
|
|
|
|
|
183
|
3
|
50
|
33
|
|
|
6
|
push @{ $self->{_sprites}{$sprite_image} }, { |
|
|
3
|
50
|
|
|
|
21
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
image => $image->source_file(), |
|
185
|
|
|
|
|
|
|
width => $image->width(), |
|
186
|
|
|
|
|
|
|
height => $image->height(), |
|
187
|
|
|
|
|
|
|
x => $self->{_x}, |
|
188
|
|
|
|
|
|
|
y => $self->{_y}, |
|
189
|
|
|
|
|
|
|
selector => $image->get_css_selector( $self->{css_selector_prefix} ), |
|
190
|
|
|
|
|
|
|
is_background => ( |
|
191
|
|
|
|
|
|
|
defined $image->is_background() |
|
192
|
|
|
|
|
|
|
? $image->is_background() |
|
193
|
|
|
|
|
|
|
: $self->{is_background} |
|
194
|
|
|
|
|
|
|
) ? 1 : 0, |
|
195
|
|
|
|
|
|
|
repeat => $self->{layout} ne PACKED_LAYOUT && $image->is_repeat() |
|
196
|
|
|
|
|
|
|
? $self->{layout} eq HORIZONTAL_LAYOUT ? 'y' : 'x' |
|
197
|
|
|
|
|
|
|
: 'no' |
|
198
|
|
|
|
|
|
|
, |
|
199
|
|
|
|
|
|
|
}; |
|
200
|
|
|
|
|
|
|
|
|
201
|
3
|
|
|
|
|
9
|
return; |
|
202
|
|
|
|
|
|
|
} |
|
203
|
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
sub save_repeated_images { |
|
205
|
0
|
|
|
0
|
0
|
0
|
my ($self, $image) = @_; |
|
206
|
|
|
|
|
|
|
|
|
207
|
0
|
|
|
|
|
0
|
push @{ $self->{_repeated_images} }, { |
|
|
0
|
|
|
|
|
0
|
|
|
208
|
|
|
|
|
|
|
image => $image, |
|
209
|
|
|
|
|
|
|
x => $self->{_x}, |
|
210
|
|
|
|
|
|
|
y => $self->{_y}, |
|
211
|
|
|
|
|
|
|
}; |
|
212
|
|
|
|
|
|
|
|
|
213
|
0
|
|
|
|
|
0
|
return; |
|
214
|
|
|
|
|
|
|
} |
|
215
|
|
|
|
|
|
|
|
|
216
|
|
|
|
|
|
|
sub post_process { |
|
217
|
3
|
|
|
3
|
0
|
6
|
my ($self, $image) = @_; |
|
218
|
|
|
|
|
|
|
|
|
219
|
3
|
50
|
|
|
|
16
|
$self->{ $self->{layout} eq VERTICAL_LAYOUT ? '_y' : '_x' } += $image->width; |
|
220
|
|
|
|
|
|
|
|
|
221
|
3
|
|
|
|
|
12
|
return; |
|
222
|
|
|
|
|
|
|
} |
|
223
|
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
sub write { |
|
225
|
3
|
|
|
3
|
1
|
5
|
my ($self) = @_; |
|
226
|
|
|
|
|
|
|
|
|
227
|
3
|
50
|
|
|
|
9
|
return if $self->is_blank(); |
|
228
|
|
|
|
|
|
|
|
|
229
|
3
|
|
|
|
|
26
|
$self->process_repeated_images(); |
|
230
|
|
|
|
|
|
|
|
|
231
|
3
|
50
|
|
|
|
10
|
$self->set_transparent_color( $self->{transparent_color} ) |
|
232
|
|
|
|
|
|
|
if $self->{transparent_color}; |
|
233
|
|
|
|
|
|
|
|
|
234
|
3
|
|
|
|
|
30
|
$self->set_quality( $self->{image_quality} ); |
|
235
|
|
|
|
|
|
|
|
|
236
|
3
|
|
|
|
|
7
|
$self->SUPER::write( $self->target_file() ); |
|
237
|
|
|
|
|
|
|
|
|
238
|
3
|
|
|
|
|
5
|
$self->{_sprite_no}++; |
|
239
|
|
|
|
|
|
|
|
|
240
|
3
|
|
|
|
|
11
|
$self->reset(); |
|
241
|
|
|
|
|
|
|
|
|
242
|
3
|
|
|
|
|
6
|
return; |
|
243
|
|
|
|
|
|
|
} |
|
244
|
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
sub process_repeated_images { |
|
246
|
3
|
|
|
3
|
0
|
5
|
my ($self) = @_; |
|
247
|
|
|
|
|
|
|
|
|
248
|
3
|
50
|
|
|
|
5
|
return unless scalar @{ $self->{_repeated_images} }; |
|
|
3
|
|
|
|
|
15
|
|
|
249
|
|
|
|
|
|
|
|
|
250
|
0
|
0
|
|
|
|
|
my $meter = $self->{layout} eq VERTICAL_LAYOUT ? 'width' : 'height'; |
|
251
|
0
|
|
|
|
|
|
my $original_sprite_size = $self->$meter(); |
|
252
|
0
|
0
|
|
|
|
|
my $max_sprite_size = $self->{ $self->{layout} eq VERTICAL_LAYOUT ? 'max_sprite_width' : 'max_sprite_height' }; |
|
253
|
0
|
|
|
|
|
|
my @images_size = reverse sort map { $_->{image}->$meter() } @{ $self->{_repeated_images} }; |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
254
|
0
|
|
|
|
|
|
my $max_image_size = shift @images_size; |
|
255
|
|
|
|
|
|
|
|
|
256
|
0
|
0
|
|
|
|
|
for ( |
|
257
|
|
|
|
|
|
|
my $k = int($original_sprite_size / $max_image_size) + ($original_sprite_size % $max_image_size ? 1 : 0); |
|
258
|
|
|
|
|
|
|
$k * $max_image_size <= $max_sprite_size; |
|
259
|
|
|
|
|
|
|
$k++ |
|
260
|
|
|
|
|
|
|
) { |
|
261
|
0
|
|
|
|
|
|
my $extented_sprite_size = $k * $max_image_size; |
|
262
|
0
|
0
|
|
|
|
|
unless (grep { $extented_sprite_size % $_ } @images_size) { |
|
|
0
|
|
|
|
|
|
|
|
263
|
0
|
0
|
|
|
|
|
$self->extent( |
|
264
|
|
|
|
|
|
|
$meter eq 'width' |
|
265
|
|
|
|
|
|
|
? ( $extented_sprite_size, $self->height() ) |
|
266
|
|
|
|
|
|
|
: ( $self->width() , $extented_sprite_size ) |
|
267
|
|
|
|
|
|
|
); |
|
268
|
|
|
|
|
|
|
|
|
269
|
0
|
|
|
|
|
|
foreach my $image_info (@{ $self->{_repeated_images} }) { |
|
|
0
|
|
|
|
|
|
|
|
270
|
0
|
|
|
|
|
|
my $image = $image_info->{image}; |
|
271
|
0
|
|
|
|
|
|
my $size = $image->$meter(); |
|
272
|
|
|
|
|
|
|
|
|
273
|
0
|
0
|
|
|
|
|
while (($image_info->{ $self->{layout} eq VERTICAL_LAYOUT ? 'x' : 'y' } += $size) < $extented_sprite_size) { |
|
274
|
0
|
|
|
|
|
|
$self->composite( $image, $image_info->{x}, $image_info->{y} ) |
|
275
|
|
|
|
|
|
|
} |
|
276
|
|
|
|
|
|
|
} |
|
277
|
|
|
|
|
|
|
|
|
278
|
0
|
|
|
|
|
|
return; |
|
279
|
|
|
|
|
|
|
} |
|
280
|
|
|
|
|
|
|
} |
|
281
|
|
|
|
|
|
|
|
|
282
|
0
|
|
|
|
|
|
$self->{_repeated_images} = []; |
|
283
|
|
|
|
|
|
|
|
|
284
|
0
|
|
|
|
|
|
die "Can't process repeated images"; |
|
285
|
|
|
|
|
|
|
} |
|
286
|
|
|
|
|
|
|
|
|
287
|
|
|
|
|
|
|
1; |