Date: Mon, 11 Sep 2000 10:07:59 -0400 From: "Andresen,Jason R." <jandrese@mitre.org> To: Chip <chip@wiegand.org> Cc: "freebsd-questions@freebsd.org" <freebsd-questions@FreeBSD.ORG> Subject: Re: Making thumbnail images Message-ID: <39BCE73F.80D641D@mitre.org> References: <39BC0225.520792D6@wiegand.org>
next in thread | previous in thread | raw e-mail | index | archive | help
[-- Attachment #1 --]
Chip wrote:
>
> I am interested in a program that will take a large number (over
> 600) of jpg images and create thumbnails of them. I have tried
> something called qp and it doesn't seem to do squat. I also
> looked
> at webmagick but it appears to have a huge learning curve and I
> just don't have time for that. Any other suggestions?
Well, I've got this old perl script that I whipped up ages ago. You'll
need netpbm and jpeg installed. The command like options you most
likely want are: ./genindex -s index -f jpg [-i]
You will need to edit a couple of paths near the top of the script if
you want to use the -i option, just point them to the included html
files (and modify those if you want. :)
The -i generates HTML index pages with clickable imagemaps. Be warned,
the netpbm code still has a bug that occasionally munges the colors on
the generated index page. Caveat empretor.
--
_ _ _ ___ ____ ___ ______________________________________
/ \/ \ | ||_ _|| _ \|___| | Jason Andresen -- jandrese@mitre.org
/ /\/\ \ | | | | | |/ /|_|_ | Views expressed may not reflect those
/_/ \_\|_| |_| |_|\_\|___| | of the Mitre Corporation.
[-- Attachment #2 --]
#!/usr/bin/perl -w
# genindex -- Generate indexes from JPEGs, GIFs, and PNGs using
# minimal disk space
# Thanks to Jef Poskanzer for the original pnmindex, which gave me the
# idea for this script.
# Copyright (C) 1991 by Jef Poskanzer.
# Copyright (C) 1997 Jason Andresen
# Permission to use, copy, modify, and distribute this software and its
# documentation for any purpose and without fee is hereby granted, provided
# that the above copyright notice appear in all copies and that both that
# copyright notice and this permission notice appear in supporting
# documentation. This software is provided "as is" without express or
# implied warranty.
# Revision History:
# 1.0: Inital release, complete rewrite of Jef Poskanzer's pnmindex utility
# 1.1: Added -o support.
# 1.2: Added support for different file output types (gif, jpeg).
# 1.2.5: Checked extension of -o file to determine what type of compression
# to use on the output file.
# 1.3: Added support for splitting output files.
# 1.3.5: Added help screen
# 2.0: Added the Client-Side imagemap generation option.
# 2.1.1: Fixed bug with >2 indexes.
# 2.1: Added the -r option to force remaking of directories.
# 2.2: Added the -d option to show progress dots.
# 2.3: Added the -p option to show percentage progress.
# Libraries
use Cwd;
use English;
use IO::Handle;
# Set for autoflush
STDOUT->autoflush(1);
# Signal trapper handler
sub sighand
{
system "rm -f $tempdir/$$.image.temp*";
system "rm -f $tempdir/$$.index.temp*";
exit (0);
}
# Trap all apropriate signals and clean up before quitting
$SIG{INT}='sighand';
$SIG{QUIT}='sighand';
$SIG{HUP}='sighand';
$SIG{KILL}='sighand';
$SIG{TERM}='sighand';
# Some user defined constants
# These are the base web pages that are modified to create the imagemaps
# you don't need to bother with these if you are not making client-side
# imagemaps (-i option).
# These files replace strings embeded in the HTML file to create the
# web pages. These are the strings:
# *DIRECTORY Replaced with the imagemaps CWD
# *SHORTDIR Replaced with the imagemaps Directory name
# *MAPDEF Replaced with the imagemap Definition
# *IMAP Replaced with the invocation of the Imagemap
# *FILELIST Replaced with the list of imagemaps (for multiple
# indexes)
# The strings must be alone on the line:
# Correct
# -------
# <TITLE> Directory of
# *DIRECTORY
# </TITLE>
#
# Incorrect
# ---------
# <TITLE> Directory of *DIRECTORY </TITLE>
# See included examples for more information.
$mappage = "/home/jandrese/bin/imap.html";
$multipage = "/home/jandrese/bin/mmap.html";
$mainout = "index.html";
$imapprefix = "subindex";
# Initalize the variables
$size=100; # Scale each image to approx $size x $size
$across=8; # Number of images across.
$colors=256; # Maximum number of colors to use.
$back="-white"; # The default background color.
$tempdir="/tmp"; # Your temporary directoy.
$outfile="STDOUT"; # This is the output file.
$outformat="pnm"; # This is the format of the output.
$jpegquality=75; # The quality of the jpeg output.
# ( 0 <= N <= 100 )
$splitprefix=""; # The prefix of the splitted files.
$splitnum=6; # The number of rows per split index.
$testmode="FALSE"; # Test the index instead of actually creating it
$verbose="FALSE"; # Verbose mode.
$dir=cwd(); # Get the current working directory.
$printhelp="FALSE"; # Display the help message and quit.
$genIMAP="FALSE"; # Create a client side imagemap.
$forceremake="FALSE"; # Force the index to be remade, weather it
# needs it or not.
$showdots="TRUE"; # Show percentage dots
$termwidth=80; # Width of the terminal in characters
$showperc="FALSE"; # Show progress as a percentage
# Process all of the command line arguments
while ( $arg = shift )
{
SWITCH:
{
if ( $arg eq "-black" ) { $back="-black"; last SWITCH; }
if ( $arg eq "-white" ) { $back="-white"; last SWITCH; }
if ( $arg eq "-size" ) { $size = shift; last SWITCH; }
if ( $arg eq "-across" ) { $across = shift; last SWITCH; }
if ( $arg eq "-colors" ) { $colors = shift; last SWITCH; }
if ( $arg eq "-depth" ) { $colors = 2**shift; last SWITCH; }
if ( $arg eq "-o" ) { $outfile = shift; last SWITCH; }
if ( $arg eq "-f" ) { $outformat = shift; last SWITCH; }
if ( $arg eq "-s" ) { $splitprefix = shift; last SWITCH;}
if ( $arg eq "-sn" ) { $splitnum = shift; last SWITCH; }
if ( $arg eq "-t" ) { $testmode = "TRUE"; last SWITCH; }
if ( $arg eq "-v" ) { $verbose = "TRUE"; last SWITCH; }
if ( $arg eq "-h" ) { $printhelp = "TRUE"; last SWITCH; }
if ( $arg eq "-i" ) { $genIMAP = "TRUE"; last SWITCH; }
if ( $arg eq "-r" ) { $forceremake = "TRUE"; last SWITCH; }
if ( $arg eq "-d" ) { $showdots = "TRUE";
$showperc = "FALSE"; last SWITCH; }
if ( $arg eq "+d" ) { $showdots = "FALSE"; last SWITCH; }
if ( $arg eq "-p" ) { $showperc = "TRUE";
$showdots = "FALSE"; last SWITCH; }
if ( $arg eq "+p" ) { $showperc = "FALSE"; last SWITCH; }
print STDERR "Sorry, I don't understand $arg.\n";
}
}
# Help screen
if ( $printhelp eq "TRUE" )
{
print "$0: Generate indexes.\n";
print "\n";
print "This script generates an index image (thumbnails with names)\n";
print "in the directory it is executed in. Several options are\n";
print "recognised, including:\n";
print "\t-black: black background\n";
print "\t-white: white background\n";
print "\t-size: size of thumbnail, default: $size\n";
print "\t-across: number of thumbnails in a row, default: $across\n";
print "\t-colors: number of colors to quanitize to, default: $colors\n";
print "\t-depth: final image depth (duplicates colors, as 2**depth)\n";
print "\t-o: outfile, filename for single output (example: index.gif)\n";
print "\t-f: outformat, format for index (gif, jpg, pnm)\n";
print "\t-s: Split prefix, prefix to append to split files (ex: index)\n";
print "\t-sn: Number of rows in a split index, default: $splitnum\n";
print "\t-t: Testmode, only print out what would be done.\n";
print "\t-v: Verbose, tell the user way more than they need to know.\n";
print "\t-h: But you've found this feature already ;)\n";
print "\t-i: Generate a client side imagemap HTML file for index\n";
print "\t-r: Remake the index, even if it does not need it\n";
print "\t-d: Show progress dots (do not use with -v)\n";
print "\t-p: Show progress meter as a percentage\n";
exit(0);
}
# Set up some temporary variables
$pict = 0;
$splitpict = 0;
$dotpos = 0;
# Check to see if the index needs to be remade or not
if ($verbose eq "TRUE" )
{
print STDERR "Checking to see if the index for $dir needs to be updated.\n"
}
if ( -e ".index.txt" )
{
system ("ls > .$$.index.new.txt");
$diffout = `diff .index.txt .$$.index.new.txt`;
unlink(".$$.index.new.txt");
if ($diffout eq "")
{
if ($verbose eq "TRUE" || $testmode eq "TRUE" )
{
print STDERR "$dir is up to date\n";
}
if ( $forceremake eq "FALSE" )
{
# Do not exit if we are going to force the index to
# be remade, but exit if we aren't and the directory
# has not changed.
exit 0; # The index is up to date
}
}
else
{
if ($testmode eq "TRUE")
{
die "$dir needs to be updated.\n";
}
}
}
if ($testmode eq "TRUE")
{
die "$dir needs to be updated.\n";
}
if ($verbose eq "TRUE" )
{
print STDERR "Determining output format.\n";
}
# Figure out what type of file the user wants as output
$tpos = -1;
$pos = $tpos;
while (( $tpos = index($outfile, ".", $tpos)) > -1 )
{ $pos = ++$tpos; }
$extn = substr($outfile, $pos);
# Set up the output format filters for the output you select
if ( $outformat eq "gif" || $extn eq "gif" )
{
$outfilter=" | ppmtogif -quiet ";
$outformat="gif";
$extn="gif";
}
elsif ( $outformat eq "jpeg" || $outformat eq "jpg"
|| $extn eq "jpg" || $extn eq "jpeg" )
{
$outfilter=" | cjpeg -optimize -quality $jpegquality ";
$outformat="jpeg";
$extn="jpg";
}
else
{
$outfilter="";
$outformat="pnm";
$extn="pnm";
}
if ($verbose eq "TRUE")
{
print STDERR "File: $outfile, Format: $outformat, Extension: $extn.\n";
}
# This is a hack that removes the old index first (only if it is named the
# same as the index you are creating. This is to prevent the inclusion of
# old indexes in the new index.
if ($splitprefix ne "")
{
system("rm -f $splitprefix*$extn");
}
if ($outfile ne "STDOUT")
{
system("rm -f $outfile");
}
# Get all of the known images from the current directory
@images=sort glob("*.{gif,jpg,png}");
$numImages=@images;
$currsplitnum=0;
$makenew=1;
# Display the dot header, if we have one
if ( $showdots eq "TRUE" )
{
print "Index for $dir\n";
print "0 10 20 30 40 50 60 70 80 90 100\n";
}
if ( $showperc eq "TRUE" )
{
print "Index for $dir\n";
print "00%";
}
# HTML generation Initalization area
if ( $genIMAP eq "TRUE" )
{
@rowwidths = $_; # The width of each row
@rowheights = $_; # The height of each row
@xsize = $_; # The x dimention of each thumbnail
$currrow = 0; # The current row number (starting at 0)
}
if ($verbose eq "TRUE" )
{
print STDERR "Generating index now...\n";
}
# Generate the index
while ($pict < $numImages)
{
@rownames=$_;
# Create a row.
for ($lcv = 0; $lcv < $across && $pict < $numImages; $lcv++)
{
$type = `file -L $images[$pict]`;
SWITCH:
{
if ($type =~ /GIF/ )
{
system "giftopnm -quiet $images[$pict] | pnmscale -xysize $size $size -quiet | ppmquant -quiet $colors > $tempdir/$$.index.temp.$lcv";
last SWITCH;
}
if ($type =~ /JPEG/ )
{
system "djpeg -pnm -fast $images[$pict] | pnmscale -xysize $size $size -quiet | ppmquant -quiet $colors > $tempdir/$$.index.temp.$lcv";
last SWITCH;
}
if ($type =~ /PNG/ )
{
system "pngtopnm $images[$pict] | pnmscale -xysize $size $size -quiet | ppmquant -quiet $colors > $tempdir/$$.index.temp.$lcv";
last SWITCH;
}
system "ppmmake rgb:ff/ff/ff $size $size > $tempdir/$$.index.temp.$lcv";
}
if ( -z "$tempdir/$$.index.temp.$lcv" )
{
# File is corrupt or something, I'll make a
# placeholder
system "pbmtext \"Corrupt\" > $tempdir/$$.index.temp.$lcv";
}
# Add the text to the bottom of the images
if ( $back eq "-white" )
{
system "pbmtext \"$images[$pict]\" | pnmcat $back -tb $tempdir/$$.index.temp.$lcv - > $tempdir/$$.image.temp.$lcv";
}
else
{
system "pbmtext \"$images[$pict]\" | pnminvert | pnmcat $back -tb $tempdir/$$.index.temp.$lcv - > $tempdir/$$.image.temp.$lcv";
}
system "rm -f $tempdir/$$.index.temp.$lcv";
$rownames[$lcv] = "$tempdir/$$.image.temp.$lcv ";
if ($verbose eq "TRUE")
{
print STDERR "Picture $images[$pict] complete on position $lcv...\n";
}
# Add the info to the HTML generation arrays if we're
# generating the client side imagemap
if ( $genIMAP eq "TRUE" )
{
open THUMBNAIL, "$tempdir/$$.image.temp.$lcv";
$xtmp = <THUMBNAIL>; # Skip the magic number
$xtmp = <THUMBNAIL>;
$xsize[$pict] = (split / /,$xtmp)[0];
close THUMBNAIL;
# Clean up some of the namespace
undef $xtmp;
}
$pict++;
# Update the counter of the screen, if it was requested
if ( $showdots eq "TRUE" )
{
$currdotpos = $pict / $numImages * $termwidth;
for ( ; $dotpos < $currdotpos; $dotpos++)
{
print ".";
}
STDOUT->flush;
}
if ( $showperc eq "TRUE" )
{
$currdotpos = $pict / $numImages;
printf "%02d%%", $currdotpos;
STDOUT->flush;
}
}
# Done creating the row.
# Now join all of the pictures in the row together into a single row
system "pnmcat $back -lr -jbottom @rownames > $tempdir/$$.index.temp.row";
if ($verbose eq "TRUE")
{
print STDERR "Joining that row.\n";
}
# If we're generating an Client side imagemap, then get the info for
# the current row
if ( $genIMAP eq "TRUE" )
{
open CURRROW, "$tempdir/$$.index.temp.row";
$rtmp = <CURRROW>; # Skip the magic number
$rtmp = <CURRROW>;
@rowsize = (split / /,$rtmp);
$rowwidths[$currrow] = $rowsize[0];
$rowheights[$currrow++] = $rowsize[1];
close CURRROW;
# Just a little tiding up...
undef $rtmp;
undef @rowsize;
}
if ( $splitprefix ne "" &&
(( $splitpict % $splitnum ) == 0 )
&& $splitpict > 0
)
{
$outfile = "$splitprefix$currsplitnum";
if ($outformat eq "gif")
{
$outfile = "$outfile.gif";
}
elsif ( $outformat eq "jpeg")
{
$outfile = "$outfile.jpg";
}
else
{
$outfile = "$outfile.pnm";
}
system "cat $tempdir/$$.index.temp | ppmquant -quiet $colors $outfilter > $outfile";
$currsplitnum++;
$makenew=1;
}
$splitpict++;
# Finally, append that row to the index file (creating a new one if it
# doesn't exist)
if ( $makenew == 1 )
{
$makenew = 0;
system "mv $tempdir/$$.index.temp.row $tempdir/$$.index.temp";
}
else
{
system "pnmcat $back -tb $tempdir/$$.index.temp $tempdir/$$.index.temp.row > $tempdir/$$.index.temp.2";
system "mv $tempdir/$$.index.temp.2 $tempdir/$$.index.temp";
}
}
if ($verbose eq "TRUE" )
{
print STDERR "Compressing imagemap...\n";
}
if ($splitprefix ne "")
{
if ( $currsplitnum == 0 )
{
$outfile = $splitprefix ;
}
else
{
$outfile = "$splitprefix$currsplitnum";
}
if ( $outformat eq "gif" )
{
$outfile = "$outfile.gif";
}
elsif ( $outformat eq "jpeg")
{
$outfile = "$outfile.jpg";
}
else
{
$outfile = "$outfile.pnm";
}
system "cat $tempdir/$$.index.temp | ppmquant -quiet $colors $outfilter > $outfile";
}
elsif ( $outfile eq "STDOUT" )
{ $redir=""; }
else
{ $redir=" > $outfile"; }
if ( $splitprefix eq "")
{
system "cat $tempdir/$$.index.temp | ppmquant -quiet $colors $outfilter $redir";
}
system "rm -f $tempdir/$$.image.temp*";
system "rm -f $tempdir/$$.index.temp*";
# Generate the HTML for a client side image map if the option -i was set
# Client side imagemaps work like this:
# In the head (or anywhere in the HTML), there is an imagemap definition.
# The format looks like so:
# First a header with the image map's name
# <map name="Whatever you want">
# Then the area definitions, these are the regions that the user is supposed
# to click on:
# <area shape="rect" alt="filename" coords"x,y,width,height" href="filename">
# finally, you include a default region, that does nothing for areas outside
# of the picture
# <area shape="default" nohref>
# And at the end, the standard closing tag
# </map>
# Now to use the imagemap, simply put a tag in your HTML like so:
# <IMG SRC="index.gif" usemap="Whatever you want">
if ( $genIMAP eq "TRUE" )
{
$numrows = @rowwidths;
# First we have to determine if we have multiple indexes
if ( $splitprefix ne "" && $currsplitnum > 0 )
{
# There are multple indexes. This is tricky, now we have
# to create a top level index of indexes and let the user
# choose which index to look at.
processHTML($multipage, $mainout, 0, $numrows,
@rowwidths, @rowheights);
for ( $lcv = 0; $lcv <= $currsplitnum; $lcv++)
{
processHTML($mappage, "$imapprefix$lcv.html", $lcv,
$numrows, @rowwidths, @rowheights);
}
}
else
{
# There is only one index to catagorize, do not make the
# chooser page.
processHTML($mappage, $mainout, 0, $numrows, @rowwidths,
@rowheights);
}
}
system("ls > .index.txt");
if ($verbose eq "TRUE")
{
print STDERR "Done.\n";
}
if ( $showdots eq "TRUE" )
{
print "\n";
}
if ( $showperc eq "TRUE" )
{
print "100%\n";
}
exit 0;
# This is the HTML generation subroutine. It does the actual work of
# generating the imagemaps through processing the template files. Be careful,
# this subroutine cannot tell the difference between index files and
# multi-index files, so no error checking can be preformed. (This may
# actually be a feature :)
# The indexnum is not required if you are generating the multi-index.
sub processHTML ( $$$$@@ )
{
$template = shift;
$htmloutfile = shift;
$indexnum = shift;
$numrows = shift;
my $shortdir = $dir;
$shortdir =~ s#.*?/([^/]*)$#$1#;
for ( $foolcv = 0; $foolcv < $numrows; $foolcv++)
{ $rowwidths[$foolcv] = shift; }
for ( $foolcv = 0; $foolcv < $numrows; $foolcv++)
{ $rowheights[$foolcv] = shift; }
if ($verbose eq "TRUE")
{
print STDERR "Processing HTML file $template into $htmloutfile.\n"
}
open TEMPLATE, $template or die "I cannot open $template, please set that constant.\n";
open OUTFILE, ">$htmloutfile" or die "I cannot open $htmloutfile, check the permissions.\n";
while ( $html = <TEMPLATE> )
{
# Current working directory
if ( $html =~ /\*DIRECTORY/ )
{
if ($verbose eq "TRUE")
{
print STDERR "Processing *DIRECTORY.\n";
}
print OUTFILE $dir;
next;
}
if ( $html =~ /\*SHORTDIR/ )
{
if ($verbose eq "TRUE" )
{
print STDERR "Processing *SHORTDIR.\n";
}
print OUTFILE $shortdir;
next;
}
# List of the multiple indexes (do not use for single
# indexes!)
if ( $html =~ /\*FILELIST/ )
{
if ($verbose eq "TRUE")
{
print STDERR "Processing *FILELIST.\n";
}
for ( $foobar = 0; $foobar <= $currsplitnum; $foobar++)
{
print OUTFILE "<A HREF=\"subindex$foobar.html\">Volume $foobar</A><BR>"
}
next;
}
# Imagemap on the HTML, not the definition
if ( $html =~ /\*IMAP/ )
{
if ($verbose eq "TRUE")
{
print STDERR "Processing *IMAP.\n";
}
if ( $splitprefix ne "" && $currsplitnum > 0 )
{
# Multiple indexes
$outfile = "$splitprefix$indexnum";
if ( $outformat eq "gif" )
{
$outfile = "$outfile.gif";
}
elsif ( $outformat eq "jpeg")
{
$outfile = "$outfile.jpg";
}
else
{
$outfile = "$outfile.pnm";
}
print OUTFILE "<IMG SRC=\"$outfile\" ALT=\"Index of $dir\" usemap=\"#index\">";
}
else
{
# Single index
print OUTFILE "<IMG SRC=\"$outfile\" ALT=\"Index of $dir\" usemap=\"#index\">";
}
next;
}
# Imagemap definition
if ( $html =~ /\*MAPDEF/ )
{
if ($verbose eq "TRUE")
{
print STDERR "Processing *MAPDEF.\n";
}
# Variables: @rowwidths = Width of each row
# @rowheights = Height of each row
# @xsize = xdimention of each thumbnail
$indexwidth = 0;
# Calculate the width of the index
for ( $htmlrow = ($indexnum * $splitnum );
($htmlrow < $numrows) &&
($htmlrow < ( $indexnum * $splitnum +
$splitnum ));
$htmlrow++)
{
if ($rowwidths[$htmlrow] > $indexwidth)
{
$indexwidth = $rowwidths[$htmlrow];
}
}
# Generate the HTML entries
$currimage = $indexnum * $splitnum * $across;
$img_y = 0;
$img_h = $rowheights[($currimage/$across)];
if ( $splitprefix eq "" )
{
# reconfigure for one big index
$indexnum = 0;
$splitnum = 32767; # Maxint for bitty boxes
}
# header
print OUTFILE "<MAP NAME=\"index\">\n";
for ( ;
$currimage < $numImages &&
$currimage < (( $indexnum + 1 ) *
$splitnum * $across );
$currimage++)
{
if ( ($currimage % $across) == 0 )
{
$rowwid =$rowwidths[$currimage/$across];
$iwid = $indexwidth;
$row_x = $iwid - $rowwid;
$row_x /= 2; # PNMmerge centers
if ($currimage != $indexnum *
$splitnum * $across)
{
$img_y += $rowheights[($currimage/$across) - 1 ];
$img_h = $img_y + $rowheights[($currimage/$across)];
}
}
$img_x = $row_x;
$row_x += $xsize[$currimage];
$img_w = $row_x;
chomp($img_y);
chomp($img_h);
print OUTFILE "<AREA SHAPE=\"rect\" ALT=\"$images[$currimage]\" COORDS=\"$img_x,$img_y,$img_w,$img_h\" HREF=\"$images[$currimage]\">\n";
}
print OUTFILE "<AREA SHAPE=\"default\" nohref>\n";
print OUTFILE "</MAP>\n";
next;
}
# Not a special line, just spit it out again.
print OUTFILE $html;
}
}
[-- Attachment #3 --]
<HTML>
<HEAD>
<TITLE>
Directory of
*SHORTDIR
</TITLE>
*MAPDEF
</HEAD>
<BODY>
<CENTER>
<FONT SIZE="+3">Directory of
*SHORTDIR
</FONT>
<BR>
*IMAP
</CENTER>
</BODY>
</HTML>
[-- Attachment #4 --]
<HTML>
<HEAD>
<TITLE>
Directory of
*SHORTDIR
</TITLE>
</HEAD>
<BODY>
<CENTER>
Directory of
*SHORTDIR
<BR>
This directory is too big for a single index. The index has been split among
several different files. Please choose one now.
<BR>
*FILELIST
</CENTER>
</BODY>
</HTML>
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?39BCE73F.80D641D>
