line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
=head1 NAME |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
XAO::ImageCache - Images caching by URLs stored in XAO::FS database |
4
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
=head1 SYNOPSIS |
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
use XAO::ImageCache; |
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
# Making new instance of Image Cache object |
10
|
|
|
|
|
|
|
my $image_Cache = XAO::ImageCache->new( |
11
|
|
|
|
|
|
|
list => $odb->fetch("/Products"), |
12
|
|
|
|
|
|
|
cache_path => "/var/httpd/shop/product/images/", |
13
|
|
|
|
|
|
|
cache_url => "/products/images/", |
14
|
|
|
|
|
|
|
source_url_key => "source_img", |
15
|
|
|
|
|
|
|
) || die "Can't make Image cache!"; |
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
# Init new empty Cache |
18
|
|
|
|
|
|
|
$image_cache->init() || die "Can't init new cache!"; |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
# Start images checking and downloading to cache |
21
|
|
|
|
|
|
|
$image_cache->check(); |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
=head1 DESCRIPTION |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
When we store images links on own database we have no real |
26
|
|
|
|
|
|
|
images on own site. Some time it may be a problem cause images may |
27
|
|
|
|
|
|
|
have no right dimension or may be deleted from source site. |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
XAO::ImageCache made for cache locally images his URL stored |
30
|
|
|
|
|
|
|
in XAO Founsation Server. Also, images may be resized automaticaly. |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
This module provide easy methods to scan XAO Foundation Server data |
33
|
|
|
|
|
|
|
lists, to extract images source URLs from data objects, to download |
34
|
|
|
|
|
|
|
images to local cache, to resize a local copy of the image to fit into |
35
|
|
|
|
|
|
|
given dimensions and to store the new local URL of the image back to |
36
|
|
|
|
|
|
|
the data object. |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
=head1 METHODS |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
=over |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
=cut |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
############################################################################### |
45
|
|
|
|
|
|
|
package XAO::ImageCache; |
46
|
1
|
|
|
1
|
|
532
|
use strict; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
41
|
|
47
|
1
|
|
|
1
|
|
5
|
use Error qw(:try); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
8
|
|
48
|
1
|
|
|
1
|
|
153
|
use XAO::Utils; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
49
|
|
49
|
1
|
|
|
1
|
|
385
|
use XAO::FS; |
|
1
|
|
|
|
|
57
|
|
|
1
|
|
|
|
|
23
|
|
50
|
1
|
|
|
1
|
|
4
|
use XAO::Errors qw(XAO::ImageCache); |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
7
|
|
51
|
1
|
|
|
1
|
|
280
|
use Digest::MD5 qw(md5 md5_hex md5_base64); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
54
|
|
52
|
1
|
|
|
1
|
|
601
|
use LWP::UserAgent; |
|
1
|
|
|
|
|
34521
|
|
|
1
|
|
|
|
|
38
|
|
53
|
1
|
|
|
1
|
|
7
|
use URI; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
24
|
|
54
|
1
|
|
|
1
|
|
257
|
use Image::Magick; |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
use Date::Manip; |
56
|
|
|
|
|
|
|
use File::Path; |
57
|
|
|
|
|
|
|
use File::Copy; |
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
use vars qw($VERSION); |
60
|
|
|
|
|
|
|
$VERSION='1.20'; |
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
############################################################################### |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
## |
65
|
|
|
|
|
|
|
# Methods prototypes |
66
|
|
|
|
|
|
|
# |
67
|
|
|
|
|
|
|
sub new ($%); |
68
|
|
|
|
|
|
|
sub init($); |
69
|
|
|
|
|
|
|
sub check($); |
70
|
|
|
|
|
|
|
sub download ($$); |
71
|
|
|
|
|
|
|
sub scale_file($$$$;$); |
72
|
|
|
|
|
|
|
sub scale_large($$$); |
73
|
|
|
|
|
|
|
sub scale_thumbnail($$$); |
74
|
|
|
|
|
|
|
sub remove_cache($); |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
# Special functions |
77
|
|
|
|
|
|
|
sub get_filename($); |
78
|
|
|
|
|
|
|
sub treat_filename($); |
79
|
|
|
|
|
|
|
sub convert_time($); |
80
|
|
|
|
|
|
|
sub throw($$); |
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
############################################################################### |
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
sub DESTROY { |
85
|
|
|
|
|
|
|
my $self = shift; |
86
|
|
|
|
|
|
|
dprint "----- XAO Image Cache finished -----"; |
87
|
|
|
|
|
|
|
} |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
############################################################################### |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
=item new($%) |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
The constructor returns a new C object. |
94
|
|
|
|
|
|
|
You can use it to make new images cache or check images |
95
|
|
|
|
|
|
|
of already existent cache. |
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
my $image_cache = XAO::ImageCache->new( |
98
|
|
|
|
|
|
|
cache_path => "cache", # set cache directory to './cache/' |
99
|
|
|
|
|
|
|
source_path => "cache/source", # set source directory to './cache/source/' |
100
|
|
|
|
|
|
|
local_path => "images/copy", # (optional) try to resolve local urls |
101
|
|
|
|
|
|
|
cache_url => "images/", # set cached images (relative) path to 'images/' |
102
|
|
|
|
|
|
|
list => $odb->fetch("/Products"), |
103
|
|
|
|
|
|
|
source_url_key => 'source_image_url', |
104
|
|
|
|
|
|
|
dest_url_key => 'dest_image_url', |
105
|
|
|
|
|
|
|
filename_key => 'product_id', |
106
|
|
|
|
|
|
|
min_width => 50, # Source image is ignored if smaller |
107
|
|
|
|
|
|
|
min_height => 50, |
108
|
|
|
|
|
|
|
size => { |
109
|
|
|
|
|
|
|
width => 320, |
110
|
|
|
|
|
|
|
height => 200, |
111
|
|
|
|
|
|
|
save_aspect_ratio => 1, |
112
|
|
|
|
|
|
|
}, |
113
|
|
|
|
|
|
|
thumbnails => { |
114
|
|
|
|
|
|
|
path => '/var/httpd/shop/product/images/tbn', |
115
|
|
|
|
|
|
|
url => '/products/images/tbn/' |
116
|
|
|
|
|
|
|
geometry => "25%", |
117
|
|
|
|
|
|
|
url_key => 'thumbnail_url', |
118
|
|
|
|
|
|
|
}, |
119
|
|
|
|
|
|
|
autocreate => 1, |
120
|
|
|
|
|
|
|
useragent => { |
121
|
|
|
|
|
|
|
agent => 'My Lovely Browser/v13.01', |
122
|
|
|
|
|
|
|
timeout => 30, |
123
|
|
|
|
|
|
|
}, |
124
|
|
|
|
|
|
|
force_download => 1, # to enforce re-downloads |
125
|
|
|
|
|
|
|
force_scale => 1, # to enforce re-scaling |
126
|
|
|
|
|
|
|
clear_on_error => 0, # don't clear DB properties even on permanent errors |
127
|
|
|
|
|
|
|
) || die "Image cache creation failure!"; |
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
A number of configuration parameters can be passed to |
130
|
|
|
|
|
|
|
XAO::ImageCache to tune functionality. |
131
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
=over |
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
=item autocreate |
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
=item cache_path |
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
=item cache_url |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
=item clear_on_error |
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
=item dest_url_key |
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
=item force_download |
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
=item force_scale |
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
=item list |
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
=item source_url_key |
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
=item size |
153
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
=item thumbnails |
155
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
=item useragent |
157
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
=back |
159
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
Follow to L |
161
|
|
|
|
|
|
|
section to see what each parameter does. |
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
If any required parameter is not present an error will be thrown. |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
=cut |
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
# |
168
|
|
|
|
|
|
|
# Creating new instance of Image Cache object. |
169
|
|
|
|
|
|
|
# |
170
|
|
|
|
|
|
|
# Parameters hash should contain following keys: |
171
|
|
|
|
|
|
|
# |
172
|
|
|
|
|
|
|
# cache_path => path to image cache directory |
173
|
|
|
|
|
|
|
# source_path => path to source image directory |
174
|
|
|
|
|
|
|
# cache_url => relative URL pointing to cached images |
175
|
|
|
|
|
|
|
# list => reference to XAO::DO::FS::List object |
176
|
|
|
|
|
|
|
# containing data elements with images data |
177
|
|
|
|
|
|
|
# source_url_key => source image url key name |
178
|
|
|
|
|
|
|
# filename_key => key name image and thumbnail file names will |
179
|
|
|
|
|
|
|
# be based on |
180
|
|
|
|
|
|
|
# |
181
|
|
|
|
|
|
|
# Optional parameters: |
182
|
|
|
|
|
|
|
# |
183
|
|
|
|
|
|
|
# dest_url_key => key name containing destination url name |
184
|
|
|
|
|
|
|
# size => { |
185
|
|
|
|
|
|
|
# width => |
186
|
|
|
|
|
|
|
# height => |
187
|
|
|
|
|
|
|
# } |
188
|
|
|
|
|
|
|
# autocreate => |
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
sub new ($%) { |
191
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
my $class = shift; |
193
|
|
|
|
|
|
|
my $self = {}; |
194
|
|
|
|
|
|
|
bless $self,$class; |
195
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
# Predefined parameters |
197
|
|
|
|
|
|
|
$self->{useragent} = { 'agent' => "XAO-ImageCache/$VERSION", }; |
198
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
# Passed parameters |
200
|
|
|
|
|
|
|
if (@_) { |
201
|
|
|
|
|
|
|
my %extra = @_; |
202
|
|
|
|
|
|
|
@$self{keys %extra} = values %extra; |
203
|
|
|
|
|
|
|
} |
204
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
# |
206
|
|
|
|
|
|
|
# Check required parameters |
207
|
|
|
|
|
|
|
# |
208
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
unless (defined($self->{source_path})) { |
210
|
|
|
|
|
|
|
$self->throw("- missing 'source_path' parameter!"); |
211
|
|
|
|
|
|
|
} |
212
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
unless (defined($self->{cache_path})) { |
214
|
|
|
|
|
|
|
$self->throw("- missing 'cache_path' parameter!"); |
215
|
|
|
|
|
|
|
} |
216
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
unless (defined($self->{list})) { |
218
|
|
|
|
|
|
|
$self->throw("- missing 'list' parameter!"); |
219
|
|
|
|
|
|
|
} |
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
unless (defined($self->{cache_url})){ |
222
|
|
|
|
|
|
|
$self->throw("- missing 'cache_url' parameter!") ; |
223
|
|
|
|
|
|
|
} |
224
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
unless (defined($self->{source_url_key})) { |
226
|
|
|
|
|
|
|
$self->throw("- missing 'source_url_key' parameter!"); |
227
|
|
|
|
|
|
|
} |
228
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
unless (defined($self->{dest_url_key})) { |
230
|
|
|
|
|
|
|
$self->throw("- missing 'dest_url_key' parameter!"); |
231
|
|
|
|
|
|
|
} |
232
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
# |
234
|
|
|
|
|
|
|
# Make sure paths end with / |
235
|
|
|
|
|
|
|
# |
236
|
|
|
|
|
|
|
$self->{'source_path'} .= '/' if $self->{'source_path'} !~ /\/$/; |
237
|
|
|
|
|
|
|
$self->{'cache_path'} .= '/' if $self->{'cache_path'} !~ /\/$/; |
238
|
|
|
|
|
|
|
$self->{'cache_url'} .= '/' if $self->{'cache_url'} !~ /\/$/; |
239
|
|
|
|
|
|
|
$self->{'thumbnails'}->{'cache_path'}.= '/' if $self->{'thumbnails'}->{'cache_path'} |
240
|
|
|
|
|
|
|
&& $self->{'thumbnails'}->{'cache_path'} !~ /\/$/; |
241
|
|
|
|
|
|
|
$self->{'thumbnails'}->{'cache_url'} .= '/' if $self->{'thumbnails'}->{'cache_url'} |
242
|
|
|
|
|
|
|
&& $self->{'thumbnails'}->{'cache_url'} !~ /\/$/; |
243
|
|
|
|
|
|
|
|
244
|
|
|
|
|
|
|
if (defined($self->{'min_period'}) && $self->{'min_period'}) { |
245
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
unless ($self->{'min_period'} =~ /\d+[smhd]/) { |
247
|
|
|
|
|
|
|
$self->throw("- incorrectly formatted 'min_period' parameter!"); |
248
|
|
|
|
|
|
|
} |
249
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
# Make sure 'min_period' parameters is in seconds |
251
|
|
|
|
|
|
|
$self->{'min_period'} =~ s/(\d+)([smhd])/$1/; |
252
|
|
|
|
|
|
|
if ($2 eq 'm') { |
253
|
|
|
|
|
|
|
$self->{'min_period'} *= 60; |
254
|
|
|
|
|
|
|
} |
255
|
|
|
|
|
|
|
elsif ($2 eq 'h') { |
256
|
|
|
|
|
|
|
$self->{'min_period'} *= 3600; |
257
|
|
|
|
|
|
|
} |
258
|
|
|
|
|
|
|
elsif ($2 eq 'd') { |
259
|
|
|
|
|
|
|
$self->{'min_period'} *= 86400; |
260
|
|
|
|
|
|
|
} |
261
|
|
|
|
|
|
|
} |
262
|
|
|
|
|
|
|
else { |
263
|
|
|
|
|
|
|
$self->{min_period} = 0; |
264
|
|
|
|
|
|
|
} |
265
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
$self->{'reload'}=1 if $self->{'force_download'}; |
267
|
|
|
|
|
|
|
|
268
|
|
|
|
|
|
|
$self->{'size'}->{'quality'}||=88; |
269
|
|
|
|
|
|
|
$self->{'thumbnails'}->{'quality'}||=88; |
270
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
# Make LWP::UserAgent instance |
272
|
|
|
|
|
|
|
my $hash_ref = $self->{'useragent'}; |
273
|
|
|
|
|
|
|
$self->{ua} = LWP::UserAgent->new( %$hash_ref) |
274
|
|
|
|
|
|
|
|| $self->throw("- LWP::UserAgent creation failure!"); |
275
|
|
|
|
|
|
|
|
276
|
|
|
|
|
|
|
$self->init() if defined($self->{autocreate} && $self->{autocreate}); |
277
|
|
|
|
|
|
|
$self; |
278
|
|
|
|
|
|
|
} |
279
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
############################################################################### |
281
|
|
|
|
|
|
|
|
282
|
|
|
|
|
|
|
=item init($) |
283
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
Cache structure initialization. |
285
|
|
|
|
|
|
|
|
286
|
|
|
|
|
|
|
Executed automaticaly if C parameter present. |
287
|
|
|
|
|
|
|
|
288
|
|
|
|
|
|
|
Create image cache directory if non existent and thumbnail cache |
289
|
|
|
|
|
|
|
directory if non existent and defined as initialization parameter. |
290
|
|
|
|
|
|
|
|
291
|
|
|
|
|
|
|
=cut |
292
|
|
|
|
|
|
|
|
293
|
|
|
|
|
|
|
sub init($) { |
294
|
|
|
|
|
|
|
my $self = shift; |
295
|
|
|
|
|
|
|
|
296
|
|
|
|
|
|
|
dprint "----- XAO Image Cache Initialization started -----"; |
297
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
my $source_path = $self->{source_path}; |
299
|
|
|
|
|
|
|
my $img_cache_path = $self->{cache_path}; |
300
|
|
|
|
|
|
|
my $thm_cache_path = $self->{thumbnails}->{cache_path}; |
301
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
# |
303
|
|
|
|
|
|
|
# Create directories if non existent |
304
|
|
|
|
|
|
|
# |
305
|
|
|
|
|
|
|
|
306
|
|
|
|
|
|
|
unless (-d $source_path) { |
307
|
|
|
|
|
|
|
mkdir($source_path,0777) |
308
|
|
|
|
|
|
|
|| $self->throw("- cache directory can't be created! $!"); |
309
|
|
|
|
|
|
|
dprint "Image Cache directory '$source_path' created."; |
310
|
|
|
|
|
|
|
} |
311
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
unless (-d $img_cache_path) { |
313
|
|
|
|
|
|
|
mkdir($img_cache_path,0777) |
314
|
|
|
|
|
|
|
|| $self->throw("- cache directory can't be created! $!"); |
315
|
|
|
|
|
|
|
dprint "Image Cache directory '$img_cache_path' created."; |
316
|
|
|
|
|
|
|
} |
317
|
|
|
|
|
|
|
|
318
|
|
|
|
|
|
|
if ($thm_cache_path) { |
319
|
|
|
|
|
|
|
unless (-d $thm_cache_path) { |
320
|
|
|
|
|
|
|
mkdir($thm_cache_path, 0777) |
321
|
|
|
|
|
|
|
|| $self->throw("- can't create thumbnails cache directory ($thm_cache_path)! $!"); |
322
|
|
|
|
|
|
|
dprint "Thumbnail Cache directory '$thm_cache_path' created."; |
323
|
|
|
|
|
|
|
} |
324
|
|
|
|
|
|
|
} |
325
|
|
|
|
|
|
|
|
326
|
|
|
|
|
|
|
$self->check() if defined($self->{autocreate} && $self->{autocreate}); |
327
|
|
|
|
|
|
|
|
328
|
|
|
|
|
|
|
return 1; |
329
|
|
|
|
|
|
|
} |
330
|
|
|
|
|
|
|
|
331
|
|
|
|
|
|
|
############################################################################### |
332
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
=item check($) |
334
|
|
|
|
|
|
|
|
335
|
|
|
|
|
|
|
Goes through given XAO FS data list, downloads images from source url |
336
|
|
|
|
|
|
|
to cache and puts cache url into destination url key and thumbnail url |
337
|
|
|
|
|
|
|
key (where applicable). |
338
|
|
|
|
|
|
|
|
339
|
|
|
|
|
|
|
XAO::ImageCache->download() will be executed for downloading each image. |
340
|
|
|
|
|
|
|
|
341
|
|
|
|
|
|
|
=cut |
342
|
|
|
|
|
|
|
|
343
|
|
|
|
|
|
|
sub check($) { |
344
|
|
|
|
|
|
|
|
345
|
|
|
|
|
|
|
my $self = shift; |
346
|
|
|
|
|
|
|
|
347
|
|
|
|
|
|
|
my $img_src_url_key = $self->{'source_url_key'}; |
348
|
|
|
|
|
|
|
my $img_dest_url_key = $self->{'dest_url_key'}; |
349
|
|
|
|
|
|
|
my $img_cache_url = $self->{'cache_url'}; |
350
|
|
|
|
|
|
|
my $thm_src_url_key = $self->{'thumbnails'}->{'source_url_key'} || ''; |
351
|
|
|
|
|
|
|
my $thm_dest_url_key = $self->{'thumbnails'}->{'dest_url_key'} || ''; |
352
|
|
|
|
|
|
|
my $thm_cache_url = $self->{'thumbnails'}->{'cache_url'} || ''; |
353
|
|
|
|
|
|
|
my $thm_cache_path = $self->{'thumbnails'}->{'cache_path'} || ''; |
354
|
|
|
|
|
|
|
|
355
|
|
|
|
|
|
|
my $getter=$self->{'get_property_sub'} || sub ($$) { |
356
|
|
|
|
|
|
|
my ($obj,$prop)=@_; |
357
|
|
|
|
|
|
|
return $prop ? $obj->get($prop) : ''; |
358
|
|
|
|
|
|
|
}; |
359
|
|
|
|
|
|
|
|
360
|
|
|
|
|
|
|
my $checked = 0; |
361
|
|
|
|
|
|
|
my $list = $self->{'list'}; |
362
|
|
|
|
|
|
|
my $list_keys = $self->{'list_keys'} || [ $list->keys ]; |
363
|
|
|
|
|
|
|
|
364
|
|
|
|
|
|
|
my $count=0; |
365
|
|
|
|
|
|
|
my $total=scalar(@$list_keys); |
366
|
|
|
|
|
|
|
foreach my $item_id (@$list_keys) { |
367
|
|
|
|
|
|
|
|
368
|
|
|
|
|
|
|
dprint "Checking ID='$item_id', count=".$count++."/$total"; |
369
|
|
|
|
|
|
|
|
370
|
|
|
|
|
|
|
my $item = $list->get($item_id); |
371
|
|
|
|
|
|
|
my $img_src_url = $getter->($item,$img_src_url_key); |
372
|
|
|
|
|
|
|
my $thm_src_url = $getter->($item,$thm_src_url_key); |
373
|
|
|
|
|
|
|
|
374
|
|
|
|
|
|
|
# Skipping products without images |
375
|
|
|
|
|
|
|
# |
376
|
|
|
|
|
|
|
next unless $img_src_url || $thm_src_url; |
377
|
|
|
|
|
|
|
|
378
|
|
|
|
|
|
|
# Download source image and create cache image and thumbnail |
379
|
|
|
|
|
|
|
# |
380
|
|
|
|
|
|
|
try { |
381
|
|
|
|
|
|
|
my ($img_cache_file, $thm_cache_file)=$self->download( |
382
|
|
|
|
|
|
|
$item, |
383
|
|
|
|
|
|
|
$img_src_url, |
384
|
|
|
|
|
|
|
$thm_src_url, |
385
|
|
|
|
|
|
|
); |
386
|
|
|
|
|
|
|
|
387
|
|
|
|
|
|
|
dprint ".storing('$img_cache_file','$thm_cache_file')"; |
388
|
|
|
|
|
|
|
my %d; |
389
|
|
|
|
|
|
|
$d{$img_dest_url_key}=$img_cache_url.$img_cache_file if $img_dest_url_key; |
390
|
|
|
|
|
|
|
$d{$thm_dest_url_key}=$thm_cache_url.$thm_cache_file if $thm_dest_url_key; |
391
|
|
|
|
|
|
|
$item->put(\%d); |
392
|
|
|
|
|
|
|
} |
393
|
|
|
|
|
|
|
otherwise { |
394
|
|
|
|
|
|
|
my $e=shift; |
395
|
|
|
|
|
|
|
eprint "$e"; |
396
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
# We don't update the item unless this is a permanent error |
398
|
|
|
|
|
|
|
# and we have a 'clear_on_error' argument. |
399
|
|
|
|
|
|
|
# |
400
|
|
|
|
|
|
|
if("$e" =~ /PERMANENT/) { |
401
|
|
|
|
|
|
|
if($self->{'clear_on_error'}) { |
402
|
|
|
|
|
|
|
dprint ".permanent error - clearing existing image/thumbnail urls"; |
403
|
|
|
|
|
|
|
my %d; |
404
|
|
|
|
|
|
|
$d{$img_dest_url_key}='' if $img_dest_url_key; |
405
|
|
|
|
|
|
|
$d{$thm_dest_url_key}='' if $thm_dest_url_key; |
406
|
|
|
|
|
|
|
$item->put(\%d); |
407
|
|
|
|
|
|
|
} |
408
|
|
|
|
|
|
|
} |
409
|
|
|
|
|
|
|
}; |
410
|
|
|
|
|
|
|
|
411
|
|
|
|
|
|
|
$checked++; |
412
|
|
|
|
|
|
|
} |
413
|
|
|
|
|
|
|
|
414
|
|
|
|
|
|
|
return $checked; |
415
|
|
|
|
|
|
|
} |
416
|
|
|
|
|
|
|
|
417
|
|
|
|
|
|
|
############################################################################### |
418
|
|
|
|
|
|
|
|
419
|
|
|
|
|
|
|
=item download($$) |
420
|
|
|
|
|
|
|
|
421
|
|
|
|
|
|
|
Downloads image into cache directory. |
422
|
|
|
|
|
|
|
|
423
|
|
|
|
|
|
|
If C contains C parameter, thumbnail is either |
424
|
|
|
|
|
|
|
downloaded into thumbnail cache directory or created from downloaded |
425
|
|
|
|
|
|
|
image. |
426
|
|
|
|
|
|
|
|
427
|
|
|
|
|
|
|
Source image URL should be passed as parameter. Source thumbnail URL is |
428
|
|
|
|
|
|
|
an optional parameter: |
429
|
|
|
|
|
|
|
|
430
|
|
|
|
|
|
|
$img_cache->download($image_source_url, $thumbnail_source_url); |
431
|
|
|
|
|
|
|
|
432
|
|
|
|
|
|
|
Downloaded image is resized if C parameter present. Thumbnail is |
433
|
|
|
|
|
|
|
resized as specified by C C parameter. |
434
|
|
|
|
|
|
|
|
435
|
|
|
|
|
|
|
When C configuration parameter is not set to True value, image |
436
|
|
|
|
|
|
|
will be downloaded into cache only if image is not already cached or if |
437
|
|
|
|
|
|
|
cached image has a later modification date than source image. |
438
|
|
|
|
|
|
|
|
439
|
|
|
|
|
|
|
=cut |
440
|
|
|
|
|
|
|
|
441
|
|
|
|
|
|
|
sub download ($$) { |
442
|
|
|
|
|
|
|
my ($self, $item, $img_src_url, $thm_src_url) = @_; |
443
|
|
|
|
|
|
|
|
444
|
|
|
|
|
|
|
my $fnm_key = $self->{filename_key} || ''; |
445
|
|
|
|
|
|
|
my $base_fnm = $fnm_key ? treat_filename($item->get($fnm_key)) |
446
|
|
|
|
|
|
|
: get_filename($img_src_url); |
447
|
|
|
|
|
|
|
my $img_fnm = $img_src_url ? $base_fnm.'_img.jpeg' : ''; |
448
|
|
|
|
|
|
|
my $img_src_fnm = $img_src_url ? $base_fnm.'_src.jpeg' : ''; |
449
|
|
|
|
|
|
|
|
450
|
|
|
|
|
|
|
my $user_agent = $self->{ua}; |
451
|
|
|
|
|
|
|
my $source_path = $self->{source_path}; |
452
|
|
|
|
|
|
|
my $img_cache_path = $self->{cache_path}; |
453
|
|
|
|
|
|
|
my $thm_cache_path = $self->{thumbnails}->{cache_path} || ''; |
454
|
|
|
|
|
|
|
|
455
|
|
|
|
|
|
|
## |
456
|
|
|
|
|
|
|
# Local path can be a reference to an array of paths |
457
|
|
|
|
|
|
|
# |
458
|
|
|
|
|
|
|
my $local_path=$self->{'local_path'} || ''; |
459
|
|
|
|
|
|
|
$local_path=[ $local_path ] unless ref($local_path); |
460
|
|
|
|
|
|
|
|
461
|
|
|
|
|
|
|
my $img_src_file = $source_path.$img_src_fnm; |
462
|
|
|
|
|
|
|
my $img_cache_file = $img_cache_path.$img_fnm; |
463
|
|
|
|
|
|
|
|
464
|
|
|
|
|
|
|
my ($thm_fnm, $thm_cache_file, $thm_src_file); |
465
|
|
|
|
|
|
|
if ($thm_cache_path) { |
466
|
|
|
|
|
|
|
$thm_fnm = $thm_src_url ? get_filename($thm_src_url) : $base_fnm; |
467
|
|
|
|
|
|
|
my $thm_src_fnm = $thm_fnm.'_thmsrc.jpeg'; |
468
|
|
|
|
|
|
|
$thm_fnm .= '_thm.jpeg'; |
469
|
|
|
|
|
|
|
$thm_cache_file = $thm_cache_path.$thm_fnm; |
470
|
|
|
|
|
|
|
$thm_src_file = $source_path.$thm_src_fnm; |
471
|
|
|
|
|
|
|
} |
472
|
|
|
|
|
|
|
|
473
|
|
|
|
|
|
|
# Download thumbnail if specified and resize (keep source and |
474
|
|
|
|
|
|
|
# resized images). If the file is missed in the cache, but it |
475
|
|
|
|
|
|
|
# exists in the sources and is actual -- then resizing it without |
476
|
|
|
|
|
|
|
# downloading. |
477
|
|
|
|
|
|
|
# |
478
|
|
|
|
|
|
|
my $time_now = time; |
479
|
|
|
|
|
|
|
if($thm_cache_path && $thm_src_url) { |
480
|
|
|
|
|
|
|
my $mtime_src = (stat($thm_src_file))[9]; |
481
|
|
|
|
|
|
|
my $period = $time_now - $mtime_src; |
482
|
|
|
|
|
|
|
if($period > $self->{'min_period'}) { |
483
|
|
|
|
|
|
|
if($thm_src_url !~ m/^(https?|ftp):\/\//i) { |
484
|
|
|
|
|
|
|
my $lfound; |
485
|
|
|
|
|
|
|
if($thm_src_url=~/^\// && -r $thm_src_url) { |
486
|
|
|
|
|
|
|
$lfound=1; |
487
|
|
|
|
|
|
|
copy($thm_src_url,$thm_src_file); |
488
|
|
|
|
|
|
|
} |
489
|
|
|
|
|
|
|
else { |
490
|
|
|
|
|
|
|
foreach my $lpath (@$local_path) { |
491
|
|
|
|
|
|
|
if(-r "$lpath/$thm_src_url") { |
492
|
|
|
|
|
|
|
copy("$lpath/$thm_src_url",$thm_src_file); |
493
|
|
|
|
|
|
|
$lfound=1; |
494
|
|
|
|
|
|
|
last; |
495
|
|
|
|
|
|
|
} |
496
|
|
|
|
|
|
|
} |
497
|
|
|
|
|
|
|
} |
498
|
|
|
|
|
|
|
if(!$lfound) { |
499
|
|
|
|
|
|
|
$self->throw("- seems to be a local URL and no local file ($thm_src_url)"); |
500
|
|
|
|
|
|
|
} |
501
|
|
|
|
|
|
|
} |
502
|
|
|
|
|
|
|
else { |
503
|
|
|
|
|
|
|
my $response = $user_agent->head($thm_src_url); |
504
|
|
|
|
|
|
|
if ($response->is_success) { |
505
|
|
|
|
|
|
|
my $mtime_web = convert_time($response->header('Last-Modified')); |
506
|
|
|
|
|
|
|
if ((!-r $thm_src_file) || ($mtime_src < $mtime_web) || $self->{'reload'} || $self->{'force_download'}) { |
507
|
|
|
|
|
|
|
$self->download_file($thm_src_url, $thm_src_file); |
508
|
|
|
|
|
|
|
} |
509
|
|
|
|
|
|
|
} |
510
|
|
|
|
|
|
|
else { |
511
|
|
|
|
|
|
|
if(-r $thm_src_file) { |
512
|
|
|
|
|
|
|
dprint "...error downloading thumbnail (".$response->status_line."), keeping existing source $thm_src_file"; |
513
|
|
|
|
|
|
|
} |
514
|
|
|
|
|
|
|
else { |
515
|
|
|
|
|
|
|
$self->throw("- can't get thumbnail header '$thm_src_url' - ".$response->status_line." (NETWORK)"); |
516
|
|
|
|
|
|
|
$thm_src_file = ''; |
517
|
|
|
|
|
|
|
} |
518
|
|
|
|
|
|
|
} |
519
|
|
|
|
|
|
|
} |
520
|
|
|
|
|
|
|
} |
521
|
|
|
|
|
|
|
else { |
522
|
|
|
|
|
|
|
dprint ".thumbnail source file current: $thm_src_url"; |
523
|
|
|
|
|
|
|
} |
524
|
|
|
|
|
|
|
|
525
|
|
|
|
|
|
|
# Resizing if required |
526
|
|
|
|
|
|
|
# |
527
|
|
|
|
|
|
|
if($thm_src_file) { |
528
|
|
|
|
|
|
|
my $mtime_cache=(stat($thm_cache_file))[9]; |
529
|
|
|
|
|
|
|
$mtime_src=(stat($thm_src_file))[9]; |
530
|
|
|
|
|
|
|
if($mtime_cache<=$mtime_src) { |
531
|
|
|
|
|
|
|
$self->scale_thumbnail($thm_src_file, $thm_cache_file); |
532
|
|
|
|
|
|
|
} |
533
|
|
|
|
|
|
|
} |
534
|
|
|
|
|
|
|
} |
535
|
|
|
|
|
|
|
|
536
|
|
|
|
|
|
|
# Download source image and resize (keep source and resized |
537
|
|
|
|
|
|
|
# images). Only download source image if cached image not present or |
538
|
|
|
|
|
|
|
# older than source. |
539
|
|
|
|
|
|
|
# |
540
|
|
|
|
|
|
|
if($img_src_url) { |
541
|
|
|
|
|
|
|
my $mtime_src = (stat($img_src_file))[9] || 0; |
542
|
|
|
|
|
|
|
my $period = $time_now - $mtime_src; |
543
|
|
|
|
|
|
|
if($self->{'force_download'} || $period>$self->{'min_period'}) { |
544
|
|
|
|
|
|
|
if($img_src_url !~ m/^(https?|ftp):\/\//i) { |
545
|
|
|
|
|
|
|
my $lfound; |
546
|
|
|
|
|
|
|
if($img_src_url=~/^\// && -r $img_src_url) { |
547
|
|
|
|
|
|
|
$lfound=1; |
548
|
|
|
|
|
|
|
copy($img_src_url,$img_src_file); |
549
|
|
|
|
|
|
|
} |
550
|
|
|
|
|
|
|
else { |
551
|
|
|
|
|
|
|
foreach my $lpath (@$local_path) { |
552
|
|
|
|
|
|
|
if(-r "$lpath/$img_src_url") { |
553
|
|
|
|
|
|
|
copy("$lpath/$img_src_url",$img_src_file); |
554
|
|
|
|
|
|
|
$lfound=1; |
555
|
|
|
|
|
|
|
last; |
556
|
|
|
|
|
|
|
} |
557
|
|
|
|
|
|
|
} |
558
|
|
|
|
|
|
|
} |
559
|
|
|
|
|
|
|
if(!$lfound) { |
560
|
|
|
|
|
|
|
$self->throw("- seems to be a local URL and no local file ($img_src_url)"); |
561
|
|
|
|
|
|
|
} |
562
|
|
|
|
|
|
|
} |
563
|
|
|
|
|
|
|
else { |
564
|
|
|
|
|
|
|
my $response = $user_agent->head($img_src_url); |
565
|
|
|
|
|
|
|
if ($response->is_success) { |
566
|
|
|
|
|
|
|
my $mtime_web = convert_time($response->header('Last-Modified')); |
567
|
|
|
|
|
|
|
if ((!-r $img_src_file) || ($mtime_src < $mtime_web) || $self->{'reload'} || $self->{'force_download'}) { |
568
|
|
|
|
|
|
|
$self->download_file($img_src_url, $img_src_file); |
569
|
|
|
|
|
|
|
} |
570
|
|
|
|
|
|
|
else { |
571
|
|
|
|
|
|
|
dprint ".image source file current: $img_src_url"; |
572
|
|
|
|
|
|
|
} |
573
|
|
|
|
|
|
|
} |
574
|
|
|
|
|
|
|
else { |
575
|
|
|
|
|
|
|
|
576
|
|
|
|
|
|
|
# This is here mainly for situations like this: a |
577
|
|
|
|
|
|
|
# superseded item content gets into a new item, but |
578
|
|
|
|
|
|
|
# the image URL is long gone, not accessible; we |
579
|
|
|
|
|
|
|
# have a cached copy and we use it. |
580
|
|
|
|
|
|
|
# |
581
|
|
|
|
|
|
|
if(-r $img_src_file) { |
582
|
|
|
|
|
|
|
dprint "...error downloading image (".$response->status_line."), keeping existing source $thm_src_file"; |
583
|
|
|
|
|
|
|
} |
584
|
|
|
|
|
|
|
else { |
585
|
|
|
|
|
|
|
$self->throw("- can't get image header for $img_src_url - ".$response->status_line." (NETWORK)"); |
586
|
|
|
|
|
|
|
$img_src_file = ''; |
587
|
|
|
|
|
|
|
} |
588
|
|
|
|
|
|
|
} |
589
|
|
|
|
|
|
|
} |
590
|
|
|
|
|
|
|
$mtime_src=(stat($img_src_file))[9] if $img_src_file; |
591
|
|
|
|
|
|
|
} |
592
|
|
|
|
|
|
|
|
593
|
|
|
|
|
|
|
if($img_src_file) { |
594
|
|
|
|
|
|
|
|
595
|
|
|
|
|
|
|
# Now checking if the source file we have is newer then what's in |
596
|
|
|
|
|
|
|
# the cache and updating the cache in that case. |
597
|
|
|
|
|
|
|
# |
598
|
|
|
|
|
|
|
my $mtime_cache=(stat($img_cache_file))[9] || 0; |
599
|
|
|
|
|
|
|
if($self->{'force_scale'} || $mtime_cache < $mtime_src) { |
600
|
|
|
|
|
|
|
$self->scale_large($img_src_file, $img_cache_file); |
601
|
|
|
|
|
|
|
} |
602
|
|
|
|
|
|
|
|
603
|
|
|
|
|
|
|
# Create thumbnail from the image source file if necessary |
604
|
|
|
|
|
|
|
# |
605
|
|
|
|
|
|
|
if($thm_cache_file && (!$thm_src_url || !$thm_src_file)) { |
606
|
|
|
|
|
|
|
$mtime_cache=(stat($thm_cache_file))[9] || 0; |
607
|
|
|
|
|
|
|
if($self->{'force_scale'} || $mtime_cache < $mtime_src) { |
608
|
|
|
|
|
|
|
$self->scale_thumbnail($img_src_file,$thm_cache_file); |
609
|
|
|
|
|
|
|
} |
610
|
|
|
|
|
|
|
$thm_src_file=1; # Just to mark that we have it |
611
|
|
|
|
|
|
|
} |
612
|
|
|
|
|
|
|
} |
613
|
|
|
|
|
|
|
} |
614
|
|
|
|
|
|
|
|
615
|
|
|
|
|
|
|
$img_fnm='' unless $img_src_file; |
616
|
|
|
|
|
|
|
$thm_fnm='' unless $thm_src_file; |
617
|
|
|
|
|
|
|
|
618
|
|
|
|
|
|
|
### dprint "...scaled->('$img_fnm','$thm_fnm')"; |
619
|
|
|
|
|
|
|
|
620
|
|
|
|
|
|
|
return ($img_fnm, $thm_fnm); |
621
|
|
|
|
|
|
|
} |
622
|
|
|
|
|
|
|
|
623
|
|
|
|
|
|
|
############################################################################### |
624
|
|
|
|
|
|
|
|
625
|
|
|
|
|
|
|
sub download_file { |
626
|
|
|
|
|
|
|
my $self = shift; |
627
|
|
|
|
|
|
|
my $source_url = shift; |
628
|
|
|
|
|
|
|
my $source_file = shift; |
629
|
|
|
|
|
|
|
|
630
|
|
|
|
|
|
|
dprint "DOWNLOAD ($source_url)->($source_file)"; |
631
|
|
|
|
|
|
|
|
632
|
|
|
|
|
|
|
my $response=$self->{'ua'}->get($source_url); |
633
|
|
|
|
|
|
|
my $errstr; |
634
|
|
|
|
|
|
|
if($response->is_success) { |
635
|
|
|
|
|
|
|
if($response->content_type =~ /^image\//) { |
636
|
|
|
|
|
|
|
open(F,"> $source_file.tmp") || $self->throw("- unable to save file '$source_file': $!"); |
637
|
|
|
|
|
|
|
binmode(F); |
638
|
|
|
|
|
|
|
print F $response->content; |
639
|
|
|
|
|
|
|
close(F); |
640
|
|
|
|
|
|
|
rename("$source_file.tmp",$source_file); |
641
|
|
|
|
|
|
|
} |
642
|
|
|
|
|
|
|
else { |
643
|
|
|
|
|
|
|
$errstr="downloaded '$source_url' is not an image (".$response->content_type.") (PERMANENT)"; |
644
|
|
|
|
|
|
|
} |
645
|
|
|
|
|
|
|
} |
646
|
|
|
|
|
|
|
else { |
647
|
|
|
|
|
|
|
$errstr="can't download '$source_url' - ".$response->status_line." (NETWORK)"; |
648
|
|
|
|
|
|
|
} |
649
|
|
|
|
|
|
|
|
650
|
|
|
|
|
|
|
return unless $errstr; |
651
|
|
|
|
|
|
|
|
652
|
|
|
|
|
|
|
# If the file is already there (from previous downloads then just |
653
|
|
|
|
|
|
|
# printing the error, but returning normally to let the file be scaled and |
654
|
|
|
|
|
|
|
# stored as image/thumbnail |
655
|
|
|
|
|
|
|
# |
656
|
|
|
|
|
|
|
if(-f $source_file && !$self->{'clear_on_error'}) { |
657
|
|
|
|
|
|
|
eprint "download_file: $errstr -- ignoring and keeping existing file"; |
658
|
|
|
|
|
|
|
return; |
659
|
|
|
|
|
|
|
} |
660
|
|
|
|
|
|
|
else { |
661
|
|
|
|
|
|
|
$self->throw("- $errstr"); |
662
|
|
|
|
|
|
|
} |
663
|
|
|
|
|
|
|
} |
664
|
|
|
|
|
|
|
|
665
|
|
|
|
|
|
|
############################################################################### |
666
|
|
|
|
|
|
|
|
667
|
|
|
|
|
|
|
sub scale_file ($$$$;$) { |
668
|
|
|
|
|
|
|
my ($self,$infile,$outfile,$params,$label)=@_; |
669
|
|
|
|
|
|
|
|
670
|
|
|
|
|
|
|
$label||='unknown'; |
671
|
|
|
|
|
|
|
|
672
|
|
|
|
|
|
|
if(!$params) { |
673
|
|
|
|
|
|
|
dprint "Copying $infile to $outfile as is ($label)"; |
674
|
|
|
|
|
|
|
copy($infile,$outfile); |
675
|
|
|
|
|
|
|
return; |
676
|
|
|
|
|
|
|
} |
677
|
|
|
|
|
|
|
|
678
|
|
|
|
|
|
|
my $geometry = ''; # image dimensions in ImageMagick geometry format |
679
|
|
|
|
|
|
|
|
680
|
|
|
|
|
|
|
my $image = Image::Magick->new() || $self->throw("- Image::Magick creation failure!"); |
681
|
|
|
|
|
|
|
my $err = $image->ReadImage($infile); |
682
|
|
|
|
|
|
|
### dprint ".source in '$infile'"; |
683
|
|
|
|
|
|
|
|
684
|
|
|
|
|
|
|
# Only throwing an error if no image was read. If we consider all |
685
|
|
|
|
|
|
|
# warnings as errors then some 3M tiff files don't parse. |
686
|
|
|
|
|
|
|
# |
687
|
|
|
|
|
|
|
# From http://www.imagemagick.org/script/perl-magick.php: |
688
|
|
|
|
|
|
|
# |
689
|
|
|
|
|
|
|
# $x = $image->Read(...); |
690
|
|
|
|
|
|
|
# warn "$x" if "$x"; # print the error message |
691
|
|
|
|
|
|
|
# $x =~ /(\d+)/; |
692
|
|
|
|
|
|
|
# print $1; # print the error number |
693
|
|
|
|
|
|
|
# print 0+$x; # print the number of images read |
694
|
|
|
|
|
|
|
# |
695
|
|
|
|
|
|
|
### $self->throw("- parsing error ($err) (PERMANENT)") if $err; |
696
|
|
|
|
|
|
|
(0 + $err)>0 || |
697
|
|
|
|
|
|
|
$self->throw("- parsing error ($err) (PERMANENT)"); |
698
|
|
|
|
|
|
|
|
699
|
|
|
|
|
|
|
# We only deal with image/* types -- otherwise ImageMagick can |
700
|
|
|
|
|
|
|
# sometimes successfully open and convert HTML or text messages into |
701
|
|
|
|
|
|
|
# images. |
702
|
|
|
|
|
|
|
# |
703
|
|
|
|
|
|
|
$image->Get('mime')=~/^image\// || $self->throw("- not an image file '$infile' (".$image->Get('mime').")"); |
704
|
|
|
|
|
|
|
|
705
|
|
|
|
|
|
|
# Get source image dimensions |
706
|
|
|
|
|
|
|
# |
707
|
|
|
|
|
|
|
my ($src_width, $src_height) = $image->Get('columns','rows'); |
708
|
|
|
|
|
|
|
|
709
|
|
|
|
|
|
|
my $min_width=$self->{'min_width'} || 10; |
710
|
|
|
|
|
|
|
my $min_height=$self->{'min_height'} || $min_width; |
711
|
|
|
|
|
|
|
|
712
|
|
|
|
|
|
|
if($src_height<=1 || $src_width<=1 || ($src_height<$min_height && $src_width<$min_width)) { |
713
|
|
|
|
|
|
|
$self->throw("- image ($src_width,$src_height) is smaller than the minimum ($min_width,$min_height) for '$label' (PERMANENT)"); |
714
|
|
|
|
|
|
|
} |
715
|
|
|
|
|
|
|
|
716
|
|
|
|
|
|
|
# Getting target image width and height |
717
|
|
|
|
|
|
|
# |
718
|
|
|
|
|
|
|
if($params->{'geometry'}){ |
719
|
|
|
|
|
|
|
$geometry = $params->{geometry}; # size was set as geometry string |
720
|
|
|
|
|
|
|
} |
721
|
|
|
|
|
|
|
elsif($params->{'save_aspect_ratio'}) { |
722
|
|
|
|
|
|
|
my $src_aspect=$src_width/$src_height; |
723
|
|
|
|
|
|
|
|
724
|
|
|
|
|
|
|
my $target_width=$params->{'width'} || $src_width; |
725
|
|
|
|
|
|
|
my $target_height=$params->{'height'} || $src_height; |
726
|
|
|
|
|
|
|
my $target_aspect=$target_width/$target_height; |
727
|
|
|
|
|
|
|
|
728
|
|
|
|
|
|
|
my ($width,$height); |
729
|
|
|
|
|
|
|
|
730
|
|
|
|
|
|
|
if($src_width<=$target_width && $src_height<=$target_height) { |
731
|
|
|
|
|
|
|
if(lc($image->Get('mime')) eq 'image/jpeg' && ($image->get('colorspace') || '') =~ /^s?RGB$/i) { |
732
|
|
|
|
|
|
|
copy($infile,$outfile); |
733
|
|
|
|
|
|
|
dprint "..copied ${src_width}x${src_height} as is for '$label' (jpeg, fits into ${target_width}x${target_height})"; |
734
|
|
|
|
|
|
|
return; |
735
|
|
|
|
|
|
|
} |
736
|
|
|
|
|
|
|
else { |
737
|
|
|
|
|
|
|
$width=$src_width; |
738
|
|
|
|
|
|
|
$height=$src_height; |
739
|
|
|
|
|
|
|
} |
740
|
|
|
|
|
|
|
} |
741
|
|
|
|
|
|
|
elsif($target_aspect>$src_aspect) { |
742
|
|
|
|
|
|
|
$height=$target_height; |
743
|
|
|
|
|
|
|
$width=int($height*$src_aspect+0.5); |
744
|
|
|
|
|
|
|
} |
745
|
|
|
|
|
|
|
else { |
746
|
|
|
|
|
|
|
$width=$target_width; |
747
|
|
|
|
|
|
|
$height=int($width/$src_aspect+0.5); |
748
|
|
|
|
|
|
|
} |
749
|
|
|
|
|
|
|
|
750
|
|
|
|
|
|
|
$geometry=$width.'x'.$height.'!'; |
751
|
|
|
|
|
|
|
} |
752
|
|
|
|
|
|
|
else { |
753
|
|
|
|
|
|
|
# Use given width & height as is (or image size if not set) |
754
|
|
|
|
|
|
|
$geometry = ($params->{'width'} || $src_width) .'x'. |
755
|
|
|
|
|
|
|
($params->{'height'} || $src_height).'!'; |
756
|
|
|
|
|
|
|
} |
757
|
|
|
|
|
|
|
|
758
|
|
|
|
|
|
|
# We don't support transparency and by default transparent regions |
759
|
|
|
|
|
|
|
# sometimes get translated to black. Forcing them into white. |
760
|
|
|
|
|
|
|
# |
761
|
|
|
|
|
|
|
$image->Set(background => 'white'); |
762
|
|
|
|
|
|
|
$image=$image->Flatten(); |
763
|
|
|
|
|
|
|
|
764
|
|
|
|
|
|
|
# This is required, otherwise new ImageMagick sometimes converts |
765
|
|
|
|
|
|
|
# images to CMYK colorspace for whatever reason. |
766
|
|
|
|
|
|
|
# |
767
|
|
|
|
|
|
|
# sRGB is the standard colorspace for monitors and printing, RGB |
768
|
|
|
|
|
|
|
# is an unspecified Red/Green/Blue encoding. Some images come out |
769
|
|
|
|
|
|
|
# darker when converted to RGB. |
770
|
|
|
|
|
|
|
# |
771
|
|
|
|
|
|
|
$image->Set( |
772
|
|
|
|
|
|
|
colorspace => 'sRGB', |
773
|
|
|
|
|
|
|
depth => 8, |
774
|
|
|
|
|
|
|
); |
775
|
|
|
|
|
|
|
|
776
|
|
|
|
|
|
|
# Scaling |
777
|
|
|
|
|
|
|
# |
778
|
|
|
|
|
|
|
$image->Scale(geometry => $geometry); |
779
|
|
|
|
|
|
|
|
780
|
|
|
|
|
|
|
# Stripping embedded profiles & comments. They sometimes take |
781
|
|
|
|
|
|
|
# upwards of 500kb |
782
|
|
|
|
|
|
|
# |
783
|
|
|
|
|
|
|
$image->Strip; |
784
|
|
|
|
|
|
|
|
785
|
|
|
|
|
|
|
# Writing the results |
786
|
|
|
|
|
|
|
# |
787
|
|
|
|
|
|
|
$image->Set(magick => 'JPEG'); |
788
|
|
|
|
|
|
|
$image->Set(quality => ($params->{'quality'} || 88)); |
789
|
|
|
|
|
|
|
|
790
|
|
|
|
|
|
|
my $rc=$image->Write($outfile); |
791
|
|
|
|
|
|
|
|
792
|
|
|
|
|
|
|
!"$rc" || die "Error writing scaled image: $rc"; |
793
|
|
|
|
|
|
|
|
794
|
|
|
|
|
|
|
dprint "..resized ${src_width}x${src_height} to $geometry for '$label'"; |
795
|
|
|
|
|
|
|
} |
796
|
|
|
|
|
|
|
|
797
|
|
|
|
|
|
|
############################################################################### |
798
|
|
|
|
|
|
|
|
799
|
|
|
|
|
|
|
=item scale_large($$$) |
800
|
|
|
|
|
|
|
|
801
|
|
|
|
|
|
|
Scaling image to given size. |
802
|
|
|
|
|
|
|
|
803
|
|
|
|
|
|
|
=cut |
804
|
|
|
|
|
|
|
|
805
|
|
|
|
|
|
|
sub scale_large($$$) { |
806
|
|
|
|
|
|
|
my ($self,$infile,$outfile)=@_; |
807
|
|
|
|
|
|
|
|
808
|
|
|
|
|
|
|
return $self->scale_file($infile,$outfile,$self->{'size'},'large'); |
809
|
|
|
|
|
|
|
} |
810
|
|
|
|
|
|
|
|
811
|
|
|
|
|
|
|
############################################################################### |
812
|
|
|
|
|
|
|
|
813
|
|
|
|
|
|
|
=item scale_thumbnail($$$) |
814
|
|
|
|
|
|
|
|
815
|
|
|
|
|
|
|
Creates thumbnail image from given source image. |
816
|
|
|
|
|
|
|
|
817
|
|
|
|
|
|
|
=cut |
818
|
|
|
|
|
|
|
|
819
|
|
|
|
|
|
|
sub scale_thumbnail($$$) { |
820
|
|
|
|
|
|
|
my ($self,$infile,$outfile)=@_; |
821
|
|
|
|
|
|
|
|
822
|
|
|
|
|
|
|
return $self->scale_file($infile,$outfile,$self->{'thumbnails'},'thumbnail'); |
823
|
|
|
|
|
|
|
} |
824
|
|
|
|
|
|
|
|
825
|
|
|
|
|
|
|
############################################################################### |
826
|
|
|
|
|
|
|
|
827
|
|
|
|
|
|
|
=item remove_cache($) |
828
|
|
|
|
|
|
|
|
829
|
|
|
|
|
|
|
Removing the ENTIRE cache directory from disk. |
830
|
|
|
|
|
|
|
|
831
|
|
|
|
|
|
|
Be carefully to use this method!!! |
832
|
|
|
|
|
|
|
|
833
|
|
|
|
|
|
|
Cache structure will be removed from disk completely! |
834
|
|
|
|
|
|
|
Set C parameter to True value to download |
835
|
|
|
|
|
|
|
images to cache without any conditions. |
836
|
|
|
|
|
|
|
|
837
|
|
|
|
|
|
|
=cut |
838
|
|
|
|
|
|
|
|
839
|
|
|
|
|
|
|
sub remove_cache($) { |
840
|
|
|
|
|
|
|
my $self = shift; |
841
|
|
|
|
|
|
|
rmtree($self->{'cache_path'}); |
842
|
|
|
|
|
|
|
} |
843
|
|
|
|
|
|
|
|
844
|
|
|
|
|
|
|
############################################################################### |
845
|
|
|
|
|
|
|
|
846
|
|
|
|
|
|
|
sub throw($$) { |
847
|
|
|
|
|
|
|
my ($self,$message)=@_; |
848
|
|
|
|
|
|
|
|
849
|
|
|
|
|
|
|
if($message=~/^-/) { |
850
|
|
|
|
|
|
|
(my $fname=(caller(1))[3])=~s/^.*://; |
851
|
|
|
|
|
|
|
$message=$fname." ".$message; |
852
|
|
|
|
|
|
|
} |
853
|
|
|
|
|
|
|
|
854
|
|
|
|
|
|
|
throw XAO::E::ImageCache $message; |
855
|
|
|
|
|
|
|
} |
856
|
|
|
|
|
|
|
|
857
|
|
|
|
|
|
|
############################################################################### |
858
|
|
|
|
|
|
|
|
859
|
|
|
|
|
|
|
=item get_filename($) |
860
|
|
|
|
|
|
|
|
861
|
|
|
|
|
|
|
File name generation for cached images. |
862
|
|
|
|
|
|
|
|
863
|
|
|
|
|
|
|
Source image URL should be passed. Returned file name is an MD5 digest |
864
|
|
|
|
|
|
|
of the source URL converted to Base64 string with all non alpha numeric |
865
|
|
|
|
|
|
|
characters are converted to C<_>. |
866
|
|
|
|
|
|
|
|
867
|
|
|
|
|
|
|
Example. |
868
|
|
|
|
|
|
|
|
869
|
|
|
|
|
|
|
Location: |
870
|
|
|
|
|
|
|
http://localhost/icons/medbutton.jpeg |
871
|
|
|
|
|
|
|
|
872
|
|
|
|
|
|
|
provide file name: |
873
|
|
|
|
|
|
|
4aFNA1utpmCNG2wEIF69mg.jpeg |
874
|
|
|
|
|
|
|
|
875
|
|
|
|
|
|
|
=cut |
876
|
|
|
|
|
|
|
|
877
|
|
|
|
|
|
|
# Return MD5 digest of given URL converted to Base64 |
878
|
|
|
|
|
|
|
# string with extension and |
879
|
|
|
|
|
|
|
sub get_filename($) { |
880
|
|
|
|
|
|
|
my $source = shift; |
881
|
|
|
|
|
|
|
my $url = URI->new($source); |
882
|
|
|
|
|
|
|
my $path= $url->path(); |
883
|
|
|
|
|
|
|
$path =~ /\./; |
884
|
|
|
|
|
|
|
my $file = md5_base64($source); |
885
|
|
|
|
|
|
|
return treat_filename($file); |
886
|
|
|
|
|
|
|
} |
887
|
|
|
|
|
|
|
|
888
|
|
|
|
|
|
|
############################################################################### |
889
|
|
|
|
|
|
|
|
890
|
|
|
|
|
|
|
=item treat_filename($) |
891
|
|
|
|
|
|
|
|
892
|
|
|
|
|
|
|
Makes sure only file name friendly characters are present: all non alpha |
893
|
|
|
|
|
|
|
numeric characters are converted to C<_>. |
894
|
|
|
|
|
|
|
|
895
|
|
|
|
|
|
|
=cut |
896
|
|
|
|
|
|
|
|
897
|
|
|
|
|
|
|
sub treat_filename($) { |
898
|
|
|
|
|
|
|
my $fnm = shift; |
899
|
|
|
|
|
|
|
$fnm =~ s/\W/_/gm; |
900
|
|
|
|
|
|
|
#$fnm =~ s/\//_/gm; |
901
|
|
|
|
|
|
|
#$fnm =~ s/\+/\-/gm; |
902
|
|
|
|
|
|
|
#$fnm =~ s/=/\-/gm; |
903
|
|
|
|
|
|
|
return $fnm; |
904
|
|
|
|
|
|
|
} |
905
|
|
|
|
|
|
|
|
906
|
|
|
|
|
|
|
############################################################################### |
907
|
|
|
|
|
|
|
# Convert 'Last-Modified' Date/Time in internet format |
908
|
|
|
|
|
|
|
# to seconds since epoch format |
909
|
|
|
|
|
|
|
# Wed, 21 Jan 2001 24:55:55 GMT |
910
|
|
|
|
|
|
|
sub convert_time($) { |
911
|
|
|
|
|
|
|
my $date_str = shift; |
912
|
|
|
|
|
|
|
#print "Last Modified: $date_str\n"; |
913
|
|
|
|
|
|
|
$date_str =~ s/,//; |
914
|
|
|
|
|
|
|
my @date_arr = split(/[\s+|:]/,$date_str); |
915
|
|
|
|
|
|
|
my %month = ( |
916
|
|
|
|
|
|
|
Jan => 0, Feb => 1, Mar => 2, Apr => 3, |
917
|
|
|
|
|
|
|
May => 4, Jun => 5, Jul => 6, Aug => 7, |
918
|
|
|
|
|
|
|
Sep => 8, Oct => 9, Nov => 10, Dec => 11, |
919
|
|
|
|
|
|
|
); |
920
|
|
|
|
|
|
|
my %wday = (Sun => 0, Mon => 1, Tue => 2, Wed => 3, Thu => 4, Fri => 5, Sat => 6); |
921
|
|
|
|
|
|
|
# Clearing leading zero |
922
|
|
|
|
|
|
|
$date_arr[1] =~ s/^0//; # Month days |
923
|
|
|
|
|
|
|
$date_arr[4] =~ s/^0//; # Hours |
924
|
|
|
|
|
|
|
$date_arr[5] =~ s/^0//; # Minutes |
925
|
|
|
|
|
|
|
$date_arr[6] =~ s/^0//; # Seconds |
926
|
|
|
|
|
|
|
my $time=eval { |
927
|
|
|
|
|
|
|
if ($date_arr[7] eq 'GMT') { |
928
|
|
|
|
|
|
|
Time::Local::timegm( |
929
|
|
|
|
|
|
|
$date_arr[6], |
930
|
|
|
|
|
|
|
$date_arr[5], |
931
|
|
|
|
|
|
|
$date_arr[4], |
932
|
|
|
|
|
|
|
$date_arr[1], |
933
|
|
|
|
|
|
|
$month{$date_arr[2]}, |
934
|
|
|
|
|
|
|
$date_arr[3], |
935
|
|
|
|
|
|
|
); |
936
|
|
|
|
|
|
|
} |
937
|
|
|
|
|
|
|
else{ |
938
|
|
|
|
|
|
|
Time::Local::timelocal( |
939
|
|
|
|
|
|
|
$date_arr[6], |
940
|
|
|
|
|
|
|
$date_arr[5], |
941
|
|
|
|
|
|
|
$date_arr[4], |
942
|
|
|
|
|
|
|
$date_arr[1], |
943
|
|
|
|
|
|
|
$month{$date_arr[2]}, |
944
|
|
|
|
|
|
|
$date_arr[3], |
945
|
|
|
|
|
|
|
); |
946
|
|
|
|
|
|
|
} |
947
|
|
|
|
|
|
|
}; |
948
|
|
|
|
|
|
|
return $time || 0; |
949
|
|
|
|
|
|
|
} |
950
|
|
|
|
|
|
|
|
951
|
|
|
|
|
|
|
############################################################################### |
952
|
|
|
|
|
|
|
|
953
|
|
|
|
|
|
|
1; |
954
|
|
|
|
|
|
|
|
955
|
|
|
|
|
|
|
=back |
956
|
|
|
|
|
|
|
|
957
|
|
|
|
|
|
|
=head1 CONFIGURATION PARAMETERS |
958
|
|
|
|
|
|
|
|
959
|
|
|
|
|
|
|
The set of configuration parameters contain required and optional parameters. |
960
|
|
|
|
|
|
|
|
961
|
|
|
|
|
|
|
Required parameters should be defined. Execution will be stoped if required |
962
|
|
|
|
|
|
|
parameter not present. |
963
|
|
|
|
|
|
|
|
964
|
|
|
|
|
|
|
Optional parameters just configure aditional functionality and may not present. |
965
|
|
|
|
|
|
|
|
966
|
|
|
|
|
|
|
=head2 Required parameters |
967
|
|
|
|
|
|
|
|
968
|
|
|
|
|
|
|
=over |
969
|
|
|
|
|
|
|
|
970
|
|
|
|
|
|
|
=item cache_path |
971
|
|
|
|
|
|
|
|
972
|
|
|
|
|
|
|
- Path string where the cache should be placed. |
973
|
|
|
|
|
|
|
|
974
|
|
|
|
|
|
|
May be absolute or relative from current execution directory path. |
975
|
|
|
|
|
|
|
|
976
|
|
|
|
|
|
|
For example. Set it to C<./cache> if you whant to place cache in |
977
|
|
|
|
|
|
|
C subdirectory of your script working directory. |
978
|
|
|
|
|
|
|
|
979
|
|
|
|
|
|
|
=item cache_url |
980
|
|
|
|
|
|
|
|
981
|
|
|
|
|
|
|
- complet URL (or relative location) to cached images. |
982
|
|
|
|
|
|
|
|
983
|
|
|
|
|
|
|
Place here your URL reflection of cache directory in condition with |
984
|
|
|
|
|
|
|
your HTTP server configuration. |
985
|
|
|
|
|
|
|
|
986
|
|
|
|
|
|
|
For example. Set it to C if your HTTP |
987
|
|
|
|
|
|
|
server configured for provide access to your cache directory by |
988
|
|
|
|
|
|
|
hostname C and location C. Cached images names |
989
|
|
|
|
|
|
|
will be added to image URL automaticaly. |
990
|
|
|
|
|
|
|
|
991
|
|
|
|
|
|
|
=item list |
992
|
|
|
|
|
|
|
|
993
|
|
|
|
|
|
|
- reference to C object containing the data objects |
994
|
|
|
|
|
|
|
with Image source URL |
995
|
|
|
|
|
|
|
|
996
|
|
|
|
|
|
|
Meaning, your data look like a XAO Foundation Server list of objects |
997
|
|
|
|
|
|
|
with references to images. This parameter should contain reference to |
998
|
|
|
|
|
|
|
to XAO::DO::FS::List object. This reference may be result of |
999
|
|
|
|
|
|
|
XAO::Objects->fetch() methode. |
1000
|
|
|
|
|
|
|
|
1001
|
|
|
|
|
|
|
XAO::ImageCache will process each record of this list. |
1002
|
|
|
|
|
|
|
|
1003
|
|
|
|
|
|
|
=item source_url_key |
1004
|
|
|
|
|
|
|
|
1005
|
|
|
|
|
|
|
- data key containing the URL of source image. |
1006
|
|
|
|
|
|
|
|
1007
|
|
|
|
|
|
|
Contain the name of key of data object containing the source image reference. |
1008
|
|
|
|
|
|
|
|
1009
|
|
|
|
|
|
|
=back |
1010
|
|
|
|
|
|
|
|
1011
|
|
|
|
|
|
|
=head2 Optional parameters |
1012
|
|
|
|
|
|
|
|
1013
|
|
|
|
|
|
|
=over |
1014
|
|
|
|
|
|
|
|
1015
|
|
|
|
|
|
|
=item dest_url_key |
1016
|
|
|
|
|
|
|
|
1017
|
|
|
|
|
|
|
- data key for storing URL of image in cache. |
1018
|
|
|
|
|
|
|
|
1019
|
|
|
|
|
|
|
Optional parameter cause image name in cache will be a MD5 Base64 |
1020
|
|
|
|
|
|
|
digest of source image path where C<=> character removed, C<\> and C<+> |
1021
|
|
|
|
|
|
|
translated to C<_> and C<-> simultaniosely. |
1022
|
|
|
|
|
|
|
|
1023
|
|
|
|
|
|
|
To get cached image name |
1024
|
|
|
|
|
|
|
|
1025
|
|
|
|
|
|
|
=item size |
1026
|
|
|
|
|
|
|
|
1027
|
|
|
|
|
|
|
- Prefered image size may set as C equal to C parameter |
1028
|
|
|
|
|
|
|
of Image::Magick module to pass it dirrectly to Image::Magick Scale function. |
1029
|
|
|
|
|
|
|
|
1030
|
|
|
|
|
|
|
Other way to set the image size is set a width and height keys to preffered |
1031
|
|
|
|
|
|
|
values. |
1032
|
|
|
|
|
|
|
|
1033
|
|
|
|
|
|
|
If one of image dimension is not defined then corresponding parameter of |
1034
|
|
|
|
|
|
|
original image will be used. |
1035
|
|
|
|
|
|
|
|
1036
|
|
|
|
|
|
|
This way, image will be resized with same aspect ratio (same proportions) to |
1037
|
|
|
|
|
|
|
the original image if C parameter present. |
1038
|
|
|
|
|
|
|
|
1039
|
|
|
|
|
|
|
Image width and height will be resized exactly to given size if |
1040
|
|
|
|
|
|
|
C parameter not present. |
1041
|
|
|
|
|
|
|
|
1042
|
|
|
|
|
|
|
Parameter C has higher priority and other parameters has no effects |
1043
|
|
|
|
|
|
|
if C peresent. |
1044
|
|
|
|
|
|
|
|
1045
|
|
|
|
|
|
|
For example. |
1046
|
|
|
|
|
|
|
|
1047
|
|
|
|
|
|
|
# Size 320x200 as geometry settings |
1048
|
|
|
|
|
|
|
%params = (size => {geometry => "320x200!"} ); |
1049
|
|
|
|
|
|
|
|
1050
|
|
|
|
|
|
|
# Size 320x200 as dimensions settings |
1051
|
|
|
|
|
|
|
%params = (size => {width => 320, height => 200} ); |
1052
|
|
|
|
|
|
|
|
1053
|
|
|
|
|
|
|
# Fit size into 320x200 with saving image proportions |
1054
|
|
|
|
|
|
|
%params = ( |
1055
|
|
|
|
|
|
|
size => { |
1056
|
|
|
|
|
|
|
width => 320, |
1057
|
|
|
|
|
|
|
height => 200, |
1058
|
|
|
|
|
|
|
save_aspect_ratio => 1, |
1059
|
|
|
|
|
|
|
} |
1060
|
|
|
|
|
|
|
); |
1061
|
|
|
|
|
|
|
|
1062
|
|
|
|
|
|
|
=item autocreate |
1063
|
|
|
|
|
|
|
|
1064
|
|
|
|
|
|
|
- create or check cache content automaticaly. |
1065
|
|
|
|
|
|
|
|
1066
|
|
|
|
|
|
|
If non zero value present, cache directory will be created |
1067
|
|
|
|
|
|
|
and images checking will be runned. Otherwithe you should run |
1068
|
|
|
|
|
|
|
init() and check() methodes manualy. |
1069
|
|
|
|
|
|
|
|
1070
|
|
|
|
|
|
|
Existent cache directory will not be removed. You may do it |
1071
|
|
|
|
|
|
|
manualy using remove_cache() methode. |
1072
|
|
|
|
|
|
|
|
1073
|
|
|
|
|
|
|
=item force_download |
1074
|
|
|
|
|
|
|
|
1075
|
|
|
|
|
|
|
- each image should be reloaded to cache and processed without |
1076
|
|
|
|
|
|
|
dependance of source image modification time. Any conditions |
1077
|
|
|
|
|
|
|
ignored. |
1078
|
|
|
|
|
|
|
|
1079
|
|
|
|
|
|
|
=item thumbnail |
1080
|
|
|
|
|
|
|
|
1081
|
|
|
|
|
|
|
- thumbnails creator configuration |
1082
|
|
|
|
|
|
|
|
1083
|
|
|
|
|
|
|
Some thubnails configuration parameters may be set for |
1084
|
|
|
|
|
|
|
automatic thumbnails creation. This parameter should contain |
1085
|
|
|
|
|
|
|
the reference to hash with thumbnails configuration parameters. |
1086
|
|
|
|
|
|
|
|
1087
|
|
|
|
|
|
|
Only C parameter is required. Other parameters are |
1088
|
|
|
|
|
|
|
optional. |
1089
|
|
|
|
|
|
|
|
1090
|
|
|
|
|
|
|
=over |
1091
|
|
|
|
|
|
|
|
1092
|
|
|
|
|
|
|
=item path |
1093
|
|
|
|
|
|
|
|
1094
|
|
|
|
|
|
|
path where thumbnail images should be placed. |
1095
|
|
|
|
|
|
|
|
1096
|
|
|
|
|
|
|
=item url |
1097
|
|
|
|
|
|
|
|
1098
|
|
|
|
|
|
|
URL for access to thumbnails directory. Same way as C. |
1099
|
|
|
|
|
|
|
|
1100
|
|
|
|
|
|
|
=item url_key |
1101
|
|
|
|
|
|
|
|
1102
|
|
|
|
|
|
|
Data object key name where thumbnail URL should be stored. |
1103
|
|
|
|
|
|
|
|
1104
|
|
|
|
|
|
|
=item geometry |
1105
|
|
|
|
|
|
|
|
1106
|
|
|
|
|
|
|
Geometry string to set thumbnail images size in Image Magick geometry |
1107
|
|
|
|
|
|
|
format. May be set as dimension ("320x200!") or as persent of actual |
1108
|
|
|
|
|
|
|
size of cached image ("25%"). |
1109
|
|
|
|
|
|
|
|
1110
|
|
|
|
|
|
|
Default value is "50%" the half of actual image size. |
1111
|
|
|
|
|
|
|
|
1112
|
|
|
|
|
|
|
=back |
1113
|
|
|
|
|
|
|
|
1114
|
|
|
|
|
|
|
=item useragent |
1115
|
|
|
|
|
|
|
|
1116
|
|
|
|
|
|
|
- configuration parameters hash for LWP::UserAgent |
1117
|
|
|
|
|
|
|
|
1118
|
|
|
|
|
|
|
=over |
1119
|
|
|
|
|
|
|
|
1120
|
|
|
|
|
|
|
=item agent |
1121
|
|
|
|
|
|
|
|
1122
|
|
|
|
|
|
|
Default value C |
1123
|
|
|
|
|
|
|
|
1124
|
|
|
|
|
|
|
=item env_proxy |
1125
|
|
|
|
|
|
|
|
1126
|
|
|
|
|
|
|
Default value 1 |
1127
|
|
|
|
|
|
|
|
1128
|
|
|
|
|
|
|
=item keep_alive |
1129
|
|
|
|
|
|
|
|
1130
|
|
|
|
|
|
|
Default value 1 |
1131
|
|
|
|
|
|
|
|
1132
|
|
|
|
|
|
|
=item timeout |
1133
|
|
|
|
|
|
|
|
1134
|
|
|
|
|
|
|
Default value 30 |
1135
|
|
|
|
|
|
|
|
1136
|
|
|
|
|
|
|
=back |
1137
|
|
|
|
|
|
|
|
1138
|
|
|
|
|
|
|
For more information please follow to L |
1139
|
|
|
|
|
|
|
|
1140
|
|
|
|
|
|
|
=back |
1141
|
|
|
|
|
|
|
|
1142
|
|
|
|
|
|
|
=head1 SEE ALSO |
1143
|
|
|
|
|
|
|
|
1144
|
|
|
|
|
|
|
Specifics of List API can be found in |
1145
|
|
|
|
|
|
|
|
1146
|
|
|
|
|
|
|
L. |
1147
|
|
|
|
|
|
|
|
1148
|
|
|
|
|
|
|
For additional information please see |
1149
|
|
|
|
|
|
|
|
1150
|
|
|
|
|
|
|
L, |
1151
|
|
|
|
|
|
|
|
1152
|
|
|
|
|
|
|
L, |
1153
|
|
|
|
|
|
|
|
1154
|
|
|
|
|
|
|
L, |
1155
|
|
|
|
|
|
|
|
1156
|
|
|
|
|
|
|
Refer to L documentation for additional |
1157
|
|
|
|
|
|
|
information about setting of image scaling parameters. |
1158
|
|
|
|
|
|
|
|
1159
|
|
|
|
|
|
|
Refer to L documentation for additional |
1160
|
|
|
|
|
|
|
information about user agent parameters. |
1161
|
|
|
|
|
|
|
|
1162
|
|
|
|
|
|
|
=head1 BUGS |
1163
|
|
|
|
|
|
|
|
1164
|
|
|
|
|
|
|
Please, inform me about found bugs. |
1165
|
|
|
|
|
|
|
|
1166
|
|
|
|
|
|
|
=head1 AUTHORS |
1167
|
|
|
|
|
|
|
|
1168
|
|
|
|
|
|
|
The XAO::ImageCache package maintained by |
1169
|
|
|
|
|
|
|
Konstantin Safronov . Specification by |
1170
|
|
|
|
|
|
|
Andrew Maltsew |
1171
|
|
|
|
|
|
|
|
1172
|
|
|
|
|
|
|
=cut |