]> git.defcon.no Git - plsgen/blob - plsgen
Added first release code version
[plsgen] / plsgen
1 #!/usr/bin/perl
2 use Image::ExifTool;
3 use POSIX;
4 use AppConfig;
5 use Getopt::Long;
6 use strict;
7
8 # TODO: filename.txt for file comments
9 # TODO: Templating of EXIF
10 # TODO: Priority/sorting of EXFI tags
11 # TODO: Possibility for hide/show EXIF
12 # TODO: RSS support? Delegate that to frontend?
13 # TODO: Save reference to main-index thumbnail.
14 # TODO: Clear old generated files and meta on regen
15 # TODO: Use perlmagick et. al instead of convert/jhead..
16
17 # Runtime data
18 my $title = undef;
19 my $htmlonly = 0;
20 my $configfile = undef;
21 my $halp = undef;
22
23 GetOptions (
24 "title=s" => \$title,
25 "htmlonly!" => \$htmlonly,
26 "config=s" => \$configfile,
27 "help" => \$halp
28 );
29 if ( $halp )
30 {
31 print "\nplsgen version 0.1\n";
32 print "Copyright Jon Langseth, BSD lisence\n\n";
33 print " --title='Your album title'\n";
34 print " Sets the album title. Title will be stored in .title\n";
35 print " If no title is given, it will be read from .title, if present\n";
36 print " --htmlonly\n";
37 print " Add this option to only generate HTML files\n";
38 print " No image operations will be performed with this option\n";
39 print " --config=/path/to/config\n";
40 print " Overrides default config file location.\n";
41 print " Default is to look for ./plsgen.cfg, then ../plsgen.cfg\n";
42 print " and finally /etc/plsgen.cfg.\n";
43 print "\n";
44 exit;
45 }
46
47 # Configuration data
48 my $config = get_config( $configfile );
49 my $full_tpl_file = $config->full_tpl_file;
50 my $index_tpl_file = $config->index_tpl_file;
51 my $css_file = $config->css_file;
52 my $navigation_script = $config->navigation_script;
53 my $columns = $config->columns;
54 my $rows = $config->rows;
55 my $thumb_pre = $config->thumb_pre;
56 my $thumb_post = $config->thumb_post;
57 my $idx_prev_text = $config->idx_prev_text;
58 my $idx_next_text = $config->idx_next_text;
59 my $idx_ret_text = $config->idx_ret_text;
60 my $footer_tag = $config->footer_tag;
61
62 # Get or save the title, depending..
63 if ( (not $title) && ( -f ".title" ) )
64 {
65 open TF, "<.title";
66 $title = <TF>;
67 chomp($title);
68 close TF;
69 }
70 elsif ( $title )
71 {
72 open TF, ">.title";
73 print TF $title . "\n";
74 close TF;
75 }
76
77 mkdir "thumb";
78 mkdir "view";
79
80 # Glob file names to an array
81 my @images = glob("*png *.jpg *.JPG *.gif *.GIF");
82 # Keep count of total number of images
83 my $imagecount = $#images;
84
85 my ($current, $previous, $next);
86 my $indexcount = 1;
87 my $indexfile;
88
89 my $main_meta = "<link rel='stylesheet' href='" . $css_file . "' type='text/css' />";
90 my $navigation_header = "<script type='text/javascript' src='" . $navigation_script . "'></script>";
91
92 my $thumbs = "<div class='thumbnails'>";
93
94 my $indexes = ceil( $imagecount/($rows*$columns) );
95 my $gentime = localtime;
96
97 # In groups of N ( X rows x Y colums of index):
98 # - Step through image array:
99 for ( my $i = 1; $i <= $imagecount; $i++)
100 {
101 $current = $images[$i-1];
102 # - - Previous image is previous location in array, unless cur=first
103 $previous = $images[$i-2] if $i > 1;
104 $previous = undef if $i == 1;
105 # - - Next image is next location in array, unless cur=last.
106 $next = $images[$i] if $i < ( $imagecount);
107 $next = undef if $i >= ( $imagecount);
108
109 #Set up text-strings for template replacement
110 if ( $indexcount == 1 ) { $indexfile = "index.html"; }
111 else { $indexfile = "index" . $indexcount . ".html"; }
112 my $navscript = gen_navscript( $previous, $next, $indexfile );
113 my $position = $i . " of " . $imagecount;
114 my $prev_text = "<a href='" . $previous . ".html'><img src='thumb/" . $previous . "' /></a>";
115 my $next_text = "<a href='" . $next . ".html'><img src='thumb/" . $next . "' /></a>";
116 my $cur_index_text = "<a href='". $indexfile ."'>" . $idx_ret_text . "</a>";
117 my $current_display = "view/" . $current;
118
119 printf ("Processing image %s: %s\n", $position, $current);
120
121 # - - If rotated according to EXIF, do rotation
122 my $exif = get_exifdata( $current );
123 if ( $exif->{'Orientation'} =~ m/rotate/i )
124 {
125 system("jhead -autorot " . $current . ">/dev/null") unless $htmlonly;
126 }
127 my $exif_text = get_exifblock($exif);
128
129 # - - Create thumbnail image (resize to new image)
130 system("convert " . $current . " -geometry '160x120>' thumb/" . $current) unless $htmlonly;
131 # - - Create normal display image (resize to new image)
132 system("convert " . $current . " -geometry '800x600>' view/" . $current) unless $htmlonly;
133
134 # - - Create full view HTML file
135 my $cur_html;
136 open TEMPLATE, "<" . $full_tpl_file or die "UNABLE TO LOAD TEMPLATE $full_tpl_file\n";
137 while (<TEMPLATE>)
138 {
139 if ( $previous ) { $_ =~ s/%\{previous\}/$prev_text/; }
140 else { $_ =~ s/%\{previous\}//; }
141
142 if ( $next ) { $_ =~ s/%\{next\}/$next_text/; }
143 else { $_ =~ s/%\{next\}//; }
144
145 $_ =~ s/%\{index\}/$cur_index_text/;
146 $_ =~ s/%\{title\}/$title/;
147 $_ =~ s/%\{main_meta\}/$main_meta/;
148 $_ =~ s/%\{navigation_script\}/$navigation_header/;
149 $_ =~ s/%\{position\}/$position/;
150 $_ =~ s/%\{current\}/$current/;
151 $_ =~ s/%\{current_display\}/$current_display/;
152 $_ =~ s/%\{exif\}/$exif_text/;
153 $_ =~ s/%\{gallery_timestamp\}/$gentime/;
154 $_ =~ s/%\{navscript\}/$navscript/;
155 $_ =~ s/%\{footer_tag\}/$footer_tag/;
156 $cur_html .= $_;
157 }
158 close TEMPLATE;
159 open HTML, ">" . $current . ".html" or die "UNABLE TO WRITE\n";
160 print HTML $cur_html;
161 close HTML;
162
163 # - - Append image thumbnail code to current index content
164 $thumbs .= $thumb_pre . "<a href='" . $current . ".html'><img src='thumb/" . $current . "' /></a>" . $thumb_post;
165 if ( $i % ($rows*$columns) == 0 )
166 {
167 $thumbs .= "</div>";
168 # - - On each Y, terminate index file/group:
169 make_index( $index_tpl_file, $indexcount, $indexes, $thumbs);
170 $thumbs = "<div class='thumbnails'>";
171 $indexcount++;
172 }
173 elsif ( $i % ($columns) == 0 )
174 {
175 # - - On each X, terminate index content row
176 $thumbs .= "\n</div>\n<div class='thumbnails'>";
177 }
178 }
179 $thumbs .= "</div>";
180 make_index( $index_tpl_file, $indexcount, $indexes, $thumbs);
181 # Done.
182
183
184 # -------------- Functions supporting above code -----------------------
185 sub make_index
186 {
187 my $tpl = shift;
188 my $idxcount = shift;
189 my $lastidx = shift;
190 my $thumbs = shift;
191
192 my $gentime = localtime;
193 my $html;
194
195 my $prev_file;
196 my $prev_text;
197 my $next_file;
198 my $next_text;
199 my $indexfile;
200
201 # If index counter is 1, filename is index.html
202 $indexfile = ( $indexcount ==1 ) ? "index.html" : "index" . $idxcount . ".html";
203
204 # If index counter is > 1, add previous index link.
205 if ( $idxcount > 1 )
206 {
207 $prev_file = "index" . ($idxcount-1) . ".html";
208 $prev_file = "index.html" if ( $idxcount == 2 );
209 $prev_text = "<a href='$prev_file'>" . $idx_prev_text . "</a>";
210 }
211
212 # If current image is last in array, do not add nex-index link
213 if ( $idxcount < $lastidx )
214 {
215 $next_file = "index" . ($idxcount+1) . ".html";
216 $next_text = "<a href='" . $next_file . "'>" . $idx_next_text . "</a>";
217 }
218
219 my $position = $indexcount . " of " . $lastidx;
220 my $navscript = gen_navscript( $prev_file, $next_file );
221
222 open TEMPLATE, "<" . $tpl or die "UNABLE TO LOAD TEMPLATE\n";
223 while (<TEMPLATE>)
224 {
225 $_ =~ s/%\{previous\}/$prev_text/;
226 $_ =~ s/%\{next\}/$next_text/;
227 $_ =~ s/%\{title\}/$title/;
228 $_ =~ s/%\{position\}/$position/;
229 $_ =~ s/%\{main_meta\}/$main_meta/;
230 $_ =~ s/%\{navigation_script\}/$navigation_header/;
231 $_ =~ s/%\{thumbnails\}/$thumbs/;
232 $_ =~ s/%\{gallery_timestamp\}/$gentime/;
233 $_ =~ s/%\{navscript\}/$navscript/;
234 $_ =~ s/%\{footer_tag\}/$footer_tag/;
235 $html .= $_;
236 }
237 close TEMPLATE;
238 open HTML, ">" . $indexfile or die "UNABLE TO WRITE\n";
239 print HTML $html;
240 close HTML;
241
242 }
243
244 sub get_exifdata ($)
245 {
246 my $image = shift;
247 my $exifTool = new Image::ExifTool;
248 $exifTool->Options(Unknown => 1);
249
250 my $exif;
251 my $info = $exifTool->ImageInfo($image);
252 $exif->{'Make'} = $info->{'Make'};
253 $exif->{'Model'} = $info->{'Model'};
254 #$exif->{'Orientation'} = $info->{'Orientation'};
255 $exif->{'ExposureTime'} = $info->{'ExposureTime'};
256 $exif->{'FNumber'} = $info->{'FNumber'};
257 $exif->{'ISO'} = $info->{'ISO'};
258 $exif->{'CreateDate'} = $info->{'CreateDate'};
259 $exif->{'ExposureCompensation'} = $info->{'ExposureCompensation'};
260 $exif->{'Flash'} = $info->{'Flash'};
261 $exif->{'FocalLength'} = $info->{'FocalLength'};
262 #$exif->{'ColorSpace'} = $info->{'ColorSpace'};
263 #$exif->{'FileSource'} = $info->{'FileSource'};
264 $exif->{'ExposureMode'} = $info->{'ExposureMode'};
265 $exif->{'Macro'} = $info->{'Macro'};
266 $exif->{'LensType'} = $info->{'LensType'};
267 return $exif;
268 }
269
270 sub get_exifblock
271 {
272 my $exif = shift;
273 my $exifTool = new Image::ExifTool;
274 my $block = "<table id='exifdata' cellspacing='0'>\n";
275 $block .= "<tr class='exifhead'><td>EXIF Parameter</td><td>Value</td></tr>\n";
276 my $tagcount = 0;
277 my $flipflop = 0;
278 foreach my $tag ( keys %$exif )
279 {
280 my $val = $exif->{$tag};
281 next unless $val;
282 $block .= "<tr class='exiflight'>" if $flipflop;
283 $block .= "<tr class='exifdark'>" if not $flipflop;
284 $block .= "\t<td>";
285 $block .= $exifTool->GetDescription($tag);
286 $block .= "</td>\n";
287 $block .= "\t<td>";
288 $block .= $val;
289 $block .= "</td>\n";
290 $block .= "</tr>\n";
291 $flipflop = not $flipflop;
292 $tagcount++;
293 }
294 $block .= "</table>";
295 $block = undef if not $tagcount;
296 return $block;
297 }
298
299 sub gen_navscript
300 {
301 my $prev = shift;
302 my $next = shift;
303 my $index = shift;
304
305 $prev =~ s/\.html//;
306 $next =~ s/\.html//;
307
308 my $scriptbuffer = "<script type='text/javascript'>\n";
309 $scriptbuffer .= "\tnav_reg_prev('" . $prev . "');\n" if $prev;
310 $scriptbuffer .= "\tnav_reg_next('" . $next . "');\n" if $next;
311 $scriptbuffer .= "\tnav_reg_index('" . $index . "');\n" if $index;
312 $scriptbuffer .= "\tnav_reg_onkeypress();\n";
313 $scriptbuffer .= "</script>\n";
314 return $scriptbuffer;
315 }
316
317 sub get_config
318 {
319 # My standard way of implementing AppConfig use ...
320 my $filename = shift;
321 if ( not $filename )
322 {
323 my @files = ( "./plsgen.cfg", "../plsgen.cfg", "/etc/plsgen.cfg" );
324 foreach my $file ( @files ) {
325 $filename = $file;
326 last if ( -f $filename );
327 }
328 }
329
330 my $cfg = AppConfig->new(
331 {
332 CASE => 1,
333 ERROR => \&cfg_error,
334 GLOBAL => {
335 DEFAULT => "<unset>",
336 ARGCOUNT => AppConfig::ARGCOUNT_ONE
337 },
338 }
339
340 );
341 $cfg->define('full_tpl_file');
342 $cfg->full_tpl_file("/usr/local/share/plsgen/full.tpl");
343 $cfg->define('index_tpl_file');
344 $cfg->index_tpl_file("/usr/local/share/plsgen/index.tpl");
345 $cfg->define('css_file');
346 $cfg->css_file("../style.css");
347 $cfg->define('navigation_script');
348 $cfg->navigation_script("../nav.js");
349 $cfg->define('columns');
350 $cfg->columns(4);
351 $cfg->define('rows');
352 $cfg->rows(3);
353 $cfg->define('thumb_pre');
354 $cfg->thumb_pre("<div class='thumb'>");
355 $cfg->define('thumb_post');
356 $cfg->thumb_post("</div>");
357 $cfg->define('idx_prev_text');
358 $cfg->idx_prev_text("&larr; Back");
359 $cfg->define('idx_next_text');
360 $cfg->idx_next_text("Next &rarr;");
361 $cfg->define('idx_ret_text');
362 $cfg->idx_ret_text("To index");
363 $cfg->define('footer_tag');
364 $cfg->footer_tag('plsgen : Perl Simple Gallery Generator 0.1');
365
366 $cfg->file($filename) if -f $filename;
367 return $cfg;
368 }
369
370 sub cfg_error {
371 die "Error occured in config-handling: $_\n";
372 }
373