#!/perl -w
# NAME: genimgindex.pl (see earlier simpe imgindex.pl)
# AIM: Given a BASE folder, seek all IMAGE files, and build
# an 'index' table of images, as HTML ...
# Commands: in-folder [-out out-file]
# 27/09/2007 - some features
# $add_dir and $add_siz to ADD a directory and size columns
# and using ImageMagick identify (if installed) to get image dimensions
# 15/03/2008 - add mutiple columns, especially if image constrained to small thumbnail size
#
use strict;
use warnings;
use File::Basename;
use File::stat;
use Cwd;
require 'logfile.pl' or die "Unable to load logfile.pl ...\n";
require 'relative.pl' or die "Unable to load relative.pl ...\n";
# log file stuff
my ($LF);
my $pgmname = $0;
if ($pgmname =~ /\w{1}:\\.*/) {
    my @tmpsp = split(/\\/,$pgmname);
    $pgmname = $tmpsp[-1];
}
my $outfile = "temp.$pgmname.txt";
open_log($outfile);
###prt( "$0 ... Hello, World ...\n" );

my $def_out = 'C:\Documents and Settings\Geoff McLane\My Documents\My Pictures\Nikon\20080715'; 
my $def_in = $def_out.'\normal';
my $def_alt = '';
##my $def_out = 'C:\HOMEPAGE\GA\travel\maroc\jetphoto'; 
##my $def_in = $def_out.'\128x128';
##my $def_alt = '../pics';

#my $def_out = 'C:\Documents and Settings\Geoff McLane\My Documents\My Pictures\Nikon\20080517\temp'; 
##my $def_in = $def_out;
##my $def_out = 'C:\Documents and Settings\Geoff McLane\My Documents\Sue'; 
##my $def_in = $def_out. '\images';
##my $def_in = 'C:\Documents and Settings\Geoff McLane\My Documents\Sue\pics01';
##my $def_in = 'C:\Documents and Settings\Geoff McLane\My Documents\My Pictures\Scans2007';
###my $def_in = 'C:\Documents and Settings\Geoff McLane\My Documents\MISC\HKFlat\img4';
##my $def_in = "G:\\HOMEPAGE\\Max5\\1lynesite";

my $out_file = $def_out .'\tempout.htm';
my $cwdir = getcwd();

# FEATURES
my $one_cell = 1;	# put ALL information in one cell
my $add_name = 1;	# add FILENAME column
my $add_dir = 0;	# add DIRECTORY column
my $add_siz = 0;	# add FILE SIZE column
my $add_isz = 1;	# add IMAGE SIZE column
# ### TARGET WIDTH/HEIGHT maximum ###
my $set_max = 1;	# constrain image size to $targwid img_max
my $targwid = 300;	# maximum display size
#my $targwid = 200;	# maximum display size
#my $targwid = 800;	# maximum display size

# ### ADD CLICK LINK ###
my $add_lnk = 1;	# add LINK to image
my $add_alt_link = 0; # add link to another folder
my $alt_src_link = '';
# ######################

# NUMBER OF COLUMNS - This is really only if $one_cell used
##my $add_cols = 1;	# number of COLUMNS in output
##my $add_cols = 3;	# number of COLUMNS in output
my $add_cols = 2;	# number of COLUMNS in output
#################################################

my $add_blank = 1;	# open LINK in NEW PAGE - $add_link must be ON above
my $recursive = 0;	# recursive into sub-folders
my $fix_relat = 1;	# images relative to $def_out
my $load_html = 1;	# load written HTML

### program constants
my @imgfiles = qw( .jpg .jpeg .gif .png );
my @fpfolders = qw( _vti_cnf _vti_cnf _private _derived );
# debug stuff
my $dbg1 = 1;	# use default in folder, so can be RUN without command line
my $dbg2 = 0;	# use full file name, else relative, to SEE images
my $dbg3 = 0;	# show image size stuff
my $tdbg_rel = 0;

### program variables
my @imglist = ();
my $in_folder = '';
my $full_html = ''; # string that is the HTML file

my $html_bgn = <<"EOF";
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
 <head>
  <meta http-equiv="Content-Language"
        content="en-gb">
  <meta http-equiv="Content-Type"
        content="text/html; charset=us-ascii">
  <meta name="generator"
        content="genindex3.pl">
  <title>
   Image Index
  </title>
  <style type="text/css">
<!-- /* some style 2007.05.24 */
  body {
   margin:0cm 1cm;
   background-image:url('clds3.jpg');
  }
  h1{
        background:#efefef;
        border-style:solid;
        border-color:#d9e2e2;
        border-width:1px;
        padding-top:2px;
        padding-bottom:2px;
        padding-left:2px;
        padding-right:2px;
        font-size:200%;
        text-align:center;
  }
  h2 { font-size: 12pt; font-weight: bold; background-color: #CCCCFF }
  .ctr { text-align:center; }
  -->
  </style>
 </head>
 <body>
  <h1>
   Image Index
  </h1>

  <p class="ctr">
   <a href="../home2.htm">home</a>
  </p>

  <div align="center">
   <center>
    <table border="2"
           cellpadding="2"
           id="Num1"
           summary="Table of Images">
EOF

my $html_end_table = <<"EOF";
    </table>
   </center>
  </div>
EOF

my $html_link = <<"EOF";

  <p class="ctr">
   <a href="../home2.htm">home</a>
  </p>
EOF

my $html_end = <<"EOF";
 </body>
</html>
EOF

parse_args(@ARGV);

collect_image_files( $in_folder );
my $cnt = scalar @imglist;
prt( "Found $cnt image files ...\n" );

write_html_file( $out_file );
system $out_file if ($load_html);
close_log($outfile,1);
exit(0);

#################################################################
### subs below

sub write_html_file {
	my ($of) = shift;

	my $wrap = 0;
	my $targ = '';
	my $irel = '';
	$targ = "\n           target=\"_blank\"" if ($add_blank);

	$full_html = $html_bgn;

	$full_html .= "     <tr>\n";
	$wrap = 0;
	while ($wrap < $add_cols) {
		$wrap++;
		$full_html .= "      <th>\n       Name\n      </th>\n" if ($add_name && !$one_cell);
		$full_html .= "      <th>\n       Directory\n      </th>\n" if ($add_dir && !$one_cell);
		$full_html .= "      <th>\n       Image\n      </th>\n";
		$full_html .= "      <th>\n       Size\n      </th>\n" if ($add_isz && !$one_cell);
		$full_html .= "      <th>\n       Bytes\n      </th>\n" if ($add_siz && !$one_cell);
	}
	$full_html .= "     </tr>\n";

	#if ($def_in eq $def_out) {
	#	$irel = '';
	#} else {
		$irel = get_relative_path_test( $def_in, $def_out );
	#}
	prt( "Using relative path of [$irel] ...\n" );
	#foreach my $fil (@imglist)
	$wrap = 0;	# restart WRAP
	for (my $i = 0; $i < $cnt; $i++) {
		###last if ($i > 1);
		my $i2 = $i + 1;
		my $fil = $imglist[$i];
		my $sf = substr( $fil, length($in_folder) + 1 );
		my ($nm, $dir, $ext) = fileparse( $sf, qr/\.[^.]*/ );
		my $sb = stat($fil);
		my $isz = '';
		my $ratio = 1;
		my $iwd = 1;
		my $iht = 1;
		my $attr = '';
		my $const = '';
		my ($imgSx, $imgSy);
		my $src = $sf;
		my $relsrc = $irel.$sf;
		my $relpath = get_relative_path( $cwdir, $dir );
		my $outsrc = $src;
		$outsrc = $relsrc if ($fix_relat);
		my $imgsrc = $outsrc;
		if ($add_alt_link && length($alt_src_link)) {
			$outsrc = $alt_src_link . '/' . $src;
		}
		#$src = dos_2_unix($fil) if ($dbg2);
		$src = path_2_html($fil) if ($dbg2);
		if ($add_isz || $set_max) {
			$isz = get_image_size($fil);
			if ($set_max) {
				$iwd = get_image_width($isz);
				$iht = get_image_height($isz);
				$ratio = $iwd / $iht;
				if (($iwd > $targwid) || ($iht > $targwid)) {
					if($ratio > 1) {
						$imgSx = $targwid;
						$imgSy = int($targwid / $ratio);
					} else {
						$imgSx = int($targwid * $ratio);
						$imgSy = $targwid;
					}
					$attr =  "            width=\"$imgSx\"\n";
                    $attr .= "            height=\"$imgSy\"";
					$const = "".$imgSx."x".$imgSy;
				}
			}
		}
		$dir = "." if (length($dir) == 0);

		$full_html .= "\n     <tr>\n" if ($wrap == 0);
		if ($add_name && !$one_cell) {
			$full_html .= "<td align=\"left\" valign=\"top\">\n";
			$full_html .= $sf;
			$full_html .= "\n</td>\n";
		}

		if ($add_dir && !$one_cell) {
			$full_html .= "<td align=\"left\" valign=\"top\">\n";
			##$full_html .= dos_2_unix($dir);
			$full_html .= $relpath;
			$full_html .= "\n</td>\n";
		}

		# main IMAGE cell
		$full_html .= "      <td>\n";
		$full_html .= "       <a href=\"$outsrc\"$targ>" if ($add_lnk);
		$full_html .= "<img src=\"";
		$full_html .= $imgsrc;
		$full_html .= "\"\n";
        $full_html .= "$attr\n" if length($attr);
        $full_html .= "            alt=\"image index file $i2\">";
		$full_html .= "</a>\n" if ($add_lnk);
		if ($one_cell) {
			$full_html .= "       <br>\n       rp: $relpath\n" if ($add_dir && length($relpath));
			$full_html .= "       <br>\n       fn: $sf\n" if ($add_name && length($sf));
			$full_html .= "       <br>\n       is: $isz\n" if ($add_isz && length($isz));
			$full_html .= "       <br>\n       ct: $const\n" if ($add_isz && length($const));
			$full_html .= "       <br>\n       fs: ".get_nn($sb->size)."\n" if ($add_siz);
		}
		$full_html .= "      </td>\n";

		if ($add_isz  && !$one_cell && length($isz)) {
			$full_html .= "<td align=\"left\" valign=\"top\">\n";
			$full_html .= $isz;
			$full_html .= $const if length($const);
			$full_html .= "\n</td>\n";
		}
		if ($add_siz && !$one_cell) {
			$full_html .= "<td align=\"right\" valign=\"top\">\n";
			$full_html .= get_nn($sb->size);
			$full_html .= "\n</td>\n";
		}

		$wrap++;
		if ($wrap == $add_cols) {
			$full_html .= "     </tr>\n";
			$wrap = 0;
		}

		prt( "$sf ($irel) [$src]...\n" );
	}
	# finish off the row, if required
	if ($wrap) {
		while ($wrap < $add_cols) {
			$full_html .= "      <td>\n&nbsp;/n      </td>\n" if ($add_name && !$one_cell);
			$full_html .= "      <td>\n&nbsp;/n      </td>\n" if ($add_dir && !$one_cell);
			$full_html .= "      <td>\n       no image\n      </td>\n";
			$full_html .= "      <td>\n&nbsp;\n      </td>\n" if ($add_isz && !$one_cell);
			$full_html .= "      <td>\n&nbsp;\n      </td>\n" if ($add_siz && !$one_cell);
			$wrap++;
		}
		$full_html .= "     </tr>\n";
	}

    $full_html .= $html_end_table;
    $full_html .= $html_link;
    $full_html .= "  <!-- Generated by $pgmname on ".scalar localtime(time())." -->\n";
    $full_html .= $html_end;
    prt( "======================================================================\n" );
    prt( "$full_html\n" );
    prt( "======================================================================\n" );

    # dump it to FILE
	if (open OUTF, ">$of") {
        print OUTF $full_html;
        close OUTF;
    	prt( "Written HTML to $of ...\n" );
    } else {
    	prt( "ERROR: FAILED TO WRITE $of !!!\n" );
    }
}


sub parse_args {
	my (@av) = @_;
	while (@av) {
		my $arg = $av[0];
		if (substr($arg,0,1) eq "-") {
			if ($arg eq '-out') {
				shift @av;
				if (@av) {
					$out_file = $av[0];
					prt( "Set out file to [$out_file] ...\n" );
				} else {
					mydie( "ERROR: -out MUST have a following file name ...\n" );
				}
			}
		} else {
			if (length($in_folder)) {
				mydie( "ERROR: Already have IN-FOLDER [$in_folder]! What is this? [$arg]?\n" );
			}
			$in_folder = $arg;
			prt( "Set in folder to [$in_folder] ...\n" );
		}
		shift @av;
	}
	if ( (length($alt_src_link) == 0) && $dbg1 && length($def_alt) ) { # like = '../pics';
		$alt_src_link = $def_alt;
		prt( "Set in alternate source to [$alt_src_link], the debug default ...\n" );
	}
	if (length($in_folder) == 0) {
		if ($dbg1) {
			$in_folder = $def_in;
			prt( "Set in folder to [$in_folder], the debug default ...\n" );
		} else {
			mydie( "ERROR: No input folder found ...\n" );
		}
	}

}

sub my_in_file {
	my ($fil) = shift;
	my ($nm, $dir, $ext) = fileparse( $fil, qr/\.[^.]*/ );
	foreach my $e (@imgfiles) {
		if (lc($e) eq lc($ext)) {
			return 1;
		}
	}
	return 0;
}

sub is_fp_folder {
	my ($fil) = shift;
	foreach my $fp (@fpfolders) {
		if (lc($fp) eq lc($fil)) {
			return 1;
		}
	}
	return 0;
}


sub collect_image_files {
	my $inf = shift;
	prt( "Processing $inf folder ...\n" );
	if ( opendir( DIR, $inf ) ) {
		my @files = readdir(DIR);
		closedir DIR;
		foreach my $fl (@files) {
			if (($fl eq '.') || ($fl eq '..') ||
				 is_fp_folder($fl) ) {
				next;
			}
			my $ff = $inf . "\\" . $fl;
			if (-d $ff) {
				collect_image_files($ff) if ($recursive);
			} else {
				if (my_in_file($fl)) {
					push(@imglist, $ff);
				}
			}
		}
	} else {
		prt( "WARNING: Can NOT open $inf ... $! ...\n" );
	}
}

sub get_nn { # perl nice number nicenum add commas
	my ($n) = shift;
	if (length($n) > 3) {
		my $mod = length($n) % 3;
		my $ret = (($mod > 0) ? substr( $n, 0, $mod ) : '');
		my $mx = int( length($n) / 3 );
		for (my $i = 0; $i < $mx; $i++ ) {
			if (($mod == 0) && ($i == 0)) {
				$ret .= substr( $n, ($mod+(3*$i)), 3 );
			} else {
				$ret .= ',' . substr( $n, ($mod+(3*$i)), 3 );
			}
		}
		return $ret;
	}
	return $n;
}

sub dos_2_unix {
	my ($du) = shift;
	$du =~ s/\\/\//g;
	return $du;
}

sub path_2_html {
	my ($pth) = shift;
	$pth = dos_2_unix($pth);
	###$pth =~ s/ /%20/g;
	return $pth;
}

sub get_image_width {
	my ($is) = shift;
	my $wid = 0;
	my @arr = split(/x/,$is);
	if (scalar @arr == 2) {
		$wid = $arr[0];
	}
	return $wid;
}

sub get_image_height {
	my ($is) = shift;
	my $hgt = 0;
	my @arr = split(/x/,$is);
	if (scalar @arr == 2) {
		$hgt = $arr[1];
	}
	return $hgt;
}

sub get_image_size {
	my ($if) = shift;
	my $is = '';
	if (open (IDT, "identify \"$if\"|")) {
		my @arr2 = <IDT>;
		close IDT;
		foreach my $ln (@arr2) {
			chomp $ln;
			prt( "[$ln]\n" ) if ($dbg3);
			if (substr($ln,0,length($if)) eq $if) {
				my $ln2 = substr($ln,length($if));
				$ln2 =~ s/^\s//;
				prt( "$ln2\n" ) if ($dbg3);
				if ($ln2 =~ /\s(\d+x\d+)\s/) {
					$is = $1;
				}
			}
		}
	} else {
		prt( "ERROR: I can't open [$if], or 'identify.exe' not in path ...\n" );
	}
	return $is;
}

sub get_relative_path_test {
	my ($target, $fromdir) = @_;
	my ($colonpos, $path, $posval, $diffpos);
    ##my ($from, $to);
	my ($tlen, $flen);
    my ($tolen, $fromlen);
    my ($cht, $chf);
	my $retrel = "";
	# only work with slash - convert DOS backslash to slash
	$target = path_d2u($target);
	$fromdir = path_d2u($fromdir);
	# add '/' to target. if missing
	if (substr($target, length($target)-1, 1) ne '/') {
		$target .= '/';
	}
	# add '/' to fromdir. if missing
	if (substr($fromdir, length($fromdir)-1, 1) ne '/') {
		$fromdir .= '/';
	}

	# remove drives, if present
    if ( ( $colonpos = index( $target, ":" ) ) != -1 ) {
		$target = substr( $target, $colonpos+1 );
	}
	if ( ( $colonpos = index( $fromdir, ":" ) ) != -1 ) {
        $fromdir = substr( $fromdir, $colonpos+1 );
    }
	# got the TO and FROM ...
	#$to = $target;
	#$from = $fromdir;
    $tolen = length($target);
    $fromlen = length($fromdir);
	prt( "To   [$target]($tolen),\nfrom [$fromdir]($fromlen) ...\n" ) if ($tdbg_rel);
	$path = '';
	$posval = 0;
	$retrel = '';
	# // Step through the paths until a difference is found (ignore slash differences)
	# // or until the end of one is found
	# while ( substr($from,$posval,1) && substr($to,$posval,1) ) {
	while ( ($posval < $tolen) && ($posval < $fromlen) ) {
        $chf = substr($fromdir,$posval,1);
        $cht = substr($target,$posval,1);
		if ( $chf eq $cht ) {
			$posval++; # bump to next
		} else {
            prt( "First diff [$chf] ne [$cht] ...\n" ) if ($tdbg_rel);
			last; # break;
		}
	}
	##if ( !substr($from,$posval,1) ) {
	if ( $posval >= $fromlen ) {
        prt( "Ran out of from ...\n" ) if ($tdbg_rel);
    }
    ##if ( !substr($to,$posval,1) ) {
    if ( $posval >= $tolen ) {
        prt( "Ran out of to ...\n" ) if ($tdbg_rel);
    }

	# // Save the position of the first difference
	$diffpos = $posval;
    prt( "First diff found at offset $posval ... ".substr($target,$posval)." ...\n" ) if ($tdbg_rel);

	# // Check if the directories are the same or
	# // the if target is in a subdirectory of the fromdir
	if ( ( !substr($fromdir,$posval,1) ) &&
		 ( substr($target,$posval,1) eq "/" || !substr($target,$posval,1) ) )
	{
		# // Build relative path
		$diffpos = length($target);
		if (($posval + 1) < $diffpos) {
			$diffpos-- if ($diffpos);
			if ($diffpos > $posval) {
				$diffpos -= $posval;
			} else {
				$diffpos = 0;
			}
			###$retrel = substr( $target, $posval+1, length( $target ) );
			prt( "Return substr of target, from ".($posval+1).", for $diffpos length ...\n" ) if ($tdbg_rel);
			###$retrel = substr( $target, $posval+1, $diffpos );
			$retrel = substr( $target, ($posval+1) );
		} else {
			prt( "posval+1 (".($posval+1).") greater than length $diffpos ...\n" ) if ($tdbg_rel);
		}
	} else {
		# // find out how many "../"'s are necessary
		# // Step through the fromdir path, checking for slashes
		# // each slash encountered requires a "../"
		#$posval++;
		while ( substr($fromdir,$posval,1) ) {
			prt( "Check for slash ... $posval in $fromdir\n" ) if ($tdbg_rel);
			if ( substr($fromdir,$posval,1) eq "/" ) { # || ( substr($fromdir,$posval,1) eq "\\" ) ) {
				prt( "Found a slash, add a '../' \n" ) if ($tdbg_rel);
				$path .= "../";
			}
			$posval++;
		}
		prt( "Backed relative path = [$path] ...\n" ) if ($tdbg_rel);

		# // Search backwards to find where the first common directory
		# // as some letters in the first different directory names
		# // may have been the same
		$diffpos--;
		while ( ( substr($target,$diffpos,1) ne "/" ) && substr($target,$diffpos,1) ) {
			$diffpos--;
		}
		# // Build relative path to return
		$retrel = $path . substr( $target, $diffpos+1, length( $target ) );
    }
	prt( "Returning [$retrel] ...\n" ) if ($tdbg_rel);
	return $retrel;
}

# eof - genimgindex.pl
