#!/usr/local/bin/perl 

# pcd-to-jpg-and-fpx.pl

# distributed by philg@mit.edu under the GNU Public License
# authored by an old girlfriend who wishes to remain anonymous

# for more on how to use this program, visit 
# http://photo.net/wtr/thebook/images.html 

# calling this program
# we assume that we are already CD'd into the target directory
# e.g., ~loser/public_html/pcd1234/
# and that this directory already contains a spec file, probably
# something like pcd1234-description.text, but this is an input

# pcd-to-jpg-and-fpx.pl <description-file-name>

# this program is supposed to take an entire PhotoCD and convert it to
# JPEGs.  Also, it creates three index files.  One contains anchors to
# be used in-line in text.  One contains one HTML table per image.
# This is as close to having a captioned image as one can get in the
# impoverished world of HTML.  The final file is probably only of
# interest to Philip Greenspun because it is for generating tutorials
# in http://photo.net/photo/ (it displays information that can help
# teach other photographers).

# for each image, the program also generates an AOLserver .tcl file 
# (if you are running Apache, you will probably want to change this
# to make a Perl CGI script instead).  
# the name of the .tcl file is going to be the same as the .jpg, e.g., 
# philip-and-alex-on-bed-1.tcl

# we produce an extra page, index-fpx.html, with all the thumbnails
# linked to the .tcl files

# format for the description file
# first part of the description file contains info about entire disk
# then each line describes one image

# line1: WHICH RESOLUTIONS BY DEFAULT
# default_resolutions: <base/16?><base/4?><base?><4base?><16base?><64base?>
# where each <base?> is a 0 or 1

# example:  pull base/16, base, and 4base out of each Image Pac:  101100
# (note:  only ProPhotoCDs have 64base scans)

# line2: COPYRIGHT SPEC
# copyright: <6 char resolution spec> | <copyright text in string quotes>
# so to add a copyright note to base and 4base, the line would read
# copyright:  001100 | "copyright 1997 Philip Greenspun"
# we provide this flexibility because base/16 and base/4 images
# are really too small for a visible copyright notice
# notes:  (1) the copyright text is added to JFIF files at all
# resolutions as a comment but it won't be visible; (2) if the copyright
# text is "" then no copyright info will be inserted

# line3: BORDERS
# we need to turn black borders on or off because scanned slides often
# already have a border; we're going to assume that disk is either all
# slides or prints and not make it adjustable per-image
# border: yes  OR border: no

# line4: SHARPENING
# sharpen: yes OR sharpen: no

# line5: URL STUB
# url_stub:whatever you want in front of the file names in IMGs and HREFs

# each image to be converted gets one line, immediately following the above
# <number on disk>|<target file name>|<which_resolutions>|<caption>|<tech details>|<alt>|<tutorial info>

# example:  58|alex||my baby|Canon EOS, 50mm lens, Kodak E100 film, f/5.6 and 1/125|

# in this case, this software should pull Image Pac IMG0058.pcd off the PhotoCD
# WHICH_RESOLUTIONS wasn't specified so we use the default for this PCD.  Suppose
# it is 101100.  In that case, the base/16 image is converted and saved as
# alex-58.1.jpg  (note that the image number was tacked onto the file name and that the 
# resolution is added).  The base image is converted and saved as alex-58.3.jpg.
# The 4base image is converted and saved as alex-58.4.jpg.

# HTML anchors are created in the index.html file:
# <a href="alex-58.3.jpg"><img src="alex-58.1.jpg" alt="$alt"></a>
# <a href="alex-58.4.jpg">BIG</a>

# note: if the ALT is unspecified in the conversion line then we just
# use $caption

# an HTML table is added created to the index-table.html file:
# <table><tr><td> align=center>
#<a href="alex-58.3.jpg"><img src="alex-58.1.jpg" ALT="$alt"></a>
#<br>
#<a href="alex-58.4.jpg">BIG</a>
#<td>
# $caption
#</tr></table>

# an HTML table is added created to the index-tutorial.html file:
# <table><tr><td> align=center>
#<a href="alex-58.3.jpg"><img src="alex-58.1.jpg" ALT="$alt"></a>
#<br>
#<a href="alex-58.4.jpg">BIG</a>
#<td>
# $caption
# <p>
# $tech_details
# <p>
# $tutorial_info
#</tr></table>

# Note: if, instead of image number (e.g., 3),
# we have rr<image number> (e.g., rr3) then we'll rotate right 90
# degrees (this is to deal with PhotoCDs that we're properly tagged by
# the PIW operator).

# notes on which files get linked to which others...
# typically base/16 and base are converted and the first becomes an IMG 
# anchor for the second.
# if the base/4 image (256x384) and 4base (1000x1500) are converted then 
# the first becomes an IMG anchor for the second.
# if both of these pairs are converted, then the index.html et al files
# should contain two entries for each picture.

#TO DO:  
#  0) add a sq<image number> option to have black borders cropped
#     off for 6x6 medium format images that were scanned to ProPhotoCD
#  1) clean up and comment
#  2) check both the copyright_res string && whether the copyright text is blank
#before a -draw option is issued.
#move files to *.bak rather than dying if they already exist- print warning
#need to do this for convert-cmds

#pcd-to-jpg-and-fpx.pl
#usage:  pcd-to-jpg-and-fpx.pl {-indexonly} <description file> 

######################PARAMETERS#############################################
#FILE LOCATIONS
   $exec_cmd = '/opt/local/bin/convert';   #the exec name for ImageMagick
#Image Pac location; only the lowercase portion varies
#   $pcd_image_directory = '/cdrom/PHOTO_CD/IMAGES/';  
  $pcd_image_directory = '/web/philg/incoming/pcd4749/';  
# set this to 1 if filenames look like "IMG0023.PCD;1"
   $pcd_image_filenames_contain_semicolon_p = 0;

#IMAGE MAGICK DEFAULTS
   $x_display = "homepage.lcs.mit.edu:0";
   @interlaces = ('NONE', 'NONE', 'NONE', 'NONE', 'NONE', 'NONE');
#default color for copyright string
   @pen_colors = ("white", "white", "white", "white", "white", "white");  
#default vertical border widths for each of the 6 image sizes
   @x_borders = (2, 4, 8, 10, 10, 10);  
   @y_borders = (3, 6, 12, 15, 15, 15);  #default horizontal border widths
#default border colors
   @border_colors = ("black", "black", "black", "black", "black", "black");  
#difference between rightmost position of copyright string and rightmost 
#x coordinate of image (including vertical border
   @x_offsets = (5, 5, 5, 5, 5, 5); 
#difference between bottom of lower horizontal border and bottom of 
#copyright string
   @y_offsets = (2, 2, 2, 2, 2, 2);  
   @sharpens = (50, 50, 50, 50, 50, 50);  #default sharpen values
#widths for horizontal images
   @image_widths = (128, 256, 512, 1024, 2048, 4096);  
#heights for horizontal images
   @image_heights = (192, 384, 768, 1536, 3072, 6144);  
   @font_widths = (6, 6, 6, 8, 8, 8);
   @font_heights = (9, 9, 9, 13, 13, 13);

#OUTPUT FILENAMES
   $index_filename = "index.html";
   $table_filename = "index-table.html";
   $tutorial_filename = "index-tutorial.html";
   $fpx_filename = "index-fpx.html";
   $convert_filename = "convert_commands";

# random weird stuff for FPX conversion
   # current converters can't be in Unix pipeline; need to 
   # write to a ppm file and then run ppmtofpx
   $fpx_ppm_scratch_file = "/extra1/fpx_ppm_scratch_file.ppm";
   # for a Pro disk, we'd want to change this to 5 (we're 0-based)
   $fpx_res_index = 4;
   # if 1 then we don't try to make FPX
   # but only refer to them as IMG0008.fpx etc.
   $using_batch_converter_for_fpx_files_p = 1;
   # if set to 0, we'll just get IMG0008.fpx instead of foobar-8.fpx
   $give_fpx_files_fancy_name_p = 0;


#HTML HEADERS AND FOOTERS
   $html_header = '<html>
<head>
<title>PhotoCD Index</title>
</head>

<body bgcolor=#ffffff text=#000000>
<h2>PhotoCD Index</h2>
<hr>
';
  $html_footer_1 = '
<hr>
';
  # the copyright string from the description file will be sandwiched in between
  $html_footer_2 = '

</body>
</html>
';
#DEFAULT RESOLUTIONS for Img src, big, huge
   $img = 1;
   $big = 3;
   $huge = 4;
########################END PARAMETERS#######################################

#check to ensure that only one description file has been specified, and
#that it is readable

$name = (shift(@ARGV) || &usage); 
#check to see if they are specifying the -indexonly option
if ($name eq "-indexonly") {
    $INDEXONLY = 1;
    $name = (shift(@ARGV) || &usage);
}
(@ARGV == 0) || &usage;
open(INFILE, $name) || die "Unable to open $name\n";

#parse the first five lines (default setup) 
$str = <INFILE>;
($str = &res_check($str)) || die "Bad default resolution format: $str";
$default_resolutions = $str;

($str, $copyright_text) = split(/\|/, <INFILE>);
($str = &res_check($str))|| die "Bad copyright resolution format: $str";
$copyright_resolutions = $str;
chop($copyright_text);

($borderfront, $borderback) = split(/:/, <INFILE>);
($_ = &yes_no_check($borderback)) || 
	die "Border default not correctly specified: $_";
$border = $_;

($sharpfront, $sharpback) = split(/:/, <INFILE>);
($_ = &yes_no_check($sharpback)) || 
	die "Sharpening default not correctly specified: $_";
$sharpen = $_;

#get the directory for the jpeg file location-- used only in the
#index files
($jpeg_image_dir_front, $jpeg_image_dir) = split(/:/, <INFILE>);
$jpeg_image_dir =~ s/\s//g;
# somewhere someone forgot to use the variable "url_stub"
$url_stub = $jpeg_image_dir;

#open handles to the three output files
if(-e $index_filename) {
    print "moving $index_filename to $index_filename.bak\n";
    rename ($index_filename, "$index_filename.bak") || 
	die "unable to rename $index_filename";}
open(INDEX, ">$index_filename") || die "cannot create $index_filename";


if(-e $table_filename) {
    print "moving $table_filename to $table_filename.bak\n";
    rename ($table_filename, "$table_filename.bak") ||die "unable to rename $table_filename";}
open(TABLE, ">$table_filename") || die "cannot create $table_filename";

if(-e $tutorial_filename) {
    print "moving $tutorial_filename to $tutorial_filename.bak\n";
    rename ($tutorial_filename, "$tutorial_filename.bak") ||die "unable to rename $tutorial_filename";}
open(TUTORIAL,">$tutorial_filename") ||die "cannot create $tutorial_filename";

if(-e $fpx_filename) {
    print "moving $fpx_filename to $fpx_filename.bak\n";
    rename ($fpx_filename, "$fpx_filename.bak") ||die "unable to rename $fpx_filename";}
open(FPX, ">$fpx_filename") || die "cannot create $fpx_filename";

open(CONVERT, ">$convert_filename") || die "cannot create $convert_filename";

# add html headers
print INDEX $html_header;
print TABLE $html_header;
print TUTORIAL $html_header;
print FPX $html_header;

#get indications for each individual image

while($_ = <INFILE>) {
	#parse the line and do a cursory check on format
	$_ =~ /^\s*$/ && next;  #if it's a blank line, skip it
	# chop off the trailing carriage return (only if it exists)
	$temp = $_;
	if ( chop($temp) eq "\n" ) { 
	    $_ = $temp;
	}
	($number_on_disk, $target_file_name, $which_resolutions, 
	 $caption, $tech_details, $alt, $tutorial_info) = split(/\|/);

	if ( substr($number_on_disk,0,2) eq "rr" ) {
	    $forced_rotation = 90;
	    # strip off leading two chars
	    $number_on_disk = substr($number_on_disk,2);
	} else {
	    $forced_rotation = 0;
	}
	
	# kill off white space in which_resolutions
	$which_resolutions =~ s/\s//g;
	
	if ($which_resolutions) { #if they specified a new resolution, check it
		&res_check($which_resolutions) || 
		die "Bad resolution in image format: $_"; }
	else {
		$which_resolutions = $default_resolutions;  #otherwise use default
	}
	
	#if they don't specify alt, use caption
	$alt || ($alt = $caption);
	
	#put the image res characters into an array to make looping easier
	@image_resolutions = split(//,$which_resolutions);
	@copyright_resolutions = split(//, $copyright_resolutions);
	#find the orientation for this image- since it doesn't depend on 
	#resolution, use the first size
	$imagefile = &create_pcd_image_filename($number_on_disk, 1);
	$horizontal_p = &horizontal_p($imagefile);
	if ($forced_rotation != 0) {
	    $horizontal_p = !$horizontal_p;
	}

	#jpegfront is without a resolution specification.  we tack that
	#on while iterating through the desired resolutions
	#this makes it slightly more efficient to create the html files
	$jpegfront = &create_jpeg_front($number_on_disk, $target_file_name);
	
	#reset some arrays
	@heights = @widths = ();

	#cycle through the desired resolutions to convert
	for ($i=0; $i<=5; $i++){
	    
	    #calculate height & width ( for the HEIGHT & WIDTH tag values
	    #and for the position parameter calculation)
	    #need to do this for all files, not just extracted ones
	    #so that HEIGHT & WIDTH tags can be calculated
	    
	    #this needs to be calculated once per image because the
	    #values will change depending on the image orientaton.
	    #should consider calculating a "horizontal height/width"
	    #and a "vertical heght/width" array outside the image
	    #description processing loop 

	    #first, check to see if borders are turned off.  if so,
	    #set all border sizes to 0

	    if ($border eq "NO"){
		@y_borders = @x_borders = ();}
 
	    if ($horizontal_p) {   #it's horizontal
		$heights[$i] = ($image_heights[$i] + (2 * $y_borders[$i]));
		$widths[$i] = ($image_widths[$i] + (2 * $x_borders[$i]));
	    } else {  #it's vertical
		$heights[$i] = ($image_widths[$i] + (2 * $y_borders[$i]));
		$widths[$i] = ($image_heights[$i] + (2 * $x_borders[$i]));
	    }
	    # the FPX function needs to know how big the BASE image is
	    if ( $i == 2 ) {
		$base_image_height = $heights[2];
		$base_image_width = $widths[2];
	    }

	    if ($image_resolutions[$i]){  #if they want to pull this size

		#create strings for images
		$imagefile = &create_pcd_image_filename($number_on_disk, $i);
		$jpegfile = &create_jpeg_filename($jpegfront, $i);

		#calculate the position parameters for draw
		$sizeof_copyright = length($copyright_text);

		$draw_height = $heights[$i] - $y_offsets[$i] - 
		    $font_heights[$i];

		$draw_width = $widths[$i] - $x_offsets[$i] - 
		    ($font_widths[$i] * $sizeof_copyright);		   
		
		@full_exec_cmd = &create_full_exec_cmd($i);

		unless ($INDEXONLY) {
		    #call ImageMagick to convert images
		    print "@full_exec_cmd\n";
		    system(@full_exec_cmd) && die "Unable to execute: $!";
		}
		
		#write the commands to a text file that can be src'd
		print CONVERT "@full_exec_cmd\n";
		
	    }
	}

	# we're done with making the JPEGs; let's make the FPX file
	# we pull the regular or Pro PCD file depending on setting
	# of $photo_cd_resolution_for_fpx (5 or 6)

	$draw_height = $heights[$fpx_res_index] - $y_offsets[$fpx_res_index] - 
	    $font_heights[$fpx_res_index];
	
	$draw_width = $widths[$fpx_res_index] - $x_offsets[$fpx_res_index] - 
	    ($font_widths[$fpx_res_index] * $sizeof_copyright);
	
	# don't you just love passing args as global variables -- philg
	# (commenting on ex-girlfriend's Perl code)

	if ( $using_batch_converter_for_fpx_files_p ) {
	    $padded_image_number = sprintf("%4s", $number_on_disk);
	    $padded_image_number =~ s/ /0/g;
	    $fpx_filename = "IMG" . $padded_image_number . '.fpx';
	} else {
	    if ( $give_fpx_files_fancy_name_p ) {
		$fpx_filename = $jpegfront . ".fpx";
	    } else {
		# we're doing the conversion but we're pretending to be 
		# Ho John's batch conversion tool
		$padded_image_number = sprintf("%4s", $number_on_disk);
		$padded_image_number =~ s/ /0/g;
		$fpx_filename = "IMG" . $padded_image_number . '.fpx';
	    }
	    @pcd_to_ppm_exec_cmd = &create_pcd_to_ppm_for_fpx_cmd($fpx_res_index);
	    unless ($INDEXONLY) {
		#call ImageMagick to convert images
		print "@pcd_to_ppm_exec_cmd\n";
		system(@pcd_to_ppm_exec_cmd) && die "Unable to execute: $!";
		print "converting PPM to FPX...\n";
		system("/usr/local/bin/ppmtofpx -o $fpx_filename < $fpx_ppm_scratch_file")
		}
	    #write the commands to a text file that can be src'd
	    print CONVERT "@pcd_to_ppm_exec_cmd\n";
	    print CONVERT "/usr/local/bin/ppmtofpx -o $fpx_filename < $fpx_ppm_scratch_file";
	}

	# we have to produce the .tcl file now
	$tcl_filename = $jpegfront . ".tcl";
	open(ONETCLFILE,">$tcl_filename") ||die "cannot create $tcl_filename";
	print ONETCLFILE "# image number $number_on_disk from $url_stub
# this is the target for a thumbnail JPEG at
# " . $jpeg_image_dir . &create_jpeg_filename($jpegfront,0) . "
# this Tcl file will return HTML with an in-line version of 
# " . $jpeg_image_dir . &create_jpeg_filename($jpegfront,2) . "
# plus links to a 1000x1500 pixel JPEG
# " . $jpeg_image_dir . &create_jpeg_filename($jpegfront,3) . "
# and a FlashPix file, which is a little dicier because 
# I keep moving my servers around (a good reason not to have this
# file just be static).

# the caption for this photo is 

# $caption

# and it will be displayed along with the tech details, if present:

# $tech_details

";

	# we're done printing the Tcl header, let's print the Tcl function calls
	print ONETCLFILE "set the_whole_page [philg_img_target \$conn ";
	# now we print one argument at a time
	print ONETCLFILE '"' . DQ($url_stub) . '" ';
	print ONETCLFILE '"' . DQ($fpx_filename) . '" ';
	print ONETCLFILE '"' . DQ($jpegfront) . '" ';
	print ONETCLFILE '"' . DQ($base_image_width) . '" ';
	print ONETCLFILE '"' . DQ($base_image_height) . '" ';
	print ONETCLFILE '"' . DQ($copyright_text) . '" ';
	print ONETCLFILE '"' . DQ($caption) . '" ';
	print ONETCLFILE '"' . DQ($tech_details) . '" ';
	print ONETCLFILE '"' . DQ($tutorial_info) . '" ';
	print ONETCLFILE ']
ns_return $conn 200 text/html $the_whole_page
';
        close(ONETCLFILE);

#Now that we're done with a line, create/add to the index files.  Here
#we assume that all files will follow the $img $big $huge format (usually
#1, 3, 4 as resolutions
#Note:  this is how the index is created even if one or more of the {1,3,4}
#resolutions are not extracted from the PCD

	#create/add to index.html
	$index_entry = &create_index_entry($jpegfront);
	print INDEX $index_entry;

	#create/add to index-table.html
	$table_entry = &create_table_entry($jpegfront);
	print TABLE $table_entry;

	#create/add-to index-tutorial.html
	$tutorial_entry = &create_tutorial_entry($jpegfront);
	print TUTORIAL $tutorial_entry;

	$fpx_entry = &create_fpx_index_entry($jpegfront);
	print FPX $fpx_entry

}

#add html footers & copyright

print INDEX $html_footer_1 . $copyright_text . $html_footer_2;
print TABLE $html_footer_1 . $copyright_text . $html_footer_2;
print TUTORIAL $html_footer_1 . $copyright_text . $html_footer_2;



#close up all the files
close(INFILE);
close(INDEX);
close(TABLE);
close(TUTORIAL);
close(FPX);
close(CONVERT);

#SUBS
sub usage {
    die "Usage: $0 {-indexonly} <filename>\n";
}

sub res_check {
    local($_) = @_;
    s/\s//g;  		#strip off whitespace
    /[01]{6}/ || ($_ = "");	#make sure format is 6 chars from (0,1)
    return $_;
}

sub yes_no_check {
    local($_) = @_;
    s/\s//g;			#strip whitespace
    tr/a-z/A-Z/;			#translate to all uppercase
    (/YES/ || /NO/) || ($_ = "");	#make sure flag is either YES or NO
    return $_;
}

# is the image horizontal?  If so, return 1

sub horizontal_p {
    local($name, $buf, $check1, $check2, $rotate, $trotate, $retval);
    $name = $_[0];
    open (PCDFIL, $name) || die ("$name: $!\n");
    read(PCDFIL, $buf, 3*0x800, 0);

    $check1 = substr($buf, 0, 7);
    $check2 = substr($buf, 0x800, 3);

    if (($check1 ne "PCD_OPA") && ($check2 ne "PCD")) {
	die "$name: not a PCD image file";
    }
    
    $rotate = substr($buf, 0x0e02, 1);
    $trotate = (0x0003 & ord($rotate));
    
    $retval = ($trotate == 1 || $trotate == 3) ? 1 : 0;
    
    close(PCDFIL);
    
    return $retval;
}


sub create_pcd_image_filename{
    local($num, $res) = @_;
    local($retname);
    # pad $num with leading zeros to 4-characters
    $num = sprintf("%4s", $num);
    $num =~ s/ /0/g;
    $retname = $pcd_image_directory . "IMG" .$num . '.PCD';
    if ( $pcd_image_filenames_contain_semicolon_p ) {
	$retname .= ";1";
    }

    return $retname;
}


# this returns something like "philip-and-alex-on-bed-1"

sub create_jpeg_front{
    local($num, $name) = @_;
    local($retname);
    if($name =~ /^\s*$/){     #if it's all whitespace
	$retname = $num; }
    else {
	$retname = $name . "-" . $num;
    }
    return $retname;
}


sub create_jpeg_filename{
    local($name, $res) = @_;
    local($retname);
    #the indices run from 0-5, but we want the name from 1-6
    $res++;
    $retname = $name . '.' . $res . '.' . "jpg";
    return $retname;
}

sub create_tutorial_entry{ 
    local($name) = @_; 
    local($entry, $altstr); 

    if ($alt){
	$altstr = '" ALT="' . $alt . '"';}
    else{
	$altstr = '"';}
$entry =
    "<table><tr><td>\n" . '<a href="' . $jpeg_image_dir . $name
    . ".$big.jpg" . '"><img HEIGHT=' . $heights[($img - 1)] . ' WIDTH='
    . $widths[($img - 1)] . ' src="' . $jpeg_image_dir . $name . ".$img.jpg" . $altstr . '></a>' . "\n<br>\n<a href=". '"'. $jpeg_image_dir .$name
    . ".$huge.jpg" . '">BIG</a>'
    . "\n<td>\n$caption\n<p>\n$tech_details\n<p>\n$tutorial_info\n</tr></table>\n\n";
    
    return $entry;


}

sub create_table_entry{ 
    local($name) = @_; 
    local($entry, $altstr); 


    if ($alt){
	$altstr = '" ALT="' . $alt . '"';}
    else{
	$altstr = '"';}

$entry =
    "<table><tr><td>\n" . '<a href="' . $jpeg_image_dir .$name
    . ".$big.jpg" . '"><img HEIGHT=' . $heights[($img -1)] . ' WIDTH='
    . $widths[($img - 1)] . ' src="' . $jpeg_image_dir .$name . ".$img.jpg" . $altstr. '></a>' . "\n<br>\n<a href=". '"'. $jpeg_image_dir .$name
    . ".$huge.jpg" . '">BIG</a>'
    . "\n<td>\n$caption\n</tr></table>\n\n"; 

    return $entry;

}

sub create_index_entry{ 
    local($name) = @_; 
    local($entry, $height, $width, $altstr);
    $height = $heights[($img - 1)];
    $width = $widths[($img - 1)];

    
    if ($alt){
	$altstr = '" ALT="' . $alt . '"';}
    else{
	$altstr = '"';}

$entry = '<a href="' . $jpeg_image_dir . "$name" . ".$big.jpg" . '"><img HEIGHT=' . $height
    . ' WIDTH=' . $width . ' src="' . $jpeg_image_dir . "$name" . ".$img.jpg" . $altstr . '></a>' . "\n<a href=". '"'. $jpeg_image_dir . "$name"
    . ".$huge.jpg" . '">BIG</a>' . "\n\n"; 

    return $entry;
}

sub create_fpx_index_entry{ 
    local($name) = @_; 
    local($entry, $height, $width, $altstr);
    $height = $heights[($img - 1)];
    $width = $widths[($img - 1)];

    
    if ($alt){
	$altstr = '" ALT="' . $alt . '"';}
    else{
	$altstr = '"';}

$entry = '<a href="' . $jpeg_image_dir . "$name" . ".tcl" . '"><img HEIGHT=' . $height
    . ' WIDTH=' . $width . ' src="' . $jpeg_image_dir . "$name" . ".$img.jpg" . $altstr . '></a>' . "\n\n"; 

    return $entry;
}

sub create_full_exec_cmd{
    local($i) = @_;
    local(@retval, $interlace_cmd, $sharpen_cmd, $border_cmd, 
	  $bordercolor_cmd, $comment_cmd, $font_cmd, $pen_cmd, $draw_cmd,
	  $display_cmd, $pcd_name, $jpeg_name);

    if ( $forced_rotation == 0 ) {
	$interlace_cmd = " -interlace $interlaces[$i]";
    } else {
	$interlace_cmd = " -rotate $forced_rotation -interlace $interlaces[$i]";
    }
    
    if ($sharpen eq "YES"){
	$sharpen_cmd = " -sharpen $sharpens[$i]";}
    
    if ($border eq "YES"){
	$border_cmd = " -border $x_borders[$i]x$y_borders[$i]";
	$bordercolor_cmd = " -bordercolor $border_colors[$i]";}

    $comment_cmd = " -comment \'$copyright_text\'";

    if($copyright_resolutions[$i]){
	$display_cmd = " -display $x_display";
	$draw_cmd = 
	    " -draw \'text $draw_width,$draw_height \"$copyright_text\"'";
	$font_cmd = " -font $font_widths[$i]x$font_heights[$i]";
	$pen_cmd = " -pen $pen_colors[$i]";
    }

    #we index from 0-5, but want the filename from 1-6
    $i++;
    $pcd_name = " '$imagefile\[$i]'";

    $jpeg_name = " $jpegfile";

    @retval = ($exec_cmd .  $interlace_cmd . $sharpen_cmd .
	       $bordercolor_cmd . $border_cmd . $comment_cmd . $font_cmd . 
	       $display_cmd . $pen_cmd . $draw_cmd . $pcd_name . $jpeg_name);

    return @retval;
}


sub create_pcd_to_ppm_for_fpx_cmd{
    local($i) = @_;
    local(@retval, $interlace_cmd, $sharpen_cmd, $border_cmd, 
	  $bordercolor_cmd, $comment_cmd, $font_cmd, $pen_cmd, $draw_cmd,
	  $display_cmd, $pcd_name, $jpeg_name);

    if ( $forced_rotation == 0 ) {
	$interlace_cmd = " -interlace $interlaces[$i]";
    } else {
	$interlace_cmd = " -rotate $forced_rotation -interlace $interlaces[$i]";
    }
    
    if ($sharpen eq "YES"){
	$sharpen_cmd = " -sharpen $sharpens[$i]";}
    
    if ($border eq "YES"){
	$border_cmd = " -border $x_borders[$i]x$y_borders[$i]";
	$bordercolor_cmd = " -bordercolor $border_colors[$i]";}

    $comment_cmd = " -comment \'$copyright_text\'";

    if($copyright_resolutions[$i]){
	$display_cmd = " -display $x_display";
	$draw_cmd = 
	    " -draw \'text $draw_width,$draw_height \"$copyright_text\"'";
	$font_cmd = " -font $font_widths[$i]x$font_heights[$i]";
	$pen_cmd = " -pen $pen_colors[$i]";
    }

    #we index from 0-5, but want the filename from 1-6
    $i++;
    $pcd_name = " '$imagefile\[$i]'";

    @retval = ($exec_cmd .  $interlace_cmd . $sharpen_cmd .
	       $bordercolor_cmd . $border_cmd . $comment_cmd . $font_cmd . 
	       $display_cmd . $pen_cmd . $draw_cmd . $pcd_name . " " . $fpx_ppm_scratch_file);

    return @retval;
}

# take double quotes and escape them with \ so that Tcl can read strings
# also escape dollar signs

sub DQ { 
    local($_) = @_;
    s/"/\\"/g;
    s/\$/\\\$/g;
    return $_;
}