1: magical incantation finds Perl as long as it's in the user's path
2eval 'exec perl -wS $0 ${1+"$@"}'
3	if 0;
4
5############################################################################
6# Please change this accordingly if you change the DESTDIR in the tarball
7# distribution Makefile or the --prefix of the RPM installation
8$LIBDIR = "/usr/local/lib/igal2";
9# for example if you make DESTDIR=/usr then $LIBDIR="/usr/lib/igal2"
10############################################################################
11#
12# A short note from Eric Pop the developer of the "old" igal version:
13# Note to do-it-yourselvers and Computer Science types:  the IGAL code is
14# UGLY.  I'm am amateur programmer, not a CS type.  If my scrappy code runs
15# and gives the right results, I'm happy.  If others find it useful, that's
16# wonderful.  I hope my comments can help decipher the mess below a bit.  I
17# wrote IGAL partly because I wanted another excuse to learn Perl (it's
18# useful for my research too) and because other image gallery generators
19# had hairy dependencies and didn't do what I needed.  So... my apologies
20# if the spaghetti below makes you cringe.  It works for me, so I don't
21# really have plans (or time) to clean it up.
22#
23############################################################################
24# If you KNOW you have the ImageMagick package installed (e.g commands like
25# identify and convert) then setting this equal to 1 may speed up the code a
26# bit (igal will stop checking for these commands every time it runs)
27#
28$HAVEIM = 0;
29############################################################################
30# If you KNOW you have the libjpeg stuff installed (e.g commands like cjpeg,
31# djpeg and pnmscale) then setting this equal to 1 may speed up the code a
32# bit (igal will stop checking for these commands every time it runs)
33#
34$HAVELJ = 0;
35############################################################################
36
37# This is IGAL version 2.2, an online Image GALlery generator.
38#   Copyright (C) 2000 Eric Pop, 2003 Wolfgang Trexler
39#   This version was enhanced by Wolfgang Trexler (wt) Apr. 2003 - May 2016
40#
41#   This program is free software; you can redistribute it and/or modify
42#   it under the terms of the GNU General Public License as published by
43#   the Free Software Foundation; either version 2 of the License, or
44#   (at your option) any later version.
45#
46#   This program is distributed in the hope that it will be useful,
47#   but WITHOUT ANY WARRANTY; without even the implied warranty of
48#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
49#   GNU General Public License for more details.
50#
51#   You should have received a copy of the GNU General Public License
52#   along with this program; if not, write to the Free Software
53#   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
54#
55# Author: Eric Pop, Dept. of Electrical Engineering, Stanford University
56# Email: epop@stanford.edu
57# Enhancements were done by: Wolfgang Trexler, Alexander Zangerl
58# EMail: wt-igal@trexler.at
59
60use FileHandle;
61use Getopt::Long;
62use POSIX qw(ceil floor);
63# Check if EXIF Tool library is installed
64$ExifTool = eval "use Image::ExifTool; 1" ? 1 : 0;
65
66
67# some constants
68$VERSION = "2.2";
69$Getopt::Long::ignorecase = 0;
70$itile = "tile.png";
71$slidetemplate = "slidetemplate2.html";
72$indextemplate = "indextemplate2.html";
73$csstemplate = "igal2.css";
74$directorylinefile = "directoryline2.html";
75$captionfile = ".captions";
76$userigaldir = "$ENV{'HOME'}/.igal2";
77$thumbprefix = ".thumb_";
78$slideprefix = ".slide_";
79$destback = "";
80STDOUT->autoflush("1");
81
82# default command-line argument values
83$opt_a = "0";          # to write image size under thumbnails in index page
84$opt_c = "0";          # -c to use user-supplied captions
85$opt_C = "0";          # same as -c, but preserve image names as captions
86$opt_d = ".";          # look in current directory "."
87$opt_e = "0";          # write EXIF information under image
88$opt_f = "0";          # -f to force thumbnail regeneration
89$opt_h = "0";
90$opt_i = "index.html"; # name of the main thumbnail index file
91$opt_k = "0";          # -k for the captions to also be used as slide titles
92$opt_m = "";           # -m Apply a watermark to each image
93$opt_n = "0";          # -n to use image file names for the .html files
94$opt_o = "";           # -o dir specifies alternate prefix for target links
95$opt_p = "3";          # cellpadding value for the thumbnail index tables
96$opt_r = "0";          # -r to omit the film reel effect altogether
97$opt_s = "0";          # -s to make no slides, just thumbnail links to images
98$opt_t = "21";         # height of the .tile.png tiled image
99$opt_u = "0";          # write captions under thumbnails on index page
100$opt_w = "5";          # index rows are 5 images wide by default
101$opt_x = "0";          # -x to omit the image count from the caption
102$opt_y = "0";          # max height of a thumbnail (defaults to 75 below)
103$opt_ad = "0";         # write out only dimensions
104$opt_as = "0";         # write out only file size
105$opt_bigy = "0";       # max height of the slides.  use if images are huge.
106$opt_con = "";         # options to be passed to convert or cjpeg
107$opt_help = "0";       # displays brief usage message; same as -h
108$opt_www = "0";        # makes everything world-readable
109$opt_xy = "0";         # scale thumbs to n pixels in their longer dimension
110$opt_dest = "";        # Destination directory of helper files
111$opt_AddSubdir = "0";  # Add subdirectories to index.html file
112$opt_pagination = "0"; # maximum number of images on one page, zero means no pagination
113
114$usage = <<"END_OF_USAGE";
115This is iGal2 $VERSION an HTML image slide show generator.
116Syntax:  igal [-option -option ...]
117Options:     -a           write image sizes under thumbnails on index page
118             -c           first generate and then use captions
119             -C           like -c, but preserve file names as captions
120             -d <dir>     operate on files in directory <dir> (.)
121             -e           write EXIF information under image (needs Image::ExifTool)
122             -f           force thumbnail regeneration
123             -h           displays this brief help; same as --help
124             -i <file>    name of the main thumbnail index file (index.html)
125             -k           use the image captions for the HTML slide titles
126             -m <file>    Automatically add watermark to each image
127             -n           use image file names for the HTML slide files
128             -p <n>       cellpadding value of thumbnail index tables (3)
129             -r           omit the film reel effect altogether
130             -s           make no HTML slides, link thumbnails to images
131             -t <n>       height of the film reel tiled image (21)
132             -u           write captions under thumbnails on index page
133             -w <n>       rows in thumbnail index are <n> images wide (5)
134             -x           omit the image count from the captions
135             -y <n>       scale all thumbnails to the same height <n> (75)
136             --ad         like -a, but write only the image dimensions
137             --as         like -a, but write only the file size (in kbytes)
138             --bigy <n>   like -y, use it if you have very large image files
139             --con <>     options to pass to convert or cjpeg (e.g. -quality N)
140             --help       displays this brief help; same as -h
141             --www        make all iGal files world-readable
142             --xy <n>     scale thumbs to <n> pixels in their longer dimension
143             ------------- N E W   F U N C T I O N S --------------------------
144	     --dest <dir> Destination directory for the helper files
145			  (thumbnails, slides, etc.) igal generates. This is
146			  relative to the operative directory -d and has to be
147			  one level below (.)
148	     --AddSubdir  If igal finds further directories beneath your image
149	     	          directory -d, it will generate HTML Links in the
150			  index file (index.html) to this directories.
151		 	  Default is (off). Directories given with --dest or
152			  starting with a "." will be ignored.
153			  Note: igal will not work recursively, it just adds
154                          HTML links to the directories below.
155             -m <file>    Automatically add watermark to each image - this
156                          works well with a transparent .gif, but anything
157                          can be used - edit the "composite" line later on
158                          to adjust visibility/position of mark if required
159                          Originals will be left with a .unmarked extension
160             -o <dir>     Root URL of alternate location for the links to full
161                          size images. Use this if your indexes will be in
162                          a different location/server from the back end images
163             --pagination <n> Maximum number of images on one page.
164                          If the given number of images is reached a new page
165                          is started. Pagination number <n> should be a multiple
166                          of parameter -w (default 5).
167                          Default 0 - means no pagination at all.
168Note:         default values are given in parentheses (where applicable).
169Authors:      Wolfgang Trexler <wt-igal\@trexler.at>
170              Eric Pop <epop\@stanford.edu> (original igal)
171	      contributions:
172              Stewart Addison <contactsxa\@gmail.com>, Riku Kalinen,
173              Alexander Zangerl
174URL:          http://igal.trexler.at/
175END_OF_USAGE
176
177# store command-line options upfront to write in the index <HEAD>
178@igal_options = @ARGV;
179
180# process command-line arguments (overriding defaults above)
181GetOptions('a','c','C','d=s','e','f','h','i=s','k','m=s','n','o=s',
182           'p=i','r','s','t=i','u','w=i','x','y=i','ad','as',
183           'bigy=i', 'con=s','help','im','www','xy=i', 'dest=s',
184	   'AddSubdir', 'pagination=s') or die "$usage";
185
186die $usage if ($opt_help or $opt_h);
187# deal with the competing -y and --xy options
188if (($opt_y == 0) and ($opt_xy == 0)) {
189	$opt_y = 75;    # default, if neither -y nor --xy is specified
190} else {
191	$opt_f = "1";   # if either is specified, force thumbnail regeneration
192}
193die "Please only specify one of the -y and --xy options\n" if ($opt_y and $opt_xy);
194# other error (sanity) checks
195die "Please enter nonnegative thumbnail dimensions\n" if (($opt_y < 0) or ($opt_xy < 0));
196die "Please enter a nonnegative cellpadding value\n" if ($opt_p < 0);
197die "Please choose at least one image per index row\n" if ($opt_w <= 0);
198die "Please enter a nonnegative tiled image height\n" if ($opt_t < 0);
199die "Please enter a nonnegative pagination value\n" if ($opt_pagination < 0);
200$opt_o = "$opt_o/" if ( $opt_o );
201
202die "Critical failure: Lib Image::ExifTool not install but EXIF Tags (option -e) requested\n" if (($ExifTool == 0) and ($opt_e));
203
204# strip any unnecessary slashes from the end of the given $opt_d directory
205$opt_d =~ s/\/$//;
206
207# let users store their templates in a $HOME/.igal directory, if it exists,
208# instead of the site-wide /usr/local/lib/igal (from line 8 up top)
209$LIBDIR = $userigaldir if ((-r $userigaldir) && (-d $userigaldir));
210
211# load up image files from $opt_d into array @imgfiles
212opendir DIR, $opt_d or die "Can't open directory $opt_d\n";
213
214# find and read all jp(e)g, gif and png files
215@jpgfiles = grep((!/^\./ and /\.jpe?g$/i), readdir DIR);
216rewinddir DIR;   # this is CRUCIAL here!!!
217@giffiles = grep((!/^\./ and /\.gif$/i), readdir DIR);
218rewinddir DIR;   # this is CRUCIAL here!!!
219@pngfiles = grep((!/^\./ and /\.png$/i), readdir DIR);
220@imgfiles = @jpgfiles;
221push(@imgfiles, @giffiles);
222push(@imgfiles, @pngfiles);
223
224@imgfiles = sort @imgfiles;      # sort alphabetically, by file name
225$njpg = @jpgfiles;
226$nfiles = @imgfiles;             # how many total image files i've loaded
227
228die "Can't find any image files in directory $opt_d\n" if ($nfiles == 0);
229
230# find and read all directories (except beginning with . and igal destination) for later use
231if ($opt_AddSubdir) {
232	rewinddir DIR;
233	foreach $file (readdir DIR) {
234		if (-d "$opt_d/$file" && !($file =~ /^\./) && !($file =~ /$opt_dest/)) {
235			push(@directories, $file);
236		}
237	}
238	if (@directories) {
239		@directories = sort @directories;      # sort alphabetically, by name
240	} else {
241		print "Information: Option --AddSubdir is set, but can't find any matching subdiretories!\n";
242	}
243
244
245}
246
247closedir DIR;
248
249# Store image extensions
250@imgext = (); @captions = ();
251
252foreach $file (@imgfiles) {
253	# store image captions & extensions in separate arrays along the way
254	$file =~ m/(^.*)\.(\w{3,4})$/;
255	push(@captions, $1);
256	push(@imgext, $2);
257}
258
259
260# wt 08.04.03: check for destination directory of igal files, and create it if necessary
261$opt_dest =~ s/\/$//;     # strip any unnecessary slashes from the end of the given $opt_dest directory
262if (length $opt_dest > 0) {
263	if ($opt_dest =~ m/(\/|\\|\#|<|>|%|\"|\s)/) {
264		die "\nYour destination directory ($opt_dest) contains a character ($1) which\nis not allowed inside an URL.  URIs may not contain delimiters such as \\, <, >, #, %, \" or \nwhite space.\n\n";
265	}
266	if (! -d "$opt_d/$opt_dest") {
267		mkdir "$opt_d/$opt_dest" or die "Can't create directory for igal files ($opt_d/$opt_dest) [$!]";
268	}
269	print "Using directory $opt_d/$opt_dest for igal files (except for index.html)\n";
270	$opt_dest = "$opt_dest/";	# Append / to directory for further use
271	$destback = "../";		# will be used in html later on to find the directory where images reside
272}
273
274
275# if the -c (or -C) option was supplied let user specify captions, else see below
276if ($opt_c or $opt_C) {
277	if (! -r "$opt_d/$opt_dest$captionfile") {
278		# create $captionfile file if it doesn't exist
279		print "Found $nfiles image files in directory $opt_d\n";
280#		die "Please select more files for your slide show!\n" if ($nfiles <= 1);
281		open(CAP,">$opt_d/$opt_dest$captionfile") or die "Can't create $opt_d/$opt_dest$captionfile file\n";
282		print "Creating the $opt_dest$captionfile file...\n";
283		print CAP "# This is igal's $captionfile file, first generated ", scalar localtime, ".\n";
284		print CAP "# To the left of the separator are the image file names.  Enter your captions\n# on the right side, one per line.  The captions may include HTML tags.\n# To add any comments to this file or to exclude any images from the slide \n# show, add a # sign at the beginning of their respective lines.  You may\n# also change the order of images in your slide show at this time.\n\n";
285			for ($i = 0; $i < $nfiles; $i++) {
286				print CAP "$imgfiles[$i] ---- ";
287				print CAP "$captions[$i]" if $opt_C;
288				print CAP "\n";
289			}
290		close(CAP);
291		die "Now edit the $opt_dest$captionfile file to your liking and rerun igal -c\n";
292	} else {
293		# read in files specified in the .captions file
294		open(CAP,"$opt_d/$opt_dest$captionfile") or die "Can't open $opt_d/$opt_dest$captionfile file\n";
295		@imgfiles = ();     # reset arrays b/c we're rereading them
296		@captions = (); @imgext = (); $njpg = 0;
297		print "Reading the $captionfile file ... ";
298		while (defined($line = <CAP>)) {
299			chomp($line); $line =~ s/^\s*//; $line =~ s/\s*$//;
300			# only read lines with the ---- delimiter that don't start with #
301			if (($line =~ m/\w\s*----\s*/) && !($line =~ m/^\#/)) {
302				@arr = split(/\s*----\s*/,$line);
303				# first check image extensions
304				$temp = $arr[0]; $temp =~ s/^.*\.//;
305				push(@imgfiles,$arr[0]);
306				push(@imgext, $temp);
307				push(@arr,"") if (scalar @arr == 1);
308				push(@captions,$arr[1]);
309				$njpg++ if ($arr[0] =~ m/jpe?g/i);
310			}
311		}
312		close(CAP);
313		$nfiles = @imgfiles;
314		print "found $nfiles image files.\n";
315		die "Please select more files for your slide show!\n" if ($nfiles < 1);
316	}
317} else {
318	print "Found $nfiles image files in directory $opt_d\n";
319}
320
321# find out if the imagemagick commands exist
322$HAVEIM = (&exist("identify") and &exist("convert")) unless ($HAVEIM);
323print "\nWARNING:  commands identify/convert missing!\nThe ImageMagick (imagemagick.org) or GraphicsMagick package with compatibility doesn't seem to be\ninstalled.  Image dimensions will not be available in the generated HTML.\nOnly JPG images are supported... falling back onto cjpeg/djpeg/pnmscale.\n\n" unless ($HAVEIM);
324
325# find out if the libjpeg commands exist
326$HAVELJ = (&exist("cjpeg") and &exist("djpeg") &exist("pnmscale")) unless ($HAVELJ or ($njpg == 0) or $HAVEIM);
327print "\nWARNING:  at least one of the commands \"cjpeg\", \"djpeg\" and \"pnmscale\" is not\ninstalled.  You can find these at rpmfind.net (inside libjpeg and libgr-progs)\nor you can download the source code from:\n    http://www.ijg.org/ and\n    http://netpbm.sourceforge.net/\n\n" unless ($HAVELJ or ($njpg == 0) or $HAVEIM);
328
329# give up if no image processing commands can be found
330die "ERROR:  the necessary image processing tools aren't installed on your system.\nPlease obtain them as specified above.\n\n" unless ($HAVEIM or $HAVELJ);
331
332# initialize the arrays that will hold image file sizes
333@xdim=(); @ydim=(); @isiz=();
334
335# Jan 13, 2003:  i played around w/the various ways in which convert can
336# resize images, i.e with -scale, -sample, -geometry (equivalent to -resize)
337# and lo and behold, i realized that igal will run MUCH faster when resizing
338# is done with -scale while quality is about same as with -geometry (in igal
339# 1.3 and earlier).  using -sample gives me a bit more speed advantage but
340# is not worth using as the scaled-down output seems to be pretty poor.
341# here are some timed-runs on a directory w/some images:
342# 	* w/convert -sample (poor quality) 7.24 sec
343#	* w/convert -scale (ok quality) 9.14 sec
344#	* w/convert -resize (ok quality) 23.8 sec
345#	* w/cjpeg/djpeg (ok quality) 20.1 sec
346# so from now on all convert -scale is used everywhere below because it seems
347# to be the clear winner for quality vs speed.
348
349# generate .thumbnails in the same directory with the original image files (or in the given --dest directory)
350# if they don't exist already or if the -f switch is given
351
352print "Creating thumbnails:  ";
353for ($i = 0; $i < $nfiles; $i++) {
354	$file = $imgfiles[$i];
355	$fullfile = "$opt_d/$file";
356	die "Can't open $fullfile\n" unless (-r $fullfile);
357	$fullthumb = "$opt_d/$opt_dest$thumbprefix$file";
358	if ((! -e $fullthumb) or $opt_f) {
359		if ($HAVEIM) {
360			$command = "convert $opt_con -scale x$opt_y \"$fullfile\" \"$fullthumb\"";
361			# opt_xy handling: determine dimensions and scale the bigger dimension
362			# Bug fixing code new since version 1.4.7
363			if ($opt_xy) {
364			        $temp = `identify -ping -format \"\%wx\%h %b\" \"$fullfile\"`;
365				$temp =~ m/(\d+)x(\d+)\s([\d\.]+[mkb]*)/i;
366				$width = $1; $height = $2; $temp = $3;
367				if ($width > $height) {
368				    $dimension = "$opt_xy" . "x";
369				} else {
370				    $dimension = "x" . "$opt_xy";
371				}
372				$command = "convert $opt_con -scale $dimension \"$fullfile\" \"$fullthumb\"";
373			}
374		} else {
375			if ($imgext[$i] =~ m/(gif|png)/i) {
376				print "\nIgnoring $file:  get ImageMagick (imagemagick.org) to process GIF and PNG files.\n";
377				$command = 0;
378			} else {
379				$com1 = "djpeg \"$fullfile\"";
380				$com3 = "cjpeg $opt_con -outfile \"$fullthumb\"";
381				$scale = "pnmscale -ysize $opt_y";
382				$scale = "pnmscale -xysize $opt_xy $opt_xy" if ($opt_xy);
383				$command = $com1 . " | " . $scale . " | " . $com3;
384			}
385		}
386		system("$command") if ($command);
387		print "$thumbprefix$file " if ($command);
388	}
389}
390print "... done!\n";
391
392# determine image file sizes
393if ($HAVEIM && !($opt_bigy)) {
394	print "Determining image sizes ";
395	foreach $file (@imgfiles) {
396		$fullfile = "$opt_d/$file";
397		$temp = `identify -ping -format \"\%wx\%h %b\" \"$fullfile\"`;
398		$temp =~ m/(\d+)x(\d+)\s([\d\.]+[mkb]*)/i;
399		push(@xdim,$1);  push(@ydim,$2);  $temp = $3;
400		# round nicely in kb if identify returned the size in bytes
401		$temp = sprintf ("%.1fk", $temp/1024) if ($temp =~ s/([\d\.]+)b*$/$1/i);
402		push(@isiz,$temp);
403		print ".";
404	}
405	print " done!\n";
406}
407
408# scale down slides if the --bigy <n> option was given
409if ($opt_bigy and !($opt_s)) {
410	if ($HAVEIM) {
411		print "Scaling down big slides and determining new slide sizes:  ";
412		@xdim=(); @ydim=(); @isiz=();    # reset image size arrays
413	} else {
414		print "Scaling down big slides:  ";
415	}
416	for ($i = 0; $i < $nfiles; $i++) {
417		$file = $imgfiles[$i];
418		$fullfile = "$opt_d/$file";
419		die "Can't open $fullfile\n" unless (-r $fullfile);
420		$fullslide = "$opt_d/$opt_dest$slideprefix$file";
421		if ((! -e $fullslide) or $opt_f) {
422			if ($HAVEIM) {
423				$command = "convert $opt_con -scale x$opt_bigy \"$fullfile\" \"$fullslide\"";
424			} else {
425				if ($imgext[$i] =~ m/(gif|png)/i) {
426					print "\nIgnoring $file:  get ImageMagick (imagemagick.org) to process GIF and PNG files.\n";
427					$command = 0;
428				} else {
429					$com1 = "djpeg \"$fullfile\"";
430					$com3 = "cjpeg $opt_con -outfile \"$fullslide\"";
431					$scale = "pnmscale -ysize $opt_bigy";
432					$command = $com1 . " | " . $scale . " | " . $com3;
433				}
434			}
435			system("$command") if ($command);
436			print "$slideprefix$file " if ($command);
437		}
438		if ($HAVEIM) {
439			$temp = `identify -ping -format \"\%wx\%h %b\" \"$fullslide\"`;
440			$temp =~ m/(\d+)x(\d+)\s([\d\.]+[mkb]*)/i;
441			push(@xdim,$1);  push(@ydim,$2);  $temp = $3;
442			# round nicely in kb if identify returned the size in bytes
443			$temp = sprintf ("%.1fk", $temp/1024) if ($temp =~ s/([\d\.]+)b*$/$1/i);
444			push(@isiz,$temp);
445		}
446	}
447	print "... done!\n";
448}
449
450if ( $opt_m ) {
451        # This is a fairly simple watermarking method - this could be made
452        # more complex ...
453        die "ImageMagick required for watermarking\n" if (! &exist("composite"));
454        die "Cannot open watermark file $opt_m" if ( ! -r $opt_m );
455        print "Adding watermarks:";
456	for ($i = 0; $i < $nfiles; $i++) {
457		$file = $imgfiles[$i];
458		$original = "$file.unmarked";
459		# If original exists, user has re-run the script - don't
460		# add a second watermark
461                if ( -r $original ) {
462                        print " [$file already marked]";
463                } else {
464                        die "Can't open $file\n" unless (-r $file);
465		        rename $file, $original || die "Failed to rename $file to $original";
466		        print " $file";
467                        # Could add '&& unlink $original' but wouldn't protect against reruns
468		        system "composite -dissolve 33 -geometry +20+20 $opt_m $original $file";
469		        die "Failed to add watermark to $file" if ( ! -r $file );
470		}
471        }
472        print "\nPre-watermarked files have been left with a .unmarked extension\n";
473        print "You may wish to remove those before publishing the gallery\n";
474}
475
476# create the individual slide show files
477if ($opt_s) {
478	print "Linking thumbnails directly to image files...  Making no html slides.\n";
479	if (! -e "$opt_d/$opt_dest$csstemplate") {
480		print "No CSS template file ... getting $LIBDIR/$csstemplate\n";
481		die "$LIBDIR cannot be read or does not exist.\nPlease install igal properly.\n" unless (-r $LIBDIR);
482		die "$LIBDIR/$csstemplate cannot be read or does not exist.\nPlease install igal properly.\n" unless (-r "$LIBDIR/$csstemplate");
483		system("cp -f $LIBDIR/$csstemplate \"$opt_d/$opt_dest\"");
484        }
485} else {
486	$nfiles = @imgfiles;      # total number of files (same as # of captions)
487	@slides = ();
488	if ($opt_n) {                       # decide on the slide html file names
489		for ($i = 0; $i < $nfiles; $i++) {
490			$temp = $imgfiles[$i];
491			$temp =~ s/\.\w+?$/\.html/; # strip suffix, bug fixing (1.4.5)
492			push(@slides,$temp);
493		}
494	} else {
495		for ($i = 0; $i < $nfiles; $i++) {
496			push(@slides, $i+1 . ".html");
497		}
498	}
499	system("rm -f \"$opt_d/$opt_dest*.html\"");
500	if (! -e "$opt_d/$opt_dest$csstemplate") {
501		print "No CSS template file ... getting $LIBDIR/$csstemplate\n";
502		die "$LIBDIR cannot be read or does not exist.\nPlease install igal properly.\n" unless (-r $LIBDIR);
503		die "$LIBDIR/$csstemplate cannot be read or does not exist.\nPlease install igal properly.\n" unless (-r "$LIBDIR/$csstemplate");
504		system("cp -f $LIBDIR/$csstemplate \"$opt_d/$opt_dest\"");
505	} else {
506		print "Found CSS template file $opt_dest$csstemplate ... using it.\n";
507	}
508	if (! -e "$opt_d/$opt_dest.$slidetemplate") {
509		print "No $opt_dest.$slidetemplate file ... getting a copy from $LIBDIR/\n";
510		die "$LIBDIR cannot be read or does not exist.\nPlease install igal properly.\n" unless (-r $LIBDIR);
511		die "$LIBDIR/$slidetemplate cannot be read or does not exist.\nPlease install igal properly.\n" unless (-r "$LIBDIR/$slidetemplate");
512		system("cp -f $LIBDIR/$slidetemplate \"$opt_d/$opt_dest.$slidetemplate\"");
513	} else {
514		print "Found $opt_dest.$slidetemplate file ... using it.\n";
515	}
516	print "Creating individual slides:  ";
517	# read slidetemplate from filesystem once
518	$slidetemplate_string = read_file_in_string("$opt_d/$opt_dest.$slidetemplate");
519	for ($i = 0; $i < $nfiles; $i++) {
520		$workarea = $slidetemplate_string;	# fill work area with slidetemplate
521		open(SW,">$opt_d/$opt_dest$slides[$i]") or die "Can't create slide file\n";
522		print "$slides[$i] ";
523		if ($opt_k) {    # use image caption for the HTML slide title
524			$title = $captions[$i];
525		} else {         # otherwise use the image name (strip suffix)
526			$title = $imgfiles[$i];
527			$title =~ s/\.\w+?$//;
528		}
529		$workarea =~ s/<!--SLIDE-TITLE-->/$title/g;
530		$imgfile_i_encoded = URLencode($imgfiles[$i]);
531		if ($opt_bigy) {
532			$slide = URLencode($slideprefix . $imgfiles[$i]);
533			if ($HAVEIM) {
534				$workarea =~ s/(<.*)<!--THIS-IMAGE-->(.)(.*>)/<A href=\"$destback$imgfile_i_encoded\">$1$slide$2 width=$xdim[$i] height=$ydim[$i] alt=\"$title\" title=\"click to see full-size\"$3<\/a>/;
535			} else {
536				$workarea =~ s/(<.*)<!--THIS-IMAGE-->(.)(.*>)/<A href=\"$destback$imgfile_i_encoded\">$1$slide$2 alt=\"$title\" title=\"click to see full-size\"$3<\/a>/;
537			}
538		} else {
539			if ($HAVEIM) {
540				$workarea =~ s/<!--THIS-IMAGE-->(.)/$destback$imgfile_i_encoded$1 width=$xdim[$i] height=$ydim[$i] alt=\"$title\"/g;
541			} else {
542				$workarea =~ s/<!--THIS-IMAGE-->/$destback$imgfile_i_encoded/g;
543			}
544		}
545
546		# add in the image counter unless -x is specified
547		if ($opt_x) {
548			$imagecaption = $captions[$i];
549		} else{
550			$imagecaption = $captions[$i] . "&nbsp;&nbsp;&nbsp;(" . ($i+1) ."/$nfiles)" if (! $opt_x);
551		}
552		$workarea =~ s/<!--IMAGE-CAPTION-->/$imagecaption/g;
553
554		# add EXIF information if -e is specified
555		if ($opt_e) {
556		    my $exif=Image::ExifTool::ImageInfo($imgfiles[$i]);
557		    my $exifinfo= "<A href=\"javascript:toggle('exifinfo');\">Show/hide EXIF data</A>\n";
558		    $exifinfo .= "<DIV id=\"exifinfo\">\n";
559		    $exifinfo .= "<TABLE><th>EXIF Tag</th><th>Value</th>\n";
560		    for my $k (sort keys %$exif) {
561			$exifinfo .= "<TR><TD>$k</TD><TD>".
562			    (ref($exif->{$k}) eq "SCALAR"?'Binary data '.length(${$exif->{$k}}).' bytes':$exif->{$k})."</TD></TR>\n";
563		    }
564		    $exifinfo .= "</TABLE></DIV>\n";
565		    $workarea =~ s/<!--EXIF-INFO-->/$exifinfo/g;
566                }
567
568		# find out if pagination is used and which number the index file has...
569		$index_file_number = ($opt_pagination) ? int ($i / $opt_pagination) : 0;
570		$index_filename = ($index_file_number == 0) ? $opt_i : "$index_file_number$opt_i";
571		$workarea =~ s/<!--INDEX-FILE-->/$destback$index_filename/g;
572
573		if ($opt_bigy) {
574			$pref = $slideprefix;
575		} else {
576			$pref = $destback;
577		}
578		if ($i == 0 && $nfiles == 1) {	# special treatment if there is exactly one file!
579			$temp = URLencode("$pref$imgfiles[0]");
580			$workarea =~ s/<!--NEXT-IMAGE-->/$temp/g;
581			$temp = URLencode("$slides[0]");
582			$workarea =~ s/<!--PREV-SLIDE-->/\"$temp\" title=\"$captions[0]\"/g;
583			$temp = URLencode("$slides[0]");
584			$workarea =~ s/<!--NEXT-SLIDE-->/\"$temp\" title=\"$captions[0]\"/g;
585		} elsif ($i == 0) {			# first image, previous points to last image
586			$temp = URLencode("$pref$imgfiles[$i+1]");
587			$workarea =~ s/<!--NEXT-IMAGE-->/$temp/g;
588			$temp = URLencode("$slides[$nfiles-1]");
589			$workarea =~ s/<!--PREV-SLIDE-->/\"$temp\" title=\"$captions[$nfiles-1]\"/g;
590			$temp = URLencode("$slides[$i+1]");
591			$workarea =~ s/<!--NEXT-SLIDE-->/\"$temp\" title=\"$captions[$i+1]\"/g;
592		} elsif ($i == $nfiles-1) {	# last image, next points to first image
593			$temp = URLencode("$pref$imgfiles[0]");
594			$workarea =~ s/<!--NEXT-IMAGE-->/$temp/g;
595			$temp = URLencode("$slides[$i-1]");
596			$workarea =~ s/<!--PREV-SLIDE-->/\"$temp\" title=\"$captions[$i-1]\"/g;
597			$temp = URLencode("$slides[0]");
598			$workarea =~ s/<!--NEXT-SLIDE-->/\"$temp\" title=\"$captions[0]\"/g;
599		} else {
600			$temp = URLencode("$pref$imgfiles[$i+1]");
601			$workarea =~ s/<!--NEXT-IMAGE-->/$temp/g;
602			$temp = URLencode("$slides[$i-1]");
603			$workarea =~ s/<!--PREV-SLIDE-->/\"$temp\" title=\"$captions[$i-1]\"/g;
604			$temp = URLencode("$slides[$i+1]");
605			$workarea =~ s/<!--NEXT-SLIDE-->/\"$temp\" title=\"$captions[$i+1]\"/g;
606		}
607		print SW "$workarea";
608		close(SW);
609	}
610
611	print "... done!\n";
612}
613
614
615#############################################################################
616# create the main index file with all the thumbnails
617if ($opt_r) {
618	print "Got option -r... omitting film reel effect.\n";
619} elsif (! -e "$opt_d/$opt_dest.$itile") {
620	print "No $opt_dest.$itile file... getting a copy from $LIBDIR/\n";
621	die "$LIBDIR cannot be read or does not exist.\nPlease install igal properly.\n" unless (-r $LIBDIR);
622	die "$LIBDIR/$itile cannot be read or does not exist.\nPlease install igal properly.\n" unless (-r "$LIBDIR/$itile");
623	system("cp -f $LIBDIR/$itile \"$opt_d/$opt_dest.$itile\"");
624} else {
625	print "Found $opt_dest.$itile file ... using it.\n";
626}
627# rescale the tiled image if the -t switch was called but -r wasn't
628if (($HAVEIM) and (! $opt_r)) {
629	$tileh = `identify -ping -format \"\%wx\%h %b\" \"$opt_d\/$opt_dest.$itile\"`;
630	$tileh =~ s/\d+x(\d+)\s[\d\.]+./$1/;
631	system("mogrify -scale x$opt_t $opt_d/$opt_dest.$itile") if ($opt_t != $tileh);
632}
633
634if (! -e "$opt_d/$opt_dest.$indextemplate") {
635	print "No $opt_dest.$indextemplate file... getting a copy from $LIBDIR/\n";
636	die "$LIBDIR cannot be read or does not exist.\nPlease install igal properly.\n" unless (-r $LIBDIR);
637	die "$LIBDIR/$indextemplate cannot be read or does not exist.\nPlease install igal properly.\n" unless (-r "$LIBDIR/$indextemplate");
638	system("cp -f $LIBDIR/$indextemplate \"$opt_d/$opt_dest.$indextemplate\"");
639} else {
640	print "Found $opt_dest.$indextemplate ... using it.\n";
641}
642
643print "Creating the index file(s) ";
644$indexfile = read_file_in_string("$opt_d/$opt_dest.$indextemplate"); # read indexfile in string to parse it
645$indexfile =~ s/<!--#IGAL-OPTIONS#-->/@igal_options/g;     # set comment about igal options in index file
646$indexfile =~ s/<!--#IGAL-CSS#-->/$opt_dest$csstemplate/g; # set the name (and path) of css template file
647
648# Generate the links for directories
649if ($opt_AddSubdir && @directories) {
650
651	if (! -e "$opt_d/$opt_dest.$directorylinefile") {
652		print "No $opt_dest.$directorylinefile file ... getting a copy from $LIBDIR/\n";
653		die "$LIBDIR cannot be read or does not exist.\nPlease install igal properly.\n" unless (-r $LIBDIR);
654		die "$LIBDIR/$directorylinefile cannot be read or does not exist.\nPlease install igal properly.\n" unless (-r "$LIBDIR/$directorylinefile");
655		system("cp -f $LIBDIR/$directorylinefile \"$opt_d/$opt_dest.$directorylinefile\"");
656	} else {
657		print "Found $opt_dest.$directorylinefile file ... using it.\n";
658	}
659
660	$output = "";
661	$directoryline = read_file_in_string("$opt_d/$opt_dest.$directorylinefile");
662	foreach $directory (@directories) {
663		$temp = $directoryline;
664		$temp =~ s/#DIRECTORY#/$directory/g;
665		$directoryURLencoded = URLencode($directory);
666		$temp =~ s/#DIRECTORY-URLENCODED#/$directoryURLencoded/g;
667		$output .= $temp;
668	}
669	$indexfile =~ s/<!--#DIRECTORYLINE#-->/$output/;
670} else {
671	$indexfile =~ s/<!--#DIRECTORIES-START#-->.*<!--#DIRECTORIES-END#-->/<!-- no directories -->/s;
672}
673$indexfile =~ s/<!--#IGAL-VERSION#-->/$VERSION/g;	#add version information
674
675#generate the table rows
676$indexfile_copy = $indexfile;
677if ($opt_pagination && $nfiles > $opt_pagination) { # pagination necessary!
678	$paginate = $opt_pagination;
679} else { 			# no pagination necessary
680	$paginate = $nfiles;
681}
682
683for ($page = 0; $page * $paginate < $nfiles; $page++) {
684	$output = "";
685	$indexfile = $indexfile_copy;
686
687	$on_this_page = int (($page+1) * $paginate <= $nfiles) ? $paginate : ($nfiles - $page*$paginate); # number of pictures on page
688	$rows = int $on_this_page/$opt_w;     # number of film rows
689	$rem = $on_this_page % $opt_w;        # number of thumbnails on last (incomplete) row
690#	print "rows=$rows - rem=$rem - on_this_page=$on_this_page\n";
691
692	if ($rem > 0) { $rows++; }	# is there a last incomplete row? if yes, we need one more circle for this one
693	for ($i = 1; $i <= $rows; $i++) {
694		#
695		$columns = ($i == $rows && $rem > 0) ? $rem : $opt_w; # last row needs less columns
696
697		$output .= "  <TABLE border=0 cellspacing=0 cellpadding=$opt_p>\n";
698		$output .= "    <TR><TD class=\"tiled\" height=$opt_t colspan=" . ($columns + 2) . ">&nbsp;</TD></TR>\n" unless ($opt_r);
699		$output .= "    <TR>\n      <TD class=\"thumb\">&nbsp;</TD>\n";
700		for ($j = 1; $j <= $columns; $j++) {
701			$fileindex = ($page * $paginate) + (($i-1)*$opt_w+$j-1);	# calculate which file is in use
702#			print "i=$i - j=$j (columns=$columns)- fileindex=$fileindex\n";
703			$output .=  "      <TD class=\"thumb\">\n      ";
704			if ($opt_s) {
705				$output .= "<A href=\"$opt_o" . URLencode($imgfiles[$fileindex]) . "\">";
706			} else {
707				$output .= "<A href=\"$opt_o$opt_dest" . URLencode($slides[$fileindex]) . "\">";
708			}
709			print ".";
710			$altname = $captions[$fileindex];
711			$thumb = $opt_dest . $thumbprefix . $imgfiles[$fileindex];
712			$thumbEncoded = $opt_dest . URLencode($thumbprefix . $imgfiles[$fileindex]);
713			if ($HAVEIM) {
714				$temp = `identify -ping -format \"\%wx\%h\" \"$opt_d/$thumb\"`;
715				$temp =~ m/(\d+)x(\d+)/;  $x=$1;  $y=$2;
716				$output .= "<IMG src=\"" . $thumbEncoded . "\" width=$x height=$y alt=\"$altname\" title=\"$altname\" border=0>";
717			} else {
718				$output .= "<IMG src=\"" . $thumbEncoded . "\" alt=\"$altname\" title=\"$altname\" border=0>";
719			}
720			$output .= "</A></TD>\n";
721		}
722		$output .= "        <TD class=\"thumb\">&nbsp;</TD>\n    </TR>\n";
723		$output .= "    <TR><TD class=\"tiled\" height=$opt_t colspan=" . ($columns+2) . ">&nbsp;</TD></TR>\n" unless ($opt_r);
724		if (($opt_a or $opt_ad or $opt_as) and $HAVEIM) {
725			$output .= "    <TR>\n      <TD>&nbsp;</TD>\n";
726			for ($j = 1; $j <= $columns; $j++) {
727				$fileindex = ($page * $paginate) + (($i-1)*$opt_w+$j-1);	# calculate which file is in use
728#				print $fileindex;
729				$output .= "      <TD>";
730				$printdim = "$isiz[$fileindex]" if $opt_as;
731				$printdim = "$xdim[$fileindex]x$ydim[$fileindex]" if $opt_ad;
732				$printdim = "$xdim[$fileindex]x$ydim[$fileindex] ($isiz[$fileindex])" if $opt_a;
733				$output .= $printdim;
734				$output .= "</TD>\n";
735			}
736			$output .= "    </TR>\n";
737		}
738	#	write image captions under images if option -u is given
739		if ($opt_u) {
740			$output .= "    <TR>\n      <TD>&nbsp;</TD>\n";
741			for ($j = 1; $j <= $columns; $j++) {
742				$fileindex = ($page * $paginate) + (($i-1)*$opt_w+$j-1);	# calculate which file is in use
743#				print $fileindex;
744				$output .= "      <TD>" . $captions[$fileindex] . "</TD>\n";
745			}
746			$output .= "    </TR>\n";
747		}
748		$output .= "  </TABLE>\n    <BR>\n";
749
750	}
751
752	# now replace placeholder in index-file with generated html code
753	$indexfile =~ s/<!-- contents with thumbnails will be inserted here by igal -->/$output/;
754	# insert pageination
755	if ($opt_pagination && $nfiles > $opt_pagination) { # pagination necessary!
756		$numberpages = ceil($nfiles / $opt_pagination);
757		$nextpage = $page+1;
758		$tmptext = "Page $nextpage of $numberpages";
759		# forward navigation
760		if (($page+1) * $paginate < $nfiles) {
761			$nextpagename = "$nextpage$opt_i";
762			$lastpage = $numberpages -1;
763			$tmptext .= "<a href=\"$nextpagename\">&nbsp;&gt;&gt;</a>&nbsp;&nbsp;<a href=\"$lastpage$opt_i\">&gt;|</a>";
764		}
765		# backward navigation
766		if ($page > 0) {
767			$prevpage = $page-1;
768			$prevpagename = ($prevpage == 0) ? $opt_i : "$prevpage$opt_i";
769			$tmptext = "<a href=\"$opt_i\">|&lt;&nbsp;&nbsp;</a><a href=\"$prevpagename\">&lt;&lt;</a> $tmptext";
770		}
771		$indexfile =~ s/<!--#IGAL-PAGINATION#-->/$tmptext/g;
772	}
773	$indexfile =~ s/<!-- \*{4}.*\*{4} -->//g;	#clean up
774	$indexfile =~ s/<!--#.*#-->//g;			#clean up
775
776	$index_filename = ($page == 0) ? $opt_i : "$page$opt_i";
777	print "$index_filename ";
778	open(IXW,">$opt_d/$index_filename") or die "Can't create main $index_filename file\n";
779	print IXW $indexfile;
780	close(IXW);
781}
782
783print " done!\n";
784
785# if --www was invoked make all images world-readable at the END
786if ($opt_www) {
787	$dir = ($opt_d eq ".") ? $opt_dest : "$opt_d/$opt_dest";
788	$dir =~ s/\ /\\ /g;	# escape blanks in directory/filenames for system call
789	print "\nMaking all igal files world-readable for WWW publishing...\n";
790	print "chmod a+r $dir$csstemplate\n";
791	system("chmod a+r $dir$csstemplate");
792	print "chmod a+r $dir*.html\n";
793	system("chmod a+r $dir*.html");
794	print "chmod a+r $dir$thumbprefix*.*\n";
795	system("chmod a+r $dir$thumbprefix*.*");
796	print "chmod a+r $dir$slideprefix*.*\n";
797	system("chmod a+r $dir$slideprefix*.*");
798	print "chmod a+r $dir.$itile\n" unless($opt_r);
799	system("chmod a+r $dir.$itile") unless($opt_r);
800	print "chmod a+r ";
801	# imagefiles are in same directory, therefore $dir has to be set different
802	$dir = ($opt_d eq ".") ? "" : "$opt_d/";
803	foreach $file (@imgfiles) {
804		print "$dir$file ";
805		system("chmod a+r \"$dir$file\"");
806	}
807	print "\nDone!\n";
808}
809
810##############################################################################
811
812# subroutine that checks if a certain program is in the user's path
813# usage &exist("identify") --> 1 (or 0 if it doesn't exist)
814sub exist {
815    local($program) = @_;
816    foreach $dir (split(/:/,$ENV{'PATH'})) {
817		return 1 if (-f "$dir/$program");
818    }
819	return 0;
820}
821
822
823# subroutine that reads a file in a string...
824# called with $string = read_file_in_string("datei.txt");
825sub read_file_in_string {
826	local($filename) = @_;
827
828	open(FILE,$filename) or die "Can't open file $filename [$!]\n";
829	local $/;
830	$string = <FILE>;
831	close(FILE);
832
833	return $string;
834}
835
836# subroutine that URL encodes a string...
837# called with $string = URLencode("text to encode");
838sub URLencode {
839	local($string) = @_;
840	$string =~ s/([^a-zA-Z0-9\.\_])/sprintf "%%%02X",ord($1)/eg;
841
842	return $string
843}
844