blib/lib/HTML/KhatGallery/Core.pm | |||
---|---|---|---|
Criterion | Covered | Total | % |
statement | 39 | 702 | 5.5 |
branch | 0 | 202 | 0.0 |
condition | 0 | 71 | 0.0 |
subroutine | 13 | 58 | 22.4 |
pod | 44 | 44 | 100.0 |
total | 96 | 1077 | 8.9 |
line | stmt | bran | cond | sub | pod | time | code |
---|---|---|---|---|---|---|---|
1 | package HTML::KhatGallery::Core; | ||||||
2 | our $VERSION = '0.2405'; # VERSION | ||||||
3 | 3 | 3 | 13976 | use strict; | |||
3 | 4 | ||||||
3 | 72 | ||||||
4 | 3 | 3 | 11 | use warnings; | |||
3 | 5 | ||||||
3 | 85 | ||||||
5 | |||||||
6 | =head1 NAME | ||||||
7 | |||||||
8 | HTML::KhatGallery::Core - the core methods for HTML::KhatGallery | ||||||
9 | |||||||
10 | =head1 VERSION | ||||||
11 | |||||||
12 | version 0.2405 | ||||||
13 | |||||||
14 | =head1 SYNOPSIS | ||||||
15 | |||||||
16 | # implicitly | ||||||
17 | use HTML::KhatGallery qw(HTML::KhatGallery::Core HTML::KhatGallery::Plugin::MyPlugin ...); | ||||||
18 | |||||||
19 | # or explicitly | ||||||
20 | require HTML::KhatGallery; | ||||||
21 | |||||||
22 | @plugins = qw(HTML::KhatGallery::Core HTML::KhatGallery::Plugin::MyPlugin ...); | ||||||
23 | HTML::KhatGallery->import(@plugins); | ||||||
24 | HTML::KhatGallery->run(%args); | ||||||
25 | |||||||
26 | |||||||
27 | =head1 DESCRIPTION | ||||||
28 | |||||||
29 | HTML::KhatGallery is a photo-gallery generator. | ||||||
30 | |||||||
31 | HTML::KhatGallery::Core provides the core functionality of the system. | ||||||
32 | Other functions can be added or overridden by plugin modules. | ||||||
33 | |||||||
34 | =cut | ||||||
35 | |||||||
36 | 3 | 3 | 1095 | use POSIX qw(ceil); | |||
3 | 14194 | ||||||
3 | 11 | ||||||
37 | 3 | 3 | 3090 | use File::Basename; | |||
3 | 9 | ||||||
3 | 189 | ||||||
38 | 3 | 3 | 16 | use File::Spec; | |||
3 | 3 | ||||||
3 | 75 | ||||||
39 | 3 | 3 | 13 | use Cwd qw(realpath); | |||
3 | 3 | ||||||
3 | 100 | ||||||
40 | 3 | 3 | 1050 | use File::stat; | |||
3 | 16361 | ||||||
3 | 9 | ||||||
41 | 3 | 3 | 1082 | use YAML qw(Dump LoadFile); | |||
3 | 15057 | ||||||
3 | 127 | ||||||
42 | 3 | 3 | 3789 | use Image::ExifTool; | |||
3 | 130744 | ||||||
3 | 1497 | ||||||
43 | |||||||
44 | =head1 CLASS METHODS | ||||||
45 | |||||||
46 | =head2 run | ||||||
47 | |||||||
48 | HTML::KhatGallery->run(%args); | ||||||
49 | |||||||
50 | C |
||||||
51 | this module; other methods are called internally by this one. | ||||||
52 | |||||||
53 | This method orchestrates all the work; it creates a new object, | ||||||
54 | and applies all the actions. | ||||||
55 | |||||||
56 | Arguments: | ||||||
57 | |||||||
58 | =over | ||||||
59 | |||||||
60 | =item B |
||||||
61 | |||||||
62 | The name of the captions file; which is in the same directory | ||||||
63 | as the images which it describes. This file is in L |
||||||
64 | For example: | ||||||
65 | |||||||
66 | --- | ||||||
67 | index.html: this is the caption for the album as a whole | ||||||
68 | image1.png: this is the caption for image1.png | ||||||
69 | image2.jpg: I like the second image | ||||||
70 | |||||||
71 | (default: captions.yml) | ||||||
72 | |||||||
73 | =item B |
||||||
74 | |||||||
75 | Instead of generating files, clean up the thumbnail directories to | ||||||
76 | remove thumbnails and image HTML pages for images which are no | ||||||
77 | longer there. | ||||||
78 | |||||||
79 | =item B |
||||||
80 | |||||||
81 | Set the level of debugging output. The higher the level, the more verbose. | ||||||
82 | (developer only) | ||||||
83 | (default: 0) | ||||||
84 | |||||||
85 | =item B |
||||||
86 | |||||||
87 | Regular expression to match the directories we are interested in. | ||||||
88 | Hidden directories and the thumbnail directory will never be included. | ||||||
89 | |||||||
90 | =item B |
||||||
91 | |||||||
92 | Force the re-generation of all the HTML files even if they already | ||||||
93 | exist. If false (the default) then a given HTML file will only be | ||||||
94 | created if there is a change in that particular directory. | ||||||
95 | |||||||
96 | =item B |
||||||
97 | |||||||
98 | Force the re-generation of the thumbnail images even if they already | ||||||
99 | exist. If false (the default) then a given (thumbnail) image file will | ||||||
100 | only be created if it doesn't already exist. | ||||||
101 | |||||||
102 | =item B |
||||||
103 | |||||||
104 | Regular expression determining what filenames should be interpreted | ||||||
105 | as images. | ||||||
106 | |||||||
107 | =item B | ||||||
108 | |||||||
109 | Array reference containing formats for meta-data from the images. | ||||||
110 | Field names are surrounded by % characters. For example: | ||||||
111 | |||||||
112 | meta => ['Date: %DateTime%', '%Comment%'], | ||||||
113 | |||||||
114 | If an image doesn't have that particular field, the data for that field is not | ||||||
115 | shown. All the meta-data is placed after any caption the image has. | ||||||
116 | |||||||
117 | =item B |
||||||
118 | |||||||
119 | Template for HTML pages. The default template is this: | ||||||
120 | |||||||
121 | |||||||
122 | "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> | ||||||
123 | |||||||
124 | |||||||
125 | |
||||||
126 | |||||||
127 | |||||||
128 | |||||||
129 | |||||||
130 | |||||||
131 | |||||||
132 | |||||||
133 | This can be a string or a filename. | ||||||
134 | |||||||
135 | =item B |
||||||
136 | |||||||
137 | The number of images to display per index page. | ||||||
138 | |||||||
139 | =item B |
||||||
140 | |||||||
141 | The name of the directory where thumbnails and image-pages are put. | ||||||
142 | It is a subdirectory below the directory where its images are. | ||||||
143 | (default: tn) | ||||||
144 | |||||||
145 | =item B |
||||||
146 | |||||||
147 | The size of the thumbnails. This doesn't actually define the dimensions | ||||||
148 | of the thumbnails, but their area. This gives better-quality thumbnails. | ||||||
149 | (default:100x100) | ||||||
150 | |||||||
151 | =item B |
||||||
152 | |||||||
153 | The directory to look for images in; this will be searched for images and | ||||||
154 | sub-directories. If this is not given, the current directory is used. | ||||||
155 | |||||||
156 | =item B |
||||||
157 | |||||||
158 | The directory to create galleries in; HTML and thumbnails will be created | ||||||
159 | there. If this is not given, it is the same as B |
||||||
160 | |||||||
161 | =item B |
||||||
162 | |||||||
163 | The URL of the top images directory; if the top_out_dir isn't the | ||||||
164 | same as the top_dir, then we need to know this in order | ||||||
165 | to link to the images in the images directory. | ||||||
166 | |||||||
167 | =item B |
||||||
168 | |||||||
169 | Print informational messages. | ||||||
170 | |||||||
171 | =back | ||||||
172 | |||||||
173 | =cut | ||||||
174 | sub run { | ||||||
175 | 0 | 0 | 1 | my $class = shift; | |||
176 | 0 | my %args = ( | |||||
177 | parent=>'', | ||||||
178 | @_ | ||||||
179 | ); | ||||||
180 | |||||||
181 | 0 | my $self = $class->new(%args); | |||||
182 | 0 | $self->init(); | |||||
183 | print "Processing directory $self->{top_dir}\n" | ||||||
184 | 0 | 0 | if $self->{verbose}; | ||||
185 | |||||||
186 | 0 | $self->do_dir_actions(''); | |||||
187 | } # run | ||||||
188 | |||||||
189 | =head1 OBJECT METHODS | ||||||
190 | |||||||
191 | Only of interest to developers and those wishing to write plugins. | ||||||
192 | |||||||
193 | =head2 new | ||||||
194 | |||||||
195 | Make a new object. See L for the arguments. | ||||||
196 | This method should not be overridden by plugin writers; use L | ||||||
197 | instead. | ||||||
198 | |||||||
199 | =cut | ||||||
200 | |||||||
201 | sub new { | ||||||
202 | 0 | 0 | 1 | my $class = shift; | |||
203 | 0 | 0 | my $self = bless ({@_}, ref ($class) || $class); | ||||
204 | |||||||
205 | 0 | return ($self); | |||||
206 | } # new | ||||||
207 | |||||||
208 | =head2 init | ||||||
209 | |||||||
210 | Do some initialization of the object after it's created. | ||||||
211 | See L for the arguments. | ||||||
212 | Set up defaults for things which haven't been defined. | ||||||
213 | |||||||
214 | Plugin writers should override this method rather than L | ||||||
215 | if they want to do some initialization for their plugin. | ||||||
216 | |||||||
217 | =cut | ||||||
218 | |||||||
219 | sub init { | ||||||
220 | 0 | 0 | 1 | my $self = shift; | |||
221 | |||||||
222 | # some defaults | ||||||
223 | 0 | 0 | $self->{per_page} ||= 16; | ||||
224 | 0 | 0 | $self->{thumbdir} ||= 'tn'; | ||||
225 | 0 | 0 | $self->{captions_file} ||= 'captions.yml'; | ||||
226 | 0 | 0 | $self->{thumb_geom} ||= '100x100'; | ||||
227 | 0 | 0 | $self->{force_html} ||= 0; | ||||
228 | 0 | 0 | $self->{force_images} ||= 0; | ||||
229 | |||||||
230 | 0 | 0 | $self->{debug_level} ||= 0; | ||||
231 | # if there's no top dir, make it the current one | ||||||
232 | 0 | 0 | if (!defined $self->{top_dir}) | ||||
233 | { | ||||||
234 | 0 | $self->{top_dir} = '.'; | |||||
235 | } | ||||||
236 | 0 | $self->{top_dir} = File::Spec->rel2abs($self->{top_dir}); | |||||
237 | 0 | $self->{top_base} = basename($self->{top_dir}); | |||||
238 | |||||||
239 | # top_out_dir | ||||||
240 | 0 | 0 | if (!defined $self->{top_out_dir}) | ||||
241 | { | ||||||
242 | 0 | $self->{top_out_dir} = $self->{top_dir}; | |||||
243 | } | ||||||
244 | 0 | $self->{top_out_dir} = File::Spec->rel2abs($self->{top_out_dir}); | |||||
245 | 0 | $self->{top_out_base} = basename($self->{top_out_dir}); | |||||
246 | |||||||
247 | # trim top_url if it has a trailing slash | ||||||
248 | 0 | 0 | if (defined $self->{top_url}) | ||||
249 | { | ||||||
250 | 0 | $self->{top_url} =~ s!/$!!; | |||||
251 | } | ||||||
252 | else | ||||||
253 | { | ||||||
254 | 0 | $self->{top_url} = ''; | |||||
255 | } | ||||||
256 | |||||||
257 | # calculate width and height of thumbnail display | ||||||
258 | 0 | $self->{thumb_geom} =~ /(\d+)x(\d+)/; | |||||
259 | 0 | $self->{thumb_width} = $1; | |||||
260 | 0 | $self->{thumb_height} = $2; | |||||
261 | 0 | $self->{pixelcount} = $self->{thumb_width} * $self->{thumb_height}; | |||||
262 | |||||||
263 | 0 | 0 | if (!defined $self->{dir_actions}) | ||||
264 | { | ||||||
265 | 0 | $self->{dir_actions} = [qw(init_settings | |||||
266 | read_captions | ||||||
267 | read_dir | ||||||
268 | read_out_dir | ||||||
269 | filter_images | ||||||
270 | sort_images | ||||||
271 | filter_dirs | ||||||
272 | sort_dirs | ||||||
273 | make_index_page | ||||||
274 | process_images | ||||||
275 | process_subdirs | ||||||
276 | tidy_up | ||||||
277 | )]; | ||||||
278 | } | ||||||
279 | 0 | 0 | if (!defined $self->{clean_actions}) | ||||
280 | { | ||||||
281 | 0 | $self->{clean_actions} = [qw(init_settings | |||||
282 | read_dir | ||||||
283 | filter_images | ||||||
284 | filter_dirs | ||||||
285 | clean_thumb_dir | ||||||
286 | process_subdirs | ||||||
287 | tidy_up | ||||||
288 | )]; | ||||||
289 | } | ||||||
290 | |||||||
291 | 0 | 0 | if (!defined $self->{image_actions}) | ||||
292 | { | ||||||
293 | 0 | $self->{image_actions} = [qw(init_image_settings | |||||
294 | make_thumbnail | ||||||
295 | make_image_page | ||||||
296 | image_tidy_up | ||||||
297 | )]; | ||||||
298 | } | ||||||
299 | |||||||
300 | 0 | 0 | if (!defined $self->{image_match}) | ||||
301 | { | ||||||
302 | 0 | my @img_ext = map {"\.$_\$"} | |||||
0 | |||||||
303 | qw(jpg jpeg png gif tif tiff pcx xwd xpm xbm); | ||||||
304 | 0 | my $img_re = join('|', @img_ext); | |||||
305 | 0 | $self->{image_match} = qr/$img_re/i; | |||||
306 | } | ||||||
307 | |||||||
308 | 0 | 0 | if (!defined $self->{page_template}) | ||||
309 | { | ||||||
310 | 0 | $self->{page_template} = < | |||||
311 | |||||||
312 | "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> | ||||||
313 | |||||||
314 | |||||||
315 | |
||||||
316 | |||||||
317 | |||||||
318 | |||||||
319 | |||||||
320 | |||||||
321 | |||||||
322 | EOT | ||||||
323 | } | ||||||
324 | |||||||
325 | 0 | return ($self); | |||||
326 | } # init | ||||||
327 | |||||||
328 | =head2 do_dir_actions | ||||||
329 | |||||||
330 | $self->do_dir_actions($dir); | ||||||
331 | |||||||
332 | Do all the actions in the $self->{dir_actions} list, for the | ||||||
333 | given directory. If cleaning, do the actions in the 'clean_actions' | ||||||
334 | list instead. | ||||||
335 | If the dir is empty, this is taken to be the directory given in | ||||||
336 | $self->{top_dir}, the top-level directory. | ||||||
337 | |||||||
338 | =cut | ||||||
339 | sub do_dir_actions { | ||||||
340 | 0 | 0 | 1 | my $self = shift; | |||
341 | 0 | my $dir = shift; | |||||
342 | |||||||
343 | 0 | my %state = (); | |||||
344 | 0 | $state{stop} = 0; | |||||
345 | 0 | $state{dir} = $dir; | |||||
346 | |||||||
347 | 3 | 3 | 28 | no strict qw(subs refs); | |||
3 | 5 | ||||||
3 | 276 | ||||||
348 | my @actions = ($self->{clean} | ||||||
349 | 0 | ? @{$self->{clean_actions}} | |||||
350 | 0 | 0 | : @{$self->{dir_actions}}); | ||||
0 | |||||||
351 | 0 | while (@actions) | |||||
352 | { | ||||||
353 | 0 | my $action = shift @actions; | |||||
354 | 0 | 0 | last if $state{stop}; | ||||
355 | 0 | $state{action} = $action; | |||||
356 | 0 | $self->debug(2, "action: $action"); | |||||
357 | 0 | $self->$action(\%state); | |||||
358 | } | ||||||
359 | 3 | 3 | 18 | use strict qw(subs refs); | |||
3 | 4 | ||||||
3 | 254 | ||||||
360 | 0 | 1; | |||||
361 | } # do_dir_actions | ||||||
362 | |||||||
363 | =head2 do_image_actions | ||||||
364 | |||||||
365 | $self->do_image_actions(\%dir_state, @images); | ||||||
366 | |||||||
367 | Do all the actions in the $self->{image_actions} list, for the | ||||||
368 | given images. | ||||||
369 | |||||||
370 | =cut | ||||||
371 | sub do_image_actions { | ||||||
372 | 0 | 0 | 1 | my $self = shift; | |||
373 | 0 | my $dir_state = shift; | |||||
374 | 0 | my @images = @_; | |||||
375 | |||||||
376 | 0 | my %images_state = (); | |||||
377 | |||||||
378 | 3 | 3 | 16 | no strict qw(subs refs); | |||
3 | 5 | ||||||
3 | 327 | ||||||
379 | 0 | for (my $i = 0; $i < @images; $i++) | |||||
380 | { | ||||||
381 | 0 | %images_state = (); | |||||
382 | 0 | $images_state{stop} = 0; | |||||
383 | 0 | $images_state{images} = \@images; | |||||
384 | 0 | $images_state{num} = $i; | |||||
385 | 0 | $images_state{cur_img} = $images[$i]; | |||||
386 | # pop off each action as we go; | ||||||
387 | # that way it's possible for an action to | ||||||
388 | # manipulate the actions array | ||||||
389 | 0 | @{$images_state{image_actions}} = @{$self->{image_actions}}; | |||||
0 | |||||||
0 | |||||||
390 | 0 | while (@{$images_state{image_actions}}) | |||||
0 | |||||||
391 | { | ||||||
392 | 0 | my $action = shift @{$images_state{image_actions}}; | |||||
0 | |||||||
393 | 0 | 0 | last if $images_state{stop}; | ||||
394 | 0 | $images_state{action} = $action; | |||||
395 | 0 | $self->debug(2, "image_action: $action"); | |||||
396 | 0 | $self->$action($dir_state, | |||||
397 | \%images_state); | ||||||
398 | } | ||||||
399 | } | ||||||
400 | 3 | 3 | 21 | use strict qw(subs refs); | |||
3 | 6 | ||||||
3 | 14809 | ||||||
401 | 0 | 1; | |||||
402 | } # do_image_actions | ||||||
403 | |||||||
404 | =head1 Dir Action Methods | ||||||
405 | |||||||
406 | Methods implementing directory-related actions. All such actions | ||||||
407 | expect a reference to a state hash, and generally will update either | ||||||
408 | that hash or the object itself, or both, in the course of their | ||||||
409 | running. | ||||||
410 | |||||||
411 | =head2 init_settings | ||||||
412 | |||||||
413 | Initialize various settings that need to be set before everything | ||||||
414 | else. | ||||||
415 | |||||||
416 | This is not the same as "init", because this is the start of | ||||||
417 | the dir_actions sequence; we do it for each directory (or sub-directory) | ||||||
418 | we traverse. | ||||||
419 | |||||||
420 | =cut | ||||||
421 | sub init_settings { | ||||||
422 | 0 | 0 | 1 | my $self = shift; | |||
423 | 0 | my $dir_state = shift; | |||||
424 | |||||||
425 | $dir_state->{abs_dir} = File::Spec->catdir( | ||||||
426 | 0 | realpath($self->{top_dir}), $dir_state->{dir}); | |||||
427 | $dir_state->{abs_out_dir} = File::Spec->catdir( | ||||||
428 | 0 | realpath($self->{top_out_dir}), $dir_state->{dir}); | |||||
429 | 0 | my @path = File::Spec->splitdir($dir_state->{abs_dir}); | |||||
430 | 0 | 0 | if ($dir_state->{dir}) | ||||
431 | { | ||||||
432 | 0 | $dir_state->{dirbase} = pop @path; | |||||
433 | 0 | $dir_state->{parent} = pop @path; | |||||
434 | 0 | $dir_state->{dir_url} = $self->{top_url} . '/' . $dir_state->{dir}; | |||||
435 | } | ||||||
436 | else # first dir | ||||||
437 | { | ||||||
438 | 0 | $dir_state->{dirbase} = pop @path; | |||||
439 | 0 | $dir_state->{parent} = ''; | |||||
440 | 0 | $dir_state->{dir_url} = $self->{top_url}; | |||||
441 | } | ||||||
442 | # thumbnail dir for this directory | ||||||
443 | $dir_state->{abs_thumbdir} = File::Spec->catdir($dir_state->{abs_out_dir}, | ||||||
444 | 0 | $self->{thumbdir}); | |||||
445 | |||||||
446 | # reset the per-directory redo_html flag | ||||||
447 | 0 | $dir_state->{redo_html} = 0; | |||||
448 | |||||||
449 | } # init_settings | ||||||
450 | |||||||
451 | =head2 read_captions | ||||||
452 | |||||||
453 | Set the $dir_state->{captions} hash to contain all the | ||||||
454 | captions for this directory (if they exist) | ||||||
455 | |||||||
456 | =cut | ||||||
457 | sub read_captions { | ||||||
458 | 0 | 0 | 1 | my $self = shift; | |||
459 | 0 | my $dir_state = shift; | |||||
460 | |||||||
461 | my $captions_file = File::Spec->catfile($dir_state->{abs_dir}, | ||||||
462 | 0 | $self->{captions_file}); | |||||
463 | 0 | 0 | if (!-f $captions_file) | ||||
464 | { | ||||||
465 | $captions_file = File::Spec->catfile($dir_state->{abs_out_dir}, | ||||||
466 | 0 | $self->{captions_file}); | |||||
467 | } | ||||||
468 | 0 | 0 | if (-f $captions_file) | ||||
469 | { | ||||||
470 | 0 | $dir_state->{captions} = {}; | |||||
471 | 0 | $dir_state->{captions} = LoadFile($captions_file); | |||||
472 | } | ||||||
473 | } # read_captions | ||||||
474 | |||||||
475 | =head2 read_dir | ||||||
476 | |||||||
477 | Read the $dir_state->{dir} directory. Sets $dir_state->{subdirs}, and | ||||||
478 | $dir_state->{files} with the relative subdirs, and other files. | ||||||
479 | |||||||
480 | =cut | ||||||
481 | sub read_dir { | ||||||
482 | 0 | 0 | 1 | my $self = shift; | |||
483 | 0 | my $dir_state = shift; | |||||
484 | |||||||
485 | 0 | my $dh; | |||||
486 | 0 | 0 | opendir($dh, $dir_state->{abs_dir}) or die "Can't opendir $dir_state->{abs_dir}: $!"; | ||||
487 | 0 | my @subdirs = (); | |||||
488 | 0 | my @files = (); | |||||
489 | 0 | while (my $fn = readdir($dh)) | |||||
490 | { | ||||||
491 | 0 | my $abs_fn = File::Spec->catfile($dir_state->{abs_dir}, $fn); | |||||
492 | 0 | 0 | 0 | if ($fn =~ /^\./ or $fn eq $self->{thumbdir}) | |||
0 | |||||||
0 | |||||||
493 | { | ||||||
494 | # skip | ||||||
495 | } | ||||||
496 | elsif (-d $abs_fn) | ||||||
497 | { | ||||||
498 | 0 | push @subdirs, $fn; | |||||
499 | } | ||||||
500 | # ignore any html files | ||||||
501 | elsif ($fn =~ /\.html$/) | ||||||
502 | { | ||||||
503 | } | ||||||
504 | else | ||||||
505 | { | ||||||
506 | 0 | push @files, $fn; | |||||
507 | } | ||||||
508 | } | ||||||
509 | 0 | closedir($dh); | |||||
510 | |||||||
511 | 0 | $dir_state->{subdirs} = \@subdirs; | |||||
512 | 0 | $dir_state->{files} = \@files; | |||||
513 | } # read_dir | ||||||
514 | |||||||
515 | =head2 read_out_dir | ||||||
516 | |||||||
517 | Read the $dir_state->{dir} directory in the output tree. | ||||||
518 | Sets $dir_state->{index_files} with the index*.html files. | ||||||
519 | |||||||
520 | =cut | ||||||
521 | sub read_out_dir { | ||||||
522 | 0 | 0 | 1 | my $self = shift; | |||
523 | 0 | my $dir_state = shift; | |||||
524 | |||||||
525 | 0 | my @index_files = (); | |||||
526 | 0 | 0 | if (-d $dir_state->{abs_out_dir}) | ||||
527 | { | ||||||
528 | 0 | my $dh; | |||||
529 | 0 | 0 | opendir($dh, $dir_state->{abs_out_dir}) or die "Can't opendir $dir_state->{abs_out_dir}: $!"; | ||||
530 | 0 | while (my $fn = readdir($dh)) | |||||
531 | { | ||||||
532 | 0 | my $abs_fn = File::Spec->catfile($dir_state->{abs_out_dir}, $fn); | |||||
533 | 0 | 0 | 0 | if ($fn =~ /^\./ or $fn eq $self->{thumbdir}) | |||
0 | |||||||
534 | { | ||||||
535 | # skip | ||||||
536 | } | ||||||
537 | # remember the index files | ||||||
538 | elsif ($fn =~ /index.*\.html$/) | ||||||
539 | { | ||||||
540 | 0 | push @index_files, $fn; | |||||
541 | } | ||||||
542 | } | ||||||
543 | 0 | closedir($dh); | |||||
544 | } | ||||||
545 | |||||||
546 | 0 | $dir_state->{index_files} = \@index_files; | |||||
547 | } # read_out_dir | ||||||
548 | |||||||
549 | =head2 filter_images | ||||||
550 | |||||||
551 | Sets $dir_state->{files} to contain only image files that | ||||||
552 | we are interested in. | ||||||
553 | |||||||
554 | =cut | ||||||
555 | sub filter_images { | ||||||
556 | 0 | 0 | 1 | my $self = shift; | |||
557 | 0 | my $dir_state = shift; | |||||
558 | |||||||
559 | 0 | 0 | 0 | if ($self->{image_match} | |||
560 | 0 | and @{$dir_state->{files}}) | |||||
561 | { | ||||||
562 | 0 | my $img_match = $self->{image_match}; | |||||
563 | my @images = grep { | ||||||
564 | 0 | /$img_match/ | |||||
565 | 0 | } @{$dir_state->{files}}; | |||||
0 | |||||||
566 | 0 | $dir_state->{files} = \@images; | |||||
567 | } | ||||||
568 | } # filter_images | ||||||
569 | |||||||
570 | =head2 sort_images | ||||||
571 | |||||||
572 | Sorts the $dir_state->{files} array. | ||||||
573 | |||||||
574 | =cut | ||||||
575 | sub sort_images { | ||||||
576 | 0 | 0 | 1 | my $self = shift; | |||
577 | 0 | my $dir_state = shift; | |||||
578 | |||||||
579 | 0 | 0 | if (@{$dir_state->{files}}) | ||||
0 | |||||||
580 | { | ||||||
581 | 0 | my @images = sort @{$dir_state->{files}}; | |||||
0 | |||||||
582 | 0 | $dir_state->{files} = \@images; | |||||
583 | } | ||||||
584 | } # sort_images | ||||||
585 | |||||||
586 | =head2 filter_dirs | ||||||
587 | |||||||
588 | Sets $dir_state->{subdirs} to contain only directories that | ||||||
589 | we are interested in. | ||||||
590 | |||||||
591 | =cut | ||||||
592 | sub filter_dirs { | ||||||
593 | 0 | 0 | 1 | my $self = shift; | |||
594 | 0 | my $dir_state = shift; | |||||
595 | |||||||
596 | 0 | 0 | 0 | if ($self->{dir_match} | |||
597 | 0 | and @{$dir_state->{subdirs}}) | |||||
598 | { | ||||||
599 | 0 | my $dir_match = $self->{dir_match}; | |||||
600 | my @dirs = grep { | ||||||
601 | 0 | /$dir_match/ | |||||
602 | 0 | } @{$dir_state->{subdirs}}; | |||||
0 | |||||||
603 | 0 | $dir_state->{subdirs} = \@dirs; | |||||
604 | } | ||||||
605 | } # filter_dirs | ||||||
606 | |||||||
607 | =head2 sort_dirs | ||||||
608 | |||||||
609 | Sorts the $dir_state->{subdirs} array. | ||||||
610 | |||||||
611 | =cut | ||||||
612 | sub sort_dirs { | ||||||
613 | 0 | 0 | 1 | my $self = shift; | |||
614 | 0 | my $dir_state = shift; | |||||
615 | |||||||
616 | 0 | 0 | if (@{$dir_state->{subdirs}}) | ||||
0 | |||||||
617 | { | ||||||
618 | 0 | my @dirs = sort @{$dir_state->{subdirs}}; | |||||
0 | |||||||
619 | 0 | $dir_state->{subdirs} = \@dirs; | |||||
620 | } | ||||||
621 | } # sort_dirs | ||||||
622 | |||||||
623 | =head2 make_index_page | ||||||
624 | |||||||
625 | Make the index page(s) for this directory. | ||||||
626 | |||||||
627 | =cut | ||||||
628 | sub make_index_page { | ||||||
629 | 0 | 0 | 1 | my $self = shift; | |||
630 | 0 | my $dir_state = shift; | |||||
631 | |||||||
632 | # determine the number of pages | ||||||
633 | # To make things easier, always put the subdirs on each index page | ||||||
634 | 0 | my $num_files = @{$dir_state->{files}}; | |||||
0 | |||||||
635 | 0 | my $pages = ceil($num_files / $self->{per_page}); | |||||
636 | # if there are only subdirs make sure you still make an index | ||||||
637 | 0 | 0 | 0 | if ($pages == 0 and @{$dir_state->{subdirs}}) | |||
0 | |||||||
638 | { | ||||||
639 | 0 | $pages = 1; | |||||
640 | } | ||||||
641 | 0 | $dir_state->{pages} = $pages; | |||||
642 | |||||||
643 | # make the output dir if it doesn't exist | ||||||
644 | 0 | 0 | if (!-d $dir_state->{abs_out_dir}) | ||||
645 | { | ||||||
646 | 0 | mkdir $dir_state->{abs_out_dir}; | |||||
647 | } | ||||||
648 | |||||||
649 | # if we have any new images in this directory, we need to re-make the index | ||||||
650 | # files because we don't know which index file it will appear in, | ||||||
651 | # and we need to re-make the other HTML files because | ||||||
652 | # we need to re-generate the prev/next links | ||||||
653 | 0 | $dir_state->{redo_html} = $self->index_needs_rebuilding($dir_state); | |||||
654 | |||||||
655 | # if forcing HTML, delete the old index pages | ||||||
656 | # just in case we are going to have fewer pages | ||||||
657 | # this time around | ||||||
658 | 0 | 0 | 0 | if ($self->{force_html} or $dir_state->{redo_html}) | |||
659 | { | ||||||
660 | 0 | foreach my $if (@{$dir_state->{index_files}}) | |||||
0 | |||||||
661 | { | ||||||
662 | 0 | my $ff = File::Spec->catfile($dir_state->{abs_out_dir}, $if); | |||||
663 | 0 | unlink $ff; | |||||
664 | } | ||||||
665 | } | ||||||
666 | |||||||
667 | 0 | 0 | if ($self->{verbose}) | ||||
668 | { | ||||||
669 | # if the first index is gone, we're rebuilding all of them | ||||||
670 | 0 | my $first_index | |||||
671 | = $self->get_index_pagename(dir_state=>$dir_state, | ||||||
672 | page=>1, get_filename=>1); | ||||||
673 | 0 | 0 | if (!-f $first_index) | ||||
674 | { | ||||||
675 | 0 | print "making $pages indexes\n"; | |||||
676 | } | ||||||
677 | } | ||||||
678 | |||||||
679 | # for each page | ||||||
680 | 0 | for (my $page = 1; $page <= $pages; $page++) | |||||
681 | { | ||||||
682 | # calculate the filename | ||||||
683 | 0 | my $ifile = $self->get_index_pagename(dir_state=>$dir_state, | |||||
684 | page=>$page, get_filename=>1); | ||||||
685 | 0 | 0 | if (-f $ifile) | ||||
686 | { | ||||||
687 | 0 | next; | |||||
688 | } | ||||||
689 | |||||||
690 | # figure which files are in this page | ||||||
691 | # Determine number of images to skip | ||||||
692 | 0 | my @images = (); | |||||
693 | 0 | 0 | if (@{$dir_state->{files}}) | ||||
0 | |||||||
694 | { | ||||||
695 | 0 | my $skip = $self->{per_page} * ($page-1); | |||||
696 | # index of last entry to include | ||||||
697 | 0 | my $last = $skip + $self->{per_page}; | |||||
698 | 0 | 0 | $last = $num_files if ($last > $num_files); | ||||
699 | 0 | $last--; # need the index, not the count | |||||
700 | 0 | @images = @{$dir_state->{files}}[$skip .. $last]; | |||||
0 | |||||||
701 | } | ||||||
702 | |||||||
703 | 0 | my @content = (); | |||||
704 | 0 | push @content, $self->start_index_page($dir_state, $page); | |||||
705 | # add the subdirs | ||||||
706 | 0 | push @content, $self->make_index_subdirs($dir_state, $page); | |||||
707 | # add the images | ||||||
708 | 0 | push @content, $self->make_image_index(dir_state=>$dir_state, | |||||
709 | page=>$page, images=>\@images); | ||||||
710 | 0 | push @content, $self->end_index_page($dir_state, $page); | |||||
711 | 0 | my $content = join('', @content); | |||||
712 | |||||||
713 | # make the head stuff | ||||||
714 | 0 | my $title = $self->make_index_title($dir_state, $page); | |||||
715 | 0 | my $style = $self->make_index_style($dir_state, $page); | |||||
716 | |||||||
717 | # put the page content in the template | ||||||
718 | 0 | my $out = $self->get_template($self->{page_template}); | |||||
719 | # save the content of the template in case we read it | ||||||
720 | # from a file | ||||||
721 | 0 | $self->{page_template} = $out; | |||||
722 | 0 | $out =~ s//$title/; | |||||
723 | 0 | $out =~ s//$style/; | |||||
724 | 0 | $out =~ s//$content/; | |||||
725 | |||||||
726 | # write the page to the file | ||||||
727 | 0 | my $fh = undef; | |||||
728 | 0 | 0 | open($fh, ">", $ifile) or die "Could not open $ifile for writing: $!"; | ||||
729 | 0 | print $fh $out; | |||||
730 | 0 | close($fh); | |||||
731 | } # for each page | ||||||
732 | } # make_index_page | ||||||
733 | |||||||
734 | =head2 clean_thumb_dir | ||||||
735 | |||||||
736 | Clean unused thumbnails and image-pages from | ||||||
737 | the thumbnail directory of this directory | ||||||
738 | |||||||
739 | =cut | ||||||
740 | sub clean_thumb_dir { | ||||||
741 | 0 | 0 | 1 | my $self = shift; | |||
742 | 0 | my $dir_state = shift; | |||||
743 | |||||||
744 | 0 | my $dir = File::Spec->catdir($dir_state->{abs_out_dir}, $self->{thumbdir}); | |||||
745 | 0 | my @pics = @{$dir_state->{files}}; | |||||
0 | |||||||
746 | 0 | $self->debug(2, "cleaning dir: $dir"); | |||||
747 | |||||||
748 | 0 | 0 | return unless -d $dir; | ||||
749 | |||||||
750 | # store the pics as a hash to make checking easier | ||||||
751 | 0 | my %pics_hash = (); | |||||
752 | 0 | foreach my $pic ( @pics ) | |||||
753 | { | ||||||
754 | 0 | $pics_hash{$pic} = 1; | |||||
755 | } | ||||||
756 | |||||||
757 | # Read the thumbnail directory | ||||||
758 | 0 | my $dirh; | |||||
759 | 0 | opendir($dirh,$dir); | |||||
760 | 0 | my @files = grep(!/^\.{1,2}$/, readdir($dirh)); | |||||
761 | 0 | closedir($dirh); | |||||
762 | |||||||
763 | # Check each file to make sure it's a currently used thumbnail or image_page | ||||||
764 | 0 | foreach my $file ( @files ) | |||||
765 | { | ||||||
766 | 0 | my $remove = ''; | |||||
767 | 0 | my $name = $file; | |||||
768 | 0 | 0 | if ($name =~ s/\.html$//) | ||||
0 | |||||||
769 | { | ||||||
770 | # change the last underscore to a dot | ||||||
771 | 0 | $name =~ s/_([a-zA-Z0-9]+)$/.$1/; | |||||
772 | $remove = "unused image page" | ||||||
773 | 0 | 0 | unless (exists $pics_hash{$name}); | ||||
774 | } | ||||||
775 | elsif ($name =~ /(.+)\.jpg$/i) { | ||||||
776 | # Thumbnail? | ||||||
777 | 0 | $name = $1; | |||||
778 | # change the last underscore to a dot | ||||||
779 | 0 | $name =~ s/_([a-zA-Z0-9]+)$/.$1/; | |||||
780 | 0 | $self->debug(2, "thumb: $name"); | |||||
781 | $remove = "unused thumbnail" | ||||||
782 | 0 | 0 | unless (exists $pics_hash{$name}); | ||||
783 | } else { | ||||||
784 | 0 | $remove = "unknown file"; | |||||
785 | } | ||||||
786 | 0 | 0 | if ($remove) { | ||||
787 | 0 | 0 | print "Remove $remove: $file\n" if $self->{verbose}; | ||||
788 | 0 | my $fullname = File::Spec->catfile($dir, $file); | |||||
789 | 0 | 0 | warn "Couldn't erase [$file]" | ||||
790 | unless unlink $fullname; | ||||||
791 | } | ||||||
792 | } # for each file | ||||||
793 | } # clean_thumb_dir | ||||||
794 | |||||||
795 | =head2 process_images | ||||||
796 | |||||||
797 | Process the images from this directory. | ||||||
798 | |||||||
799 | =cut | ||||||
800 | sub process_images { | ||||||
801 | 0 | 0 | 1 | my $self = shift; | |||
802 | 0 | my $dir_state = shift; | |||||
803 | |||||||
804 | 0 | $self->do_image_actions($dir_state, @{$dir_state->{files}}); | |||||
0 | |||||||
805 | } # process_images | ||||||
806 | |||||||
807 | =head2 process_subdirs | ||||||
808 | |||||||
809 | Process the sub-directories of this directory. | ||||||
810 | |||||||
811 | =cut | ||||||
812 | sub process_subdirs { | ||||||
813 | 0 | 0 | 1 | my $self = shift; | |||
814 | 0 | my $dir_state = shift; | |||||
815 | |||||||
816 | 0 | my @image_dirs = @{$dir_state->{subdirs}}; | |||||
0 | |||||||
817 | |||||||
818 | 0 | foreach my $subdir (@image_dirs) | |||||
819 | { | ||||||
820 | 0 | my $dir = $subdir; | |||||
821 | 0 | 0 | if ($dir_state->{dir}) | ||||
822 | { | ||||||
823 | 0 | $dir = File::Spec->catdir($dir_state->{dir}, $subdir); | |||||
824 | } | ||||||
825 | 0 | 0 | print "=== $dir ===\n" if $self->{verbose}; | ||||
826 | 0 | $self->do_dir_actions($dir); | |||||
827 | } | ||||||
828 | } # process_subdirs | ||||||
829 | |||||||
830 | =head2 tidy_up | ||||||
831 | |||||||
832 | Cleanup after processing this directory. | ||||||
833 | |||||||
834 | =cut | ||||||
835 | sub tidy_up { | ||||||
836 | 0 | 0 | 1 | my $self = shift; | |||
837 | 0 | my $dir_state = shift; | |||||
838 | |||||||
839 | } # tidy_up | ||||||
840 | |||||||
841 | =head1 Image Action Methods | ||||||
842 | |||||||
843 | Methods implementing per-image actions. | ||||||
844 | |||||||
845 | =head2 init_image_settings | ||||||
846 | |||||||
847 | Initialize settings for the current image. | ||||||
848 | |||||||
849 | =cut | ||||||
850 | sub init_image_settings { | ||||||
851 | 0 | 0 | 1 | my $self = shift; | |||
852 | 0 | my $dir_state = shift; | |||||
853 | 0 | my $img_state = shift; | |||||
854 | |||||||
855 | $img_state->{abs_img} = File::Spec->catfile($dir_state->{abs_dir}, | ||||||
856 | 0 | $img_state->{cur_img}); | |||||
857 | 0 | $img_state->{info} = $self->get_image_info($img_state->{abs_img}); | |||||
858 | |||||||
859 | } # init_image_settings | ||||||
860 | |||||||
861 | =head2 make_thumbnail | ||||||
862 | |||||||
863 | Make a thumbnail of the current image. | ||||||
864 | Constant pixel count among generated images based on | ||||||
865 | http://www.chaosreigns.com/code/thumbnail/ | ||||||
866 | |||||||
867 | =cut | ||||||
868 | sub make_thumbnail { | ||||||
869 | 0 | 0 | 1 | my $self = shift; | |||
870 | 0 | my $dir_state = shift; | |||||
871 | 0 | my $img_state = shift; | |||||
872 | |||||||
873 | my $thumb_file = $self->get_thumbnail_name( | ||||||
874 | dir_state=>$dir_state, image=>$img_state->{cur_img}, | ||||||
875 | 0 | type=>'file'); | |||||
876 | 0 | 0 | if (!$self->need_to_generate_image($dir_state, $img_state, | ||||
877 | check_image=>$thumb_file)) | ||||||
878 | { | ||||||
879 | 0 | return; | |||||
880 | } | ||||||
881 | # make the thumbnail dir if it doesn't exist | ||||||
882 | 0 | 0 | if (!-d $dir_state->{abs_thumbdir}) | ||||
883 | { | ||||||
884 | 0 | mkdir $dir_state->{abs_thumbdir}; | |||||
885 | } | ||||||
886 | |||||||
887 | 0 | my $command = ''; | |||||
888 | 0 | 0 | if ($img_state->{cur_img} =~ /\.gif$/) | ||||
889 | { | ||||||
890 | # in case this is an animated gif, get the first frame only | ||||||
891 | $command = sprintf('convert -geometry "%d@>" %s %s', | ||||||
892 | $self->{pixelcount}, | ||||||
893 | 0 | $img_state->{abs_img}[0], | |||||
894 | $thumb_file); | ||||||
895 | } | ||||||
896 | else | ||||||
897 | { | ||||||
898 | $command = sprintf('convert -geometry "%d@>" %s %s', | ||||||
899 | $self->{pixelcount}, | ||||||
900 | $img_state->{abs_img}, | ||||||
901 | 0 | $thumb_file); | |||||
902 | } | ||||||
903 | 0 | 0 | system($command) == 0 | ||||
904 | or die "$command failed"; | ||||||
905 | |||||||
906 | } # make_thumbnail | ||||||
907 | |||||||
908 | =head2 make_image_page | ||||||
909 | |||||||
910 | Make HTML page for current image. | ||||||
911 | |||||||
912 | =cut | ||||||
913 | sub make_image_page { | ||||||
914 | 0 | 0 | 1 | my $self = shift; | |||
915 | 0 | my $dir_state = shift; | |||||
916 | 0 | my $img_state = shift; | |||||
917 | |||||||
918 | 0 | my $img_name = $img_state->{cur_img}; | |||||
919 | my $img_page_file = $self->get_image_pagename(dir_state=>$dir_state, | ||||||
920 | image=>$img_state->{cur_img}, | ||||||
921 | 0 | type=>'file'); | |||||
922 | 0 | 0 | 0 | if (-f $img_page_file | |||
0 | |||||||
923 | and !$self->{force_html} | ||||||
924 | and !$dir_state->{redo_html}) | ||||||
925 | { | ||||||
926 | 0 | return; | |||||
927 | } | ||||||
928 | # make the thumbnail dir if it doesn't exist | ||||||
929 | 0 | 0 | if (!-d $dir_state->{abs_thumbdir}) | ||||
930 | { | ||||||
931 | 0 | mkdir $dir_state->{abs_thumbdir}; | |||||
932 | } | ||||||
933 | 0 | my @content = (); | |||||
934 | 0 | push @content, $self->start_image_page($dir_state, $img_state); | |||||
935 | # add the image itself | ||||||
936 | 0 | push @content, $self->make_image_content($dir_state, $img_state); | |||||
937 | 0 | push @content, $self->end_image_page($dir_state, $img_state); | |||||
938 | 0 | my $content = join('', @content); | |||||
939 | |||||||
940 | # make the head stuff | ||||||
941 | 0 | my $title = $self->make_image_title($dir_state, $img_state); | |||||
942 | 0 | my $style = $self->make_image_style($dir_state, $img_state); | |||||
943 | |||||||
944 | # put the page content in the template | ||||||
945 | 0 | my $out = $self->get_template($self->{page_template}); | |||||
946 | # save the content of the template in case we read it | ||||||
947 | # from a file | ||||||
948 | 0 | $self->{page_template} = $out; | |||||
949 | 0 | $out =~ s//$title/; | |||||
950 | 0 | $out =~ s//$style/; | |||||
951 | 0 | $out =~ s//$content/; | |||||
952 | |||||||
953 | # write the page to the file | ||||||
954 | 0 | my $fh = undef; | |||||
955 | 0 | 0 | open($fh, ">", $img_page_file) or die "Could not open $img_page_file for writing: $!"; | ||||
956 | 0 | print $fh $out; | |||||
957 | 0 | close($fh); | |||||
958 | } # make_image_page | ||||||
959 | |||||||
960 | =head2 image_tidy_up | ||||||
961 | |||||||
962 | Clean up after the current image. | ||||||
963 | |||||||
964 | =cut | ||||||
965 | sub image_tidy_up { | ||||||
966 | 0 | 0 | 1 | my $self = shift; | |||
967 | 0 | my $dir_state = shift; | |||||
968 | 0 | my $img_state = shift; | |||||
969 | |||||||
970 | } # image_tidy_up | ||||||
971 | |||||||
972 | =head1 Helper Methods | ||||||
973 | |||||||
974 | Methods which can be called from within other methods. | ||||||
975 | |||||||
976 | =head2 start_index_page | ||||||
977 | |||||||
978 | push @content, $self->start_index_page($dir_state, $page); | ||||||
979 | |||||||
980 | Create the start-of-page for an index page. | ||||||
981 | This contains page content, not full etc (that's expected | ||||||
982 | to be in the full-page template). | ||||||
983 | It contains the header, link to parent dirs and links to | ||||||
984 | previous and next index-pages, and the album caption. | ||||||
985 | |||||||
986 | =cut | ||||||
987 | sub start_index_page { | ||||||
988 | 0 | 0 | 1 | my $self = shift; | |||
989 | 0 | my $dir_state = shift; | |||||
990 | 0 | my $page = shift; | |||||
991 | |||||||
992 | 0 | my @out = (); | |||||
993 | 0 | push @out, " \n"; |
|||||
994 | |||||||
995 | # Path array contains basenames from the top dir down to the current dir. | ||||||
996 | 0 | my @path = split(/[\/\\]/, $dir_state->{dir}); | |||||
997 | |||||||
998 | # Note that what we want is the top_out_base and not the top_base | ||||||
999 | # because if they are not the same (because top_out_dir was set) | ||||||
1000 | # the salient info is the output directory and not the source directory. | ||||||
1001 | 0 | unshift @path, $self->{top_out_base}; | |||||
1002 | |||||||
1003 | # we want to create relative links to all the dirs | ||||||
1004 | # above the current one, so work backwards | ||||||
1005 | 0 | my %uplinks = (); | |||||
1006 | 0 | my $uplink = ''; | |||||
1007 | 0 | foreach my $dn (reverse @path) | |||||
1008 | { | ||||||
1009 | 0 | $uplinks{$dn} = $uplink; | |||||
1010 | 0 | 0 | 0 | if (!$uplink and $page > 1) | |||
1011 | { | ||||||
1012 | 0 | $uplinks{$dn} = "index.html"; | |||||
1013 | } | ||||||
1014 | else | ||||||
1015 | { | ||||||
1016 | 0 | $uplink .= '../'; | |||||
1017 | } | ||||||
1018 | } | ||||||
1019 | 0 | my @header = (); | |||||
1020 | 0 | foreach my $dn (@path) | |||||
1021 | { | ||||||
1022 | 0 | my $pretty = $dn; | |||||
1023 | 0 | $pretty =~ s/_/ /g; | |||||
1024 | 0 | 0 | if ($uplinks{$dn}) | ||||
1025 | { | ||||||
1026 | 0 | push @header, "$pretty"; | |||||
1027 | } | ||||||
1028 | else | ||||||
1029 | { | ||||||
1030 | 0 | push @header, $pretty; | |||||
1031 | } | ||||||
1032 | } | ||||||
1033 | 0 | push @out, ''; |
|||||
1034 | 0 | push @out, join(' :: ', @header); | |||||
1035 | 0 | push @out, "\n"; | |||||
1036 | |||||||
1037 | # now for the prev, next links | ||||||
1038 | 0 | push @out, $self->make_index_prev_next($dir_state, $page); | |||||
1039 | |||||||
1040 | # and now for the album caption | ||||||
1041 | 0 | 0 | if (exists $dir_state->{captions}) | ||||
1042 | { | ||||||
1043 | 0 | my $index_caption = 'index.html'; | |||||
1044 | 0 | 0 | 0 | if (exists $dir_state->{captions}->{$index_caption} | |||
1045 | and defined $dir_state->{captions}->{$index_caption}) | ||||||
1046 | { | ||||||
1047 | 0 | push @out, ' '; |
|||||
1048 | 0 | push @out, $dir_state->{captions}->{$index_caption}; | |||||
1049 | 0 | push @out, "\n"; | |||||
1050 | } | ||||||
1051 | } | ||||||
1052 | |||||||
1053 | 0 | return join('', @out); | |||||
1054 | } # start_index_page | ||||||
1055 | |||||||
1056 | =head2 make_index_prev_next | ||||||
1057 | |||||||
1058 | my $links = $self->start_index_page($dir_state, $page); | ||||||
1059 | |||||||
1060 | Make the previous next other-index-pages links for the | ||||||
1061 | given index-page. Generally called for the top and bottom | ||||||
1062 | of the index page. | ||||||
1063 | |||||||
1064 | =cut | ||||||
1065 | sub make_index_prev_next { | ||||||
1066 | 0 | 0 | 1 | my $self = shift; | |||
1067 | 0 | my $dir_state = shift; | |||||
1068 | 0 | my $page = shift; | |||||
1069 | |||||||
1070 | 0 | my @out = (); | |||||
1071 | 0 | 0 | if ($dir_state->{pages} > 1) | ||||
1072 | { | ||||||
1073 | 0 | push @out, ' '; |
|||||
1074 | # prev | ||||||
1075 | 0 | my $label = '< - prev'; | |||||
1076 | 0 | 0 | if ($page > 1) | ||||
1077 | { | ||||||
1078 | 0 | my $iurl = $self->get_index_pagename(dir_state=>$dir_state, | |||||
1079 | page=>$page - 1, get_filename=>0); | ||||||
1080 | 0 | push @out, "$label "; | |||||
1081 | } | ||||||
1082 | |||||||
1083 | # pages, but only if more than two | ||||||
1084 | 0 | 0 | if ($dir_state->{pages} > 2) | ||||
1085 | { | ||||||
1086 | 0 | for (my $i = 1; $i <= $dir_state->{pages}; $i++) | |||||
1087 | { | ||||||
1088 | 0 | 0 | if ($page == $i) | ||||
1089 | { | ||||||
1090 | 0 | push @out, " [$i] "; | |||||
1091 | } | ||||||
1092 | else | ||||||
1093 | { | ||||||
1094 | 0 | my $iurl = $self->get_index_pagename(dir_state=>$dir_state, | |||||
1095 | page=>$i, get_filename=>0); | ||||||
1096 | 0 | push @out, " $i "; | |||||
1097 | } | ||||||
1098 | } | ||||||
1099 | } | ||||||
1100 | 0 | $label = 'next ->'; | |||||
1101 | 0 | 0 | if (($page+1) <= $dir_state->{pages}) | ||||
1102 | { | ||||||
1103 | 0 | my $iurl = $self->get_index_pagename(dir_state=>$dir_state, | |||||
1104 | page=>$page + 1, get_filename=>0); | ||||||
1105 | 0 | push @out, " $label"; | |||||
1106 | } | ||||||
1107 | 0 | push @out, "\n"; | |||||
1108 | } | ||||||
1109 | |||||||
1110 | 0 | return join('', @out); | |||||
1111 | } # make_index_prev_next | ||||||
1112 | |||||||
1113 | =head2 end_index_page | ||||||
1114 | |||||||
1115 | push @content, $self->end_index_page($dir_state, $page); | ||||||
1116 | |||||||
1117 | Create the end-of-page for an index page. | ||||||
1118 | This contains page content, not full etc (that's expected | ||||||
1119 | to be in the full-page template). | ||||||
1120 | |||||||
1121 | =cut | ||||||
1122 | sub end_index_page { | ||||||
1123 | 0 | 0 | 1 | my $self = shift; | |||
1124 | 0 | my $dir_state = shift; | |||||
1125 | 0 | my $page = shift; | |||||
1126 | |||||||
1127 | 0 | my @out = (); | |||||
1128 | 0 | push @out, "\n \n"; |
|||||
1129 | 0 | push @out, $self->make_index_prev_next($dir_state, $page); | |||||
1130 | 0 | push @out, "\n"; | |||||
1131 | 0 | return join('', @out); | |||||
1132 | } # end_index_page | ||||||
1133 | |||||||
1134 | =head2 make_index_subdirs | ||||||
1135 | |||||||
1136 | push @content, $self->make_index_subdirs($dir_state, $page); | ||||||
1137 | |||||||
1138 | Create the subdirs section; this contains links to subdirs. | ||||||
1139 | |||||||
1140 | =cut | ||||||
1141 | sub make_index_subdirs { | ||||||
1142 | 0 | 0 | 1 | my $self = shift; | |||
1143 | 0 | my $dir_state = shift; | |||||
1144 | 0 | my $page = shift; | |||||
1145 | |||||||
1146 | 0 | my @out = (); | |||||
1147 | |||||||
1148 | 0 | 0 | if (@{$dir_state->{subdirs}}) | ||||
0 | |||||||
1149 | { | ||||||
1150 | 0 | push @out, "\n \n"; |
|||||
1151 | 0 | push @out, " \n"; |
|||||
1152 | # subdirs | ||||||
1153 | 0 | foreach my $subdir (@{$dir_state->{subdirs}}) | |||||
0 | |||||||
1154 | { | ||||||
1155 | 0 | push @out, < | |||||
1156 | |
||||||
1157 | $subdir | ||||||
1158 | |||||||
1159 | EOT | ||||||
1160 | } | ||||||
1161 | 0 | push @out, "\n"; | |||||
1162 | } | ||||||
1163 | 0 | return join('', @out); | |||||
1164 | } # make_index_subdirs | ||||||
1165 | |||||||
1166 | =head2 make_image_index | ||||||
1167 | |||||||
1168 | push @content, $self->make_image_index(dir_state=>$dir_state, | ||||||
1169 | page=>$page, images=>\@images); | ||||||
1170 | |||||||
1171 | Create the images section; this contains links to image-pages, with thumbnails. | ||||||
1172 | |||||||
1173 | =cut | ||||||
1174 | sub make_image_index { | ||||||
1175 | 0 | 0 | 1 | my $self = shift; | |||
1176 | 0 | my %args = ( | |||||
1177 | @_ | ||||||
1178 | ); | ||||||
1179 | 0 | my $dir_state = $args{dir_state}; | |||||
1180 | |||||||
1181 | 0 | my @out = (); | |||||
1182 | |||||||
1183 | 0 | 0 | if (@{$args{images}}) | ||||
0 | |||||||
1184 | { | ||||||
1185 | 0 | push @out, "\n \n"; |
|||||
1186 | 0 | push @out, " \n"; |
|||||
1187 | # subdirs | ||||||
1188 | 0 | foreach my $image (@{$args{images}}) | |||||
0 | |||||||
1189 | { | ||||||
1190 | 0 | my $image_link = $self->get_image_pagename(dir_state=>$dir_state, | |||||
1191 | image=>$image, type=>'parent'); | ||||||
1192 | 0 | my $thumbnail_link = $self->get_thumbnail_name( | |||||
1193 | dir_state=>$dir_state, | ||||||
1194 | image=>$image, type=>'parent'); | ||||||
1195 | 0 | my $image_name = $self->get_image_pagename(dir_state=>$dir_state, | |||||
1196 | image=>$image, type=>'pretty'); | ||||||
1197 | 0 | push @out, < | |||||
1198 | |
||||||
1199 | |
||||||
1200 | |
||||||
1201 | $image_name | ||||||
1202 | |||||||
1203 | |||||||
1204 | EOT | ||||||
1205 | } | ||||||
1206 | 0 | push @out, "\n"; | |||||
1207 | } | ||||||
1208 | 0 | return join('', @out); | |||||
1209 | } # make_image_index | ||||||
1210 | |||||||
1211 | =head2 make_index_title | ||||||
1212 | |||||||
1213 | Make the title for the index page. | ||||||
1214 | This is expected to go inside a |
||||||
1215 | in the page template. | ||||||
1216 | |||||||
1217 | =cut | ||||||
1218 | sub make_index_title { | ||||||
1219 | 0 | 0 | 1 | my $self = shift; | |||
1220 | 0 | my $dir_state = shift; | |||||
1221 | 0 | my $page = shift; | |||||
1222 | |||||||
1223 | 0 | my @out = (); | |||||
1224 | # title | ||||||
1225 | 0 | push @out, $dir_state->{dirbase}; | |||||
1226 | 0 | 0 | push @out, " ($page)" if $page > 1; | ||||
1227 | 0 | return join('', @out); | |||||
1228 | } # make_index_title | ||||||
1229 | |||||||
1230 | =head2 make_index_style | ||||||
1231 | |||||||
1232 | Make the style tags for the index page. This will be put in the | ||||||
1233 | part of the template. | ||||||
1234 | |||||||
1235 | =cut | ||||||
1236 | sub make_index_style { | ||||||
1237 | 0 | 0 | 1 | my $self = shift; | |||
1238 | 0 | my $dir_state = shift; | |||||
1239 | 0 | my $page = shift; | |||||
1240 | |||||||
1241 | 0 | my @out = (); | |||||
1242 | # style | ||||||
1243 | 0 | my $thumb_area_width = $self->{thumb_width} * 1.5; | |||||
1244 | # 1.5 times the thumbnail, plus a fudge-factor for the words underneath | ||||||
1245 | 0 | my $thumb_area_height = ($self->{thumb_height} * 1.5) + 20; | |||||
1246 | 0 | push @out, < | |||||
1247 | |||||||
1273 | EOT | ||||||
1274 | 0 | return join('', @out); | |||||
1275 | } # make_index_style | ||||||
1276 | |||||||
1277 | =head2 get_index_pagename | ||||||
1278 | |||||||
1279 | my $name = self->get_index_pagename( | ||||||
1280 | dir_state=>$dir_state, | ||||||
1281 | page=>$page, | ||||||
1282 | get_filename=>0); | ||||||
1283 | |||||||
1284 | Get the name of the given index page; either the file name | ||||||
1285 | or the relative URL. | ||||||
1286 | |||||||
1287 | =cut | ||||||
1288 | sub get_index_pagename { | ||||||
1289 | 0 | 0 | 1 | my $self = shift; | |||
1290 | 0 | my %args = ( | |||||
1291 | get_filename=>0, | ||||||
1292 | @_ | ||||||
1293 | ); | ||||||
1294 | 0 | my $dir_state = $args{dir_state}; | |||||
1295 | 0 | my $page = $args{page}; | |||||
1296 | |||||||
1297 | 0 | my $pagename; | |||||
1298 | 0 | 0 | if ($page == 1) | ||||
0 | |||||||
1299 | { | ||||||
1300 | 0 | $pagename = 'index.html'; | |||||
1301 | } | ||||||
1302 | elsif ($dir_state->{pages} > 9) | ||||||
1303 | { | ||||||
1304 | 0 | $pagename = sprintf("index%02d.html", $page); | |||||
1305 | } | ||||||
1306 | else | ||||||
1307 | { | ||||||
1308 | 0 | $pagename = "index${page}.html"; | |||||
1309 | } | ||||||
1310 | |||||||
1311 | 0 | 0 | if ($args{get_filename}) | ||||
1312 | { | ||||||
1313 | 0 | return File::Spec->catfile($dir_state->{abs_out_dir}, $pagename); | |||||
1314 | } | ||||||
1315 | else # get URL | ||||||
1316 | { | ||||||
1317 | 0 | return $pagename; | |||||
1318 | } | ||||||
1319 | } # get_index_pagename | ||||||
1320 | |||||||
1321 | =head2 get_image_pagename | ||||||
1322 | |||||||
1323 | my $name = self->get_image_pagename( | ||||||
1324 | dir_state=>$dir_state, | ||||||
1325 | image=>$image, | ||||||
1326 | type=>'file'); | ||||||
1327 | |||||||
1328 | Get the name of the image page; either the file name | ||||||
1329 | or the relative URL from above, or the relative URL | ||||||
1330 | from the sibling, or a 'pretty' name suitable for a title. | ||||||
1331 | |||||||
1332 | The 'type' can be 'file', 'parent', 'sibling' or 'pretty'. | ||||||
1333 | |||||||
1334 | =cut | ||||||
1335 | sub get_image_pagename { | ||||||
1336 | 0 | 0 | 1 | my $self = shift; | |||
1337 | 0 | my %args = ( | |||||
1338 | type=>'parent', | ||||||
1339 | @_ | ||||||
1340 | ); | ||||||
1341 | 0 | my $dir_state = $args{dir_state}; | |||||
1342 | 0 | my $image = $args{image}; | |||||
1343 | |||||||
1344 | 0 | my $thumbdir = $self->{thumbdir}; | |||||
1345 | 0 | my $img_page = $image; | |||||
1346 | # change the last dot to underscore | ||||||
1347 | 0 | $img_page =~ s/\.(\w+)$/_$1/; | |||||
1348 | 0 | $img_page .= ".html"; | |||||
1349 | 0 | 0 | if ($args{type} eq 'file') | ||||
0 | |||||||
0 | |||||||
0 | |||||||
1350 | { | ||||||
1351 | 0 | return File::Spec->catfile($dir_state->{abs_out_dir}, $thumbdir, $img_page); | |||||
1352 | } | ||||||
1353 | elsif ($args{type} eq 'parent') | ||||||
1354 | { | ||||||
1355 | 0 | return "${thumbdir}/${img_page}"; | |||||
1356 | } | ||||||
1357 | elsif ($args{type} eq 'sibling') | ||||||
1358 | { | ||||||
1359 | 0 | return ${img_page}; | |||||
1360 | } | ||||||
1361 | elsif ($args{type} eq 'pretty') | ||||||
1362 | { | ||||||
1363 | 0 | my $pretty = ${image}; | |||||
1364 | 0 | $pretty =~ s/\.(\w+)$//; | |||||
1365 | 0 | $pretty =~ s/_/ /g; | |||||
1366 | 0 | return $pretty; | |||||
1367 | } | ||||||
1368 | 0 | return ''; | |||||
1369 | } # get_image_pagename | ||||||
1370 | |||||||
1371 | =head2 get_thumbnail_name | ||||||
1372 | |||||||
1373 | my $name = self->get_thumbnail_name( | ||||||
1374 | dir_state=>$dir_state, | ||||||
1375 | image=>$image, | ||||||
1376 | type=>'file'); | ||||||
1377 | |||||||
1378 | Get the name of the image thumbnail file; either the file name | ||||||
1379 | or the relative URL from above, or the relative URL | ||||||
1380 | from the sibling. | ||||||
1381 | |||||||
1382 | The 'type' can be 'file', 'parent', 'sibling'. | ||||||
1383 | |||||||
1384 | =cut | ||||||
1385 | sub get_thumbnail_name { | ||||||
1386 | 0 | 0 | 1 | my $self = shift; | |||
1387 | 0 | my %args = ( | |||||
1388 | type=>'parent', | ||||||
1389 | @_ | ||||||
1390 | ); | ||||||
1391 | 0 | my $dir_state = $args{dir_state}; | |||||
1392 | 0 | my $image = $args{image}; | |||||
1393 | |||||||
1394 | 0 | my $thumbdir = $self->{thumbdir}; | |||||
1395 | 0 | my $thumb = $image; | |||||
1396 | # change the last dot to underscore | ||||||
1397 | 0 | $thumb =~ s/\.([\w]+)$/_$1/; | |||||
1398 | 0 | $thumb .= ".jpg"; | |||||
1399 | 0 | 0 | if ($args{type} eq 'file') | ||||
0 | |||||||
0 | |||||||
1400 | { | ||||||
1401 | 0 | return File::Spec->catfile($dir_state->{abs_out_dir}, $thumbdir, $thumb); | |||||
1402 | } | ||||||
1403 | elsif ($args{type} eq 'parent') | ||||||
1404 | { | ||||||
1405 | 0 | return "${thumbdir}/${thumb}"; | |||||
1406 | } | ||||||
1407 | elsif ($args{type} eq 'sibling') | ||||||
1408 | { | ||||||
1409 | 0 | return ${thumb}; | |||||
1410 | } | ||||||
1411 | 0 | return ''; | |||||
1412 | } # get_thumbnail_name | ||||||
1413 | |||||||
1414 | =head2 get_caption | ||||||
1415 | |||||||
1416 | my $name = self->get_caption( | ||||||
1417 | dir_state=>$dir_state, | ||||||
1418 | img_state->$img_state, | ||||||
1419 | image=>$image) | ||||||
1420 | |||||||
1421 | Get the caption for this image. | ||||||
1422 | This also gets the meta-data if any is required. | ||||||
1423 | |||||||
1424 | =cut | ||||||
1425 | sub get_caption { | ||||||
1426 | 0 | 0 | 1 | my $self = shift; | |||
1427 | 0 | my %args = ( | |||||
1428 | @_ | ||||||
1429 | ); | ||||||
1430 | 0 | my $dir_state = $args{dir_state}; | |||||
1431 | 0 | my $img_state = $args{img_state}; | |||||
1432 | 0 | my $image = $args{image}; | |||||
1433 | |||||||
1434 | 0 | my @out = (); | |||||
1435 | 0 | 0 | if (exists $dir_state->{captions}) | ||||
1436 | { | ||||||
1437 | 0 | 0 | 0 | if (exists $dir_state->{captions}->{$image} | |||
1438 | and defined $dir_state->{captions}->{$image}) | ||||||
1439 | { | ||||||
1440 | 0 | push @out, $dir_state->{captions}->{$image}; | |||||
1441 | } | ||||||
1442 | } | ||||||
1443 | 0 | 0 | 0 | if ($img_state and defined $self->{meta} and @{$self->{meta}}) | |||
0 | 0 | ||||||
1444 | { | ||||||
1445 | # only add the meta data if it's there | ||||||
1446 | 0 | foreach my $fieldspec (@{$self->{meta}}) | |||||
0 | |||||||
1447 | { | ||||||
1448 | 0 | $fieldspec =~ /%([\w\s]+)%/; | |||||
1449 | 0 | my $field = $1; | |||||
1450 | 0 | 0 | 0 | if (exists $img_state->{info}->{$field} | |||
0 | |||||||
1451 | and defined $img_state->{info}->{$field} | ||||||
1452 | and $img_state->{info}->{$field}) | ||||||
1453 | { | ||||||
1454 | 0 | my $val = $fieldspec; | |||||
1455 | 0 | my $fieldval = $img_state->{info}->{$field}; | |||||
1456 | # make the fieldval HTML-safe | ||||||
1457 | 0 | $fieldval =~ s/&/&/g; | |||||
1458 | 0 | $fieldval =~ s/</g; | |||||
1459 | 0 | $fieldval =~ s/>/>/g; | |||||
1460 | 0 | $val =~ s/%${field}%/$fieldval/g; | |||||
1461 | 0 | push @out, $val; | |||||
1462 | } | ||||||
1463 | } | ||||||
1464 | } | ||||||
1465 | 0 | return join("\n", @out); | |||||
1466 | } # get_caption | ||||||
1467 | |||||||
1468 | =head2 get_template | ||||||
1469 | |||||||
1470 | my $templ = $self->get_template($template); | ||||||
1471 | |||||||
1472 | Get the given template (read if it's from a file) | ||||||
1473 | |||||||
1474 | =cut | ||||||
1475 | sub get_template { | ||||||
1476 | 0 | 0 | 1 | my $self = shift; | |||
1477 | 0 | my $template = shift; | |||||
1478 | |||||||
1479 | 0 | 0 | 0 | if ($template !~ /\n/ | |||
1480 | && -r $template) | ||||||
1481 | { | ||||||
1482 | 0 | local $/ = undef; | |||||
1483 | 0 | my $fh; | |||||
1484 | 0 | 0 | open($fh, $template) | ||||
1485 | or die "Could not open ", $template; | ||||||
1486 | 0 | $template = <$fh>; | |||||
1487 | 0 | close($fh); | |||||
1488 | } | ||||||
1489 | 0 | return $template; | |||||
1490 | } # get_template | ||||||
1491 | |||||||
1492 | =head2 start_image_page | ||||||
1493 | |||||||
1494 | push @content, $self->start_image_page($dir_state, $img_state); | ||||||
1495 | |||||||
1496 | Create the start-of-page for an image page. | ||||||
1497 | This contains page content, not full etc (that's expected | ||||||
1498 | to be in the full-page template). | ||||||
1499 | It contains the header, link to parent dirs and links to | ||||||
1500 | previous and next image-pages. | ||||||
1501 | |||||||
1502 | =cut | ||||||
1503 | sub start_image_page { | ||||||
1504 | 0 | 0 | 1 | my $self = shift; | |||
1505 | 0 | my $dir_state = shift; | |||||
1506 | 0 | my $img_state = shift; | |||||
1507 | |||||||
1508 | 0 | my @out = (); | |||||
1509 | 0 | push @out, " \n"; |
|||||
1510 | |||||||
1511 | # Path array contains basenames from the top dir | ||||||
1512 | # down to the current dir. | ||||||
1513 | 0 | my @path = split(/[\/\\]/, $dir_state->{dir}); | |||||
1514 | 0 | unshift @path, $self->{top_out_base}; | |||||
1515 | # we want to create relative links to all the dirs | ||||||
1516 | # including the current one, so work backwards | ||||||
1517 | 0 | my %uplinks = (); | |||||
1518 | 0 | my $uplink = ''; | |||||
1519 | 0 | foreach my $dn (reverse @path) | |||||
1520 | { | ||||||
1521 | 0 | $uplink .= '../'; | |||||
1522 | 0 | $uplinks{$dn} = $uplink; | |||||
1523 | } | ||||||
1524 | 0 | my @breadcrumb = (); | |||||
1525 | 0 | foreach my $dn (@path) | |||||
1526 | { | ||||||
1527 | 0 | 0 | if ($uplinks{$dn}) | ||||
1528 | { | ||||||
1529 | 0 | push @breadcrumb, "$dn"; | |||||
1530 | } | ||||||
1531 | else | ||||||
1532 | { | ||||||
1533 | 0 | push @breadcrumb, $dn; | |||||
1534 | } | ||||||
1535 | } | ||||||
1536 | 0 | push @out, ''; |
|||||
1537 | 0 | push @out, $img_state->{cur_img}; | |||||
1538 | 0 | push @out, "\n"; | |||||
1539 | 0 | push @out, ' | |||||
1540 | 0 | push @out, join(' > ', @breadcrumb); | |||||
1541 | 0 | push @out, "\n"; | |||||
1542 | |||||||
1543 | # now for the prev, next links | ||||||
1544 | 0 | push @out, $self->make_image_prev_next(dir_state=>$dir_state, | |||||
1545 | img_state=>$img_state); | ||||||
1546 | |||||||
1547 | 0 | return join('', @out); | |||||
1548 | } # start_image_page | ||||||
1549 | |||||||
1550 | =head2 end_image_page | ||||||
1551 | |||||||
1552 | push @content, $self->end_image_page($dir_state, $img_state); | ||||||
1553 | |||||||
1554 | Create the end-of-page for an image page. | ||||||
1555 | This contains page content, not full etc (that's expected | ||||||
1556 | to be in the full-page template). | ||||||
1557 | |||||||
1558 | =cut | ||||||
1559 | sub end_image_page { | ||||||
1560 | 0 | 0 | 1 | my $self = shift; | |||
1561 | 0 | my $dir_state = shift; | |||||
1562 | 0 | my $img_state = shift; | |||||
1563 | |||||||
1564 | 0 | my @out = (); | |||||
1565 | |||||||
1566 | # now for the prev, next links | ||||||
1567 | 0 | push @out, $self->make_image_prev_next(dir_state=>$dir_state, | |||||
1568 | img_state=>$img_state, | ||||||
1569 | use_thumb=>1); | ||||||
1570 | 0 | push @out, "\n\n"; | |||||
1571 | |||||||
1572 | 0 | return join('', @out); | |||||
1573 | } # end_image_page | ||||||
1574 | |||||||
1575 | =head2 make_image_prev_next | ||||||
1576 | |||||||
1577 | my $links = $self->make_image_prev_next( | ||||||
1578 | dir_state=>$dir_state, | ||||||
1579 | img_state=>$img_state); | ||||||
1580 | |||||||
1581 | Make the previous next other-image-pages links for the | ||||||
1582 | given image-page. Generally called for the top and bottom | ||||||
1583 | of the image page. | ||||||
1584 | |||||||
1585 | =cut | ||||||
1586 | sub make_image_prev_next { | ||||||
1587 | 0 | 0 | 1 | my $self = shift; | |||
1588 | 0 | my %args = ( | |||||
1589 | use_thumb=>0, | ||||||
1590 | @_ | ||||||
1591 | ); | ||||||
1592 | 0 | my $dir_state = $args{dir_state}; | |||||
1593 | 0 | my $img_state = $args{img_state}; | |||||
1594 | |||||||
1595 | 0 | my $img_num = $img_state->{num}; | |||||
1596 | 0 | my @out = (); | |||||
1597 | 0 | 0 | if ($dir_state->{files} > 1) | ||||
1598 | { | ||||||
1599 | 0 | push @out, ' '; |
|||||
1600 | # prev | ||||||
1601 | 0 | push @out, ""; | |||||
1602 | 0 | my $label = '< - prev'; | |||||
1603 | 0 | my $iurl; | |||||
1604 | my $turl; | ||||||
1605 | 0 | 0 | if ($img_num > 0) | ||||
1606 | { | ||||||
1607 | $iurl = $self->get_image_pagename(dir_state=>$dir_state, | ||||||
1608 | 0 | image=>$img_state->{images}->[$img_num - 1], | |||||
1609 | type=>'sibling'); | ||||||
1610 | $turl = $self->get_thumbnail_name(dir_state=>$dir_state, | ||||||
1611 | 0 | image=>$img_state->{images}->[$img_num - 1], | |||||
1612 | type=>'sibling'); | ||||||
1613 | } | ||||||
1614 | else | ||||||
1615 | { | ||||||
1616 | # loop to the last image | ||||||
1617 | $iurl = $self->get_image_pagename(dir_state=>$dir_state, | ||||||
1618 | 0 | image=>$img_state->{images}->[$#{$img_state->{images}}], | |||||
0 | |||||||
1619 | type=>'sibling'); | ||||||
1620 | $turl = $self->get_thumbnail_name(dir_state=>$dir_state, | ||||||
1621 | 0 | image=>$img_state->{images}->[$#{$img_state->{images}}], | |||||
0 | |||||||
1622 | type=>'sibling'); | ||||||
1623 | } | ||||||
1624 | 0 | push @out, "$label "; | |||||
1625 | 0 | 0 | if ($args{use_thumb}) | ||||
1626 | { | ||||||
1627 | 0 | push @out, " |
|||||
1628 | } | ||||||
1629 | 0 | push @out, ""; | |||||
1630 | |||||||
1631 | 0 | push @out, ""; | |||||
1632 | 0 | $label = 'next ->'; | |||||
1633 | 0 | 0 | if (($img_num+1) < @{$img_state->{images}}) | ||||
0 | |||||||
1634 | { | ||||||
1635 | $iurl = $self->get_image_pagename(dir_state=>$dir_state, | ||||||
1636 | 0 | image=>$img_state->{images}->[$img_num + 1], | |||||
1637 | type=>'sibling'); | ||||||
1638 | $turl = $self->get_thumbnail_name(dir_state=>$dir_state, | ||||||
1639 | 0 | image=>$img_state->{images}->[$img_num + 1], | |||||
1640 | type=>'sibling'); | ||||||
1641 | } | ||||||
1642 | else | ||||||
1643 | { | ||||||
1644 | # loop to the first image | ||||||
1645 | $iurl = $self->get_image_pagename(dir_state=>$dir_state, | ||||||
1646 | 0 | image=>$img_state->{images}->[0], | |||||
1647 | type=>'sibling'); | ||||||
1648 | $turl = $self->get_thumbnail_name(dir_state=>$dir_state, | ||||||
1649 | 0 | image=>$img_state->{images}->[0], | |||||
1650 | type=>'sibling'); | ||||||
1651 | } | ||||||
1652 | 0 | 0 | if ($args{use_thumb}) | ||||
1653 | { | ||||||
1654 | 0 | push @out, " |
|||||
1655 | } | ||||||
1656 | 0 | push @out, " $label"; | |||||
1657 | 0 | push @out, ""; | |||||
1658 | 0 | push @out, "\n"; | |||||
1659 | } | ||||||
1660 | |||||||
1661 | 0 | return join('', @out); | |||||
1662 | } # make_image_prev_next | ||||||
1663 | |||||||
1664 | =head2 make_image_content | ||||||
1665 | |||||||
1666 | Make the content of the image page, the image itself. | ||||||
1667 | |||||||
1668 | =cut | ||||||
1669 | sub make_image_content { | ||||||
1670 | 0 | 0 | 1 | my $self = shift; | |||
1671 | 0 | my $dir_state = shift; | |||||
1672 | 0 | my $img_state = shift; | |||||
1673 | |||||||
1674 | 0 | my $img_name = $img_state->{cur_img}; | |||||
1675 | 0 | my $caption = $self->get_caption(dir_state=>$dir_state, | |||||
1676 | img_state=>$img_state, | ||||||
1677 | image=>$img_name); | ||||||
1678 | 0 | my $img_url = "../$img_name"; | |||||
1679 | 0 | 0 | if ($self->{top_dir} ne $self->{top_out_dir}) | ||||
1680 | { | ||||||
1681 | 0 | $img_url = $dir_state->{dir_url} . '/' . $img_name; | |||||
1682 | } | ||||||
1683 | 0 | my @out = (); | |||||
1684 | 0 | push @out, " \n"; |
|||||
1685 | 0 | my $width = $img_state->{info}->{ImageWidth}; | |||||
1686 | 0 | my $height = $img_state->{info}->{ImageHeight}; | |||||
1687 | 0 | push @out, " |
|||||
1688 | 0 | push @out, " $caption \n"; |
|||||
1689 | 0 | push @out, "\n"; | |||||
1690 | 0 | return join('', @out); | |||||
1691 | } # make_image_content | ||||||
1692 | |||||||
1693 | =head2 make_image_title | ||||||
1694 | |||||||
1695 | Make the title for the image page. | ||||||
1696 | This is expected to go inside a |
||||||
1697 | in the page template. | ||||||
1698 | |||||||
1699 | =cut | ||||||
1700 | sub make_image_title { | ||||||
1701 | 0 | 0 | 1 | my $self = shift; | |||
1702 | 0 | my $dir_state = shift; | |||||
1703 | 0 | my $img_state = shift; | |||||
1704 | |||||||
1705 | 0 | my @out = (); | |||||
1706 | # title | ||||||
1707 | 0 | push @out, $img_state->{cur_img}; | |||||
1708 | 0 | return join('', @out); | |||||
1709 | } # make_image_title | ||||||
1710 | |||||||
1711 | =head2 make_image_style | ||||||
1712 | |||||||
1713 | Make the style tags for the image page. This will be put in the | ||||||
1714 | part of the template. | ||||||
1715 | |||||||
1716 | =cut | ||||||
1717 | sub make_image_style { | ||||||
1718 | 0 | 0 | 1 | my $self = shift; | |||
1719 | 0 | my $dir_state = shift; | |||||
1720 | 0 | my $img_state = shift; | |||||
1721 | |||||||
1722 | 0 | my @out = (); | |||||
1723 | # style | ||||||
1724 | 0 | push @out, < | |||||
1725 | |||||||
1740 | EOT | ||||||
1741 | 0 | return join('', @out); | |||||
1742 | } # make_image_style | ||||||
1743 | |||||||
1744 | =head2 need_to_generate_image | ||||||
1745 | |||||||
1746 | Check if a thumbnail needs to be made (or rebuilt). | ||||||
1747 | |||||||
1748 | =cut | ||||||
1749 | sub need_to_generate_image { | ||||||
1750 | 0 | 0 | 1 | my $self = shift; | |||
1751 | 0 | my $dir_state = shift; | |||||
1752 | 0 | my $img_state = shift; | |||||
1753 | 0 | my %args = @_; | |||||
1754 | |||||||
1755 | 0 | 0 | 0 | if (!-f $args{check_image} or $self->{force_images}) | |||
1756 | { | ||||||
1757 | 0 | return 1; | |||||
1758 | } | ||||||
1759 | 0 | return 0; | |||||
1760 | } # need_to_generate_image | ||||||
1761 | |||||||
1762 | =head2 index_needs_rebuilding | ||||||
1763 | |||||||
1764 | Check to see if there are any new (or deleted) images or directories | ||||||
1765 | in this directory. | ||||||
1766 | |||||||
1767 | =cut | ||||||
1768 | sub index_needs_rebuilding { | ||||||
1769 | 0 | 0 | 1 | my $self = shift; | |||
1770 | 0 | my $dir_state = shift; | |||||
1771 | |||||||
1772 | # ------- Subdirs ------------- | ||||||
1773 | # Need to check if any of the subdirs are new or deleted | ||||||
1774 | |||||||
1775 | 0 | my @subdirs = @{$dir_state->{subdirs}}; | |||||
0 | |||||||
1776 | 0 | my @dest_subdirs = (); | |||||
1777 | 0 | my $dirh; | |||||
1778 | 0 | opendir($dirh,$dir_state->{abs_out_dir}); | |||||
1779 | 0 | while (my $fn = readdir($dirh)) | |||||
1780 | { | ||||||
1781 | 0 | my $abs_fn = File::Spec->catfile($dir_state->{abs_out_dir}, $fn); | |||||
1782 | 0 | 0 | 0 | if ($fn =~ /^\./ or $fn eq $self->{thumbdir}) | |||
0 | |||||||
1783 | { | ||||||
1784 | # skip | ||||||
1785 | } | ||||||
1786 | elsif (-d $abs_fn) | ||||||
1787 | { | ||||||
1788 | 0 | push @dest_subdirs, $fn; | |||||
1789 | } | ||||||
1790 | } | ||||||
1791 | 0 | closedir($dirh); | |||||
1792 | |||||||
1793 | 0 | my %destdir_has_src = (); | |||||
1794 | 0 | my %srcdir_has_dest = (); | |||||
1795 | # initialise to false | ||||||
1796 | 0 | foreach my $sd ( @subdirs ) | |||||
1797 | { | ||||||
1798 | 0 | $srcdir_has_dest{$sd} = 0; | |||||
1799 | } | ||||||
1800 | # Are there dest-dirs without src-dirs? | ||||||
1801 | 0 | foreach my $dsd ( @dest_subdirs ) | |||||
1802 | { | ||||||
1803 | 0 | 0 | if (exists $srcdir_has_dest{$dsd}) | ||||
1804 | { | ||||||
1805 | 0 | $srcdir_has_dest{$dsd} = 1; | |||||
1806 | 0 | $destdir_has_src{$dsd} = 1; | |||||
1807 | } | ||||||
1808 | else | ||||||
1809 | { | ||||||
1810 | 0 | $self->debug(1, "GONE DIR: $dsd"); | |||||
1811 | 0 | $destdir_has_src{$dsd} = 0; | |||||
1812 | 0 | return 1; | |||||
1813 | } | ||||||
1814 | } | ||||||
1815 | # Are there src-dirs without dest-dirs? | ||||||
1816 | 0 | while (my ($key, $dir_exists) = each(%srcdir_has_dest)) | |||||
1817 | { | ||||||
1818 | 0 | 0 | if (!$dir_exists) | ||||
1819 | { | ||||||
1820 | 0 | $self->debug(1, "NEW DIR: $key"); | |||||
1821 | 0 | return 1; | |||||
1822 | } | ||||||
1823 | } | ||||||
1824 | |||||||
1825 | # --------- Thumbnail Directory ---------- | ||||||
1826 | 0 | my $thumb_dir = File::Spec->catdir($dir_state->{abs_out_dir}, $self->{thumbdir}); | |||||
1827 | 0 | my @pics = @{$dir_state->{files}}; | |||||
0 | |||||||
1828 | 0 | $self->debug(2, "dir: $thumb_dir"); | |||||
1829 | |||||||
1830 | # if the thumbnail directory doesn't exist, then either all images | ||||||
1831 | # are new, or we don't have any images in this directory | ||||||
1832 | 0 | 0 | if (!-d $thumb_dir) | ||||
1833 | { | ||||||
1834 | 0 | 0 | return (@pics ? 1 : 0); | ||||
1835 | } | ||||||
1836 | |||||||
1837 | # Read the thumbnail directory | ||||||
1838 | 0 | opendir($dirh,$thumb_dir); | |||||
1839 | 0 | my @files = grep(!/^\.{1,2}$/, readdir($dirh)); | |||||
1840 | 0 | closedir($dirh); | |||||
1841 | |||||||
1842 | # check whether a picture has a thumbnail, and a thumbnail has a picture | ||||||
1843 | 0 | my %pic_has_tn = (); | |||||
1844 | 0 | my %tn_has_pic = (); | |||||
1845 | |||||||
1846 | # initialize to false | ||||||
1847 | 0 | foreach my $pic ( @pics ) | |||||
1848 | { | ||||||
1849 | 0 | $pic_has_tn{$pic} = 0; | |||||
1850 | } | ||||||
1851 | |||||||
1852 | # Check each file to make sure it's a currently used thumbnail or image_page | ||||||
1853 | 0 | foreach my $file ( @files ) | |||||
1854 | { | ||||||
1855 | 0 | my $name = $file; | |||||
1856 | 0 | 0 | if ($name =~ s/\.html$//) | ||||
0 | |||||||
1857 | { | ||||||
1858 | # change the last underscore to a dot | ||||||
1859 | 0 | $name =~ s/_([a-zA-Z0-9]+)$/.$1/; | |||||
1860 | 0 | 0 | if (exists $pic_has_tn{$name}) | ||||
1861 | { | ||||||
1862 | 0 | $pic_has_tn{$name} = 1; | |||||
1863 | 0 | $tn_has_pic{$name} = 1; | |||||
1864 | } | ||||||
1865 | else | ||||||
1866 | { | ||||||
1867 | 0 | $tn_has_pic{$name} = 0; | |||||
1868 | 0 | return 1; | |||||
1869 | } | ||||||
1870 | } | ||||||
1871 | elsif ($name =~ /(.+)\.jpg$/i) { | ||||||
1872 | # Thumbnail? | ||||||
1873 | 0 | $name = $1; | |||||
1874 | # change the last underscore to a dot | ||||||
1875 | 0 | $name =~ s/_([a-zA-Z0-9]+)$/.$1/; | |||||
1876 | 0 | $self->debug(2, "thumb: $name"); | |||||
1877 | 0 | 0 | if (exists $pic_has_tn{$name}) | ||||
1878 | { | ||||||
1879 | 0 | $pic_has_tn{$name} = 1; | |||||
1880 | 0 | $tn_has_pic{$name} = 1; | |||||
1881 | } | ||||||
1882 | else | ||||||
1883 | { | ||||||
1884 | 0 | $tn_has_pic{$name} = 0; | |||||
1885 | 0 | return 1; | |||||
1886 | } | ||||||
1887 | } | ||||||
1888 | } # for each file | ||||||
1889 | |||||||
1890 | # now check if there are pics without thumbnails | ||||||
1891 | 0 | while (my ($key, $tn_exists) = each(%pic_has_tn)) | |||||
1892 | { | ||||||
1893 | 0 | 0 | if (!$tn_exists) | ||||
1894 | { | ||||||
1895 | 0 | return 1; | |||||
1896 | } | ||||||
1897 | } | ||||||
1898 | |||||||
1899 | 0 | return 0; | |||||
1900 | } # index_needs_rebuilding | ||||||
1901 | |||||||
1902 | =head2 get_image_info | ||||||
1903 | |||||||
1904 | Get the image information for an image. Returns a hash of | ||||||
1905 | information. | ||||||
1906 | |||||||
1907 | %info = $self->get_image_info($image_file); | ||||||
1908 | |||||||
1909 | =cut | ||||||
1910 | sub get_image_info { | ||||||
1911 | 0 | 0 | 1 | my $self = shift; | |||
1912 | 0 | my $img_file = shift; | |||||
1913 | |||||||
1914 | 0 | my $info = Image::ExifTool::ImageInfo($img_file); | |||||
1915 | # add the basename | ||||||
1916 | 0 | my ($basename, $path, $suffix) = fileparse($img_file, qr/\.[^.]*/); | |||||
1917 | 0 | $info->{file_basename} = $basename; | |||||
1918 | 0 | return $info; | |||||
1919 | } # get_image_info | ||||||
1920 | |||||||
1921 | =head2 debug | ||||||
1922 | |||||||
1923 | $self->debug($level, $message); | ||||||
1924 | |||||||
1925 | Print a debug message (for debugging). | ||||||
1926 | Checks $self->{'debug_level'} to see if the message should be printed or | ||||||
1927 | not. | ||||||
1928 | |||||||
1929 | =cut | ||||||
1930 | sub debug { | ||||||
1931 | 0 | 0 | 1 | my $self = shift; | |||
1932 | 0 | my $level = shift; | |||||
1933 | 0 | my $message = shift; | |||||
1934 | |||||||
1935 | 0 | 0 | if ($level <= $self->{'debug_level'}) | ||||
1936 | { | ||||||
1937 | 0 | my $oh = \*STDERR; | |||||
1938 | 0 | print $oh $message, "\n"; | |||||
1939 | } | ||||||
1940 | } # debug | ||||||
1941 | |||||||
1942 | =head1 Private Methods | ||||||
1943 | |||||||
1944 | Methods which may or may not be here in future. | ||||||
1945 | |||||||
1946 | =head2 _whowasi | ||||||
1947 | |||||||
1948 | For debugging: say who called this | ||||||
1949 | |||||||
1950 | =cut | ||||||
1951 | 0 | 0 | sub _whowasi { (caller(1))[3] . '()' } | ||||
1952 | |||||||
1953 | =head1 REQUIRES | ||||||
1954 | |||||||
1955 | Test::More | ||||||
1956 | |||||||
1957 | =head1 INSTALLATION | ||||||
1958 | |||||||
1959 | To install this module, run the following commands: | ||||||
1960 | |||||||
1961 | perl Build.PL | ||||||
1962 | ./Build | ||||||
1963 | ./Build test | ||||||
1964 | ./Build install | ||||||
1965 | |||||||
1966 | Or, if you're on a platform (like DOS or Windows) that doesn't like the | ||||||
1967 | "./" notation, you can do this: | ||||||
1968 | |||||||
1969 | perl Build.PL | ||||||
1970 | perl Build | ||||||
1971 | perl Build test | ||||||
1972 | perl Build install | ||||||
1973 | |||||||
1974 | In order to install somewhere other than the default, such as | ||||||
1975 | in a directory under your home directory, like "/home/fred/perl" | ||||||
1976 | go | ||||||
1977 | |||||||
1978 | perl Build.PL --install_base /home/fred/perl | ||||||
1979 | |||||||
1980 | as the first step instead. | ||||||
1981 | |||||||
1982 | This will install the files underneath /home/fred/perl. | ||||||
1983 | |||||||
1984 | You will then need to make sure that you alter the PERL5LIB variable to | ||||||
1985 | find the modules, and the PATH variable to find the script. | ||||||
1986 | |||||||
1987 | Therefore you will need to change: | ||||||
1988 | your path, to include /home/fred/perl/script (where the script will be) | ||||||
1989 | |||||||
1990 | PATH=/home/fred/perl/script:${PATH} | ||||||
1991 | |||||||
1992 | the PERL5LIB variable to add /home/fred/perl/lib | ||||||
1993 | |||||||
1994 | PERL5LIB=/home/fred/perl/lib:${PERL5LIB} | ||||||
1995 | |||||||
1996 | |||||||
1997 | =head1 SEE ALSO | ||||||
1998 | |||||||
1999 | perl(1). | ||||||
2000 | |||||||
2001 | =head1 BUGS | ||||||
2002 | |||||||
2003 | Please report any bugs or feature requests to the author. | ||||||
2004 | |||||||
2005 | =head1 AUTHOR | ||||||
2006 | |||||||
2007 | Kathryn Andersen (RUBYKAT) | ||||||
2008 | perlkat AT katspace dot com | ||||||
2009 | http://www.katspace.org/tools | ||||||
2010 | |||||||
2011 | =head1 COPYRIGHT AND LICENCE | ||||||
2012 | |||||||
2013 | Copyright (c) 2006 by Kathryn Andersen | ||||||
2014 | |||||||
2015 | This program is free software; you can redistribute it and/or modify it | ||||||
2016 | under the same terms as Perl itself. | ||||||
2017 | |||||||
2018 | |||||||
2019 | =cut | ||||||
2020 | |||||||
2021 | 1; # End of HTML::KhatGallery::Core | ||||||
2022 | __END__ |