#!/usr/bin/perl
$ME = 'thumbindex v1.21B';
#
# this is still a program being developed... so bear with me.
# dont mind the debugging stuff (!)....
#
# USAGE: thumbindex index.jpg image_file1 image_file2 ... > outfile.html
#
# this is where PBM stuff lives (also jpeg utils)
# probably the only thing you need to change (famous last words)
$BIN = '/usr/bin'; #where image utils live
$ACROSS = 6; #default width in number of images
$SIZE = 100; #default size (square) of each thumbnail tile
# these are used to identify the process as unique and make intermediate files
$ID = $$;
$TMP = "/tmp/index$ID-";
#regexp for valid file types (returned by `file` and also extension)
$VALID_TYPES = "(gif|jpe?g)"; #case gets ignored
chop($DATE = `/bin/date '+%m/%d/%y %H:%M'`);
$URL = 'scribble.com/thumb/'; #http:// gets prepended in href
# fills out 2 or more open tiles with this text
$NOTE = "created by
$ME
$DATE
$URL";
$NO_NOTE = 1; #set this if you want no note created (which is fine by me)
# but would be cool if you left the note in the html comments
#
# start of main functionality
#
$row = 1;
$col = 1;
($INDEX_IMAGE,@IMAGES) = @ARGV;
# would be nice NOT to die, but this will help prevent me from writing
# over all my precious photos!! hah
die "$INDEX_IMAGE exists!! first arg is the index image to create.
usage: $0 index_image image1 image2 ...\n" if (-e $INDEX_IMAGE);
$IMG_SRC = $INDEX_IMAGE;
$IMG_SRC = $1 if ($IMG_SRC =~ /\/([^\/]+)$/);
@IMAGES = sort(@IMAGES);
#handle case where we have less images than $ACROSS
$ACROSS = $#IMAGES + 1 if (($#IMAGES + 1) < $ACROSS);
# if there are more than 7 rows, shrink the tile size and increase # across
if ($#IMAGES > 41) { #more than 7 rows...
$ACROSS = 7;
$SIZE = 75;
}
print STDERR "across=$ACROSS, size=$SIZE\n";
foreach $image (@IMAGES) {
push(@row_images,$image);
###print STDERR "($row,$col) -> $image\n";
if ($col == $ACROSS) {
&do_row($row,@row_images);
$col = 0;
$row++;
@row_images = ();
}
$col++;
}
# dropped out of above, but didnt finish current row:
&do_row($row,@row_images) if ($col > 1);
# NOT the above case, so $row is falsely incremented
$row-- if ($col == 1);
$ROWS = $row; #set as global reference to how many rows we made
@all_rows = ();
for ($i = 1 ; $i <= $ROWS ; $i++) {
push(@all_rows,"${TMP}row$i.pnm"); #array of all row images
}
# do the magic to stack the rows!!
$cmd = "$BIN/pnmcat -black -tb -jleft " . join(' ',@all_rows) . " | $BIN/cjpeg -quality 25 /dev/stdin > $INDEX_IMAGE";
print STDERR "combining to $INDEX_IMAGE\n";
###print STDERR "($cmd)\n";
`$cmd`;
print &build_html_index; #spit out the html
`rm /tmp/index*`; #clean up
#done!
##
## subroutines
##
# build row image from (row_num,@images)
sub do_row {
my ($r,@i) = @_;
my $i,$type,$cmd,$file,@f,$c,$name;
@f = (); $c = 0;
###print STDERR "ROW: $r; " . join(',',@i) . "\n\n";
foreach $i (@i) { #each image
$c++;
#determine type of file... might vary by system!!
chop($type = `file $i | cut -d' ' -f2`);
#if not a valid type, try the extension of it (may be wrong!)
if ($type !~ /^$VALID_TYPES$/i) {
$type = $1 if ($i =~ /\.([^\/]+)$/);
}
print STDERR "BAD TYPE ($type)\n" if ($type !~ /^$VALID_TYPES$/i); #give up
$type =~ tr/A-Z/a-z/; #shh, no shouting
if ($type =~ /^gif$/i) {
$cmd = "$BIN/giftopnm"; #converting a gif
} elsif ($type =~ /^jpe?g$/i) {
$cmd = "$BIN/djpeg -pnm"; #converting a jpeg
} else {
$cmd = $type . "topnm"; #may produce error, but what else can we do?
}
$name = $1 if ($i =~ /\/*([^\/]+)\.[^\/]*$/); #pulls out name (no ext)
$file = "$TMP${row}-$c.pnm"; #destination file
# special file info: $INFO{'R,C'} = description for javascript
$INFO{sprintf("%05d,%05d",$row,$c)} =
sprintf("$name (%sK $type) - %s",&nice_stat($i));
push(@f,$file); #@f is a list of all files being made for this row
$cmd = "$cmd '$i' | $BIN/pnmscale -width $SIZE -height $SIZE > $file";
##print STDERR "((($cmd)))\n";
`$cmd`;
print STDERR sprintf("$r: %d/%d = $file\n",$c,$#i+1);
# check to see if all went well...
if (!(-s $file)) { #zero or non-existent file
$cmd = "echo \"BAD!\n$name\n$type\" | $BIN/pbmtext | $BIN/pnmscale -width $SIZE -height $SIZE > $file";
`$cmd`;
print STDERR "*** ERROR *** $i\n";
$INFO{sprintf("%05d,%05d",$row,$c)} = "***BAD***";
}
}
# handle the special case where we want to make an info tile,
# which is actually 2 tiles wide. only do if 2 or more blank spots open.
if (!$NO_NOTE && ($#i < ($ACROSS - 2))) {
print STDERR "adding info block = ${TMP}info.pnm\n";
my $w = $SIZE * 2; #scale to 2x1 size-units
`echo \"$NOTE\" | $BIN/pbmtext | $BIN/pnmcrop -right | $BIN/pnmcrop -bottom | $BIN/pnminvert | $BIN/pnmscale -width $w -height $SIZE > ${TMP}info.pnm`;
push(@f,"${TMP}info.pnm"); #add this tile (x2) to array of this row
# create the extra map line needed for html when info is used
$EXTRA_MAP = "\n";
}
$file = "${TMP}row$row.pnm"; #row file, now create it:
$cmd = "$BIN/pnmcat -black -lr -jbottom " . join(' ',@f) . " > $file";
###print STDERR "((($cmd)))\n";
`$cmd`;
print STDERR " ROW $r -> $file\n";
}
# creates the html. edit as you like!
sub build_html_index {
my $w = $ACROSS * $SIZE;
my $h = $ROWS * $SIZE;
my $map = "";
my $k,$r,$c,$f;
# we get pieces and relative info from %INFO
for $k (sort keys %INFO) {
# $r and $c start counting at 1 (not 0), dont forget...
($r,$c) = split(/,/,$k); #results in something like (1,1)
#the filename is found by looking in @IMAGES
$f = $IMAGES[($r-1)*$ACROSS+($c-1)];
$r *= $SIZE; #convert to pixels
$c *= $SIZE;
$map .= sprintf("\n",
$c-$SIZE,$r-$SIZE,$c,$r,$f,$INFO{$k});
}
# once we get out, we use $c and $r to know where to put info tile
$EXTRA_MAP = sprintf($EXTRA_MAP,$c,$r-$SIZE,$w,$h);
# the rest is just html to return!!
# would be nice to leave $NOTE in the comments, but remove if ya like
return <
$ME: $ID
$DATE