#!/usr/bin/perl -w
# $Id: indexpage.pl,v 1.12 2002/02/28 09:26:57 hans Exp $
#
# This script generates one or more index pages and the corresponding
# thumbnails (if desired) for displaying images on the web.
#
# This script may be distributed according to the GNU GPL. If you make 
# any modifications to this, I'd like to see them. The latest version 
# can always be found at 
# http://www.lysator.liu.se/~unicorn/hacks/indexpage/
#
# Hans Persson <unicorn@lysator.liu.se>

use strict;
use Getopt::Long;
use File::Path;
use File::Copy;
use Image::Size 'html_imgsize';

$main::version = "1.0.3";

# Default values.
%main::opt = (
              "title" => 
                  "Index page generated with indexpage.pl $main::version",
              "rows" => 4,
              "cols" => 3,
              "indir" => ".",
              "outdir" => ".",
              "imagere" => q{^(.*)\..*$}, 
              # Something on the previous line fucks up the indentation.
              "makethumbs" => 1,
              "inplace" => 0,
              "thumbsize" => 120,
              "footer" => "",
              "header" => "",
              "order" => "",
              "configfile" => "$ENV{HOME}/.indexpagerc",
              "convert" => "convert",
              "htmlhead" => 
                  "<html>\n<head>\n<title>%(title)s</title>\n</head>\n<body>\n<h1>%(title)s</h1>",
              "htmlfoot" => "</body>\n</html>\n",
              "descfile" => "descriptions.txt",
              "desc" => 1,
              "index" => 1,
              "filenameprefix" => "",
              "debug" => 0,
             );

# Parse the command line options.
GetOptions("title=s", "rows=i", "cols=i", "indir=s", "outdir=s",
           "imagere=s", "makethumbs!", "inplace!", "thumbsize=i",
           "footer=s", "header=s", "order=s", "configfile=s",
           "debug!", "convert=s", "htmlhead=s", "htmlfoot=s",
           "descfile=s", "desc!", "index!", "filenameprefix=s",
           "version");

if ($main::opt_version) {
    print "indexpage.pl $main::version\n" 
        if ($main::opt_version); # FIXME: Ugly patch!
    exit;
}

# Read the default config file.
%main::opt = read_config_file($main::opt{"configfile"}, %main::opt);

# Read the user-specified config file.
if ($main::opt_configfile) {
    %main::opt = read_config_file($main::opt_configfile, %main::opt);
}

# Take care of any command line options.
$main::opt{"title"} = $main::opt_title if ($main::opt_title);
$main::opt{"rows"} = $main::opt_rows if ($main::opt_rows);
$main::opt{"cols"} = $main::opt_cols if ($main::opt_cols);
$main::opt{"indir"} = $main::opt_indir if ($main::opt_indir);
$main::opt{"outdir"} = $main::opt_outdir if ($main::opt_outdir);
$main::opt{"imagere"} = $main::opt_imagere if ($main::opt_imagere);
$main::opt{"makethumbs"} = $main::opt_makethumbs if (defined($main::opt_makethumbs));
$main::opt{"inplace"} = $main::opt_inplace if (defined($main::opt_inplace));
$main::opt{"thumbsize"} = $main::opt_thumbsize if ($main::opt_thumbsize);
$main::opt{"footer"} = $main::opt_footer if ($main::opt_footer);
$main::opt{"header"} = $main::opt_header if ($main::opt_header);
$main::opt{"order"} = $main::opt_order if ($main::opt_order);
$main::opt{"configfile"} = $main::opt_configfile if ($main::opt_configfile);
$main::opt{"convert"} = $main::opt_convert if ($main::opt_convert);
$main::opt{"htmlhead"} = $main::opt_htmlhead if ($main::opt_htmlhead);
$main::opt{"htmlfoot"} = $main::opt_htmlfoot if ($main::opt_htmlfoot);
$main::opt{"descfile"} = $main::opt_descfile if ($main::opt_descfile);
$main::opt{"desc"} = $main::opt_desc if (defined($main::opt_desc));
$main::opt{"index"} = $main::opt_index if (defined($main::opt_index));
$main::opt{"filenameprefix"} = $main::opt_filenameprefix if (defined($main::opt_filenameprefix));
$main::opt{"debug"} = $main::opt_debug if ($main::opt_debug);

if ($main::opt{"inplace"}) {
    $main::opt{"outdir"} = $main::opt{"indir"};
}
$main::geometry = "${main::opt{'thumbsize'}}x$main::opt{'thumbsize'}";
@main::order = split(/ /, $main::opt{"order"});
$main::opt{"header"} =~ s/\\n/\n/g;
$main::opt{"header"} =~ s/%\((.*?)\)s/$main::opt{$1}/ges;
$main::opt{"footer"} =~ s/\\n/\n/g;
$main::opt{"footer"} =~ s/%\((.*?)\)s/$main::opt{$1}/ges;
$main::opt{"htmlhead"} =~ s/\\n/\n/g;
$main::opt{"htmlhead"} =~ s/%\((.*?)\)s/$main::opt{$1}/ges;
$main::opt{"htmlfoot"} =~ s/\\n/\n/g;
$main::opt{"htmlfoot"} =~ s/%\((.*?)\)s/$main::opt{$1}/ges;

if ($main::opt{"debug"}) {
    debug("Title: $main::opt{'title'}");
    debug("Rows: $main::opt{'rows'}");
    debug("Cols: $main::opt{'cols'}");
    debug("Indir: $main::opt{'indir'}");
    debug("Outdir: $main::opt{'outdir'}");
    debug("Imagere: $main::opt{'imagere'}");
    debug("Makethumbs: $main::opt{'makethumbs'}");
    debug("Inplace: $main::opt{'inplace'}");
    debug("Thumbsize: $main::opt{'thumbsize'}");
    debug("Footer: $main::opt{'footer'}");
    debug("Header: $main::opt{'header'}");
    debug("Order: $main::opt{'order'}");
    debug("Configfile: $main::opt{'configfile'}");
    debug("Convert: $main::opt{'convert'}");
    debug("Htmlhead: $main::opt{'htmlhead'}");
    debug("Htmlfoot: $main::opt{'htmlfoot'}");
    debug("Descfile: $main::opt{'descfile'}");
    debug("Desc: $main::opt{'desc'}");
    debug("Index: $main::opt{'index'}");
    debug("Filenameprefix: $main::opt{'filenameprefix'}");
}

$main::pics_per_page = $main::opt{"cols"}*$main::opt{"rows"};

# Other variables.
$main::file_number = "1";
$main::pics_printed = 0;

if ($main::opt{"desc"}) {
    ($main::hasdesc, %main::desc) = &read_descriptions;
    debug("Descriptions: $main::hasdesc");
}

# Get all the image names from the input file directory.
opendir(PICS, "$main::opt{'indir'}") || die("Couldn't open dir '$main::opt{'indir'}': $!");
@main::pics = readdir(PICS);
closedir(PICS);
@main::pics = grep(/\.jpg/i, @main::pics);
foreach $main::pic (@main::pics) {
    $main::pic_nr = $main::pic;
    $main::pic_nr =~ s/$main::opt{"imagere"}/$1/;
    if ($main::pic_nr =~ m/\.jpg/) {
        print "Short name for image '$main::pic' ('$main::pic_nr') " .
            "contains '.jpg'.\nCheck your imagere setting.\n";
    }
    push(@main::pic_numbers, $main::pic_nr);
    $main::trans{$main::pic_nr} = $main::pic;
}

if ($main::opt{"makethumbs"}) {
    File::Path::mkpath("$main::opt{'outdir'}/thumbs");
}

# Find out in what order the images should be printed.
if ($main::opt{"order"}) {
    @main::piclist = @main::order;
    foreach $main::pic (@main::pic_numbers) {
        if (!grep(/$main::pic/, @main::order)) {
            push(@main::piclist, $main::pic);
        }
    }
} else {
    @main::piclist = sort(@main::pic_numbers);
}

foreach $main::pic (@main::piclist) {
    if ($main::pics_printed == 0) {
	$main::filename = &make_file_name($main::file_number);
        if (!opendir(TEST, "$main::opt{'outdir'}")) {
            File::Path::mkpath("$main::opt{'outdir'}");
        }
        if (!opendir(TEST, "$main::opt{'outdir'}/images") &&
            !$main::opt{"inplace"}) {
            File::Path::mkpath("$main::opt{'outdir'}/images");
        }
	open(INDEX, ">$main::opt{'outdir'}/$main::filename") ||
	    die("Couldn't open $main::opt{'outdir'}/$main::filename: $!");
	&print_page_header;
    }

    $main::size = html_imgsize("$main::opt{'indir'}/$main::trans{$main::pic}");
    if ($main::opt{"makethumbs"}) {
        debug("Converting: $main::opt{'convert'} -genmetry $main::geometry $main::opt{'indir'}/$main::trans{$main::pic} $main::opt{'outdir'}/thumbs/$main::pic.jpg");
        `$main::opt{"convert"} -geometry $main::geometry '$main::opt{"indir"}/$main::trans{$main::pic}' '$main::opt{"outdir"}/thumbs/$main::pic.jpg'`;
        $main::size = html_imgsize("$main::opt{'outdir'}/thumbs/$main::pic.jpg");
    }
    if ($main::opt{"outdir"} ne $main::opt{"indir"}) {
        debug("Copying " .
              "$main::opt{'indir'}/$main::trans{$main::pic}"
              . " to " .
              "$main::opt{'outdir'}/" .
              ($main::opt{"inplace"} ? "" : "images/") .
              "$main::pic.jpg");
        copy("$main::opt{'indir'}/$main::trans{$main::pic}",
             "$main::opt{'outdir'}/" . 
             ($main::opt{"inplace"} ? "" : "images/") .
             "$main::pic.jpg");
    }

    print INDEX "<tr>\n"
	if (($main::pics_printed/$main::opt{"cols"}) ==
	    int($main::pics_printed/$main::opt{"cols"}));
    print INDEX "  <td valign=top>\n";
    print INDEX "    ";
    if ($main::opt{"makethumbs"}) {
        print INDEX "<a href=\"";
        if (!$main::opt{"inplace"}) {
            print INDEX "images/$main::pic.jpg\">";
        } else {
            print INDEX "$main::trans{$main::pic}\">";
        }
    }
    print INDEX "<img src=\"";
    if ($main::opt{"makethumbs"}) {
        print INDEX "thumbs/$main::pic.jpg";
    } elsif ($main::opt{"inplace"}) {
        print INDEX "$main::trans{$main::pic}";
    } else {
        print INDEX "images/$main::pic.jpg";
    } 
    print INDEX "\" $main::size";
    if ($main::opt{"desc"}) {
        print INDEX " alt=\"" .
            ($main::hasdesc && $main::desc{$main::pic} ? 
             $main::desc{$main::pic} : 
             $main::pic) .
            "\"";
    }
    print INDEX ">";
    if ($main::opt{"makethumbs"}) {
        print INDEX "</a>";
    }
    print INDEX "\n";
    if ($main::opt{"desc"}) {
        print INDEX "    <br>" . 
            ($main::hasdesc && $main::desc{$main::pic} ? 
             $main::desc{$main::pic} : 
             $main::pic) . 
            "\n";
        print DESC "$main::pic\t\n" if (!$main::hasdesc);
    }
    print INDEX "  </td>\n";
    $main::pics_printed++;
    print INDEX "</tr>\n\n" 
	if (($main::pics_printed/$main::opt{"cols"}) ==
	    int($main::pics_printed/$main::opt{"cols"}));

    if ($main::pics_printed == $main::pics_per_page) {
	&print_page_footer;
	close(INDEX);
	$main::pics_printed = 0;
	$main::file_number++;
    }
}

&print_page_footer unless ($main::pics_printed == 0);
close(INDEX);
if ($main::opt{"desc"}) {
    close(DESC) if (!$main::hasdesc);
}

exit;


sub debug {
    my ($string) = @_;

    print "$string\n" if ($main::opt{"debug"});
}

sub read_config_file {
    my ($file, %conf) = @_;
    my ($line, $tag, $value);

    if (open(CONF, "<$file")) {
        debug("Reading settings from $file.");
        while ($line = <CONF>) {
            next if ($line =~ m/^\s*\#/);
            next if ($line =~ m/^\s*$/);
            chomp($line);
            ($tag, $value) = split(/=/, $line, 2);
            $tag = lc($tag);
            $tag =~ s/\s*//g;
            $value =~ s/^\s*//;
            $value =~ s/\s*$//;
            if ($tag eq "title") {
                $conf{"title"} = $value;
            } elsif ($tag eq "rows") {
                $conf{"rows"} = $value;
            } elsif ($tag eq "cols") {
                $conf{"cols"} = $value;
            } elsif ($tag eq "indir") {
                $conf{"indir"} = $value;
            } elsif ($tag eq "outdir") {
                $conf{"outdir"} = $value;
            } elsif ($tag eq "imagere") {
                $conf{"imagere"} = $value;
            } elsif ($tag eq "makethumbs") {
                $conf{"makethumbs"} = $value;
            } elsif ($tag eq "inplace") {
                $conf{"inplace"} = $value;
            } elsif ($tag eq "thumbsize") {
                $conf{"thumbsize"} = $value;
            } elsif ($tag eq "footer") {
                $conf{"footer"} = $value;
            } elsif ($tag eq "header") {
                $conf{"header"} = $value;
            } elsif ($tag eq "order") {
                $conf{"order"} = $value;
            } elsif ($tag eq "convert") {
                $conf{"convert"} = $value;
            } elsif ($tag eq "htmlhead") {
                $conf{"htmlhead"} = $value;
            } elsif ($tag eq "htmlfoot") {
                $conf{"htmlfoot"} = $value;
            } elsif ($tag eq "descfile") {
                $conf{"descfile"} = $value;
            } elsif ($tag eq "desc") {
                $conf{"desc"} = $value;
            } elsif ($tag eq "index") {
                $conf{"index"} = $value;
            } elsif ($tag eq "filenameprefix") {
                $conf{"filenameprefix"} = $value;
            } elsif ($tag eq "debug") {
                $conf{"debug"} = $value;
            } else {
                print "Unknown setting '$tag' in $file.\n";
            }
        }
        close(CONF);
    }
    return %conf;
}

sub create_navigator {
    my ($pages, $i);

    $pages = int($#main::pic_numbers/$main::pics_per_page)+1;
    return if ($pages == 1);

    print INDEX "<tr>\n  <td colspan=$main::opt{'cols'}>\n";
    print INDEX "<center>";
    foreach $i (1..$pages) {
	if ($i != $main::file_number) {
	    print INDEX "<a href=\"" . &make_file_name($i) . "\">";
	}
	print INDEX "$i";
	if ($i != $main::file_number) {
	    print INDEX "</a>";
	}
	if ($i != $pages) {
	    print INDEX " - ";
	}
    }
    print INDEX "</center>\n";
    print INDEX "  </td>\n</tr>\n";
}


sub print_page_header {
    print INDEX "<!-- Generated with indexpage by Hans Persson.\n" .
        "     http://www.lysator.liu.se/~unicorn/hacks/indexpage/ -->\n";
    print INDEX "$main::opt{'htmlhead'}\n";
    print INDEX "$main::opt{'header'}\n";
    print INDEX "<table>\n";
    &create_navigator;
}


sub print_page_footer {
    &create_navigator;
    print INDEX "</table>\n";
    print INDEX "$main::opt{'footer'}\n";
    print INDEX "$main::opt{'htmlfoot'}\n";
}


sub read_descriptions {
    my ($hasdesc, %desc, $line, $nr, $desc);

    # Read image labels from the descriptions file if there is one.
    if (open(DESC, "$main::opt{'descfile'}")) {
        $hasdesc = 1;
        while ($line = <DESC>) {
            chomp($line);
            ($nr, $desc) = split(/\s/, $line, 2);
            $desc =~ s/^\s*//;
            $desc{$nr} = $desc;
        }
        close(DESC);
    } else {
        $hasdesc = 0;
        open(DESC, ">$main::opt{'descfile'}") ||
            die("Couldn't create $main::opt{'descfile'}: $!");
    }
    return $hasdesc, %desc;
}


sub make_file_name {
    my ($number) = @_;
    my ($filename);

    if ($main::opt{'index'} && ($number eq "1")) {
        $filename = "index.html";
    } else {
        $filename = "$main::opt{'filenameprefix'}$number.html";
    }
}
