#!/usr/local/bin/perl 
##############################################################################
$VERSION='GTindex v1.2'; # 2 April 1997 Dale Bewley <dale@bewley.net>
#$VERSION='GTindex v1.121'; # 18 Oct. 1996 Dale Bewley <dale@bewley.net>
#VERSION='GTindex v1.12'; # 03 Oct. 1996 Dale Bewley  <dale@bewley.net>
#v1.11b1 08-16-96, v1.10 08-12-96, v1.09 07-25-96, v1.05 06-23-96
#-----------------------------------------------------------------------------
# This script was written for a specific site and may be less than portable.
# Others like it found at http://www.bewley.net/perl/
#
# Note: the web documentation is a little out of date. I'm working on pulling
#	it all into some POD at the bottom of this file.
#
# New in 1.2:
#   o -b and -l now take "none" as an option to not print bullets or lines.
#   o width and height tags added to thumbnail pages. this needs to be using
#	Image::Size instead of the subs below. I imagine most people may
#	not have that installed though.
# New in 1.12:
#   o last index has a next link at the bottom. now that points to the first
#	  index instead of a non existant one.
#
# Notes:
#	o this script requires perl5 (barely) and has been testing in win95 
#	  and UNIX
#	o to run it in win95 type: 
#	  "c:\pro\perl5\bin\perl c:\pro\perl5\scripts\gtindex.pl -v *.jpg" 
#	  or something like that.
#	o Thumbnails should be in a subdir of the dir containing your pics.
#	  They must have the SAME NAME as their full sized versions!!
#	o Say you have a dir called gfx filled full of graphics and you are in
#	  win95. Create a subdir called gfx\thumbs and copy all the graphics
#	  into there. Now get thumbsplus and convert all the graphics in 
#	  thumbs into thumbnails overwriting them with the same name. Set 
#	  $THUMB_DIR to "thumbs" and finally, cd to your gfx dir and run me.
#	o This thing is a little messy. I'll clean it up as I find time. 
#	  If you see obvious room for improvment drop me a line.
#	o This version has some new command line switches.
#
#
# Copyright (C) 1995, 1996, 1997 Dale Bewley <dale@bewley.net>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
##############################################################################


#- User Configurable Variables ----------------------------------------------#
$ALINK   = "#EE0033"; # active link color
$BGCOLOR = "#000000"; # index background color
$LINK    = "#00FF00"; # link color
$TEXT    = "#FFFFFF"; # index normal text color
$VLINK   = "#FF1CAE"; # visited link color

$BULLET  = "../bullet.gif"; # image URL or blank, "", if none.
$LINE    = "../line.gif"; # grphical HR

$MAX_ON_PAGE = 9; # maximum images on a page
$MAX_ROWS = 3; 	# maximum number of images down a column 
		# this means number of columns on page is 
		# ($MAX_ON_PAGE / $MAX_ROWS)

$SITE_NAME = "Dale's Images - "; # printed in title. prefixes $TITLE
$HOME_URL  = "http://www.bewley.net/perl/"; # home link on indexes
$THUMB_DIR = "thumbs"; # directory containing optional thumbnails of images
		   # it is assumed this will be within the current directory

$TITLE = "GTindex"; # default title and header on each index page. 
#----------------------------------------------------------------------------#


#- Help! --------------------------------------------------------------------#
sub help {
	print <<"END_OF_HELP";

$VERSION Dale Bewley <dale\@bewley.net>
    http://www.bewley.net/perl/

Description: 
    This script will create an HTML index of all the graphics specified on
    the command line. And create parallel indexes with thumbnails if you 
    have them.

Usage:
    $0 [<options>] <filespec>

Options (Defaults inside [] below):
    -b    Bullet graphic. To appear to the left of image titles. [$BULLET] 
	   "none" to do away with bullets.
    -d    Destructive. Overwrite old indexes with new ones. 
    -f    Baseref. URL to prepend all IMG SRC's. [$BASEREF]
    -h    This message.
    -l    Line graphic. To appear at the at top and bottom of indexes. [$LINE]
	   "none" to do away with line graphics.
    -m    Location of thumbnail images. [$THUMB_DIR]
    -r    Maximum rows of images in a table cell. [$MAX_ROWS]
    -s    Print size of graphic file in index next to link.
    -t    "Title of page." Don't forget the quotes! [$TITLE]
    -v    Verbose.

Examples:
    $0 -vdst "Tons of Pictures!" *.jpg *.gif
END_OF_HELP

	1;
}
#----------------------------------------------------------------------------#


#- Main Program -------------------------------------------------------------#
require('getopt.pl');	# helps handle cmd line opts. comes with Perl
&getOpts; 	# get commandline options

if ($opt_h || !@ARGV) { &help && exit; }

if (! -f $LINE) {
	print STDERR "Warning: $LINE does not exist (unless it is a URL)!\n";
}

if (! -f $BULLET) {
	print STDERR "Warning: $BULLET does not exist (unless it is a URL)!\n";
}

@FILES = @ARGV; # files left on the command line

# extract dirs from file list
foreach $i (0 .. $#FILES) { 
	push(@DIRS,splice(@FILES,$i)) if (-d $FILES[$i]);
}

@thumbnails = &getThumbs($THUMB_DIR); # get thumbnails from $THUMB_DIR

$numFiles = @FILES;
$numDirs = @DIRS;
$numIndexes = int($numFiles / $MAX_ON_PAGE); # plus remainder
$numIndexes++ if (($numFiles % $MAX_ON_PAGE) != 0); # if so then 1 incomplete

&giveVerbose if $opt_v;

$iCount=1; # initialize index count
while(@FILES) {
	# account for the thumb dir!!
	if ($iCount == 1) {
		$INDEX = "index.html";
	} else {
		$INDEX = "index$iCount.html";
	}

	*INDEX = &openIndex("INDEX", $INDEX);
	&printHeader(*INDEX, "$TITLE");
	$shiftNum = &printIndex(*INDEX);

	# print links to other indexes 
	&printIndexBar(*INDEX);
	&printFooter(*INDEX);

	if (@thumbnails) {
		*TINDEX = &openIndex("TINDEX", "t$INDEX");
		&printHeader(*TINDEX, "$TITLE"); 

		# pass "anything" as second parameter so it will include thumbnails 
		# on the index
		$shiftNum = &printIndex(*TINDEX, "with_thumbnails"); 

		# print links to other indexes 
		&printIndexBar(*TINDEX, "with_thumbnails");
		&printFooter(*TINDEX, "with_thumbnails");
	}

	splice(@FILES,0,$shiftNum);
	close INDEX;
	close TINDEX;
	$iCount++; # debug ??? hu
}
#----------------------------------------------------------------------------#


#- Get command line options -------------------------------------------------#
sub getOpts {
	&Getopt('bflmrt'); # these options accept commandline values
	# if indexes are in the same dir w/ images then you don't need a baseref
	$BULLET		= $opt_b if ($opt_b); 
	undef $BULLET if ($BULLET =~ /none/i);
	$BASEREF        = $opt_f if ($opt_f); 
	$LINE		= $opt_l if ($opt_l); 
	undef $LINE if ($LINE =~ /none/i);
	$THUMB_DIR	= $opt_m if ($opt_m); 
	$MAX_ROWS       = $opt_r if ($opt_r); 
	$TITLE		= $opt_t if ($opt_t); 
}
#----------------------------------------------------------------------------#


#- Read thumbnails in thumbdir ----------------------------------------------#
sub getThumbs {
	local($dir) = shift @_;
	local(@thumbnails);

	opendir(DIR,"$dir") || return;
	
	@thumbnails = grep(/[^.]+$/, readdir(DIR)); #reading everything not .*
	close(DIR);

	return @thumbnails;
}
#----------------------------------------------------------------------------#


#- Open next index for printing ---------------------------------------------#
sub openIndex {
	#this needs tweaking, but it seems to work
	local($FH) = shift @_; # filehandle name 
	local($INDEX) = shift @_; # filename
	local($i)=0;

	# if non destructive, let's save existing indexes
	if (!$opt_d) {
		if (-e $INDEX) {
			$INDEXbak = $INDEX;
			while (( -e $INDEXbak ) && ($i++ <= 1000)) { 
				$INDEXbak = "$INDEX$i";
			}
			rename("$INDEX", "$INDEXbak") || 
				die "Can't rename $INDEX to $INDEXbak";
			print "saving $INDEX to $INDEXbak\n" if ($opt_v);
		}
	}

	open($FH, ">$INDEX") || die "Can't open $INDEX for output $! ";
	print " opened $INDEX for output... " if ($opt_v);
	return $FH;
}
#----------------------------------------------------------------------------#


#- Print html header on index -----------------------------------------------#
sub printHeader {
	# you may carefully modify this HTML
	# pass filehandle as arg later
	local($FH) = shift @_; # filehandle to index 
	local($TITLE) = shift @_;

	$BASEREF |= "./";

	print $FH <<"E_O_HTML";
<HTML>
<HEAD>
<BASE REF="$BASEREF">
<TITLE>$SITE_NAME $TITLE</TITLE></HEAD>

<BODY BGCOLOR="$BGCOLOR" TEXT="$TEXT" LINK="$LINK" VLINK="$VLINK" ALINK="$ALINK"> 
<CENTER><b><font size="+2">$TITLE</font></b></CENTER><P>

E_O_HTML

print $FH "<CENTER><IMG ALIGN=middle SRC=\"$LINE\"></CENTER><BR>\n" if ($LINE);

}
#----------------------------------------------------------------------------#


#- Print an index -----------------------------------------------------------#
sub printIndex {
	# print the actual links to graphics in the index
	# this will totally change with template support (if i ever add it)
	# for now just pass it a file handle and if this call is to include
	# thumbnails then pass anything as a second argument 

	local($FH)     = shift @_; # filehandle to write index to 
	local($tindex) = shift @_; # set $tindex if printing thumbnails

	local($pCount) = 0; # picture count
	local($rCount) = 0; # row count (num pictures in a column)
	local($cCount) = 1; # column count

	print $FH "<CENTER>\n<TABLE CELLPADDING=5 WIDTH=100%>\n<TR VALIGN=TOP>\n";
	print $FH "\t<TD>\n\t<DL>\n";

	for ($pCount=0; $pCount < $MAX_ON_PAGE; $pCount++) {
			($pic = @FILES[$pCount]) || next; 

			if ($rCount == $MAX_ROWS) {
				$rCount = 0;
				$cCount++; # no check for cols?
				# end the table column and start the next
				print $FH "\t</DL>\n\t</TD>\n\t<TD>\n";
			}

			$rCount++;

			# list an image
			print $FH "\t\t<DD>";
			# no bullet on thumbnail ver. of index
			print $FH "<IMG SRC=\"$BULLET\">" if ($BULLET && !$tindex);
			if ($tindex) {
				# should have width and height tags! get fiximg.pl
				print $FH "<A HREF=\"$pic\">";
				#if ( grep(/$pic/, @thumbnails) > 0) { #debug
				$thumbnail = "$THUMB_DIR/$pic"; 
				if ( -e "$thumbnail" ) {
					print $FH "<IMG SRC=\"$thumbnail\"";
					# later replace this with Image::Size
					print $FH &hwTags($thumbnail) . "> ";
				} else {
					print STDERR "WARNING! $thumbnail missing! ";
					print $FH "<IMG SRC=\"$BULLET\">" if ($BULLET);
				}
				print $FH "$pic</A> ";
			} else {
				print $FH "<A HREF=\"$pic\">$pic</A> ";
			}

			if ($opt_s) {
				# display size in kilobytes
				$size = (-s $pic); $size /= 1024; $size += .5;
				$size = int($size);
				print $FH "(", $size,"kb)";
			}

			print $FH "<P>\n";
	}


	# end index
	print $FH "\t</DL>\n\t</TD>\n";
	print $FH "</TR>\n</TABLE>\n</CENTER>\n";

	print "Added $pCount files.\n" if ($opt_v);

	return $pCount; # debug
}
#----------------------------------------------------------------------------#


#- Print html footer on index -----------------------------------------------#
sub printFooter {
	local($FH) = shift @_; # filehandle to index 
	if ($LINE) {
		print $FH "<CENTER><IMG ALIGN=middle SRC=\"$LINE\">";
		print $FH "</CENTER><BR>\n";
	}
	
	print $FH <<"E_O_HTML";

<DL>
	<DD><FONT size="-2">
	 Created with 
	 <A HREF="http://www.bewley.net/perl/gtindex.html">$VERSION</A>
	 written by <A HREF="http://www.bewley.net/">Bewley Internet Solutions</A>.
	</FONT>
</DL>
</BODY>
E_O_HTML
}
#----------------------------------------------------------------------------#


#- Give some verbose info ---------------------------------------------------#
sub giveVerbose {
	# print some verbose info
	print "$VERSION\n";
	print "$numDirs directories to ignore for now (no recursion)\n";
	print scalar(@thumbnails), " thumbnails in $THUMB_DIR\n" if (@thumbnails);
	print "$numFiles graphics specified\n";
	print "$numIndexes indexes to create\n";
}
#----------------------------------------------------------------------------#


#- Print Links to Other Indexes ---------------------------------------------#
sub printIndexBar {
	local($FH) = shift @_;
	local($tindex) = shift @_;

	print $FH "<DL><DD>";

	# print link to thumbnail or no thumbnails version
	if (@thumbnails) {
		if ($tindex) {
			print $FH "[<A HREF=\"index";
			print $FH "$iCount" unless ($iCount == 1);
			print $FH ".html\">No Thumbnails</A>]\n"; 
		} else {
			print $FH "[<A HREF=\"tindex";
			print $FH "$iCount" unless ($iCount == 1);
			print $FH ".html\">Thumbnails</A>]\n"; 
		}
	}

	print $FH "[<A HREF=\"$HOME_URL\">Home</A>]\n" if ($HOME_URL);
	$prev = $iCount;
	if ($iCount == 1) {
		# nothing
	} elsif ($iCount == 2) {
		# this is a kludge? fix it later. debug
			if ($tindex) {
				print $FH "[<A HREF=\"tindex.html\">Previous</A>]\n";
			} else {
				print $FH "[<A HREF=\"index.html\">Previous</A>]\n";
			}
	} else {
			if ($tindex) {
				print $FH "[<A HREF=\"tindex", ($iCount - 1), ".html\">Previous</A>]\n";
			} else {
				print $FH "[<A HREF=\"index", ($iCount - 1), ".html\">Previous</A>]\n";
			}
	}

	# print link to all the indexes for this batch
	foreach $i (1..$numIndexes) {
		if ($i == $iCount) {
			if ($tindex) {
				print TINDEX "$i\n";
			} else {
				print INDEX "$i\n";
			}
		} elsif ($i == 1) {
			# this is a kludge
			if ($tindex) {
				print $FH "<A HREF=\"tindex.html\">1</A>\n" if (@thumbnails);
			} else {
				print $FH "<A HREF=\"index.html\">1</A>\n";
			}
		} else {
			if ($tindex) {
				print $FH "<A HREF=\"tindex$i.html\">$i</A>\n" if (@thumbnails);
			} else {
				print $FH "<A HREF=\"index$i.html\">$i</A>\n";
			}
		}
	}

	#$iCount++;
	$next = ($iCount+1);
	undef $next if ($next > $numIndexes);

	if ($tindex) {
		print $FH "[<A HREF=\"tindex$next.html\">Next</A>]" if ($FILES[0]);
	} else {
		print $FH "[<A HREF=\"index$next.html\">Next</A>]" if ($FILES[0]);
	}

	print $FH "\n</DL>\n";
}
#----------------------------------------------------------------------------#


#----------------------------------------------------------------------------#
sub hwTags {
        my ($file) = @_ ;
        open(GRAPHIC, "$file") || die "Can't open graphic $file $!";
        binmode(GRAPHIC); # necessary for non UNIX perl

        if ($file =~ /\.gif$/i) {
                $tags = &gifSize(GRAPHIC);
        } elsif ($file =~ /\.jpg$|.jpeg$/i) {
                $tags =  &jpegSize(GRAPHIC);
        } 

        close (GRAPHIC);
        return $tags;
}
#----------------------------------------------------------------------------#


#- Size Gifs ----------------------------------------------------------------#
sub gifSize {
        # return a string of height and width tags for a gif.
        # this code "adapted" from:
        # http://rajiv.org/programming/gifsize.txt

        my ($GIF) = @_;
        my ($w, $w2, $h, $h2, $gifwidth, $gifsize, $type) = () ;

        read ($GIF, $type, 3);
        seek ($GIF, 6, 0); 
        read ($GIF, $w, 1);
        read ($GIF, $w2, 1);
        read ($GIF, $h,  1); 
        read ($GIF, $h2, 1);

        $width  = ord ($w) + ord ($w2) * 256;
        $height = ord ($h) + ord ($h2) * 256;
        return ("WIDTH=\"$width\" HEIGHT=\"$height\"");
}
#----------------------------------------------------------------------------#


#----------------------------------------------------------------------------#
# jpegsize : gets the width and height (in pixels) of a jpeg file
# Andrew Tong, werdna@ugcs.caltech.edu           February 14, 1995
# modified slightly by alex@ed.ac.uk
sub jpegSize {
  my ($JPEG) = @_;
  my ($done) = 0;
  my ($size) = "";

  read($JPEG, $c1, 1); read($JPEG, $c2, 1);
  if( !((ord($c1) == 0xFF) && (ord($c2) == 0xD8))){
    print "This is not a JPEG!";
    $done=1;
  }
  while (ord($ch) != 0xDA && !$done) {
    # Find next marker (JPEG markers begin with 0xFF)
    # This can hang the program!!
    while (ord($ch) != 0xFF) {  read($JPEG, $ch, 1); }
    # JPEG markers can be padded with unlimited 0xFF's
    while (ord($ch) == 0xFF) { read($JPEG, $ch, 1); }
    # Now, $ch contains the value of the marker.
    if ((ord($ch) >= 0xC0) && (ord($ch) <= 0xC3)) {
      read ($JPEG, $junk, 3); read($JPEG, $s, 4);
      ($a,$b,$c,$d)=unpack("C"x4,$s);
      $size=join("", 'HEIGHT=',$a<<8|$b,' WIDTH=',$c<<8|$d );
      $done=1;
    } else {
      # We **MUST** skip variables, since FF's within variable names are
      # NOT valid JPEG markers
      read ($JPEG, $s, 2); 
      ($c1, $c2) = unpack("C"x2,$s); 
      $length = $c1<<8|$c2;
      if( ($length < 2) ){
        print "Erroneous JPEG marker length";
        $done=1;
      } else {
        read($JPEG, $junk, $length-2);
      }
    }
  }
  return $size;
}
#----------------------------------------------------------------------------#

__END__

=pod

=head1 NAME

gtindex.pl - Graphics and Thumbnail indexer. 

V1.2 - http://www.bewley.net/perl/gtindex.pl

=head1 SYNOPSIS

gtindex.pl [ C<-b> F<bullet url> ] [ C<-d> ] [ C<-f> F<baseref> ] [ C<-h> ] [ C<-l> F<line url> ] [ C<-m> F<directory> ]  [ C<-r> F<num rows> ] [ C<-s> ]  [ C<-t> F<page title> ] [ C<-v> ]

   Examples: 
     gtindex.pl *.jpg 
     gtindex.pl -vdt "Dale's Police Brutality Imagery" -b "none" *.gif 
     gtindex.pl -v -l "none" -r 3 -t "graphics" *.gif *.jpg 

=head1 DESCRIPTION

In case you are confused... This is a command line program only, not a CGI app, for now.

This script requires perl5 (barely) and has been testing in win95 and UNIX.
Well, it hasn't been tested on win95 lately. I<good luck>.

Use this if you have many many graphics that you would like to be able to 
browse easily with a web browser.

Say you have a dir called gfx filled full of graphics. Create a subdir called 
gfx/thumbnails and place thumbnail sized
copies of each graphic in there. How do you make the thumbnails? 
That depends on your platform. I would reccomend
C<thumbsplus> for win95 and C<convert> for UNIX. Convert is a part of the 
Imagemagik package. Now cd to your gfx dir and run this little gem.

Thumbnails must be in a subdir of the dir containing your pictures. They must 
also have the SAME NAME as their
full sized versions!! Of course you don't need thumbnails at all if you 
don't have any. Just don't create the thumbnail
dir and gtindex.pl will still work normally. Well, almost...


=head2 Example Output

=over 4

=item Dale's Images

http://www.bewley.net/photos/tindex.html

=item Jeremy Stafford-Deitsch's Shark Photos

http://www.wattcom.com/sharks/photo/tindex.html

=item Marisa Tomei Pictures

http://espsun.space.swri.edu/~joey/pics/marisa/tindex.html

=back

=head1 OPTIONS

=over 4

=item B<-b> URL

Bullet graphic URL. To appear to the left of image titles. Use -b "none" if you 
prefer no bullets.

=item B<-d>

Destructive. Overwrite old indexes. 

=item B<-f> URL

Baseref. URL to prepend all IMG SRC's. 

=item B<-h>

Help! 

=item B<-l> URL

Line graphic. To appear at the at top and bottom of indexes. Use -l "none" 
if you prefer no line graphics.

=item B<-m> dir

Directory (relative to current dir) which contains thumbnail images.

=item B<-r> number

Maximum rows or images in table cell. 

=item B<-s>

Print size of file in index. 

=item B<-t> "page title"

Title of page. Don't forget the quotes! 

=item B<-v> 

Verbose. 

=back


=head2 Variables

You may modify these variables to your heart's content. 

=over 4

=item B<$ALINK> = "#ee0033"; 

Index active link color. 

=item B<$BGCOLOR> = "#ffffff"; 

Index background color. 

=item B<$LINK> = "#6600ff"; 

Index link color.

=item B<$TEXT> = "#000000"; 

Index normal text color. 

=item B<$VLINK> = "#ee0000"; 

Index visited link color.

=item B<$BULLET> = "../images/ball.gif"; 

Default bullet next to index entry. "" if none. 

=item B<$MAX_ON_PAGE> = "12"; 

Maximum images on a page. i won't explain this because it is part of the 
hard coding and may just confuse things. 

=item B<$MAX_ROWS> = "4"; 

Maximum number of images down a column. this means you will have 
$MAX_ON_PAGE / $MAX_ROWS columns (3) 

=item B<$SITE_NAME> = "Dale's Image Gallery - "; 

Printed in title. Change this before you run it.

=item B<$HOME_URL> = "http://www.bewley.net/perl/"; 

Home link on indexes. Change this too.

=item B<$THUMB_DIR> = "thumbnails"; 

Directory containing optional thumbnails of images. it is assumed this will be 
within the current directory and thumbnails will have same names as full 
sized versions. 

=item B<$TITLE> = ""; 

Default title on each index page. 

=back

=head1 TODO

=over 4

=item  Make more portable. 

The format of the index is not very flexible right now. I'm sure it will be 
eventually. I'd like to use the template process I use on 
http://www.bewley.net/perl/gif2html.html 

=item Add recursion? 

Support subdirectories of images. Sometime..

=item  use Image::Size 

Instead of the subs within use this module for getting thubmnail dimensions.

=item  make CGIable. 

Shouldn't be much I just don't have time.

=item make less ugly!!

=back

=head1 AUTHOR

Dale Bewley, Bewley Internet Solutions Inc, mailto:sales@bewley.net

