blib/lib/Apache/Gallery.pm | |||
---|---|---|---|
Criterion | Covered | Total | % |
statement | 8 | 25 | 32.0 |
branch | 1 | 4 | 25.0 |
condition | 1 | 6 | 16.6 |
subroutine | 3 | 3 | 100.0 |
pod | n/a | ||
total | 13 | 38 | 34.2 |
line | stmt | bran | cond | sub | pod | time | code |
---|---|---|---|---|---|---|---|
1 | package Apache::Gallery; | ||||||
2 | |||||||
3 | # $Author: mil $ $Rev: 335 $ | ||||||
4 | # $Date: 2011-06-08 20:47:46 +0200 (Wed, 08 Jun 2011) $ | ||||||
5 | |||||||
6 | 6 | 6 | 75293 | use strict; | |||
6 | 12 | ||||||
6 | 361 | ||||||
7 | |||||||
8 | 6 | 6 | 33 | use vars qw($VERSION); | |||
6 | 11 | ||||||
6 | 1552 | ||||||
9 | |||||||
10 | $VERSION = "1.0.2"; | ||||||
11 | |||||||
12 | BEGIN { | ||||||
13 | |||||||
14 | 6 | 50 | 33 | 6 | 46 | if (exists($ENV{MOD_PERL_API_VERSION}) | |
15 | and ($ENV{MOD_PERL_API_VERSION}==2)) { | ||||||
16 | 0 | 0 | require mod_perl2; | ||||
17 | 0 | 0 | 0 | 0 | if ($mod_perl::VERSION >= 1.99 && $mod_perl::VERSION < 2.0) { | ||
18 | 0 | 0 | die "mod_perl 2.0.0 or later is now required"; | ||||
19 | } | ||||||
20 | 0 | 0 | require Apache2::ServerRec; | ||||
21 | 0 | 0 | require Apache2::RequestRec; | ||||
22 | 0 | 0 | require Apache2::Log; | ||||
23 | 0 | 0 | require APR::Table; | ||||
24 | 0 | 0 | require Apache2::RequestIO; | ||||
25 | 0 | 0 | require Apache2::SubRequest; | ||||
26 | 0 | 0 | require Apache2::Const; | ||||
27 | |||||||
28 | 0 | 0 | Apache2::Const->import(-compile => 'OK','DECLINED','FORBIDDEN','NOT_FOUND','HTTP_NOT_MODIFIED'); | ||||
29 | |||||||
30 | 0 | 0 | $::MP2 = 1; | ||||
31 | } else { | ||||||
32 | 6 | 8912 | require mod_perl; | ||||
33 | |||||||
34 | 0 | require Apache; | |||||
35 | 0 | require Apache::Constants; | |||||
36 | 0 | require Apache::Request; | |||||
37 | |||||||
38 | 0 | Apache::Constants->import('OK','DECLINED','FORBIDDEN','NOT_FOUND'); | |||||
39 | 0 | $::MP2 = 0; | |||||
40 | } | ||||||
41 | } | ||||||
42 | |||||||
43 | use Image::Info qw(image_info); | ||||||
44 | use Image::Size qw(imgsize); | ||||||
45 | use Image::Imlib2; | ||||||
46 | use Text::Template; | ||||||
47 | use File::stat; | ||||||
48 | use File::Spec; | ||||||
49 | use POSIX qw(floor); | ||||||
50 | use URI::Escape; | ||||||
51 | use CGI; | ||||||
52 | use CGI::Cookie; | ||||||
53 | use Encode; | ||||||
54 | use HTTP::Date; | ||||||
55 | use Digest::MD5 qw(md5_base64); | ||||||
56 | |||||||
57 | use Data::Dumper; | ||||||
58 | |||||||
59 | # Regexp for escaping URI's | ||||||
60 | my $escape_rule = "^A-Za-z0-9\-_.!~*'()\/"; | ||||||
61 | my $memoized; | ||||||
62 | |||||||
63 | sub handler { | ||||||
64 | |||||||
65 | my $r = shift or Apache2::RequestUtil->request(); | ||||||
66 | |||||||
67 | unless (($r->method eq 'HEAD') or ($r->method eq 'GET')) { | ||||||
68 | return $::MP2 ? Apache2::Const::DECLINED() : Apache::Constants::DECLINED(); | ||||||
69 | } | ||||||
70 | |||||||
71 | if ((not $memoized) and ($r->dir_config('GalleryMemoize'))) { | ||||||
72 | require Memoize; | ||||||
73 | Memoize::memoize('get_imageinfo'); | ||||||
74 | $memoized=1; | ||||||
75 | } | ||||||
76 | |||||||
77 | $r->headers_out->{"X-Powered-By"} = "apachegallery.dk $VERSION - Hest design!"; | ||||||
78 | $r->headers_out->{"X-Gallery-Version"} = '$Rev: 335 $ $Date: 2011-06-08 20:47:46 +0200 (Wed, 08 Jun 2011) $'; | ||||||
79 | |||||||
80 | my $filename = $r->filename; | ||||||
81 | $filename =~ s/\/$//; | ||||||
82 | my $topdir = $filename; | ||||||
83 | |||||||
84 | my $media_rss_enabled = $r->dir_config('GalleryEnableMediaRss'); | ||||||
85 | |||||||
86 | # Just return the http headers if the client requested that | ||||||
87 | if ($r->header_only) { | ||||||
88 | |||||||
89 | if (!$::MP2) { | ||||||
90 | $r->send_http_header; | ||||||
91 | } | ||||||
92 | |||||||
93 | if (-f $filename or -d $filename) { | ||||||
94 | return $::MP2 ? Apache2::Const::OK() : Apache::Constants::OK(); | ||||||
95 | } | ||||||
96 | else { | ||||||
97 | return $::MP2 ? Apache2::Const::NOT_FOUND() : Apache::Constants::NOT_FOUND(); | ||||||
98 | } | ||||||
99 | } | ||||||
100 | |||||||
101 | my $cgi = new CGI; | ||||||
102 | |||||||
103 | # Handle selected images | ||||||
104 | if ($cgi->param('selection')) { | ||||||
105 | my @selected = $cgi->param('selection'); | ||||||
106 | my $content = join " \n",@selected; |
||||||
107 | $r->content_type('text/html'); | ||||||
108 | $r->headers_out->{'Content-Length'} = length($content); | ||||||
109 | |||||||
110 | if (!$::MP2) { | ||||||
111 | $r->send_http_header; | ||||||
112 | } | ||||||
113 | |||||||
114 | $r->print($content); | ||||||
115 | return $::MP2 ? Apache2::Const::OK() : Apache::Constants::OK(); | ||||||
116 | } | ||||||
117 | |||||||
118 | # Selectmode providing checkboxes beside all thumbnails | ||||||
119 | my $select_mode = $cgi->param('select'); | ||||||
120 | |||||||
121 | # Let Apache serve icons without us modifying the request | ||||||
122 | if ($r->uri =~ m/^\/icons/i) { | ||||||
123 | return $::MP2 ? Apache2::Const::DECLINED() : Apache::Constants::DECLINED(); | ||||||
124 | } | ||||||
125 | # Lookup the file in the cache and scale the image if the cached | ||||||
126 | # image does not exist | ||||||
127 | if ($r->uri =~ m/\.cache\//i) { | ||||||
128 | |||||||
129 | my $filename = $r->filename().$r->path_info(); | ||||||
130 | $filename =~ s/\.cache//; | ||||||
131 | |||||||
132 | $filename =~ m/\/(\d+)x(\d+)\-/; | ||||||
133 | my $image_width = $1; | ||||||
134 | my $image_height = $2; | ||||||
135 | |||||||
136 | $filename =~ s/\/(\d+)x(\d+)\-//; | ||||||
137 | |||||||
138 | my ($width, $height, $type) = imgsize($filename); | ||||||
139 | |||||||
140 | my $imageinfo = get_imageinfo($r, $filename, $type, $width, $height); | ||||||
141 | |||||||
142 | my $cached = scale_picture($r, $filename, $image_width, $image_height, $imageinfo); | ||||||
143 | |||||||
144 | my $file = cache_dir($r, 0); | ||||||
145 | $file =~ s/\.cache//; | ||||||
146 | |||||||
147 | my $subr = $r->lookup_file($file); | ||||||
148 | $r->content_type($subr->content_type()); | ||||||
149 | |||||||
150 | if ($::MP2) { | ||||||
151 | my $fileinfo = stat($file); | ||||||
152 | |||||||
153 | my $nonce = md5_base64($fileinfo->ino.$fileinfo->mtime); | ||||||
154 | if ($r->headers_in->{"If-None-Match"} eq $nonce) { | ||||||
155 | return Apache2::Const::HTTP_NOT_MODIFIED(); | ||||||
156 | } | ||||||
157 | |||||||
158 | if ($r->headers_in->{"If-Modified-Since"} && str2time($r->headers_in->{"If-Modified-Since"}) < $fileinfo->mtime) { | ||||||
159 | return Apache2::Const::HTTP_NOT_MODIFIED(); | ||||||
160 | } | ||||||
161 | |||||||
162 | $r->headers_out->{"Content-Length"} = $fileinfo->size; | ||||||
163 | $r->headers_out->{"Last-Modified-Date"} = time2str($fileinfo->mtime); | ||||||
164 | $r->headers_out->{"ETag"} = $nonce; | ||||||
165 | $r->sendfile($file); | ||||||
166 | return Apache2::Const::OK(); | ||||||
167 | } | ||||||
168 | else { | ||||||
169 | $r->path_info(''); | ||||||
170 | $r->filename($file); | ||||||
171 | return Apache::Constants::DECLINED(); | ||||||
172 | } | ||||||
173 | |||||||
174 | } | ||||||
175 | |||||||
176 | my $uri = $r->uri; | ||||||
177 | $uri =~ s/\/$//; | ||||||
178 | |||||||
179 | unless (-f $filename or -d $filename) { | ||||||
180 | show_error($r, 404, "404!", "No such file or directory: ".uri_escape($r->uri, $escape_rule)); | ||||||
181 | return $::MP2 ? Apache2::Const::OK() : Apache::Constants::OK(); | ||||||
182 | } | ||||||
183 | |||||||
184 | my $doc_pattern = $r->dir_config('GalleryDocFile'); | ||||||
185 | unless ($doc_pattern) { | ||||||
186 | $doc_pattern = '\.(mpe?g|avi|mov|asf|wmv|doc|mp3|ogg|pdf|rtf|wav|dlt|txt|html?|csv|eps)$' | ||||||
187 | } | ||||||
188 | my $img_pattern = $r->dir_config('GalleryImgFile'); | ||||||
189 | unless ($img_pattern) { | ||||||
190 | $img_pattern = '\.(jpe?g|png|tiff?|ppm)$' | ||||||
191 | } | ||||||
192 | |||||||
193 | # Let Apache serve files we don't know how to handle anyway | ||||||
194 | if (-f $filename && $filename !~ m/$img_pattern/i) { | ||||||
195 | return $::MP2 ? Apache2::Const::DECLINED() : Apache::Constants::DECLINED(); | ||||||
196 | } | ||||||
197 | |||||||
198 | if (-d $filename) { | ||||||
199 | |||||||
200 | unless (-d cache_dir($r, 0)) { | ||||||
201 | unless (create_cache($r, cache_dir($r, 0))) { | ||||||
202 | return $::MP2 ? Apache2::Const::OK() : Apache::Constants::OK(); | ||||||
203 | } | ||||||
204 | } | ||||||
205 | |||||||
206 | my $tpl_dir = $r->dir_config('GalleryTemplateDir'); | ||||||
207 | |||||||
208 | # Instead of reading the templates every single time | ||||||
209 | # we need them, create a hash of template names and | ||||||
210 | # the associated Text::Template objects. | ||||||
211 | my %templates = create_templates({layout => "$tpl_dir/layout.tpl", | ||||||
212 | index => "$tpl_dir/index.tpl", | ||||||
213 | directory => "$tpl_dir/directory.tpl", | ||||||
214 | picture => "$tpl_dir/picture.tpl", | ||||||
215 | file => "$tpl_dir/file.tpl", | ||||||
216 | comment => "$tpl_dir/dircomment.tpl", | ||||||
217 | nocomment => "$tpl_dir/nodircomment.tpl", | ||||||
218 | rss => "$tpl_dir/rss.tpl", | ||||||
219 | rss_item => "$tpl_dir/rss_item.tpl", | ||||||
220 | navdirectory => "$tpl_dir/navdirectory.tpl", | ||||||
221 | }); | ||||||
222 | |||||||
223 | |||||||
224 | |||||||
225 | |||||||
226 | my %tpl_vars; | ||||||
227 | |||||||
228 | $tpl_vars{TITLE} = "Index of: $uri"; | ||||||
229 | |||||||
230 | if ($media_rss_enabled) { | ||||||
231 | # Put the RSS feed on all directory listings | ||||||
232 | $tpl_vars{META} = ''; | ||||||
233 | } | ||||||
234 | |||||||
235 | unless (opendir (DIR, $filename)) { | ||||||
236 | show_error ($r, 500, $!, "Unable to access directory $filename: $!"); | ||||||
237 | return $::MP2 ? Apache2::Const::OK() : Apache::Constants::OK(); | ||||||
238 | } | ||||||
239 | |||||||
240 | $tpl_vars{MENU} = generate_menu($r); | ||||||
241 | |||||||
242 | $tpl_vars{FORM_BEGIN} = $select_mode?' | ||||||
243 | $tpl_vars{FORM_END} = $select_mode?'':''; | ||||||
244 | |||||||
245 | # Read, sort, and filter files | ||||||
246 | my @files = grep { !/^\./ && -f "$filename/$_" } readdir (DIR); | ||||||
247 | |||||||
248 | @files=gallerysort($r, @files); | ||||||
249 | |||||||
250 | my @downloadable_files; | ||||||
251 | |||||||
252 | if (@files) { | ||||||
253 | # Remove unwanted files from list | ||||||
254 | my @new_files = (); | ||||||
255 | foreach my $picture (@files) { | ||||||
256 | |||||||
257 | my $file = $topdir."/".$picture; | ||||||
258 | |||||||
259 | if ($file =~ /$img_pattern/i) { | ||||||
260 | push (@new_files, $picture); | ||||||
261 | } | ||||||
262 | |||||||
263 | if ($file =~ /$doc_pattern/i) { | ||||||
264 | push (@downloadable_files, $picture); | ||||||
265 | } | ||||||
266 | |||||||
267 | } | ||||||
268 | @files = @new_files; | ||||||
269 | } | ||||||
270 | |||||||
271 | # Read and sort directories | ||||||
272 | rewinddir (DIR); | ||||||
273 | my @directories = grep { !/^\./ && -d "$filename/$_" } readdir (DIR); | ||||||
274 | my $dirsortby; | ||||||
275 | if (defined($r->dir_config('GalleryDirSortBy'))) { | ||||||
276 | $dirsortby=$r->dir_config('GalleryDirSortBy'); | ||||||
277 | } else { | ||||||
278 | $dirsortby=$r->dir_config('GallerySortBy'); | ||||||
279 | } | ||||||
280 | if ($dirsortby && $dirsortby =~ m/^(size|atime|mtime|ctime)$/) { | ||||||
281 | @directories = map(/^\d+ (.*)/, sort map(stat("$filename/$_")->$dirsortby()." $_", @directories)); | ||||||
282 | } else { | ||||||
283 | @directories = sort @directories; | ||||||
284 | } | ||||||
285 | |||||||
286 | closedir(DIR); | ||||||
287 | |||||||
288 | |||||||
289 | # Combine directories and files to one listing | ||||||
290 | my @listing; | ||||||
291 | push (@listing, @directories); | ||||||
292 | push (@listing, @files); | ||||||
293 | push (@listing, @downloadable_files); | ||||||
294 | |||||||
295 | if (@listing) { | ||||||
296 | |||||||
297 | my $filelist; | ||||||
298 | |||||||
299 | my $file_counter = 0; | ||||||
300 | my $start_at = 1; | ||||||
301 | my $max_files = $r->dir_config('GalleryMaxThumbnailsPerPage'); | ||||||
302 | |||||||
303 | if (defined($cgi->param('start'))) { | ||||||
304 | $start_at = $cgi->param('start'); | ||||||
305 | if ($start_at < 1) { | ||||||
306 | $start_at = 1; | ||||||
307 | } | ||||||
308 | } | ||||||
309 | |||||||
310 | my $browse_links = ""; | ||||||
311 | if (defined($max_files)) { | ||||||
312 | |||||||
313 | for (my $i=1; $i<=scalar(@listing); $i++) { | ||||||
314 | |||||||
315 | my $from = $i; | ||||||
316 | |||||||
317 | my $to = $i+$max_files-1; | ||||||
318 | if ($to > scalar(@listing)) { | ||||||
319 | $to = scalar(@listing); | ||||||
320 | } | ||||||
321 | |||||||
322 | if ($start_at < $from || $start_at > $to) { | ||||||
323 | $browse_links .= "$from - ".$to." "; | ||||||
324 | } | ||||||
325 | else { | ||||||
326 | $browse_links .= "$from - $to "; | ||||||
327 | } | ||||||
328 | |||||||
329 | $i+=$max_files-1; | ||||||
330 | |||||||
331 | } | ||||||
332 | |||||||
333 | } | ||||||
334 | |||||||
335 | $tpl_vars{BROWSELINKS} = $browse_links; | ||||||
336 | |||||||
337 | DIRLOOP: | ||||||
338 | foreach my $file (@listing) { | ||||||
339 | |||||||
340 | $file_counter++; | ||||||
341 | |||||||
342 | if ($file_counter < $start_at) { | ||||||
343 | next; | ||||||
344 | } | ||||||
345 | |||||||
346 | if (defined($max_files) && $file_counter > $max_files+$start_at-1) { | ||||||
347 | last DIRLOOP; | ||||||
348 | } | ||||||
349 | |||||||
350 | my $thumbfilename = $topdir."/".$file; | ||||||
351 | |||||||
352 | my $fileurl = $uri."/".$file; | ||||||
353 | |||||||
354 | # Debian bug #619625 |
||||||
355 | if (-d $thumbfilename && ! -e $thumbfilename . ".ignore") { | ||||||
356 | my $dirtitle = ''; | ||||||
357 | if (-e $thumbfilename . ".folder") { | ||||||
358 | $dirtitle = get_filecontent($thumbfilename . ".folder"); | ||||||
359 | } | ||||||
360 | |||||||
361 | $dirtitle = $dirtitle ? $dirtitle : $file; | ||||||
362 | $dirtitle =~ s/_/ /g if $r->dir_config('GalleryUnderscoresToSpaces'); | ||||||
363 | |||||||
364 | $tpl_vars{FILES} .= | ||||||
365 | $templates{directory}->fill_in(HASH=> {FILEURL => uri_escape($fileurl, $escape_rule), | ||||||
366 | FILE => $dirtitle, | ||||||
367 | } | ||||||
368 | ); | ||||||
369 | |||||||
370 | } | ||||||
371 | # Debian bug #619625 |
||||||
372 | elsif (-f $thumbfilename && $thumbfilename =~ /$doc_pattern/i && $thumbfilename !~ /$img_pattern/i && ! -e $thumbfilename . ".ignore") { | ||||||
373 | my $type = lc($1); | ||||||
374 | my $stat = stat($thumbfilename); | ||||||
375 | my $size = $stat->size; | ||||||
376 | my $filetype; | ||||||
377 | |||||||
378 | if ($thumbfilename =~ m/\.(mpe?g|avi|mov|asf|wmv)$/i) { | ||||||
379 | $filetype = "video-$type"; | ||||||
380 | } elsif ($thumbfilename =~ m/\.(txt|html?)$/i) { | ||||||
381 | $filetype = "text-$type"; | ||||||
382 | } elsif ($thumbfilename =~ m/\.(mp3|ogg|wav)$/i) { | ||||||
383 | $filetype = "sound-$type"; | ||||||
384 | } elsif ($thumbfilename =~ m/$doc_pattern/i) { | ||||||
385 | $filetype = "application-$type"; | ||||||
386 | } else { | ||||||
387 | $filetype = "unknown"; | ||||||
388 | } | ||||||
389 | |||||||
390 | # Debian bug #348724 |
||||||
391 | # not images | ||||||
392 | my $filetitle = $file; | ||||||
393 | $filetitle =~ s/_/ /g if $r->dir_config('GalleryUnderscoresToSpaces'); | ||||||
394 | |||||||
395 | $tpl_vars{FILES} .= | ||||||
396 | $templates{file}->fill_in(HASH => {%tpl_vars, | ||||||
397 | FILEURL => uri_escape($fileurl, $escape_rule), | ||||||
398 | ALT => "Size: $size Bytes", | ||||||
399 | FILE => $filetitle, | ||||||
400 | TYPE => $type, | ||||||
401 | FILETYPE => $filetype, | ||||||
402 | } | ||||||
403 | ); | ||||||
404 | } | ||||||
405 | # Debian bug #619625 |
||||||
406 | elsif (-f $thumbfilename && ! -e $thumbfilename . ".ignore") { | ||||||
407 | |||||||
408 | my ($width, $height, $type) = imgsize($thumbfilename); | ||||||
409 | next if $type eq 'Data stream is not a known image file format'; | ||||||
410 | |||||||
411 | my @filetypes = qw(JPG TIF PNG PPM GIF); | ||||||
412 | |||||||
413 | next unless (grep $type eq $_, @filetypes); | ||||||
414 | my ($thumbnailwidth, $thumbnailheight) = get_thumbnailsize($r, $width, $height); | ||||||
415 | my $imageinfo = get_imageinfo($r, $thumbfilename, $type, $width, $height); | ||||||
416 | my $cached = get_scaled_picture_name($thumbfilename, $thumbnailwidth, $thumbnailheight); | ||||||
417 | |||||||
418 | my $rotate = readfile_getnum($r, $imageinfo, $thumbfilename.".rotate"); | ||||||
419 | |||||||
420 | # Debian bug #348724 |
||||||
421 | # HTML |
||||||
422 | my $filetitle = $file; | ||||||
423 | $filetitle =~ s/_/ /g if $r->dir_config('GalleryUnderscoresToSpaces'); | ||||||
424 | |||||||
425 | my %file_vars = (FILEURL => uri_escape($fileurl, $escape_rule), | ||||||
426 | FILE => $filetitle, | ||||||
427 | DATE => $imageinfo->{DateTimeOriginal} ? $imageinfo->{DateTimeOriginal} : '', # should this really be a stat of the file instead of ''? | ||||||
428 | SRC => uri_escape($uri."/.cache/$cached", $escape_rule), | ||||||
429 | HEIGHT => (grep($rotate==$_, (1, 3)) ? $thumbnailwidth : $thumbnailheight), | ||||||
430 | WIDTH => (grep($rotate==$_, (1, 3)) ? $thumbnailheight : $thumbnailwidth), | ||||||
431 | SELECT => $select_mode?' ':'',); | ||||||
432 | $tpl_vars{FILES} .= $templates{picture}->fill_in(HASH => {%tpl_vars, | ||||||
433 | %file_vars, | ||||||
434 | }, | ||||||
435 | ); | ||||||
436 | |||||||
437 | if ($media_rss_enabled) { | ||||||
438 | my ($content_image_width, undef, $content_image_height) = get_image_display_size($cgi, $r, $width, $height); | ||||||
439 | my %item_vars = ( | ||||||
440 | THUMBNAIL => uri_escape($uri."/.cache/$cached", $escape_rule), | ||||||
441 | LINK => uri_escape($fileurl, $escape_rule), | ||||||
442 | TITLE => $file, | ||||||
443 | CONTENT => uri_escape($uri."/.cache/".$content_image_width."x".$content_image_height."-".$file, $escape_rule) | ||||||
444 | ); | ||||||
445 | $tpl_vars{ITEMS} .= $templates{rss_item}->fill_in(HASH => { | ||||||
446 | %item_vars | ||||||
447 | }); | ||||||
448 | } | ||||||
449 | } | ||||||
450 | } | ||||||
451 | } | ||||||
452 | else { | ||||||
453 | $tpl_vars{FILES} = "No files found"; | ||||||
454 | $tpl_vars{BROWSELINKS} = ""; | ||||||
455 | } | ||||||
456 | |||||||
457 | # Generate prev and next directory menu items | ||||||
458 | $filename =~ m/(.*)\/.*?$/; | ||||||
459 | my $parent_filename = $1; | ||||||
460 | |||||||
461 | $r->document_root =~ m/(.*)\/$/; | ||||||
462 | my $root_path = $1; | ||||||
463 | print STDERR "$filename vs $root_path\n"; | ||||||
464 | if ($filename ne $root_path) { | ||||||
465 | unless (opendir (PARENT_DIR, $parent_filename)) { | ||||||
466 | show_error ($r, 500, $!, "Unable to access parent directory $parent_filename: $!"); | ||||||
467 | return $::MP2 ? Apache2::Const::OK() : Apache::Constants::OK(); | ||||||
468 | } | ||||||
469 | |||||||
470 | # Debian bug #619625 |
||||||
471 | my @neighbour_directories = grep { !/^\./ && -d "$parent_filename/$_" && ! -e "$parent_filename/$_" . ".ignore" } readdir (PARENT_DIR); | ||||||
472 | my $dirsortby; | ||||||
473 | if (defined($r->dir_config('GalleryDirSortBy'))) { | ||||||
474 | $dirsortby=$r->dir_config('GalleryDirSortBy'); | ||||||
475 | } else { | ||||||
476 | $dirsortby=$r->dir_config('GallerySortBy'); | ||||||
477 | } | ||||||
478 | if ($dirsortby && $dirsortby =~ m/^(size|atime|mtime|ctime)$/) { | ||||||
479 | @neighbour_directories = map(/^\d+ (.*)/, sort map(stat("$parent_filename/$_")->$dirsortby()." $_", @neighbour_directories)); | ||||||
480 | } else { | ||||||
481 | @neighbour_directories = sort @neighbour_directories; | ||||||
482 | } | ||||||
483 | |||||||
484 | closedir(PARENT_DIR); | ||||||
485 | |||||||
486 | my $neightbour_counter = 0; | ||||||
487 | foreach my $neighbour_directory (@neighbour_directories) { | ||||||
488 | if ($parent_filename.'/'.$neighbour_directory eq $filename) { | ||||||
489 | if ($neightbour_counter > 0) { | ||||||
490 | print STDERR "prev directory is " .$neighbour_directories[$neightbour_counter-1] ."\n"; | ||||||
491 | my $linktext = $neighbour_directories[$neightbour_counter-1]; | ||||||
492 | if (-e $parent_filename.'/'.$neighbour_directories[$neightbour_counter-1] . ".folder") { | ||||||
493 | $linktext = get_filecontent($parent_filename.'/'.$neighbour_directories[$neightbour_counter-1] . ".folder"); | ||||||
494 | } | ||||||
495 | my %info = ( | ||||||
496 | URL => "../".$neighbour_directories[$neightbour_counter-1], | ||||||
497 | LINK_NAME => "<<< $linktext", | ||||||
498 | DIR_FILES => "", | ||||||
499 | ); | ||||||
500 | $tpl_vars{PREV_DIR_FILES} = $templates{navdirectory}->fill_in(HASH=> {%info}); | ||||||
501 | print STDERR $tpl_vars{PREV_DIR_FILES} ."\n"; | ||||||
502 | |||||||
503 | } | ||||||
504 | if ($neightbour_counter < scalar @neighbour_directories - 1) { | ||||||
505 | my $linktext = $neighbour_directories[$neightbour_counter+1]; | ||||||
506 | if (-e $parent_filename.'/'.$neighbour_directories[$neightbour_counter+1] . ".folder") { | ||||||
507 | $linktext = get_filecontent($parent_filename.'/'.$neighbour_directories[$neightbour_counter+1] . ".folder"); | ||||||
508 | } | ||||||
509 | my %info = ( | ||||||
510 | URL => "../".$neighbour_directories[$neightbour_counter+1], | ||||||
511 | LINK_NAME => "$linktext >>>", | ||||||
512 | DIR_FILES => "", | ||||||
513 | ); | ||||||
514 | $tpl_vars{NEXT_DIR_FILES} = $templates{navdirectory}->fill_in(HASH=> {%info}); | ||||||
515 | print STDERR "next directory is " .$neighbour_directories[$neightbour_counter+1] ."\n"; | ||||||
516 | } | ||||||
517 | } | ||||||
518 | $neightbour_counter++; | ||||||
519 | } | ||||||
520 | } | ||||||
521 | |||||||
522 | if (-f $topdir . '.comment') { | ||||||
523 | my $comment_ref = get_comment($topdir . '.comment'); | ||||||
524 | my %comment_vars; | ||||||
525 | $comment_vars{COMMENT} = $comment_ref->{COMMENT} . ' ' if $comment_ref->{COMMENT}; |
||||||
526 | $comment_vars{TITLE} = $comment_ref->{TITLE} if $comment_ref->{TITLE}; | ||||||
527 | $tpl_vars{DIRCOMMENT} = $templates{comment}->fill_in(HASH => \%comment_vars); | ||||||
528 | $tpl_vars{TITLE} = $comment_ref->{TITLE} if $comment_ref->{TITLE}; | ||||||
529 | } else { | ||||||
530 | $tpl_vars{DIRCOMMENT} = $templates{nocomment}->fill_in(HASH=>\%tpl_vars); | ||||||
531 | } | ||||||
532 | |||||||
533 | if ($cgi->param('rss')) { | ||||||
534 | $tpl_vars{MAIN} = $templates{rss}->fill_in(HASH => \%tpl_vars); | ||||||
535 | $r->content_type('application/rss+xml'); | ||||||
536 | } else { | ||||||
537 | $tpl_vars{MAIN} = $templates{index}->fill_in(HASH => \%tpl_vars); | ||||||
538 | $tpl_vars{MAIN} = $templates{layout}->fill_in(HASH => \%tpl_vars); | ||||||
539 | $r->content_type('text/html'); | ||||||
540 | } | ||||||
541 | |||||||
542 | $r->headers_out->{'Content-Length'} = length($tpl_vars{MAIN}); | ||||||
543 | |||||||
544 | if (!$::MP2) { | ||||||
545 | $r->send_http_header; | ||||||
546 | } | ||||||
547 | |||||||
548 | $r->print($tpl_vars{MAIN}); | ||||||
549 | return $::MP2 ? Apache2::Const::OK() : Apache::Constants::OK(); | ||||||
550 | |||||||
551 | } | ||||||
552 | else { | ||||||
553 | |||||||
554 | # original size | ||||||
555 | if (defined($ENV{QUERY_STRING}) && $ENV{QUERY_STRING} eq 'orig') { | ||||||
556 | if ($r->dir_config('GalleryAllowOriginal') ? 1 : 0) { | ||||||
557 | $r->filename($filename); | ||||||
558 | return $::MP2 ? Apache2::Const::DECLINED() : Apache::Constants::DECLINED(); | ||||||
559 | } else { | ||||||
560 | return $::MP2 ? Apache2::Const::FORBIDDEN() : Apache::Constants::FORBIDDEN(); | ||||||
561 | } | ||||||
562 | } | ||||||
563 | |||||||
564 | # Create cache dir if not existing | ||||||
565 | my @tmp = split (/\//, $filename); | ||||||
566 | my $picfilename = pop @tmp; | ||||||
567 | my $path = (join "/", @tmp)."/"; | ||||||
568 | my $cache_path = cache_dir($r, 1); | ||||||
569 | |||||||
570 | unless (-d $cache_path) { | ||||||
571 | unless (create_cache($r, $cache_path)) { | ||||||
572 | return $::MP2 ? Apache2::Const::OK() : Apache::Constants::OK(); | ||||||
573 | } | ||||||
574 | } | ||||||
575 | |||||||
576 | my ($orig_width, $orig_height, $type) = imgsize($filename); | ||||||
577 | |||||||
578 | my $imageinfo = get_imageinfo($r, $filename, $type, $orig_width, $orig_height); | ||||||
579 | |||||||
580 | my ($image_width, $width, $height, $original_size) = get_image_display_size($cgi, $r, $orig_width, $orig_height); | ||||||
581 | |||||||
582 | my $cached = get_scaled_picture_name($filename, $image_width, $height); | ||||||
583 | |||||||
584 | my $tpl_dir = $r->dir_config('GalleryTemplateDir'); | ||||||
585 | |||||||
586 | my %templates = create_templates({layout => "$tpl_dir/layout.tpl", | ||||||
587 | picture => "$tpl_dir/showpicture.tpl", | ||||||
588 | navpicture => "$tpl_dir/navpicture.tpl", | ||||||
589 | info => "$tpl_dir/info.tpl", | ||||||
590 | scale => "$tpl_dir/scale.tpl", | ||||||
591 | scaleactive => "$tpl_dir/scaleactive.tpl", | ||||||
592 | orig => "$tpl_dir/orig.tpl", | ||||||
593 | refresh => "$tpl_dir/refresh.tpl", | ||||||
594 | interval => "$tpl_dir/interval.tpl", | ||||||
595 | intervalactive => "$tpl_dir/intervalactive.tpl", | ||||||
596 | slideshowisoff => "$tpl_dir/slideshowisoff.tpl", | ||||||
597 | slideshowoff => "$tpl_dir/slideshowoff.tpl", | ||||||
598 | pictureinfo => "$tpl_dir/pictureinfo.tpl", | ||||||
599 | nopictureinfo => "$tpl_dir/nopictureinfo.tpl", | ||||||
600 | }); | ||||||
601 | |||||||
602 | my %tpl_vars; | ||||||
603 | |||||||
604 | my $resolution = (($image_width > $orig_width) && ($height > $orig_height)) ? | ||||||
605 | "$orig_width x $orig_height" : "$image_width x $height"; | ||||||
606 | |||||||
607 | $tpl_vars{TITLE} = "Viewing ".$r->uri()." at $image_width x $height"; | ||||||
608 | $tpl_vars{META} = " "; | ||||||
609 | $tpl_vars{RESOLUTION} = $resolution; | ||||||
610 | $tpl_vars{MENU} = generate_menu($r); | ||||||
611 | $tpl_vars{SRC} = uri_escape(".cache/$cached", $escape_rule); | ||||||
612 | $tpl_vars{URI} = $r->uri(); | ||||||
613 | |||||||
614 | my $exif_mode = $r->dir_config('GalleryEXIFMode'); | ||||||
615 | unless ($exif_mode) { | ||||||
616 | $exif_mode = 'namevalue'; | ||||||
617 | } | ||||||
618 | |||||||
619 | unless (opendir(DATADIR, $path)) { | ||||||
620 | show_error($r, 500, "Unable to access directory", "Unable to access directory $path"); | ||||||
621 | return $::MP2 ? Apache2::Const::OK() : Apache::Constants::OK(); | ||||||
622 | } | ||||||
623 | my @pictures = grep { /$img_pattern/i && ! -e "$path/$_" . ".ignore" } readdir (DATADIR); | ||||||
624 | closedir(DATADIR); | ||||||
625 | @pictures = gallerysort($r, @pictures); | ||||||
626 | |||||||
627 | $tpl_vars{TOTAL} = scalar @pictures; | ||||||
628 | |||||||
629 | my $prevpicture; | ||||||
630 | my $nextpicture; | ||||||
631 | |||||||
632 | for (my $i=0; $i <= $#pictures; $i++) { | ||||||
633 | if ($pictures[$i] eq $picfilename) { | ||||||
634 | |||||||
635 | $tpl_vars{NUMBER} = $i+1; | ||||||
636 | |||||||
637 | $prevpicture = $pictures[$i-1]; | ||||||
638 | my $displayprev = ($i>0 ? 1 : 0); | ||||||
639 | |||||||
640 | if ($r->dir_config("GalleryWrapNavigation")) { | ||||||
641 | $prevpicture = $pictures[$i>0 ? $i-1 : $#pictures]; | ||||||
642 | $displayprev = 1; | ||||||
643 | } | ||||||
644 | if ($prevpicture and $displayprev) { | ||||||
645 | my ($orig_width, $orig_height, $type) = imgsize($path.$prevpicture); | ||||||
646 | my ($thumbnailwidth, $thumbnailheight) = get_thumbnailsize($r, $orig_width, $orig_height); | ||||||
647 | my $imageinfo = get_imageinfo($r, $path.$prevpicture, $type, $orig_width, $orig_height); | ||||||
648 | my $cached = get_scaled_picture_name($path.$prevpicture, $thumbnailwidth, $thumbnailheight); | ||||||
649 | my %nav_vars; | ||||||
650 | $nav_vars{URL} = uri_escape($prevpicture, $escape_rule); | ||||||
651 | $nav_vars{FILENAME} = $prevpicture; | ||||||
652 | $nav_vars{WIDTH} = $width; | ||||||
653 | $nav_vars{PICTURE} = uri_escape(".cache/$cached", $escape_rule); | ||||||
654 | $nav_vars{DIRECTION} = "« prev"; | ||||||
655 | $nav_vars{ACCESSKEY} = "P"; | ||||||
656 | $tpl_vars{BACK} = $templates{navpicture}->fill_in(HASH => \%nav_vars); | ||||||
657 | } | ||||||
658 | else { | ||||||
659 | $tpl_vars{BACK} = " "; | ||||||
660 | } | ||||||
661 | |||||||
662 | $nextpicture = $pictures[$i+1]; | ||||||
663 | if ($r->dir_config("GalleryWrapNavigation")) { | ||||||
664 | $nextpicture = $pictures[$i == $#pictures ? 0 : $i+1]; | ||||||
665 | } | ||||||
666 | |||||||
667 | if ($nextpicture) { | ||||||
668 | my ($orig_width, $orig_height, $type) = imgsize($path.$nextpicture); | ||||||
669 | my ($thumbnailwidth, $thumbnailheight) = get_thumbnailsize($r, $orig_width, $orig_height); | ||||||
670 | my $imageinfo = get_imageinfo($r, $path.$nextpicture, $type, $thumbnailwidth, $thumbnailheight); | ||||||
671 | my $cached = get_scaled_picture_name($path.$nextpicture, $thumbnailwidth, $thumbnailheight); | ||||||
672 | my %nav_vars; | ||||||
673 | $nav_vars{URL} = uri_escape($nextpicture, $escape_rule); | ||||||
674 | $nav_vars{FILENAME} = $nextpicture; | ||||||
675 | $nav_vars{WIDTH} = $width; | ||||||
676 | $nav_vars{PICTURE} = uri_escape(".cache/$cached", $escape_rule); | ||||||
677 | $nav_vars{DIRECTION} = "next »"; | ||||||
678 | $nav_vars{ACCESSKEY} = "N"; | ||||||
679 | |||||||
680 | $tpl_vars{NEXT} = $templates{navpicture}->fill_in(HASH => \%nav_vars); | ||||||
681 | $tpl_vars{NEXTURL} = uri_escape($nextpicture, $escape_rule); | ||||||
682 | } | ||||||
683 | else { | ||||||
684 | $tpl_vars{NEXT} = " "; | ||||||
685 | $tpl_vars{NEXTURL} = '#'; | ||||||
686 | } | ||||||
687 | } | ||||||
688 | } | ||||||
689 | |||||||
690 | my $foundcomment = 0; | ||||||
691 | if (-f $path . '/' . $picfilename . '.comment') { | ||||||
692 | my $comment_ref = get_comment($path . '/' . $picfilename . '.comment'); | ||||||
693 | $foundcomment = 1; | ||||||
694 | $tpl_vars{COMMENT} = $comment_ref->{COMMENT} . ' ' if $comment_ref->{COMMENT}; |
||||||
695 | $tpl_vars{TITLE} = $comment_ref->{TITLE} if $comment_ref->{TITLE}; | ||||||
696 | } elsif ($r->dir_config('GalleryCommentExifKey')) { | ||||||
697 | my $comment = decode("utf8", $imageinfo->{$r->dir_config('GalleryCommentExifKey')}); | ||||||
698 | $tpl_vars{COMMENT} = encode("iso-8859-1", $comment); | ||||||
699 | } else { | ||||||
700 | $tpl_vars{COMMENT} = ''; | ||||||
701 | } | ||||||
702 | |||||||
703 | my @infos = split /, /, $r->dir_config('GalleryInfo') ? $r->dir_config('GalleryInfo') : 'Picture Taken => DateTimeOriginal, Flash => Flash'; | ||||||
704 | my $foundinfo = 0; | ||||||
705 | my $exifvalues; | ||||||
706 | foreach (@infos) { | ||||||
707 | |||||||
708 | my ($human_key, $exif_key) = (split " => ")[0,1]; | ||||||
709 | my $value = $imageinfo->{$human_key}; | ||||||
710 | if (defined($value)) { | ||||||
711 | |||||||
712 | $foundinfo = 1; | ||||||
713 | |||||||
714 | if ($exif_mode eq 'namevalue') { | ||||||
715 | my %info_vars; | ||||||
716 | $info_vars{KEY} = $human_key; | ||||||
717 | $info_vars{VALUE} = $value; | ||||||
718 | $tpl_vars{INFO} .= $templates{info}->fill_in(HASH => \%info_vars); | ||||||
719 | } | ||||||
720 | |||||||
721 | if ($exif_mode eq 'variables') { | ||||||
722 | $tpl_vars{"EXIF_".uc($exif_key)} = $value; | ||||||
723 | } | ||||||
724 | |||||||
725 | if ($exif_mode eq 'values') { | ||||||
726 | $exifvalues .= "| ".$value." "; | ||||||
727 | } | ||||||
728 | |||||||
729 | } | ||||||
730 | |||||||
731 | } | ||||||
732 | |||||||
733 | if ($exif_mode eq 'values') { | ||||||
734 | if (defined($exifvalues)) { | ||||||
735 | $tpl_vars{EXIFVALUES} = $exifvalues; | ||||||
736 | } | ||||||
737 | else { | ||||||
738 | $tpl_vars{EXIFVALUES} = ""; | ||||||
739 | } | ||||||
740 | } | ||||||
741 | |||||||
742 | if ($foundcomment and !$foundinfo) { | ||||||
743 | $tpl_vars{INFO} = ""; | ||||||
744 | } | ||||||
745 | |||||||
746 | if ($exif_mode ne 'namevalue') { | ||||||
747 | $tpl_vars{INFO} = ""; | ||||||
748 | } | ||||||
749 | |||||||
750 | if ($exif_mode eq 'namevalue' && $foundinfo or $foundcomment) { | ||||||
751 | |||||||
752 | $tpl_vars{PICTUREINFO} = $templates{pictureinfo}->fill_in(HASH => \%tpl_vars); | ||||||
753 | |||||||
754 | unless (defined($exifvalues)) { | ||||||
755 | $tpl_vars{EXIFVALUES} = ""; | ||||||
756 | } | ||||||
757 | |||||||
758 | } | ||||||
759 | else { | ||||||
760 | $tpl_vars{PICTUREINFO} = $templates{nopictureinfo}->fill_in(HASH => \%tpl_vars); | ||||||
761 | } | ||||||
762 | |||||||
763 | # Fill in sizes and determine if any are smaller than the | ||||||
764 | # actual image. If they are, $scaleable=1 | ||||||
765 | my $scaleable = 0; | ||||||
766 | my @sizes = split (/ /, $r->dir_config('GallerySizes') ? $r->dir_config('GallerySizes') : '640 800 1024 1600'); | ||||||
767 | foreach my $size (@sizes) { | ||||||
768 | if ($size<=$original_size) { | ||||||
769 | my %sizes_vars; | ||||||
770 | $sizes_vars{IMAGEURI} = uri_escape($r->uri(), $escape_rule); | ||||||
771 | $sizes_vars{SIZE} = $size; | ||||||
772 | $sizes_vars{WIDTH} = $size; | ||||||
773 | if ($width == $size) { | ||||||
774 | $tpl_vars{SIZES} .= $templates{scaleactive}->fill_in(HASH => \%sizes_vars); | ||||||
775 | } | ||||||
776 | else { | ||||||
777 | $tpl_vars{SIZES} .= $templates{scale}->fill_in(HASH => \%sizes_vars); | ||||||
778 | } | ||||||
779 | $scaleable = 1; | ||||||
780 | } | ||||||
781 | } | ||||||
782 | |||||||
783 | unless ($scaleable) { | ||||||
784 | my %sizes_vars; | ||||||
785 | $sizes_vars{IMAGEURI} = uri_escape($r->uri(), $escape_rule); | ||||||
786 | $sizes_vars{SIZE} = $original_size; | ||||||
787 | $sizes_vars{WIDTH} = $original_size; | ||||||
788 | $tpl_vars{SIZES} .= $templates{scaleactive}->fill_in(HASH => \%sizes_vars); | ||||||
789 | } | ||||||
790 | |||||||
791 | $tpl_vars{IMAGEURI} = uri_escape($r->uri(), $escape_rule); | ||||||
792 | |||||||
793 | if ($r->dir_config('GalleryAllowOriginal')) { | ||||||
794 | $tpl_vars{SIZES} .= $templates{orig}->fill_in(HASH => \%tpl_vars); | ||||||
795 | } | ||||||
796 | |||||||
797 | my @slideshow_intervals = split (/ /, $r->dir_config('GallerySlideshowIntervals') ? $r->dir_config('GallerySlideshowIntervals') : '3 5 10 15 30'); | ||||||
798 | foreach my $interval (@slideshow_intervals) { | ||||||
799 | |||||||
800 | my %slideshow_vars; | ||||||
801 | $slideshow_vars{IMAGEURI} = uri_escape($r->uri(), $escape_rule); | ||||||
802 | $slideshow_vars{SECONDS} = $interval; | ||||||
803 | $slideshow_vars{WIDTH} = ($width > $height ? $width : $height); | ||||||
804 | |||||||
805 | if ($cgi->param('slideshow') && $cgi->param('slideshow') == $interval and $nextpicture) { | ||||||
806 | $tpl_vars{SLIDESHOW} .= $templates{intervalactive}->fill_in(HASH => \%slideshow_vars); | ||||||
807 | } | ||||||
808 | else { | ||||||
809 | |||||||
810 | $tpl_vars{SLIDESHOW} .= $templates{interval}->fill_in(HASH => \%slideshow_vars); | ||||||
811 | |||||||
812 | } | ||||||
813 | } | ||||||
814 | |||||||
815 | if ($cgi->param('slideshow') and $nextpicture) { | ||||||
816 | |||||||
817 | $tpl_vars{SLIDESHOW} .= $templates{slideshowoff}->fill_in(HASH => \%tpl_vars); | ||||||
818 | |||||||
819 | unless ((grep $cgi->param('slideshow') == $_, @slideshow_intervals)) { | ||||||
820 | show_error($r, 200, "Invalid interval", "Invalid slideshow interval choosen"); | ||||||
821 | return $::MP2 ? Apache2::Const::OK() : Apache::Constants::OK(); | ||||||
822 | } | ||||||
823 | |||||||
824 | $tpl_vars{URL} = uri_escape($nextpicture, $escape_rule); | ||||||
825 | $tpl_vars{WIDTH} = ($width > $height ? $width : $height); | ||||||
826 | $tpl_vars{INTERVAL} = $cgi->param('slideshow'); | ||||||
827 | $tpl_vars{META} .= $templates{refresh}->fill_in(HASH => \%tpl_vars); | ||||||
828 | |||||||
829 | } | ||||||
830 | else { | ||||||
831 | $tpl_vars{SLIDESHOW} .= $templates{slideshowisoff}->fill_in(HASH => \%tpl_vars); | ||||||
832 | } | ||||||
833 | |||||||
834 | $tpl_vars{MAIN} = $templates{picture}->fill_in(HASH => \%tpl_vars); | ||||||
835 | $tpl_vars{MAIN} = $templates{layout}->fill_in(HASH => \%tpl_vars); | ||||||
836 | |||||||
837 | $r->content_type('text/html'); | ||||||
838 | $r->headers_out->{'Content-Length'} = length($tpl_vars{MAIN}); | ||||||
839 | |||||||
840 | if (!$::MP2) { | ||||||
841 | $r->send_http_header; | ||||||
842 | } | ||||||
843 | |||||||
844 | $r->print($tpl_vars{MAIN}); | ||||||
845 | return $::MP2 ? Apache2::Const::OK() : Apache::Constants::OK(); | ||||||
846 | |||||||
847 | } | ||||||
848 | |||||||
849 | } | ||||||
850 | |||||||
851 | sub cache_dir { | ||||||
852 | |||||||
853 | my ($r, $strip_filename) = @_; | ||||||
854 | |||||||
855 | my $cache_root; | ||||||
856 | |||||||
857 | unless ($r->dir_config('GalleryCacheDir')) { | ||||||
858 | |||||||
859 | $cache_root = '/var/cache/www/'; | ||||||
860 | if ($r->server->is_virtual) { | ||||||
861 | $cache_root = File::Spec->catdir($cache_root, $r->server->server_hostname); | ||||||
862 | } else { | ||||||
863 | $cache_root = File::Spec->catdir($cache_root, $r->location); | ||||||
864 | } | ||||||
865 | |||||||
866 | } else { | ||||||
867 | |||||||
868 | $cache_root = $r->dir_config('GalleryCacheDir'); | ||||||
869 | |||||||
870 | } | ||||||
871 | |||||||
872 | # If the uri contains .cache we need to remove it | ||||||
873 | my $uri = $r->uri; | ||||||
874 | $uri =~ s/\.cache//; | ||||||
875 | |||||||
876 | my (undef, $dirs, $filename) = File::Spec->splitpath($uri); | ||||||
877 | # We don't need a volume as this is a relative path | ||||||
878 | |||||||
879 | if ($strip_filename) { | ||||||
880 | return(File::Spec->canonpath(File::Spec->catdir($cache_root, $dirs))); | ||||||
881 | } else { | ||||||
882 | return(File::Spec->canonpath(File::Spec->catfile($cache_root, $dirs, $filename))); | ||||||
883 | } | ||||||
884 | } | ||||||
885 | |||||||
886 | sub create_cache { | ||||||
887 | |||||||
888 | my ($r, $path) = @_; | ||||||
889 | |||||||
890 | unless (mkdirhier ($path)) { | ||||||
891 | show_error($r, 500, $!, "Unable to create cache directory in $path: $!"); | ||||||
892 | return 0; | ||||||
893 | } | ||||||
894 | |||||||
895 | return 1; | ||||||
896 | } | ||||||
897 | |||||||
898 | sub mkdirhier { | ||||||
899 | |||||||
900 | my $dir = shift; | ||||||
901 | |||||||
902 | unless (-d $dir) { | ||||||
903 | |||||||
904 | unless (mkdir($dir, 0755)) { | ||||||
905 | my $parent = $dir; | ||||||
906 | $parent =~ s/\/[^\/]*$//; | ||||||
907 | |||||||
908 | mkdirhier($parent); | ||||||
909 | |||||||
910 | mkdir($dir, 0755); | ||||||
911 | } | ||||||
912 | } | ||||||
913 | } | ||||||
914 | |||||||
915 | sub get_scaled_picture_name { | ||||||
916 | |||||||
917 | my ($fullpath, $width, $height) = @_; | ||||||
918 | |||||||
919 | my (undef, undef, $type) = imgsize($fullpath); | ||||||
920 | |||||||
921 | my @dirs = split(/\//, $fullpath); | ||||||
922 | my $filename = pop(@dirs); | ||||||
923 | my $newfilename; | ||||||
924 | |||||||
925 | if (grep $type eq $_, qw(PPM TIF GIF)) { | ||||||
926 | $newfilename = $width."x".$height."-".$filename; | ||||||
927 | # needs to be configurable | ||||||
928 | $newfilename =~ s/\.(\w+)$/-$1\.jpg/; | ||||||
929 | } else { | ||||||
930 | $newfilename = $width."x".$height."-".$filename; | ||||||
931 | } | ||||||
932 | |||||||
933 | return $newfilename; | ||||||
934 | |||||||
935 | } | ||||||
936 | |||||||
937 | sub scale_picture { | ||||||
938 | |||||||
939 | my ($r, $fullpath, $width, $height, $imageinfo) = @_; | ||||||
940 | |||||||
941 | my @dirs = split(/\//, $fullpath); | ||||||
942 | my $filename = pop(@dirs); | ||||||
943 | |||||||
944 | my ($orig_width, $orig_height, $type) = imgsize($fullpath); | ||||||
945 | |||||||
946 | my $cache = cache_dir($r, 1); | ||||||
947 | |||||||
948 | my $newfilename = get_scaled_picture_name($fullpath, $width, $height); | ||||||
949 | |||||||
950 | if (($width > $orig_width) && ($height > $orig_height)) { | ||||||
951 | # Run it through the resize code anyway to get watermarks | ||||||
952 | $width = $orig_width; | ||||||
953 | $height = $orig_height; | ||||||
954 | } | ||||||
955 | |||||||
956 | my ($thumbnailwidth, $thumbnailheight) = get_thumbnailsize($r, $orig_width, $orig_height); | ||||||
957 | |||||||
958 | # Do we want to generate a new file in the cache? | ||||||
959 | my $scale = 1; | ||||||
960 | |||||||
961 | if (-f $cache."/".$newfilename) { | ||||||
962 | $scale = 0; | ||||||
963 | |||||||
964 | # Check to see if the image has changed | ||||||
965 | my $filestat = stat($fullpath); | ||||||
966 | my $cachestat = stat($cache."/".$newfilename); | ||||||
967 | if ($filestat->mtime >= $cachestat->mtime) { | ||||||
968 | $scale = 1; | ||||||
969 | } | ||||||
970 | |||||||
971 | # Check to see if the .rotate file has been added or changed | ||||||
972 | if (-f $fullpath . ".rotate") { | ||||||
973 | my $rotatestat = stat($fullpath . ".rotate"); | ||||||
974 | if ($rotatestat->mtime > $cachestat->mtime) { | ||||||
975 | $scale = 1; | ||||||
976 | } | ||||||
977 | } | ||||||
978 | # Check to see if the copyrightimage has been added or changed | ||||||
979 | if ($r->dir_config('GalleryCopyrightImage') && -f $r->dir_config('GalleryCopyrightImage')) { | ||||||
980 | unless ($width == $thumbnailwidth or $width == $thumbnailheight) { | ||||||
981 | my $copyrightstat = stat($r->dir_config('GalleryCopyrightImage')); | ||||||
982 | if ($copyrightstat->mtime > $cachestat->mtime) { | ||||||
983 | $scale = 1; | ||||||
984 | } | ||||||
985 | } | ||||||
986 | } | ||||||
987 | |||||||
988 | } | ||||||
989 | |||||||
990 | if ($scale) { | ||||||
991 | |||||||
992 | my $newpath = $cache."/".$newfilename; | ||||||
993 | my $rotate = readfile_getnum($r, $imageinfo, $fullpath . ".rotate"); | ||||||
994 | my $quality = $r->dir_config('GalleryQuality'); | ||||||
995 | |||||||
996 | if ($width == $thumbnailwidth or $width == $thumbnailheight) { | ||||||
997 | |||||||
998 | resizepicture($r, $fullpath, $newpath, $width, $height, $rotate, '', '', '', '', '', ''); | ||||||
999 | |||||||
1000 | } else { | ||||||
1001 | |||||||
1002 | resizepicture($r, $fullpath, $newpath, $width, $height, $rotate, | ||||||
1003 | ($r->dir_config('GalleryCopyrightImage') ? $r->dir_config('GalleryCopyrightImage') : ''), | ||||||
1004 | ($r->dir_config('GalleryTTFDir') ? $r->dir_config('GalleryTTFDir') : ''), | ||||||
1005 | ($r->dir_config('GalleryCopyrightText') ? $r->dir_config('GalleryCopyrightText') : ''), | ||||||
1006 | ($r->dir_config('GalleryCopyrightColor') ? $r->dir_config('GalleryCopyrightColor') : ''), | ||||||
1007 | ($r->dir_config('GalleryTTFFile') ? $r->dir_config('GalleryTTFFile') : ''), | ||||||
1008 | ($r->dir_config('GalleryTTFSize') ? $r->dir_config('GalleryTTFSize') : ''), | ||||||
1009 | ($r->dir_config('GalleryCopyrightBackgroundColor') ? $r->dir_config('GalleryCopyrightBackgroundColor') : ''), | ||||||
1010 | $quality); | ||||||
1011 | |||||||
1012 | } | ||||||
1013 | } | ||||||
1014 | |||||||
1015 | return $newfilename; | ||||||
1016 | |||||||
1017 | } | ||||||
1018 | |||||||
1019 | sub get_thumbnailsize { | ||||||
1020 | my ($r, $orig_width, $orig_height) = @_; | ||||||
1021 | |||||||
1022 | my $gallerythumbnailsize=$r->dir_config('GalleryThumbnailSize'); | ||||||
1023 | |||||||
1024 | if (defined($gallerythumbnailsize)) { | ||||||
1025 | warn("Invalid setting for GalleryThumbnailSize") unless | ||||||
1026 | $gallerythumbnailsize =~ /^\s*\d+\s*x\s*\d+\s*$/i; | ||||||
1027 | } | ||||||
1028 | |||||||
1029 | my ($thumbnailwidth, $thumbnailheight) = split(/x/i, ($gallerythumbnailsize) ? $gallerythumbnailsize : "100x75"); | ||||||
1030 | |||||||
1031 | my $width = $thumbnailwidth; | ||||||
1032 | my $height = $thumbnailheight; | ||||||
1033 | |||||||
1034 | # If the image is rotated, flip everything around. | ||||||
1035 | if (defined $r->dir_config('GalleryThumbnailSizeLS') | ||||||
1036 | and $r->dir_config('GalleryThumbnailSizeLS') eq '1' | ||||||
1037 | and $orig_width < $orig_height) { | ||||||
1038 | |||||||
1039 | $width = $thumbnailheight; | ||||||
1040 | $height = $thumbnailwidth; | ||||||
1041 | } | ||||||
1042 | |||||||
1043 | my $scale = ($orig_width ? $width/$orig_width : 1); | ||||||
1044 | |||||||
1045 | if ($orig_height) { | ||||||
1046 | if ($orig_height * $scale > $thumbnailheight) { | ||||||
1047 | $scale = $height/$orig_height; | ||||||
1048 | $width = $orig_width * $scale; | ||||||
1049 | } | ||||||
1050 | } | ||||||
1051 | |||||||
1052 | $height = $orig_height * $scale; | ||||||
1053 | |||||||
1054 | $height = floor($height); | ||||||
1055 | $width = floor($width); | ||||||
1056 | |||||||
1057 | return ($width, $height); | ||||||
1058 | } | ||||||
1059 | |||||||
1060 | sub get_image_display_size { | ||||||
1061 | my ($cgi, $r, $orig_width, $orig_height) = @_; | ||||||
1062 | |||||||
1063 | my $width = $orig_width; | ||||||
1064 | |||||||
1065 | my $original_size=$orig_height; | ||||||
1066 | if ($orig_width>$orig_height) { | ||||||
1067 | $original_size=$orig_width; | ||||||
1068 | } | ||||||
1069 | |||||||
1070 | # Check if the selected width is allowed | ||||||
1071 | my @sizes = split (/ /, $r->dir_config('GallerySizes') ? $r->dir_config('GallerySizes') : '640 800 1024 1600'); | ||||||
1072 | |||||||
1073 | my %cookies = fetch CGI::Cookie; | ||||||
1074 | |||||||
1075 | if ($cgi->param('width')) { | ||||||
1076 | unless ((grep $cgi->param('width') == $_, @sizes) or ($cgi->param('width') == $original_size)) { | ||||||
1077 | show_error($r, 200, "Invalid width", "The specified width is invalid"); | ||||||
1078 | return $::MP2 ? Apache2::Const::OK() : Apache::Constants::OK(); | ||||||
1079 | } | ||||||
1080 | |||||||
1081 | $width = $cgi->param('width'); | ||||||
1082 | my $cookie = new CGI::Cookie(-name => 'GallerySize', -value => $width, -expires => '+6M'); | ||||||
1083 | $r->headers_out->{'Set-Cookie'} = $cookie; | ||||||
1084 | |||||||
1085 | } elsif ($cookies{'GallerySize'} && (grep $cookies{'GallerySize'}->value == $_, @sizes)) { | ||||||
1086 | |||||||
1087 | $width = $cookies{'GallerySize'}->value; | ||||||
1088 | |||||||
1089 | } else { | ||||||
1090 | $width = $sizes[0]; | ||||||
1091 | } | ||||||
1092 | |||||||
1093 | my $scale; | ||||||
1094 | my $image_width; | ||||||
1095 | if ($orig_width<$orig_height) { | ||||||
1096 | $scale = ($orig_height ? $width/$orig_height: 1); | ||||||
1097 | $image_width=$width*$orig_width/$orig_height; | ||||||
1098 | } | ||||||
1099 | else { | ||||||
1100 | $scale = ($orig_width ? $width/$orig_width : 1); | ||||||
1101 | $image_width = $width; | ||||||
1102 | } | ||||||
1103 | |||||||
1104 | my $height = $orig_height * $scale; | ||||||
1105 | |||||||
1106 | $image_width = floor($image_width); | ||||||
1107 | $width = floor($width); | ||||||
1108 | $height = floor($height); | ||||||
1109 | |||||||
1110 | return ($image_width, $width, $height, $original_size); | ||||||
1111 | } | ||||||
1112 | |||||||
1113 | sub get_imageinfo { | ||||||
1114 | my ($r, $file, $type, $width, $height) = @_; | ||||||
1115 | my $imageinfo = {}; | ||||||
1116 | if ($type eq 'Data stream is not a known image file format') { | ||||||
1117 | # should never be reached, this is supposed to be handled outside of here | ||||||
1118 | log_error("Something was fishy with the type of the file $file\n"); | ||||||
1119 | } else { | ||||||
1120 | |||||||
1121 | # Some files, like TIFF, PNG, GIF do not have EXIF info | ||||||
1122 | # embedded but use .thm files instead. | ||||||
1123 | $imageinfo = get_imageinfo_from_thm_file($file, $width, $height); | ||||||
1124 | |||||||
1125 | # If there is no .thm file and our file is a JPEG file we try to extract the EXIf | ||||||
1126 | # info using Image::Info | ||||||
1127 | unless (defined($imageinfo) && (grep $type eq $_, qw(JPG))) { | ||||||
1128 | # Only for files that natively keep the EXIF info in the same file | ||||||
1129 | $imageinfo = image_info($file); | ||||||
1130 | } | ||||||
1131 | } | ||||||
1132 | |||||||
1133 | unless (defined($imageinfo->{width}) and defined($imageinfo->{height})) { | ||||||
1134 | $imageinfo->{width} = $width; | ||||||
1135 | $imageinfo->{height} = $height; | ||||||
1136 | } | ||||||
1137 | |||||||
1138 | my @infos = split /, /, $r->dir_config('GalleryInfo') ? $r->dir_config('GalleryInfo') : 'Picture Taken => DateTimeOriginal, Flash => Flash'; | ||||||
1139 | foreach (@infos) { | ||||||
1140 | |||||||
1141 | my ($human_key, $exif_key) = (split " => ")[0,1]; | ||||||
1142 | if (defined($exif_key) && defined($imageinfo->{$exif_key})) { | ||||||
1143 | my $value = ""; | ||||||
1144 | if (ref($imageinfo->{$exif_key}) eq 'Image::TIFF::Rational') { | ||||||
1145 | $value = $imageinfo->{$exif_key}->as_string; | ||||||
1146 | } | ||||||
1147 | elsif (ref($imageinfo->{$exif_key}) eq 'ARRAY') { | ||||||
1148 | foreach my $element (@{$imageinfo->{$exif_key}}) { | ||||||
1149 | if (ref($element) eq 'ARRAY') { | ||||||
1150 | foreach (@{$element}) { | ||||||
1151 | $value .= $_ . ' '; | ||||||
1152 | } | ||||||
1153 | } | ||||||
1154 | elsif (ref($element) eq 'HASH') { | ||||||
1155 | $value .= " { "; |
||||||
1156 | foreach (sort keys %{$element}) { | ||||||
1157 | $value .= "$_ = " . $element->{$_} . ' '; | ||||||
1158 | } | ||||||
1159 | $value .= "} "; | ||||||
1160 | } | ||||||
1161 | else { | ||||||
1162 | $value .= $element; | ||||||
1163 | } | ||||||
1164 | $value .= ' '; | ||||||
1165 | } | ||||||
1166 | } | ||||||
1167 | else { | ||||||
1168 | my $exif_value = $imageinfo->{$exif_key}; | ||||||
1169 | if ($human_key eq 'Flash' && $exif_value =~ m/\d/) { | ||||||
1170 | my %flashmodes = ( | ||||||
1171 | "0" => "No", | ||||||
1172 | "1" => "Yes", | ||||||
1173 | "9" => "Yes", | ||||||
1174 | "16" => "No (Compulsory) Should be External Flash", | ||||||
1175 | "17" => "Yes (External)", | ||||||
1176 | "24" => "No", | ||||||
1177 | "25" => "Yes (Auto)", | ||||||
1178 | "73" => "Yes (Compulsory, Red Eye Reducing)", | ||||||
1179 | "89" => "Yes (Auto, Red Eye Reducing)" | ||||||
1180 | ); | ||||||
1181 | $exif_value = defined $flashmodes{$exif_value} ? $flashmodes{$exif_value} : 'unknown flash mode'; | ||||||
1182 | } | ||||||
1183 | $value = $exif_value; | ||||||
1184 | } | ||||||
1185 | if ($exif_key eq 'MeteringMode') { | ||||||
1186 | my $exif_value = $imageinfo->{$exif_key}; | ||||||
1187 | if ($exif_value =~ /^\d+$/) { | ||||||
1188 | my %meteringmodes = ( | ||||||
1189 | '0' => 'unknown', | ||||||
1190 | '1' => 'Average', | ||||||
1191 | '2' => 'CenterWeightedAverage', | ||||||
1192 | '3' => 'Spot', | ||||||
1193 | '4' => 'MultiSpot', | ||||||
1194 | '5' => 'Pattern', | ||||||
1195 | '6' => 'Partial', | ||||||
1196 | '255' => 'Other' | ||||||
1197 | ); | ||||||
1198 | $exif_value = defined $meteringmodes{$exif_value} ? $meteringmodes{$exif_value} : 'unknown metering mode'; | ||||||
1199 | } | ||||||
1200 | $value = $exif_value; | ||||||
1201 | |||||||
1202 | } | ||||||
1203 | if ($exif_key eq 'LightSource') { | ||||||
1204 | my $exif_value = $imageinfo->{$exif_key}; | ||||||
1205 | if ($exif_value =~ /^\d+$/) { | ||||||
1206 | my %lightsources = ( | ||||||
1207 | '0' => 'unknown', | ||||||
1208 | '1' => 'Daylight', | ||||||
1209 | '2' => 'Fluorescent', | ||||||
1210 | '3' => 'Tungsten (incandescent light)', | ||||||
1211 | '4' => 'Flash', | ||||||
1212 | '9' => 'Fine weather', | ||||||
1213 | '10' => 'Cloudy weather', | ||||||
1214 | '11' => 'Shade', | ||||||
1215 | '12' => 'Daylight fluorescent', | ||||||
1216 | '13' => 'Day white fluorescent', | ||||||
1217 | '14' => 'Cool white fluorescent', | ||||||
1218 | '15' => 'White fluorescent', | ||||||
1219 | '17' => 'Standard light A', | ||||||
1220 | '18' => 'Standard light B', | ||||||
1221 | '19' => 'Standard light C', | ||||||
1222 | '20' => 'D55', | ||||||
1223 | '21' => 'D65', | ||||||
1224 | '22' => 'D75', | ||||||
1225 | '23' => 'D50', | ||||||
1226 | '24' => 'ISO studio tungsten', | ||||||
1227 | '255' => 'other light source' | ||||||
1228 | ); | ||||||
1229 | $exif_value = defined $lightsources{$exif_value} ? $lightsources{$exif_value} : 'unknown light source'; | ||||||
1230 | } | ||||||
1231 | $value = $exif_value; | ||||||
1232 | } | ||||||
1233 | if ($exif_key eq 'FocalLength') { | ||||||
1234 | if ($value =~ /^(\d+)\/(\d+)$/) { | ||||||
1235 | $value = eval { $1 / $2 }; | ||||||
1236 | if ($@) { | ||||||
1237 | $value = $@; | ||||||
1238 | } else { | ||||||
1239 | $value = int($value + 0.5) . "mm"; | ||||||
1240 | |||||||
1241 | } | ||||||
1242 | } | ||||||
1243 | } | ||||||
1244 | if ($exif_key eq 'ShutterSpeedValue') { | ||||||
1245 | if ($value =~ /^((?:\-)?\d+)\/(\d+)$/) { | ||||||
1246 | $value = eval { $1 / $2 }; | ||||||
1247 | if ($@) { | ||||||
1248 | $value = $@; | ||||||
1249 | } else { | ||||||
1250 | eval { | ||||||
1251 | $value = 1/(exp($value*log(2))); | ||||||
1252 | if ($value < 1) { | ||||||
1253 | $value = "1/" . (int((1/$value))); | ||||||
1254 | } else { | ||||||
1255 | $value = int($value*10)/10; | ||||||
1256 | } | ||||||
1257 | }; | ||||||
1258 | if ($@) { | ||||||
1259 | $value = $@; | ||||||
1260 | } else { | ||||||
1261 | $value = $value . " sec"; | ||||||
1262 | } | ||||||
1263 | } | ||||||
1264 | } | ||||||
1265 | } | ||||||
1266 | if ($exif_key eq 'ApertureValue') { | ||||||
1267 | if ($value =~ /^(\d+)\/(\d+)$/) { | ||||||
1268 | $value = eval { $1 / $2 }; | ||||||
1269 | if ($@) { | ||||||
1270 | $value = $@; | ||||||
1271 | } else { | ||||||
1272 | # poor man's rounding | ||||||
1273 | $value = int(exp($value*log(2)*0.5)*10)/10; | ||||||
1274 | $value = "f" . $value; | ||||||
1275 | } | ||||||
1276 | } | ||||||
1277 | } | ||||||
1278 | if ($exif_key eq 'FNumber') { | ||||||
1279 | if ($value =~ /^(\d+)\/(\d+)$/) { | ||||||
1280 | $value = eval { $1 / $2 }; | ||||||
1281 | if ($@) { | ||||||
1282 | $value = $@; | ||||||
1283 | } else { | ||||||
1284 | $value = int($value*10+0.5)/10; | ||||||
1285 | $value = "f" . $value; | ||||||
1286 | } | ||||||
1287 | } | ||||||
1288 | } | ||||||
1289 | $imageinfo->{$human_key} = $value; | ||||||
1290 | } | ||||||
1291 | } | ||||||
1292 | |||||||
1293 | if ($r->dir_config('GalleryUseFileDate') && | ||||||
1294 | ($r->dir_config('GalleryUseFileDate') eq '1' | ||||||
1295 | || !$imageinfo->{"Picture Taken"} )) { | ||||||
1296 | |||||||
1297 | my $st = stat($file); | ||||||
1298 | $imageinfo->{"DateTimeOriginal"} = $imageinfo->{"Picture Taken"} = scalar localtime($st->mtime) if $st; | ||||||
1299 | } | ||||||
1300 | |||||||
1301 | return $imageinfo; | ||||||
1302 | } | ||||||
1303 | |||||||
1304 | sub get_imageinfo_from_thm_file { | ||||||
1305 | |||||||
1306 | my ($file, $width, $height) = @_; | ||||||
1307 | |||||||
1308 | my $imageinfo = undef; | ||||||
1309 | # Windows based file extensions are often .THM, so check | ||||||
1310 | # for both .thm and .THM | ||||||
1311 | my $unix_file = $file; | ||||||
1312 | my $windows_file = $file; | ||||||
1313 | $unix_file =~ s/\.(\w+)$/.thm/; | ||||||
1314 | $windows_file =~ s/\.(\w+)$/.THM/; | ||||||
1315 | |||||||
1316 | if (-e $unix_file && -f $unix_file && -r $unix_file) { | ||||||
1317 | $imageinfo = image_info($unix_file); | ||||||
1318 | $imageinfo->{width} = $width; | ||||||
1319 | $imageinfo->{height} = $height; | ||||||
1320 | } | ||||||
1321 | elsif (-e $windows_file && -f $windows_file && -r $windows_file) { | ||||||
1322 | $imageinfo = image_info($windows_file); | ||||||
1323 | $imageinfo->{width} = $width; | ||||||
1324 | $imageinfo->{height} = $height; | ||||||
1325 | } | ||||||
1326 | |||||||
1327 | return $imageinfo; | ||||||
1328 | } | ||||||
1329 | |||||||
1330 | |||||||
1331 | sub readfile_getnum { | ||||||
1332 | my ($r, $imageinfo, $filename) = @_; | ||||||
1333 | |||||||
1334 | my $rotate = 0; | ||||||
1335 | |||||||
1336 | print STDERR "orientation: ".$imageinfo->{Orientation}."\n"; | ||||||
1337 | # Check to see if the image contains the Orientation EXIF key, | ||||||
1338 | # but allow user to override using rotate | ||||||
1339 | if (!defined($r->dir_config("GalleryAutoRotate")) | ||||||
1340 | || $r->dir_config("GalleryAutoRotate") eq "1") { | ||||||
1341 | if (defined($imageinfo->{Orientation})) { | ||||||
1342 | print STDERR $imageinfo->{Orientation}."\n"; | ||||||
1343 | if ($imageinfo->{Orientation} eq 'right_top') { | ||||||
1344 | $rotate=1; | ||||||
1345 | } | ||||||
1346 | elsif ($imageinfo->{Orientation} eq 'left_bot') { | ||||||
1347 | $rotate=3; | ||||||
1348 | } | ||||||
1349 | } | ||||||
1350 | } | ||||||
1351 | |||||||
1352 | if (open(FH, "<$filename")) { | ||||||
1353 | my $temp = |
||||||
1354 | chomp($temp); | ||||||
1355 | close(FH); | ||||||
1356 | unless ($temp =~ /^\d$/) { | ||||||
1357 | $rotate = 0; | ||||||
1358 | } | ||||||
1359 | unless ($temp == 1 || $temp == 2 || $temp == 3) { | ||||||
1360 | $rotate = 0; | ||||||
1361 | } | ||||||
1362 | $rotate = $temp; | ||||||
1363 | } | ||||||
1364 | |||||||
1365 | return $rotate; | ||||||
1366 | } | ||||||
1367 | |||||||
1368 | sub get_filecontent { | ||||||
1369 | my $file = shift; | ||||||
1370 | open(FH, $file) or return undef; | ||||||
1371 | my $content = ''; | ||||||
1372 | { | ||||||
1373 | local $/; | ||||||
1374 | $content = |
||||||
1375 | } | ||||||
1376 | close(FH); | ||||||
1377 | return $content; | ||||||
1378 | } | ||||||
1379 | |||||||
1380 | sub get_comment { | ||||||
1381 | my $filename = shift; | ||||||
1382 | my $comment_ref = {}; | ||||||
1383 | $comment_ref->{TITLE} = undef; | ||||||
1384 | $comment_ref->{COMMENT} = ''; | ||||||
1385 | |||||||
1386 | open(FH, $filename) or return $comment_ref; | ||||||
1387 | my $title = |
||||||
1388 | if ($title =~ m/^TITLE: (.*)$/) { | ||||||
1389 | chomp($comment_ref->{TITLE} = $1); | ||||||
1390 | } | ||||||
1391 | else { | ||||||
1392 | $comment_ref->{COMMENT} = $title; | ||||||
1393 | } | ||||||
1394 | |||||||
1395 | while ( |
||||||
1396 | chomp; | ||||||
1397 | $comment_ref->{COMMENT} .= $_; | ||||||
1398 | } | ||||||
1399 | close(FH); | ||||||
1400 | |||||||
1401 | return $comment_ref; | ||||||
1402 | } | ||||||
1403 | |||||||
1404 | sub show_error { | ||||||
1405 | |||||||
1406 | my ($r, $statuscode, $errortitle, $error) = @_; | ||||||
1407 | |||||||
1408 | my $tpl = $r->dir_config('GalleryTemplateDir'); | ||||||
1409 | |||||||
1410 | my %templates = create_templates({layout => "$tpl/layout.tpl", | ||||||
1411 | error => "$tpl/error.tpl", | ||||||
1412 | }); | ||||||
1413 | |||||||
1414 | my %tpl_vars; | ||||||
1415 | $tpl_vars{TITLE} = "Error! $errortitle"; | ||||||
1416 | $tpl_vars{META} = ""; | ||||||
1417 | $tpl_vars{ERRORTITLE} = "Error! $errortitle"; | ||||||
1418 | $tpl_vars{ERROR} = $error; | ||||||
1419 | |||||||
1420 | $tpl_vars{MAIN} = $templates{error}->fill_in(HASH => \%tpl_vars); | ||||||
1421 | |||||||
1422 | $tpl_vars{PAGE} = $templates{layout}->fill_in(HASH => \%tpl_vars); | ||||||
1423 | |||||||
1424 | $r->status($statuscode); | ||||||
1425 | $r->content_type('text/html'); | ||||||
1426 | |||||||
1427 | $r->print($tpl_vars{PAGE}); | ||||||
1428 | |||||||
1429 | } | ||||||
1430 | |||||||
1431 | sub generate_menu { | ||||||
1432 | |||||||
1433 | my $r = shift; | ||||||
1434 | |||||||
1435 | my $root_text = (defined($r->dir_config('GalleryRootText')) ? $r->dir_config('GalleryRootText') : "root:" ); | ||||||
1436 | my $root_path = (defined($r->dir_config('GalleryRootPath')) ? $r->dir_config('GalleryRootPath') : "" ); | ||||||
1437 | |||||||
1438 | my $subr = $r->lookup_uri($r->uri); | ||||||
1439 | my $filename = $subr->filename; | ||||||
1440 | |||||||
1441 | my @links = split (/\//, $r->uri); | ||||||
1442 | my $uri = $r->uri; | ||||||
1443 | $uri =~ s/^$root_path//g; | ||||||
1444 | |||||||
1445 | @links = split (/\//, $uri); | ||||||
1446 | |||||||
1447 | # Get the full path of the base directory | ||||||
1448 | my $dirname; | ||||||
1449 | { | ||||||
1450 | my @direlem = split (/\//, $filename); | ||||||
1451 | for my $i ( 0 .. ( scalar(@direlem) - scalar(@links) ) ) { | ||||||
1452 | $dirname .= shift(@direlem) . '/'; | ||||||
1453 | } | ||||||
1454 | chop $dirname; | ||||||
1455 | } | ||||||
1456 | |||||||
1457 | my $picturename; | ||||||
1458 | if (-f $filename) { | ||||||
1459 | $picturename = pop(@links); | ||||||
1460 | } | ||||||
1461 | |||||||
1462 | if ($r->uri eq $root_path) { | ||||||
1463 | return qq{ $root_text }; | ||||||
1464 | } | ||||||
1465 | |||||||
1466 | my $menu; | ||||||
1467 | my $menuurl = $root_path; | ||||||
1468 | foreach my $link (@links) { | ||||||
1469 | |||||||
1470 | $menuurl .= $link."/"; | ||||||
1471 | my $linktext = $link; | ||||||
1472 | unless (length($link)) { | ||||||
1473 | $linktext = "$root_text "; | ||||||
1474 | } | ||||||
1475 | else { | ||||||
1476 | |||||||
1477 | $dirname = File::Spec->catdir($dirname, $link); | ||||||
1478 | |||||||
1479 | if (-e $dirname . ".folder") { | ||||||
1480 | $linktext = get_filecontent($dirname . ".folder"); | ||||||
1481 | } | ||||||
1482 | } | ||||||
1483 | |||||||
1484 | if ("$root_path$uri" eq $menuurl) { | ||||||
1485 | $menu .= "$linktext / "; | ||||||
1486 | } | ||||||
1487 | else { | ||||||
1488 | $menu .= "$linktext / "; | ||||||
1489 | } | ||||||
1490 | |||||||
1491 | } | ||||||
1492 | |||||||
1493 | if (-f $filename) { | ||||||
1494 | $menu .= $picturename; | ||||||
1495 | } | ||||||
1496 | else { | ||||||
1497 | |||||||
1498 | if ($r->dir_config('GallerySelectionMode') && $r->dir_config('GallerySelectionMode') eq '1') { | ||||||
1499 | $menu .= " | ||||||
1500 | $menu .= "?select=1\">[select] "; | ||||||
1501 | } | ||||||
1502 | } | ||||||
1503 | |||||||
1504 | return $menu; | ||||||
1505 | } | ||||||
1506 | |||||||
1507 | sub resizepicture { | ||||||
1508 | my ($r, $infile, $outfile, $x, $y, $rotate, $copyrightfile, $GalleryTTFDir, $GalleryCopyrightText, $text_color, $GalleryTTFFile, $GalleryTTFSize, $GalleryCopyrightBackgroundColor, $quality) = @_; | ||||||
1509 | |||||||
1510 | # Load image | ||||||
1511 | my $image = Image::Imlib2->load($infile) or warn("Unable to open file $infile, $!"); | ||||||
1512 | |||||||
1513 | # Scale image | ||||||
1514 | $image=$image->create_scaled_image($x, $y) or warn("Unable to scale image $infile. Are you running out of memory?"); | ||||||
1515 | |||||||
1516 | # Rotate image | ||||||
1517 | if ($rotate != 0) { | ||||||
1518 | $image->image_orientate($rotate); | ||||||
1519 | } | ||||||
1520 | |||||||
1521 | # blend copyright image onto image | ||||||
1522 | if ($copyrightfile ne '') { | ||||||
1523 | if (-f $copyrightfile and (my $logo=Image::Imlib2->load($copyrightfile))) { | ||||||
1524 | my $x = $image->get_width(); | ||||||
1525 | my $y = $image->get_height(); | ||||||
1526 | my $logox = $logo->get_width(); | ||||||
1527 | my $logoy = $logo->get_height(); | ||||||
1528 | $image->blend($logo, 0, 0, 0, $logox, $logoy, $x-$logox, $y-$logoy, $logox, $logoy); | ||||||
1529 | } | ||||||
1530 | else { | ||||||
1531 | log_error("GalleryCopyrightImage $copyrightfile was not found"); | ||||||
1532 | } | ||||||
1533 | } | ||||||
1534 | |||||||
1535 | if ($GalleryTTFDir && $GalleryCopyrightText && $GalleryTTFFile && $text_color) { | ||||||
1536 | if (!-d $GalleryTTFDir) { | ||||||
1537 | |||||||
1538 | log_error("GalleryTTFDir $GalleryTTFDir is not a dir\n"); | ||||||
1539 | |||||||
1540 | } elsif ($GalleryCopyrightText eq '') { | ||||||
1541 | |||||||
1542 | log_error("GalleryCopyrightText is empty. No text inserted to picture\n"); | ||||||
1543 | |||||||
1544 | } elsif (!-e "$GalleryTTFDir/$GalleryTTFFile") { | ||||||
1545 | |||||||
1546 | log_error("GalleryTTFFile $GalleryTTFFile was not found\n"); | ||||||
1547 | |||||||
1548 | } else { | ||||||
1549 | |||||||
1550 | $GalleryTTFFile =~ s/\.TTF$//i; | ||||||
1551 | $image->add_font_path("$GalleryTTFDir"); | ||||||
1552 | |||||||
1553 | $image->load_font("$GalleryTTFFile/$GalleryTTFSize"); | ||||||
1554 | my($text_x, $text_y) = $image->get_text_size("$GalleryCopyrightText"); | ||||||
1555 | my $x = $image->get_width(); | ||||||
1556 | my $y = $image->get_height(); | ||||||
1557 | |||||||
1558 | my $offset = 3; | ||||||
1559 | |||||||
1560 | if (($text_x < $x - $offset) && ($text_y < $y - $offset)) { | ||||||
1561 | if ($GalleryCopyrightBackgroundColor =~ /^\d+,\d+,\d+,\d+$/) { | ||||||
1562 | my ($br_val, $bg_val, $bb_val, $ba_val) = split (/,/, $GalleryCopyrightBackgroundColor); | ||||||
1563 | $image->set_colour($br_val, $bg_val, $bb_val, $ba_val); | ||||||
1564 | $image->fill_rectangle ($x-$text_x-$offset, $y-$text_y-$offset, $text_x, $text_y); | ||||||
1565 | } | ||||||
1566 | my ($r_val, $g_val, $b_val, $a_val) = split (/,/, $text_color); | ||||||
1567 | $image->set_colour($r_val, $g_val, $b_val, $a_val); | ||||||
1568 | $image->draw_text($x-$text_x-$offset, $y-$text_y-$offset, "$GalleryCopyrightText"); | ||||||
1569 | } else { | ||||||
1570 | log_error("Text is to big for the picture.\n"); | ||||||
1571 | } | ||||||
1572 | } | ||||||
1573 | } | ||||||
1574 | |||||||
1575 | if ($quality && $quality =~ m/^\d+$/) { | ||||||
1576 | $image->set_quality($quality); | ||||||
1577 | } | ||||||
1578 | |||||||
1579 | $image->save($outfile); | ||||||
1580 | |||||||
1581 | } | ||||||
1582 | |||||||
1583 | sub gallerysort { | ||||||
1584 | my $r=shift; | ||||||
1585 | my @files=@_; | ||||||
1586 | my $sortby = $r->dir_config('GallerySortBy'); | ||||||
1587 | my $filename=$r->lookup_uri($r->uri)->filename; | ||||||
1588 | $filename=(File::Spec->splitpath($filename))[1] if (-f $filename); | ||||||
1589 | if ($sortby && $sortby =~ m/^(size|atime|mtime|ctime)$/) { | ||||||
1590 | @files = map(/^\d+ (.*)/, sort map(stat("$filename/$_")->$sortby()." $_", @files)); | ||||||
1591 | } else { | ||||||
1592 | @files = sort @files; | ||||||
1593 | } | ||||||
1594 | return @files; | ||||||
1595 | } | ||||||
1596 | |||||||
1597 | # Create Text::Template objects used by Apache::Gallery. Takes a | ||||||
1598 | # hashref of template_name, template_filename pairs, and returns a | ||||||
1599 | # list of template_name, texttemplate_object pairs. | ||||||
1600 | sub create_templates { | ||||||
1601 | my $templates = shift; | ||||||
1602 | |||||||
1603 | # This routine is called whenever a template has an error. Prints | ||||||
1604 | # the error to STDERR and sticks the error in the output | ||||||
1605 | sub tt_broken { | ||||||
1606 | my %args = @_; | ||||||
1607 | # Pull out the name and filename from the arg option [see | ||||||
1608 | # Text::Template for details] | ||||||
1609 | @args{qw(name file)} = @{$args{arg}}; | ||||||
1610 | print STDERR qq(Template $args{name} ("$args{file}") is broken: $args{error}); | ||||||
1611 | # Don't include the file name in the output, as the user can see this. | ||||||
1612 | return qq(); | ||||||
1613 | } | ||||||
1614 | |||||||
1615 | |||||||
1616 | |||||||
1617 | my %texttemplate_objects; | ||||||
1618 | |||||||
1619 | for my $template_name (keys %$templates) { | ||||||
1620 | my $tt_obj = Text::Template->new(TYPE => 'FILE', | ||||||
1621 | SOURCE => $$templates{$template_name}, | ||||||
1622 | BROKEN => \&tt_broken, | ||||||
1623 | BROKEN_ARG => [$template_name, $$templates{$template_name}], | ||||||
1624 | ) | ||||||
1625 | or die "Unable to create new Text::Template object for $template_name: $Text::Template::ERROR"; | ||||||
1626 | $texttemplate_objects{$template_name} = $tt_obj; | ||||||
1627 | } | ||||||
1628 | return %texttemplate_objects; | ||||||
1629 | } | ||||||
1630 | |||||||
1631 | sub log_error { | ||||||
1632 | if ($::MP2) { | ||||||
1633 | Apache2::RequestUtil->request->log_error(shift()); | ||||||
1634 | } else { | ||||||
1635 | Apache->request->log_error(shift()); | ||||||
1636 | } | ||||||
1637 | } | ||||||
1638 | |||||||
1639 | 1; | ||||||
1640 | |||||||
1641 | =head1 NAME | ||||||
1642 | |||||||
1643 | Apache::Gallery - mod_perl handler to create an image gallery | ||||||
1644 | |||||||
1645 | =head1 SYNOPSIS | ||||||
1646 | |||||||
1647 | See the INSTALL file in the distribution for installation instructions. | ||||||
1648 | |||||||
1649 | =head1 DESCRIPTION | ||||||
1650 | |||||||
1651 | Apache::Gallery creates an thumbnail index of each directory and allows | ||||||
1652 | viewing pictures in different resolutions. Pictures are resized on the | ||||||
1653 | fly and cached. The gallery can be configured and customized in many ways | ||||||
1654 | and a custom copyright image can be added to all the images without | ||||||
1655 | modifying the original. | ||||||
1656 | |||||||
1657 | =head1 CONFIGURATION | ||||||
1658 | |||||||
1659 | In your httpd.conf you set the global options for the gallery. You can | ||||||
1660 | also override each of the options in .htaccess files in your gallery | ||||||
1661 | directories. | ||||||
1662 | |||||||
1663 | The options are set in the httpd.conf/.htaccess file using the syntax: | ||||||
1664 | B |
||||||
1665 | |||||||
1666 | Example: B |
||||||
1667 | |||||||
1668 | =over 4 | ||||||
1669 | |||||||
1670 | =item B |
||||||
1671 | |||||||
1672 | Some cameras, like the Canon G3, can detect the orientation of a | ||||||
1673 | the pictures you take and will save this information in the | ||||||
1674 | 'Orientation' EXIF field. Apache::Gallery will then automatically | ||||||
1675 | rotate your images. | ||||||
1676 | |||||||
1677 | This behavior is default but can be disabled by setting GalleryAutoRotate | ||||||
1678 | to 0. | ||||||
1679 | |||||||
1680 | =item B |
||||||
1681 | |||||||
1682 | Directory where Apache::Gallery should create its cache with scaled | ||||||
1683 | pictures. The default is /var/cache/www/ . Here, a directory for each | ||||||
1684 | virtualhost or location will be created automatically. Make sure your | ||||||
1685 | webserver has write access to the CacheDir. | ||||||
1686 | |||||||
1687 | =item B |
||||||
1688 | |||||||
1689 | Full path to the directory where you placed the templates. This option | ||||||
1690 | can be used both in your global configuration and in .htaccess files, | ||||||
1691 | this way you can have different layouts in different parts of your | ||||||
1692 | gallery. | ||||||
1693 | |||||||
1694 | No default value, this option is required. | ||||||
1695 | |||||||
1696 | =item B |
||||||
1697 | |||||||
1698 | With this option you can define which EXIF information you would like | ||||||
1699 | to present from the image. The format is: ' |
||||||
1700 | MyOtherName => OtherKeyInEXIF' | ||||||
1701 | |||||||
1702 | Examples of keys: B |
||||||
1703 | and B |
||||||
1704 | |||||||
1705 | You can view all the keys from the EXIF header using this perl-oneliner: | ||||||
1706 | |||||||
1707 | perl C<-e> 'use Data::Dumper; use Image::Info qw(image_info); print Dumper(image_info(shift));' filename.jpg | ||||||
1708 | |||||||
1709 | Default is: 'Picture Taken => DateTimeOriginal, Flash => Flash' | ||||||
1710 | |||||||
1711 | =item B |
||||||
1712 | |||||||
1713 | Defines which widths images can be scaled to. Images cannot be | ||||||
1714 | scaled to other widths than the ones you define with this option. | ||||||
1715 | |||||||
1716 | The default is '640 800 1024 1600' | ||||||
1717 | |||||||
1718 | =item B |
||||||
1719 | |||||||
1720 | Defines the width and height of the thumbnail images. | ||||||
1721 | |||||||
1722 | Defaults to '100x75' | ||||||
1723 | |||||||
1724 | =item B |
||||||
1725 | |||||||
1726 | If set to '1', B |
||||||
1727 | the thumbnail image instead of the width and height. | ||||||
1728 | |||||||
1729 | Defaults to '0'. | ||||||
1730 | |||||||
1731 | =item B |
||||||
1732 | |||||||
1733 | Image you want to blend into your images in the lower right | ||||||
1734 | corner. This could be a transparent png saying "copyright | ||||||
1735 | my name 2001". | ||||||
1736 | |||||||
1737 | Optional. | ||||||
1738 | |||||||
1739 | =item B |
||||||
1740 | |||||||
1741 | Make the navigation in the picture view wrap around (So Next | ||||||
1742 | at the end displays the first picture, etc.) | ||||||
1743 | |||||||
1744 | Set to 1 or 0, default is 0 | ||||||
1745 | |||||||
1746 | =item B |
||||||
1747 | |||||||
1748 | Allow the user to download the Original picture without | ||||||
1749 | resizing or putting the CopyrightImage on it. | ||||||
1750 | |||||||
1751 | Set to 1 or 0, default is 0 | ||||||
1752 | |||||||
1753 | =item B |
||||||
1754 | |||||||
1755 | With this option you can configure which intervals can be selected for | ||||||
1756 | a slideshow. The default is '3 5 10 15 30' | ||||||
1757 | |||||||
1758 | =item B |
||||||
1759 | |||||||
1760 | Instead of the default filename ordering you can sort by any | ||||||
1761 | stat attribute. For example size, atime, mtime, ctime. | ||||||
1762 | |||||||
1763 | =item B |
||||||
1764 | |||||||
1765 | Set this variable to sort directories differently than other items, | ||||||
1766 | can be set to size, atime, mtime and ctime; setting any other value | ||||||
1767 | will revert to sorting by name. | ||||||
1768 | |||||||
1769 | =item B |
||||||
1770 | |||||||
1771 | Cache EXIF data using Memoize - this will make Apache::Gallery faster | ||||||
1772 | when many people access the same images, but it will also cache EXIF | ||||||
1773 | data until the current Apache child dies. | ||||||
1774 | |||||||
1775 | =item B |
||||||
1776 | |||||||
1777 | Set this option to 1 to make A::G show the files timestamp | ||||||
1778 | instead of the EXIF value for "Picture taken". | ||||||
1779 | |||||||
1780 | =item B |
||||||
1781 | |||||||
1782 | Enable the selection mode. Select images with checkboxes and | ||||||
1783 | get a list of filenames. | ||||||
1784 | |||||||
1785 | =item B |
||||||
1786 | |||||||
1787 | You can choose how Apache::Gallery should display EXIF info | ||||||
1788 | from your images. | ||||||
1789 | |||||||
1790 | The default setting is 'namevalue'. This setting will make | ||||||
1791 | Apache::Gallery print out the names and values of the EXIF values | ||||||
1792 | you configure with GalleryInfo. The information will be parsed into | ||||||
1793 | $INFO in pictureinfo.tpl. | ||||||
1794 | |||||||
1795 | You can also set it to 'values' which will make A::G parse | ||||||
1796 | the configured values into the var $EXIFVALUES as 'value | value | value' | ||||||
1797 | |||||||
1798 | If you set this option to 'variables' the items you configure in GalleryInfo | ||||||
1799 | will be available to your templates as $EXIF_ |
||||||
1800 | That means that with the default setting "Picture Taken => DateTimeOriginal, | ||||||
1801 | Flash => Flash" you will have the variables $EXIF_DATETIMEORIGINAL and | ||||||
1802 | $EXIF_FLASH available to your templates. You can place them | ||||||
1803 | anywhere you want. | ||||||
1804 | |||||||
1805 | =item B |
||||||
1806 | |||||||
1807 | Change the location of gallery root. The default is "" | ||||||
1808 | |||||||
1809 | =item B |
||||||
1810 | |||||||
1811 | Change the name that appears as the root element in the menu. The | ||||||
1812 | default is "root:" | ||||||
1813 | |||||||
1814 | =item B |
||||||
1815 | |||||||
1816 | This options controls how many thumbnails should be displayed in a | ||||||
1817 | page. It requires $BROWSELINKS to be in the index.tpl template file. | ||||||
1818 | |||||||
1819 | =item B |
||||||
1820 | |||||||
1821 | Pattern matching the files you want Apache::Gallery to view in the | ||||||
1822 | index as thumbnails. | ||||||
1823 | |||||||
1824 | The default is '\.(jpe?g|png|tiff?|ppm)$' | ||||||
1825 | |||||||
1826 | =item B |
||||||
1827 | |||||||
1828 | Pattern matching the files you want Apache::Gallery to view in the index | ||||||
1829 | as normal files. All other filetypes will still be served by Apache::Gallery | ||||||
1830 | but are not visible in the index. | ||||||
1831 | |||||||
1832 | The default is '\.(mpe?g|avi|mov|asf|wmv|doc|mp3|ogg|pdf|rtf|wav|dlt|txt|html?|csv|eps)$' | ||||||
1833 | |||||||
1834 | =item B |
||||||
1835 | |||||||
1836 | To use the GalleryCopyrightText feature you must set this option to the | ||||||
1837 | directory where your True Type fonts are stored. No default is set. | ||||||
1838 | |||||||
1839 | Example: | ||||||
1840 | |||||||
1841 | PerlSetVar GalleryTTFDir '/usr/share/fonts/' | ||||||
1842 | |||||||
1843 | =item B |
||||||
1844 | |||||||
1845 | To use the GalleryCopyrightText feature this option must be set to the | ||||||
1846 | name of the True Type font you wish to use. Example: | ||||||
1847 | |||||||
1848 | PerlSetVar GalleryTTFFile 'verdanab.ttf' | ||||||
1849 | |||||||
1850 | =item B |
||||||
1851 | |||||||
1852 | Configure the size of the CopyrightText that will be inserted as | ||||||
1853 | copyright notice in the corner of your pictures. | ||||||
1854 | |||||||
1855 | Example: | ||||||
1856 | |||||||
1857 | PerlSetVar GalleryTTFSize '10' | ||||||
1858 | |||||||
1859 | =item B |
||||||
1860 | |||||||
1861 | The text that will be inserted as copyright notice. | ||||||
1862 | |||||||
1863 | Example: | ||||||
1864 | |||||||
1865 | PerlSetVar GalleryCopyrightText '(c) Michael Legart' | ||||||
1866 | |||||||
1867 | =item B |
||||||
1868 | |||||||
1869 | The text color of your copyright notice. | ||||||
1870 | |||||||
1871 | Examples: | ||||||
1872 | |||||||
1873 | White: | ||||||
1874 | PerlSetVar GalleryCopyrightColor '255,255,255,255' | ||||||
1875 | |||||||
1876 | Black: | ||||||
1877 | PerlSetVar GalleryCopyrightColor '0,0,0,255' | ||||||
1878 | |||||||
1879 | Red: | ||||||
1880 | PerlSetVar GalleryCopyrightColor '255,0,0,255' | ||||||
1881 | |||||||
1882 | Green: | ||||||
1883 | PerlSetVar GalleryCopyrightColor '0,255,0,255' | ||||||
1884 | |||||||
1885 | Blue: | ||||||
1886 | PerlSetVar GalleryCopyrightColor '0,0,255,255' | ||||||
1887 | |||||||
1888 | Transparent orange: | ||||||
1889 | PerlSetVar GalleryCopyrightColor '255,127,0,127' | ||||||
1890 | |||||||
1891 | =item B |
||||||
1892 | |||||||
1893 | The background-color of a GalleryCopyrightText | ||||||
1894 | |||||||
1895 | r,g,b,a - for examples, see GalleryCopyrightColor | ||||||
1896 | |||||||
1897 | =item B |
||||||
1898 | |||||||
1899 | The quality (1-100) of scaled images | ||||||
1900 | |||||||
1901 | This setting affects the quality of the scaled images. | ||||||
1902 | Set this to a low number to reduce the size of the scaled images. | ||||||
1903 | Remember to clear out your cache if you change this setting. | ||||||
1904 | Quality seems to default to 75, at least in the jpeg and png loader code in | ||||||
1905 | Imlib2 1.1.0. | ||||||
1906 | |||||||
1907 | Examples: | ||||||
1908 | |||||||
1909 | Quality at 50: | ||||||
1910 | PerlSetVar GalleryQuality '50' | ||||||
1911 | |||||||
1912 | =item B |
||||||
1913 | |||||||
1914 | Set this option to 1 to convert underscores to spaces in the listing | ||||||
1915 | of directory and file names, as well as in the alt attribute for HTML | ||||||
1916 | |
||||||
1917 | |||||||
1918 | =back | ||||||
1919 | |||||||
1920 | =over 4 | ||||||
1921 | |||||||
1922 | =item B |
||||||
1923 | |||||||
1924 | Set this option to e.g. ImageDescription to use this field as comments | ||||||
1925 | for images. | ||||||
1926 | |||||||
1927 | =item B |
||||||
1928 | |||||||
1929 | Set this option to 1 to enable generation of a media RSS feed. This | ||||||
1930 | can be used e.g. together with the PicLens plugin from http://piclens.com | ||||||
1931 | |||||||
1932 | =back | ||||||
1933 | |||||||
1934 | =head1 FEATURES | ||||||
1935 | |||||||
1936 | =over 4 | ||||||
1937 | |||||||
1938 | =item B |
||||||
1939 | |||||||
1940 | Some cameras, like the Canon G3, detects the orientation of a picture | ||||||
1941 | and adds this info to the EXIF header. Apache::Gallery detects this | ||||||
1942 | and automatically rotates images with this info. | ||||||
1943 | |||||||
1944 | If your camera does not support this, you can rotate the images | ||||||
1945 | manually, This can also be used to override the rotate information | ||||||
1946 | from a camera that supports that. You can also disable this behavior | ||||||
1947 | with the GalleryAutoRotate option. | ||||||
1948 | |||||||
1949 | To use this functionality you have to create file with the name of the | ||||||
1950 | picture you want rotated appended with ".rotate". The file should include | ||||||
1951 | a number where these numbers are supported: | ||||||
1952 | |||||||
1953 | "1", rotates clockwise by 90 degree | ||||||
1954 | "2", rotates clockwise by 180 degrees | ||||||
1955 | "3", rotates clockwise by 270 degrees | ||||||
1956 | |||||||
1957 | So if we want to rotate "Picture1234.jpg" 90 degrees clockwise we would | ||||||
1958 | create a file in the same directory called "Picture1234.jpg.rotate" with | ||||||
1959 | the number 1 inside of it. | ||||||
1960 | |||||||
1961 | =item B |
||||||
1962 | |||||||
1963 | To ignore a directory or a file (of any kind, not only images) you | ||||||
1964 | create a |
||||||
1965 | |||||||
1966 | =item B |
||||||
1967 | |||||||
1968 | To include comments for a directory you create a |
||||||
1969 | file where the first line can contain "TITLE: New title" which | ||||||
1970 | will be the title of the page, and a comment on the following | ||||||
1971 | lines. | ||||||
1972 | To include comments for each picture you create files called | ||||||
1973 | picture.jpg.comment where the first line can contain "TITLE: New | ||||||
1974 | title" which will be the title of the page, and a comment on the | ||||||
1975 | following lines. | ||||||
1976 | |||||||
1977 | Example: | ||||||
1978 | |||||||
1979 | TITLE: This is the new title of the page | ||||||
1980 | And this is the comment. |
||||||
1981 | And this is line two of the comment. | ||||||
1982 | |||||||
1983 | The visible name of the folder is by default identical to the name of | ||||||
1984 | the folder, but can be changed by creating a file |
||||||
1985 | with the visible name of the folder. | ||||||
1986 | |||||||
1987 | It is also possible to set GalleryCommentExifKey to the name of an EXIF | ||||||
1988 | field containing the comment, e.g. ImageDescription. The EXIF comment is | ||||||
1989 | overridden by the .comment file if it exists. | ||||||
1990 | |||||||
1991 | =back | ||||||
1992 | |||||||
1993 | =head1 DEPENDENCIES | ||||||
1994 | |||||||
1995 | =over 4 | ||||||
1996 | |||||||
1997 | =item B |
||||||
1998 | |||||||
1999 | =item B |
||||||
2000 | |||||||
2001 | =item B |
||||||
2002 | |||||||
2003 | =item B |
||||||
2004 | |||||||
2005 | =item B |
||||||
2006 | |||||||
2007 | =item B |
||||||
2008 | |||||||
2009 | =item B |
||||||
2010 | |||||||
2011 | =item B |
||||||
2012 | (ie, XFree86) | ||||||
2013 | |||||||
2014 | =item B |
||||||
2015 | Remember the -dev package when using rpm, deb or other package formats! | ||||||
2016 | |||||||
2017 | =back | ||||||
2018 | |||||||
2019 | =head1 AUTHOR | ||||||
2020 | |||||||
2021 | Michael Legart |
||||||
2022 | |||||||
2023 | =head1 COPYRIGHT AND LICENSE | ||||||
2024 | |||||||
2025 | Copyright (C) 2001-2011 Michael Legart |
||||||
2026 | |||||||
2027 | Templates designed by Thomas Kjaer |
||||||
2028 | |||||||
2029 | Apache::Gallery is free software and is released under the Artistic License. | ||||||
2030 | See B |
||||||
2031 | |||||||
2032 | The video icons are from the GNOME project. B |
||||||
2033 | |||||||
2034 | =head1 THANKS | ||||||
2035 | |||||||
2036 | Thanks to Thomas Kjaer for templates and design of B |
||||||
2037 | Thanks to Thomas Eibner and other for patches. (See the Changes file) | ||||||
2038 | |||||||
2039 | =head1 SEE ALSO | ||||||
2040 | |||||||
2041 | L |
||||||
2042 | L |
||||||
2043 | |||||||
2044 | =cut |