#!/usr/bin/perl
#
# Peukku v1.2  Copyright (c) 2002-2005 by Kai Vorma
# 
#
# This script generates a index page and the corresponding
# thumbnails 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://vode.iki.fi/photos/index.html
#
# Kai Vorma <Kai.Vorma@iki.fi>
#
#
# The script expects/creates the following directory tree
#
#  pictures/index.html		- [created] main html page
#           images.desc		- [created] list of pictures and
#                                 optional [user created] comments
#           DESC		- [optional] HTML code prepended
#                                 before thumbnails
#           TITLE               - [optional] title for HTML page
#           thumbnails/         - [created] directory for thumbnails
#           images/             - [mandatory] original full size images
#           reduced/		- [optional] reduced size images
#
#
# Configuration file (options / ~/.peukalo) options (perl syntax):
#
# $COLS=4;
# $ROWS=10;
# $THUMB_W=120;
# $SMALL_W=800
# $FOOTER="foobarzap";
# $HEADER="xyzzy";
# $BACK_LINK="http..";
#
#
# Command line options
#
# -v   verbose
# -d   debug
#

#use strict;
use Getopt::Std;
use Image::Size 'imgsize';

$| = 1;

# Globals

$COLS = 3;
$ROWS = 5;
$THUMB_W = 100;
$SMALL_W = 640;
$BACK_LINK = undef;
$FOOTER = undef;
$HEADER = undef;

# Get command line options


getopts('dv');

# Get configuration file options

$cfile="$ENV{'HOME'}/.peukalo";
if ( -s $cfile) {
  &debug("Reading $cfile..");
  do $cfile;
}

$cfile="options";
if ( -s $cfile) {
  &debug("Reading $cfile..");
  do $cfile;
}

&debug("columns = $COLS");
&debug("rows = $ROWS");
&debug("thumb size = $THUMB_W");
&debug("small pic size = $SMALL_W");


# Read title and description files

$TITLE = &get_desc_file("TITLE");
$DESC = &get_desc_file("DESC");

&debug("title = $TITLE");
&debug("description = $DESC");


# Scan directories containing images

&verb("Scanning for images..\n");
$THUMBS = &get_pics("thumbs", 0);
$SMALLS = &get_pics("reduced", 0);
$IMAGES = &get_pics("images", 1);

# Create / update small images and thumbnails

if ( !defined $THUMBS) {
  mkdir("thumbs") || die "Cannot create dir thumbs: $!\n";
}
&update_images($IMAGES, $THUMBS, "images", "thumbs", $THUMB_W);
&update_images($IMAGES, $SMALLS, "images", "reduced", $SMALL_W) if defined $SMALLS;

# Update image map

&update_image_desc($IMAGES, "images.desc");

#

if ($opt_d) {
  &debug("Images:");
  &dump($IMAGES) if defined $IMAGES;
  &debug("Smalls:");
  &dump($SMALLS) if defined $SMALLS;
  &debug("Thumbs:");
  &dump($THUMBS) if defined $THUMBS;
}

# Create index.html

&make_index_html($IMAGES);

exit 0;


# Subroutines

sub debug {
  print(STDERR "@_\n") if defined $opt_d;
}

sub verb {
  print(STDOUT "@_") if defined $opt_v;
}

sub get_desc_file {
  my $fn = $_[0];
  my($ln, $txt);

  if (open FN, $fn) {
    while (<FN>) {
      chomp;
      $txt .= &html($_) . " ";
    }
    close FN
  }
  return $txt;
}

# Replace some skandinavian characters with HTML code

sub html {
  my $txt = $_[0];

  $txt =~ s/ä/&auml;/g;
  $txt =~ s/ö/&ouml;/g;
  $txt =~ s/Ä/&Auml;/g;
  $txt =~ s/Ö/&Ouml;/g;
  $txt =~ s/å/&aring;/g;
  $txt =~ s/Å/&Aring;/g;

  return $txt;
}

# Scan directory for pictures. Return hash that contains image name
# as key and [mtime, size, width, height, description] as value.

sub get_pics {
  my($dir, $get_size) = @_;
  my(@pics, @st, $pic, %p, $w, $h);

  chdir($dir) || return undef;
  @pics = <*.jpg *.jpeg *.JPG *.JPEG>;
  for $pic (@pics) {
    if (@st = stat $pic) {
      if ($get_size) {
	($w, $h) = imgsize($pic);
	$p{$pic} = [$st[9], $st[7], $w, $h, ""];
      } else {
	$p{$pic} = [$st[9], $st[7]];
      }
    }
  }
  chdir("..");
  return \%p;
}



sub dump {
  my $hash = $_[0];
  my ($key);

  for $key (sort keys %$hash) {
    printf STDERR "  %s:%s:%s:%s:%s:%s\n", $key, @{$hash->{$key}}
  }
}

# Update thumbs or small picture directory

sub update_images {
  my($orig, $dst, $sdir, $ddir, $width) = @_;
  my($file, $nw, $nh, $ow, $oh);

  &verb("Updating images in $ddir: ");
  for $file (sort keys %$orig) {
    if (!defined $dst->{$file} || $orig->{$file}[0] > $dst->{$file}[0]) {
      &verb("$file ");
      $ow = $orig->{$file}[2];
      $oh = $orig->{$file}[3];
      ($nw, $nh) = &pic_size($width, $ow, $oh);
      &debug("\n$file: ${ow}x${oh} -> ${nw}x${nh}");
      system("/opt/local/bin/convert -geometry ${nw}x${nh} $sdir/$file $ddir/$file");
    }
  }
  &verb("Done.\n");
}

# Calculate thumb/small picture size

sub pic_size {
  my($width, $ow, $oh) = @_;
  my($nw, $nh);

  if ($ow > $oh) {
    $nw = $width;
    $nh = int($oh * $width / $ow);
  } else {
    $nh = $width;
    $nw = int($ow * $width / $oh);
  }
  return $nw,$nh;
}


# Read and update images.map file  (descriptions for pictures)

sub update_image_desc {
  my($images, $fn) = @_;
  my($pic, $desc);

  &verb("Reading & updating $fn..\n");
  if (open DESC, $fn) {
    while (<DESC>) {
      chomp;
      ($pic,$desc) = split(/:/);
      if ($desc && defined $images->{$pic}) {
	$images->{$pic}[4] = &html($desc);
      }
    }
    close DESC;
  }

  if (open DESC, ">$fn") {
    for $pic (sort keys %$images) {
      printf(DESC "%s:%s\n", $pic, $images->{$pic}[4]);
    }
    close DESC;
  } else {
    printf(STDERR "WARNING: cannot create $fn: $!\n");
  }
}


# Create index.html

sub make_index_html {
  my $images = $_[0];
  my $DW = $THUMB_W * $COLS;

  &verb("Creating index.html..\n");

  open(HTML, ">index.html") || die "Cannot open index.html: $!\n";
  printf HTML <<EOF;
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
   <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
   <meta name="Author" content="Kai Vorma">
   <meta name="GENERATOR" content="peukalo by Kai Vorma">
   <title>$TITLE</title>
</head>
<body bgcolor="#cccccc">
<center>
<h1>$TITLE</h1>
<hr width="15%">
<p>
<table>
<tr>
<td width=$DW align=left>
$DESC
</td>
</tr>
</table>
<hr width="15%">
<p>
$HEADER
</p>
<table>
EOF

  &make_table($images);

  printf HTML <<EOF2;
</table>
<hr width="15%">
<p>
$FOOTER
<p>
<A HREF=${BACK_LINK}>Back to Previous Page</A>
</p>
<p>
  <a href="http://validator.w3.org/check/referer"><img border="0"
     src="/bm/valid-html401"
     alt="Valid HTML 4.01!" height="31" width="88"></a>
</p>
</center>
</body>
</html>
EOF2

}

sub make_table {
  my $images = $_[0];
  my($pic, $desc, $size, $w, $h, $tw, $th, $table_w, $dir);
  my(@pics, $current);
  my $col = 0;

  if (defined $SMALLS) {
    $dir="reduced";
  } else {
    $dir="images";
  }
  
  for $pic (sort keys %$images) {
    ($size, $w, $h, $desc) = @{$images->{$pic}}[1..4];
    $size = int($size / 1024);
    ($tw, $th) = &pic_size($THUMB_W, $w, $h);
    $table_w = $tw + 30;

    push(@pics, [$table_w, $pic, $tw, $th, $w, $h, $size, $desc, $dir]);
    if (++$col >= $COLS) {
	picture_row(@pics);
	$col = 0; 
	@pics = ();
    }
  }
  if (@pics) {
      picture_row(@pics);
  }
}

sub picture_row {
    my (@pics) = @_;
    my($pic, $desc, $size, $w, $h, $tw, $th, $table_w, $dir);

    print HTML "<tr align=center>\n";
    foreach $current (@pics) {
	($table_w, $pic, $tw, $th, $w, $h, $size, $desc, $dir) = @$current;
	print HTML qq|<td valign=bottom width=$table_w> <a href="$dir/$pic"> <img src="thumbs/$pic" width="$tw" height="$th" alt="$pic"> </a> </td>\n|;
    }
    print HTML "</tr>\n<tr align=center>\n";
    foreach $current (@pics) {
	($table_w, $pic, $tw, $th, $w, $h, $size, $desc, $dir) = @$current;
	print HTML qq|<td valign=top width=$table_w> $pic </td>\n|;
    }
    print HTML "</tr>\n<tr align=center>\n";
    foreach $current (@pics) {
	($table_w, $pic, $tw, $th, $w, $h, $size, $desc, $dir) = @$current;
	print HTML qq|<td valign=top width=$table_w> <a href="images/$pic"> ${w}x${h} ${size}KB </a> </td>\n|;
    }
    print HTML "</tr>\n<tr align=center>\n";
    foreach $current (@pics) {
	($table_w, $pic, $tw, $th, $w, $h, $size, $desc, $dir) = @$current;
	print HTML qq|<td valign=top width=$table_w> $desc</td>\n|;
    }
    print HTML "</tr>\n";
}

sub make_table_old {
  my $images = $_[0];
  my($pic, $desc, $size, $w, $h, $tw, $th, $ws, $table_w, $dir);
  my $col = 1;

  if (defined $SMALLS) {
    $dir="reduced";
  } else {
    $dir="images";
  }
  
  for $pic (sort keys %$images) {
    ($size, $w, $h, $desc) = @{$images->{$pic}}[1..4];
    $size = int($size / 1024);
    ($tw, $th) = &pic_size($THUMB_W, $w, $h);
    $table_w = $tw + 30;
    $ws = $THUMB_W - $th;
    if ($col == 1) {
      print HTML "<tr align=center>\n";
    }

    print HTML <<EOF3;
  <td valign=top width=$table_w>
    <a href="$dir/$pic"><img src="thumbs/$pic" width="$tw" height="$th" alt="$pic"></a>
     <br>$pic
     <br><a href="images/$pic">${w}x${h} ${size}KB</a>
     <br>$desc
  </td>
EOF3

    if (++$col > $COLS) {
      print HTML "</tr>\n";
      $col = 1;
    }
  }   
   if ($col != 1) {
    print HTML "</tr>\n";
  }
}
