#! /usr/local/bin/perl
#
# $Id: webmagick.in,v 1.154 2006/07/26 03:36:05 ache Exp $
#
# You are looking at the main PERL script for WebMagick, a package to
# intelligently create HTML and JavaScript index files and imagemaps
# corresponding to a directory tree of image files.
#
# Copyright Bob Friesenhahn (bfriesen@simple.dallas.tx.us) 1996, 1997,
# 1998, 1999, 2000
#
# This work may be used for any purpose, public or private, provided
# that this work or derivations thereof are attributed to its author.
# Full copyrights to this work are maintained by its author to ensure
# that rights so bestowed are not abridged.
#
# NOTE: This program has a substantial manual. Considerable time has
# been spent writing it so please at least skim through it before
# asking questions.
#
# Requires the ImageMagick, PerlMagick, and PERL 5 packages. May
# possibly execute correctly (but with reduced performance) with
# package versions as old as:
# ImageMagick -- 3.8.4
# PerlMagick -- 1.12
# PERL -- 5.003
#
# But always tested by the author with recent versions. At the last
# update of these notes (December 19, 1998) the latest versions tested
# were:
# ImageMagick -- 4.1.6
# PerlMagick -- 1.55
# PERL -- 5.004_04
#
# While some effort is made to ensure that WebMagick will execute under
# older package versions, the author does not use these versions so
# he will only know to correct incompatabilities if they are brought
# to his attention.
#
# The latest version of WebMagick is always available from the URL
# "ftp://ftp.simplesystems.org/pub/WebMagick". Keep track of
# the latest WebMagick developments by visiting the WebMagick web page
# at "http://webmagick.sourceforge.net/".
#
# Obtain ImageMagick from "ftp://ftp.wizards.dupont.com/pub/ImageMagick"
# or visit the ImageMagick web page at
# "http://www.wizards.dupont.com/cristy/ImageMagick.html".
#
# Obtain PerlMagick from
# "ftp://ftp.wizards.dupont.com/pub/ImageMagick/perl" or visit the
# PerlMagick web page at
# "http://www.wizards.dupont.com/cristy/www/perl.html".
#
# ImageMagick and PerlMagick are written by John Cristy (cristy@dupont.com).
# WebMagick would not be possible without his wonderful software. The
# author greatly appreciates Cristy's assistance with ironing out PerlMagick's
# (or WebMagick's bugs) during the development of WebMagick.
#
# Suggestions, moral support, and patches were provided by Anthony
# Thyssen (anthony@cit.gu.edu.au). His help is very much appreciated.
#
use locale;
use POSIX qw(strftime _exit);
use Cwd;
# If your PERL barfs, you may need to comment one or more of the following
# lines out:
use strict 'refs'; # Be picky about references
use strict 'subs'; # Be picky about subroutines
use strict 'vars'; # Be picky about variable scope (explicit globals)
#
# Global variable declarations
#
my (
%RGBDB, # RGB color database
@allFiles, # List of files in current directory
@allImageFiles, # List of all source file names in directory
@cacheFiles, # List of files in the image cache
@lowresFiles, # List of files in the image lowres cache
$currentDirectory, # Current directory (absolute)
$doMontage, # Set to true if montage must be generated
$doPageHtml, # Set to true if per-page HTML files must be generated
%dirOrder, # Order directories are listed in dirindex file
%dirTitles, # Directory name to title index
%fileNames, # Hash of generated file names
%frameTargets, # Frame targets
@global_option_files, # List of rc files to source before all others
$haveImages, # Set to true if there are images in directory
$haveReadme, # Set to true if there is a README file in directory
%htmlOpts, # Options that effect HTML output
$htmlParams, # String form of HTML parameters
%iconImageSizes, # Size of icons
%iconImageUrls, # URLs for icons
$icon_base_url, # URL to icon directory
$icon_dir_path, # Path to icon directory
%icon_paths, # Paths to icon files
@imageThumbCoords, # Thumbnail imagemap coordinates
$imageFrameLink, # URL to use as source for image frame
%imageLabels, # Labels to use for images (if specified)
%imageCaptions, # Captions for perimage HTML
%tableImageLabels, # labels to use in tables
%imageOrder, # Order that images occur in imgindex file
$inChild, # Set to true if this process is a child
$currentDate,
@montageImages, # List of per-page montage image names
@montageImageSizes, # List of per-page montage image sizes
$montageArguments, # PerlMagick Montage() arguments
$montageParameters, # Montage() arguments plus others that effect montage output
$netscapeColormap, # PerlMagick image object representing Netscape color cube
$numPages, # Number of pages to represent current directory
$opt_address,
$opt_allowconfig,
$opt_anonymous,
$opt_cache,
$opt_cachedir,
$opt_cacheformat,
$opt_cachegeom,
$opt_cachemin,
$opt_centerfooter,
$opt_lowres,
$opt_lowresdir,
$opt_lowresformat,
$opt_lowresgeom,
$opt_lowresmin,
$opt_coloralink,
$opt_colorback,
$opt_colorfore,
$opt_colorlink,
$opt_colorvlink,
$opt_columns,
$opt_date,
$opt_debug,
$opt_dircoloralink,
$opt_dircolorback,
$opt_dircolorfore,
$opt_dircolorlink,
$opt_dircolorvlink,
$opt_dirfmt,
$opt_dirhtmlext,
$opt_dirindexname,
$opt_forcecache,
$opt_forcelowres,
$opt_forcegif,
$opt_forcejpeg,
$opt_forcehtml,
$opt_forcemontage,
$opt_forcenouplink,
$opt_forceuplink,
$opt_frame_name_dirview,
$opt_frame_name_imageview,
$opt_frame_name_thumbview,
$opt_frame_name_top,
$opt_frameborder,
$opt_frameddirfmt,
%opt_framefmt,
%opt_framefmt_frames,
$opt_framemarginheight,
$opt_framemarginwidth,
$opt_frames,
$opt_framestyle,
$opt_htmlext,
$opt_header,
$opt_footer,
$opt_help,
$opt_htimage,
$opt_iconbase,
$opt_iconpath,
%opt_icons,
$opt_ignore,
$opt_ignorefp,
$opt_indexinfo,
$opt_imgindexname,
$opt_indexname,
$opt_javascript,
$opt_jpegquality,
$opt_lockfile,
$opt_mapnetscape,
$opt_maptype,
$opt_maxgif,
$opt_metaauthor,
$opt_metacharset,
$opt_metaclassification,
$opt_metadescription,
$opt_metaexpires,
$opt_metakeywords,
$opt_msg_copyright,
$opt_msg_date_format,
$opt_msg_directories,
$opt_msg_directory_navigator,
$opt_msg_images,
$opt_msg_index_of_directory,
$opt_msg_index_of_files,
$opt_msg_index_through,
$opt_msg_next,
$opt_msg_pause,
$opt_msg_page_navigator,
$opt_msg_page_updated_on,
$opt_msg_prev,
$opt_msg_produced_by,
$opt_msg_readme,
$opt_msg_up,
$opt_pageindexname,
$opt_prefixpath,
$opt_prune,
$opt_readfailhook,
$opt_readme,
$opt_readmevisible,
$opt_recurse,
$opt_rgbdb,
$opt_rootpath,
$opt_rows,
$opt_serversidemap,
$opt_skip,
$opt_srcdir,
$opt_stylesheet, # URL to a CSS to use
$opt_tables,
$opt_tablebackcolor,
$opt_fancytables,
$opt_fancytableheight,
$opt_tables_bottom,
$opt_tables_params,
$opt_tables_top,
$opt_thumbbackground,
$opt_thumbbordercolor,
$opt_thumbborderwidth,
$opt_thumbcompose,
$opt_thumbfont,
$opt_thumbforeground,
$opt_thumbframe,
$opt_thumbframebgcolor,
$opt_thumbframecolor,
$opt_thumbgeometry,
$opt_thumbgravity,
$opt_thumblabel,
$opt_thumblabelwidth,
$opt_thumbmattecolor,
$opt_thumbposthook,
$opt_thumbprehook,
$opt_thumbshadow,
$opt_thumbtexture,
$opt_thumbtransparent,
$opt_title,
$opt_verbose,
$opt_version,
$opt_webmagickrc, # Per-directory WebMagick rc file name
$opt_zoomfilter,
$opt_pichtml,
$opt_pichtmlaltend,
$opt_pichtmlaltstart,
$opt_pichtmlbottom,
$opt_pichtmlext,
$opt_pichtmllink,
$opt_pichtmlnav,
$opt_pichtmlupfirst,
$opt_pichtmlputtitle,
$opt_pichtmltitletop,
$opt_pichtmltarget,
$opt_pichtmltitleend,
$opt_pichtmltitlestart,
$opt_pichtmltop,
$opt_edgelinksindex,
$pageStatusTime, # Time status file last modified
$pageNumber, # Current page number
$pathSep, # OS-specific path separator
$perlVarsLoaded, # Set to one when directory status file sourced
$perlVarsVersion, # version used for last file generation
$prefix, # installation directory
$requiredPerlVarsVersion, # version required. If less than this, regenerate
%relativePathCache, # Relative path cache
$sourceDirectory, # Directory to process
%thumbImageSizes, # thumbnail image sizes
@imageNames, # List of source file names for current page
$startTime, # Clock time when program started
%dirJsLink, # Link name to use when changing directories via JavaScript
@dirNames, # List of directories under this directory
$pageTitle, # Title for current page
%webmagickInfo # WebMagick version information as a hash
);
###########################################################################
# Internal Default Options
###########################################################################
#
#WebMagickRcTop -- Don't remove this line
#
# Copy the webmagickrc file to your home directory under the name
# .webmagickrc. Any default definitions you want to override should be
# uncommented in this file and modified.
#
# Navigation Icon Paths and URLs
# Specify the path and file name for the navigation icons.
# !!!MUST EDIT OR OVERRIDE!!!
#
$opt_rootpath = '/usr/local/www/data'; # Directory Path to top of html tree
# Needed to determine relative paths to images
$opt_prefixpath = ''; # Path or URL to prepend to root URL
# Not used if local relative paths used
$opt_iconpath = 'webmagick';
# Relative path under rootpath / prefixpath
$opt_iconbase = '';
# Global icons base URL, if not empty
$prefix = '/usr/local'; # installation directory
#
# Server-side imagemap settings
# !!!MAY NEED TO EDIT OR OVERRIDE!!!
#
$opt_htimage=''; # Base URL to server-side imagemap CGI
# On some systems this is /cgi-bin/imagemap
# Set to '' to use a ".map" URL with relative
# URLs (latest NCSA & Apache)
$opt_maptype='ncsa'; # Maptype must be 'cern' or 'ncsa'. If you are
# using Apache, specify 'ncsa'.
$opt_serversidemap = 0; # Enable server-side maps writting
$perlVarsVersion = 0; # default this to 0 for it to be overidden by appropriate status files
$requiredPerlVarsVersion = 2.3; # need this version to avoid regeneration of files
#
# RC files
#
#
# Name of per-directory rc file
$opt_webmagickrc = '.webmagickrc';
# global rc files
@global_option_files = ("${prefix}/etc/webmagickrc", "$ENV{'HOME'}/${opt_webmagickrc}");
#
# Lockfile to keep from doing same directory in two processes
#
$opt_lockfile = '.webmagick.lockfile';
# File naming
$opt_indexname = 'index.html'; # Per-directory master index file
$opt_readme = 'README.html';# Name of welcome page README file ('' = none)
$opt_pageindexname = '.index'; # Base name of secondary index files
$opt_dirindexname = '.dirindex'; # Subdirectory Title cross-reference
# dirname Directory Title
$opt_dirhtmlext = '.html'; # Use .shtml for SSI
$opt_imgindexname = '.imgindex'; # Image name to label cross-reference file
if ($^O eq "MSWin32")
{$pathSep = "\\"; }
else
{$pathSep = "/"; }
#
# HTML color and background image related options
#
# X11 RBG color database (rgb.txt) location
# Entries in this file have the form:
# Red Green Blue Color-name
# where color intensities are specified in decimal.
# e.g. 250 240 230 linen
$opt_rgbdb='/usr/X11R6/lib/X11/rgb.txt';
#
# Page Frame & non-framed pages
$opt_colorback = '#CCCCCC'; # Color -- Background
$opt_colorfore = 'black'; # Color -- Foreground
$opt_coloralink = '#FF0000'; # Color -- Active link
$opt_colorlink = '#0000EE'; # Color -- Link
$opt_colorvlink = '#551A8B'; # Color -- Visited link
#
# Directory frame (Leave options empty ('') to use page frame colors
$opt_dircolorback = '#B2B2B2'; # Color -- Background
$opt_dircolorfore = 'black'; # Color -- Foreground
$opt_dircoloralink = ''; # Color -- Active link
$opt_dircolorlink = ''; # Color -- Link
$opt_dircolorvlink = ''; # Color -- Visited link
$opt_stylesheet = ''; # no default stylesheet
$opt_allowconfig = 0; # default to not allowing configuration
# General options
$opt_anonymous = 0; # Don't show address & copyright info on pages
$opt_debug = 0; # Debug flag (default off)
$opt_recurse = 0; # Recursivally apply webmagick (default off)
$opt_prune = 0; # Do Not recurse into subdirectories (off)
$opt_ignore = 0; # Do not webmagick this directory
# but still recurse into sub-directories
$opt_ignorefp = 1; # ignore _* special FrontPage directories (on)
$opt_indexinfo = 1; # Put "Index of files"
$opt_srcdir = '.'; # Source directory path (current directory)
$opt_verbose = 0; # Verbose flag (default off)
$opt_forcecache = 0; # Force update of cached thumbnails
$opt_forcelowres = 0; # Force update of cached low resolution images
$opt_forcehtml = 0; # Force HTML files to be generated (default off)
$opt_forcemontage = 0; # Force montage (default off)
$opt_forcegif = 0; # Force GIF imagemaps (default off)
$opt_forcejpeg = 0; # Force JPEG imagemaps (default off)
$opt_forcenouplink = 0; # Force there to be no uplink in directory index list
$opt_forceuplink = 0; # Force there to be an uplink in directory index list
# (i.e. even if we didn't generate ../index.html)
$opt_jpegquality = 70; # Quality for JPEG imagemaps
$opt_help = 0; # Display usage message
$opt_version = 0; # Display version info
$opt_htmlext = '.html'; # Use .shtml for SSI
$opt_header = '
'; # Imagemap extra page header (HTML)
$opt_footer = ' '; # Imagemap extra page footer (HTML)
$opt_javascript = 0; # Enable JavaScript output
$opt_readmevisible = 0; # Make README.html be first page.
$opt_title = ''; # Page title (blank provides default title)
$opt_tables = 0; # disable tables
$opt_tablebackcolor = '#000000'; # table background color
$opt_fancytables = 0; # use a fancier table for index pages
$opt_fancytableheight = 28; # the height of the fancy table border
$opt_tables_bottom = ''; # HTML after table contents
$opt_tables_params = 'WIDTH="90%"'; # table HTML parameters
$opt_tables_top = ''; # HTML before table contents
$opt_address = ''; # Additonal address info for bottom of
# imagemap page
$opt_centerfooter = 0; # Center the footer text
$opt_date = 1; # Output updates date
$opt_pichtml = 0; # Write separate HTML for each picture
$opt_pichtmlaltend = ''; # Some words to append to ALT
$opt_pichtmlaltstart = ''; # Some words to prepend to ALT
$opt_pichtmlbottom = '';
$opt_pichtmlext = '.html'; # Use .shtml for SSI
$opt_pichtmllink = ''; # Where to link pic
$opt_pichtmlnav = 0; # Write navigation into pic's HTML
$opt_pichtmlupfirst = 1; # Put up button before next/prev
$opt_edgelinksindex = 0; # End links link back to index
$opt_pichtmlputtitle = 1; # Write picture title
$opt_pichtmltitletop = 1; # Put picture title at top
$opt_pichtmltarget = '';
$opt_pichtmltitleend = ''; # End tags for picture title
$opt_pichtmltitlestart = ''; # Start tags for picture title
$opt_pichtmltop = '
';
#
# ImageMagick Montage settings
#
$opt_maxgif = 30000; # Maximum GIF imagemap size before
# trying JPEG
$opt_columns = 6; # Max number of columns in montage grid
$opt_rows = 4; # Max number of rows in montage grid
$opt_mapnetscape = 0; # Map GIFs to Netscape 216-color cube
$opt_thumbtexture = 'false'; # Texture to tile onto the image background
$opt_thumbbackground = '#CCCCCC'; # Montage background color
$opt_thumbborderwidth = 0; # Thumbnail border width (pixels)
$opt_thumbframebgcolor = 'black'; # Inside of Frame color. Unused if no frame
$opt_thumbframecolor = '#CCCCCC'; # Color -- Frame Color
$opt_thumbtransparent = $opt_thumbbackground; # Color -- Image Transparency
$opt_thumbcompose = 'atop'; # Thumbnail image composition operation
$opt_thumbfont = 'courier'; # Label font
$opt_thumbforeground = 'black'; # Montage foreground color
$opt_thumbframe = 'false'; # Geometry of frame around thumbnail
# (default false)
$opt_thumbgeometry = '106x80+2+2>'; # Size of thumbnail images (width x height)
$opt_thumbgravity = 'Center'; # Direction thumbnail gravitates to
# (default Center)
$opt_thumblabel = '%f\n%wx%h\n%b'; # Default format for thumbnail text label
$opt_thumblabelwidth = 13; # Label width past which truncation occurs
$opt_thumbshadow = 'false'; # Enable decorative shadow under thumbnail
# (default disabled)
$opt_zoomfilter = 'Mitchell'; # Zoom (size reduction) filter
# (Box/Triangle/Mitchell)
#
# Hooks to add code to key places in WebMagick
#
$opt_thumbprehook = ''; # PerlMagick commands to execute on original
# prior reducing to thumbnail size
$opt_thumbposthook = ''; # PerlMagick commands to execute on image
# after reduction to thumbnail size
$opt_readfailhook = ''; # PERL commands to execute if reading image
# fails due to image corruption
#
# Caching related options
#
# Note: See below about sharing cache with 'xv'
# If caching is turned on, the montage grid will continue to be
# controlled by opt_thumbgeometry but the thumbnail size will be
# controlled by opt_cachegeom
$opt_cache = 1; # Cache thumbnails
$opt_cachedir = '.cache'; # Subdirectory to cache thumbnails in
$opt_cacheformat = 'JPEG'; # Format to use for thumbnails
$opt_cachegeom = $opt_thumbgeometry; # Thumbnail geometry
$opt_cachemin = 300*200; # Smallest image to cache in total pixels
# (width * height). Images smaller than
# this size will not be cached.
#PMF: I have added a low resolution of the pictures, by default 640x480
$opt_lowres = 1; # Cache low resolution images
$opt_lowresdir = '.640x480'; # Subdirectory to cache low resolution images in
$opt_lowresformat = 'JPEG'; # Format to use for low resolution images
$opt_lowresgeom = '640x480+2+2>'; # Size of low resolution images (width x height)
$opt_lowresmin = 640*480; # Smallest image to cache in total pixels
# (width * height). Images smaller than
# this size will not be cached.
# Uncomment these options to share cache with John Bradley's 'xv'
# (Visual Schnauzer format) NOTE: The 'xv' thumbnail format only
# supports 128 absolute colors so expect some montage thumbnail
# degradation when using 'xv' thumbnails.
#
#
# $opt_cacheformat = 'P7'; # 'xv's thumbnail format
# $opt_cachegeom = '80x60'; # 'xv's default thumbnail geometry is 80x60
# $opt_cachedir = '.xvpics'; # 'xv's thumbnail cache directory
# $opt_cachemin = 0; # Cache all thumbnails
#
# Uncomment remaining to obtain 'xv's Visual Schnauzer "look and feel"
#
# $opt_thumbgeometry = '92x72+2+2>';
# $opt_thumblabel = '%f';
# $opt_thumblabelwidth = 12;
# $opt_thumbgravity = 'South';
#
# Frame related options
#
$opt_frames = 1; # Use frames
$opt_framemarginwidth = 1; # Pixels allocated to frame margin in horizontal direction
$opt_framemarginheight = 1; # Pixels allocated to frame margin in vertical direction
$opt_frameborder = 1; # Enable (1) or disable (0) decorative frame borders
$opt_framestyle = 1; # Frame style to use (out of those available)
#
# Meta-tag defaults
#
$opt_metaauthor = ''; # Page author
$opt_metacharset = ''; # Page character set
$opt_metaclassification = ''; # Page classification
$opt_metadescription = ''; # Page description
$opt_metaexpires = ''; # Date page expires (e.g "Tue, 20 Aug 1996 14:25:27 GMT")
$opt_metakeywords = 'WebMagick'; # Key words
#
# Messages customization defaults
#
$opt_msg_copyright = 'Copyright ';
$opt_msg_date_format = '%B %e, %Y'; # See strftime(3)
$opt_msg_directories = 'Directories';
$opt_msg_directory_navigator = 'Directory Navigator';
$opt_msg_images = 'Images';
$opt_msg_index_of_directory = 'Index of directory';
$opt_msg_index_of_files = 'Index of files ';
$opt_msg_index_through = 'through';
$opt_msg_next = 'Next';
$opt_msg_pause = 'Pause';
$opt_msg_page_navigator = 'Page Navigator';
$opt_msg_page_updated_on = 'Page updated on';
$opt_msg_prev = 'Prev';
$opt_msg_produced_by = 'Produced by';
$opt_msg_readme = 'ReadMe';
$opt_msg_up = 'Up';
#
# Hash table of images used -- image size read internally by webmagick
#
# $opt_icons{'background'} = 'thumbs.jpg'; # Thumbnail frame background image
# $opt_icons{'dirbackground'} = 'dir.jpg'; # Directory frame background image
$opt_icons{'config'} = 'blue_c.gif'; # Configuration button
$opt_icons{'prev'} = 'blue_prev.gif'; # Previous
$opt_icons{'prev_gray'} = 'gray_prev.gif'; # Previous (grayed out)
$opt_icons{'next'} = 'blue_next.gif'; # Next
$opt_icons{'pause'} = 'blue_pause.gif'; # Next
$opt_icons{'next_gray'} = 'gray_next.gif'; # Next (grayed out)
$opt_icons{'up'} = 'blue_up.gif'; # Up
$opt_icons{'help'} = 'blue_readme.gif'; # Help Readme File
# $opt_icons{'ft_top'} = 'ft_top.gif'; # Fancy table top
# $opt_icons{'help'} = 'blue_help.gif'; # Help Alternative (Question)
# $opt_icons{'dir'} = 'blue_dir.gif'; # Directory List Icon (See below)
# $opt_icons{'ball'} = 'blue_ball.gif'; # A ball matching other icons
$opt_icons{'frame-style-1'} = 'frame-style-1.jpg';
$opt_icons{'frame-style-2'} = 'frame-style-2.jpg';
$opt_icons{'frame-style-3'} = 'frame-style-3.jpg';
$opt_icons{'frame-style-4'} = 'frame-style-4.jpg';
#
# WebMagickRcBottom -- Don't remove this line
#
# Format Templates
#
# WARNING: This is for expert web and perl programmers only do not
# modify unless you know what you are doing. To learn how frames work,
# read the pages under the URL
# http://home.netscape.com/assist/net_sites/frames.html
#
# Extra Images can be added to the above hash table and then used in
# the following format options. For example the 'dir' icon above can
# be uncommented then the following lines added below. WARNING: this
# is only useful if $opt_indexname is something else.
#
#
#
#
# Dir Listing
#
#
# Template for the Frame definition
# This allows adding frames, changing geometry, etc.
#
# Frame Target Names
$opt_frame_name_top="_top"; # Reload frames entirely
#$opt_frame_name_self="_self"; # Link to this (same) frame
#$opt_frame_name_parent="_parent"; # Link to parent frame
$opt_frame_name_dirview="dirview"; # Directory nav frame
$opt_frame_name_thumbview="thumbview"; # Imagemap (image selection) frame
$opt_frame_name_imageview="imageview"; # Image viewing frame (three frames)
#
# Simple two frame screen with directories listed in the left
# frame and imagemap/README displayed in the right frame.
#
# -------------
# | | |
# | | |
# | | |
# | | |
# | | |
# | | |
# -------------
$opt_framefmt{1}=
'
';
$opt_framefmt_frames{1}=2; # Number of frames expressed by this frame format
# Three frame screen with directories listed in top-left frame,
# imagemap displayed in bottom-left frame, and README/Images
# displayed in full-height right-hand frame.
# -------------
# | | |
# | | |
# |--| |
# | | |
# | | |
# | | |
# -------------
$opt_framefmt{2}=
'
';
$opt_framefmt_frames{2}=3; # Number of frames expressed by this frame format
# Three frame screen with directories listed in left frame,
# imagemap displayed in top-right frame, and README/Images
# displayed in lower-right frame.
# -------------
# | | |
# | |----------|
# | | |
# | | |
# | | |
# | | |
# -------------
$opt_framefmt{3}=
'
';
$opt_framefmt_frames{3}=3; # Number of frames expressed by this frame format
# Three frame screen with directories listed in lower-left frame,
# imagemap displayed in top frame, and README/Images displayed in
# lower-right frame.
# -------------
# | |
# |-- ----------|
# | | |
# | | |
# | | |
# | | |
# -------------
$opt_framefmt{4}=
'
';
$opt_framefmt_frames{4}=3; # Number of frames expressed by this frame format
#
# Template for the Directory Index Frame
#
$opt_frameddirfmt='
${uphtml}
${helphtml}
${nexthtml}
${dirhtml}
';
#
# Template for Non-Framed Top Index Page ($opt_indexname)
#
$opt_dirfmt='\n${opt_msg_directory_navigator} ...
${uphtml}
${helphtml}
${dirhtml}
${pageindexhtml}
';
# Save revision to variable
$webmagickInfo{'version'} = '2.03pre3';
###########################################################################
# End of Internal Default Options
###########################################################################
select(STDERR); $| = 1; # Make stderr unbuffered
select(STDOUT); $| = 1; # Make stdout unbuffered
umask( 022 ); # Sets default file mode 644
$startTime = time; # Save start time
$inChild = 0;
# Set signal handler to gracefully abort (hah!). Handle signal
# induced exits properly. Only the parent prints a status message.
sub sig_handler {
my ($sig) = @_;
if( ! $inChild ) {
syswrite (STDERR, "\nCaught signal SIG", 18);
syswrite (STDERR, "$sig", length("$sig"));
syswrite (STDERR, " -- aborting ...\n", 17);
}
_exit(1);
}
$SIG{'HUP'} = \&sig_handler;
$SIG{'INT'} = \&sig_handler;
$SIG{'QUIT'} = \&sig_handler;
# Allow global options files to override defaults set above (but not
# command line options)
my $goptfile;
foreach $goptfile (@global_option_files) {
sourceRcFile( $goptfile )
|| die("Error sourcing ${goptfile}\n");
}
# Eval per-directory rc files if they exist. Rc files are evaluated
# for each directory starting from $opt_rootdir until the current
# directory is reached. This supports "additive" behavior for a branch
# in the tree.
$currentDirectory=cwd(); # Get current (absolute) directory
evaluateRcFiles();
#
# We don't really like command line options but we'll support them anyway. :-)
#
use Getopt::Long;
if ( ! GetOptions(
'address=s' => \$opt_address,
'centerfooter!' => \$opt_centerfooter,
'anonymous!' => \$opt_anonymous,
'cache!' => \$opt_cache,
'cachedir=s' => \$opt_cachedir,
'cacheformat=s' => \$opt_cacheformat,
'cachegeom=s' => \$opt_cachegeom,
'cachemin=i' => \$opt_cachemin,
'lowres!' => \$opt_lowres,
'lowresdir=s' => \$opt_lowresdir,
'lowresformat=s' => \$opt_lowresformat,
'lowresgeom=s' => \$opt_lowresgeom,
'lowresmin=i' => \$opt_lowresmin,
'coloralink=s' => \$opt_coloralink,
'colorback=s' => \$opt_colorback,
'colorfore=s' => \$opt_colorfore,
'colorlink=s' => \$opt_colorlink,
'colorvlink=s' => \$opt_colorvlink,
'allowconfig!' => \$opt_allowconfig,
'columns=i' => \$opt_columns,
'date!' => \$opt_date,
'debug!' => \$opt_debug,
'dircoloralink=s' => \$opt_dircoloralink,
'dircolorback=s' => \$opt_dircolorback,
'dircolorfore=s' => \$opt_dircolorfore,
'dircolorlink=s' => \$opt_dircolorlink,
'dircolorvlink=s' => \$opt_dircolorvlink,
'dirhtmlext=s' => \$opt_dirhtmlext,
'dirindexname=s' => \$opt_dirindexname,
'footer=s' => \$opt_footer,
'forcecache!' => \$opt_forcecache,
'forcelowres!' => \$opt_forcelowres,
'forcegif!' => \$opt_forcegif,
'forcehtml!' => \$opt_forcehtml,
'forcejpeg!' => \$opt_forcejpeg,
'forcemontage!' => \$opt_forcemontage,
'forceuplink!' => \$opt_forceuplink,
'forcenouplink!' => \$opt_forcenouplink,
'framemarginwidth=i' => \$opt_framemarginwidth,
'framemarginheight=i' => \$opt_framemarginheight,
'frameborder=i' => \$opt_frameborder,
'frames!' => \$opt_frames,
'framestyle=i' => \$opt_framestyle,
'header=s' => \$opt_header,
'help!' => \$opt_help,
'htimage=s' => \$opt_htimage,
'htmlext=s' => \$opt_htmlext,
'iconbase=s' => \$opt_iconbase,
'iconpath=s' => \$opt_iconpath,
'ignorefp!' => \$opt_ignorefp,
'indexinfo!' => \$opt_indexinfo,
'imgindexname=s' => \$opt_imgindexname,
'indexname=s' => \$opt_indexname,
'javascript!' => \$opt_javascript,
'jpegquality=i' => \$opt_jpegquality,
'mapnetscape!' => \$opt_mapnetscape,
'maptype=s' => \$opt_maptype,
'maxgif=i' => \$opt_maxgif,
'msg_copyright=s' => \$opt_msg_copyright,
'msg_date_format=s' => \$opt_msg_date_format,
'msg_directories=s' => \$opt_msg_directories,
'msg_directory_navigator=s' => \$opt_msg_directory_navigator,
'msg_images=s' => \$opt_msg_images,
'msg_index_of_directory=s' => \$opt_msg_index_of_directory,
'msg_index_of_files=s' => \$opt_msg_index_of_files,
'msg_index_through=s' => \$opt_msg_index_through,
'msg_next=s' => \$opt_msg_next,
'msg_pause=s' => \$opt_msg_pause,
'msg_page_navigator=s' => \$opt_msg_page_navigator,
'msg_page_updated_on=s' => \$opt_msg_page_updated_on,
'msg_prev=s' => \$opt_msg_prev,
'msg_produced_by=s' => \$opt_msg_produced_by,
'msg_readme=s' => \$opt_msg_readme,
'msg_up=s' => \$opt_msg_up,
'pageindexname=s' => \$opt_pageindexname,
'pichtml!' => \$opt_pichtml,
'pichtmlaltend=s' => \$opt_pichtmlaltend,
'pichtmlaltstart=s' => \$opt_pichtmlaltstart,
'pichtmlbottom=s' => \$opt_pichtmlbottom,
'pichtmlext=s' => \$opt_pichtmlext,
'pichtmllink=s' => \$opt_pichtmllink,
'pichtmlnav!' => \$opt_pichtmlnav,
'pichtmlupfirst!' => \$opt_pichtmlupfirst,
'pichtmlputtitle!' => \$opt_pichtmlputtitle,
'pichtmltitletop!' => \$opt_pichtmltitletop,
'pichtmltarget=s' => \$opt_pichtmltarget,
'pichtmltitleend=s' => \$opt_pichtmltitleend,
'pichtmltitlestart=s' => \$opt_pichtmltitlestart,
'pichtmltop=s' => \$opt_pichtmltop,
'edgelinksindex!' => \$opt_edgelinksindex,
'prefixpath=s' => \$opt_prefixpath,
'readme=s' => \$opt_readme,
'readmevisible!' => \$opt_readmevisible,
'recurse!' => \$opt_recurse,
'rootpath=s' => \$opt_rootpath,
'rows=i' => \$opt_rows,
'serversidemap!' => \$opt_serversidemap,
'srcdir=s' => \$opt_srcdir,
'stylesheet=s' => \$opt_stylesheet,
'tables!' => \$opt_tables,
'tablebackcolor=s' => \$opt_tablebackcolor,
'fancytables!' => \$opt_fancytables,
'fancytableheight=i' => \$opt_fancytableheight,
'tables_bottom=s' => \$opt_tables_bottom,
'tables_params=s' => \$opt_tables_params,
'tables_top=s' => \$opt_tables_top,
'thumbtexture=s' => \$opt_thumbtexture,
'thumbbackground=s' => \$opt_thumbbackground,
'thumbborderwidth=i' => \$opt_thumbborderwidth,
'thumbframebgcolor=s' => \$opt_thumbframebgcolor,
'thumbcompose=s' => \$opt_thumbcompose,
'thumbfont=s' => \$opt_thumbfont,
'thumbforeground=s' => \$opt_thumbforeground,
'thumbframe=s' => \$opt_thumbframe,
'thumbgeometry=s' => \$opt_thumbgeometry,
'thumbgravity=s' => \$opt_thumbgravity,
'thumblabel=s' => \$opt_thumblabel,
'thumblabelwidth=s' => \$opt_thumblabelwidth,
'thumbshadow=s' => \$opt_thumbshadow,
'thumbtransparent=s' => \$opt_thumbtransparent,
'title=s' => \$opt_title,
'verbose!' => \$opt_verbose,
'version!' => \$opt_version,
'zoomfilter=s' => \$opt_zoomfilter
)
) {
help();
exit(0);
}
#
# Print help message
#
if( $opt_help ) {
help();
exit(0);
}
#
# Print version message
#
if( $opt_version ) {
version();
exit(0);
}
#
# Check if source directory is valid
#
if ( ! -d "${opt_srcdir}" ) {
print( STDERR "No ${opt_srcdir} directory\n" );
exit(1);
}
#
# Open X11 RGB database
#
if ( -f $opt_rgbdb ) {
open( RGBDB, "<$opt_rgbdb" )
|| die("Unable to open RGB database $opt_rgbdb");
while( ) {
m/^!/ && next;
my ( $red, $green, $blue, $color );
chop;
s/^[ \t]+//; # Remove any preceding spaces
($red, $green, $blue, $color) = split( /[ \t]+/, $_, 4);
$RGBDB{"\L$color"} = sprintf("#%02X%02X%02X", $red, $green, $blue);
}
close( RGBDB );
} else {
print( STDERR "Warning: X11 RGB database \'$opt_rgbdb\' not found\n" );
}
#
# Minimal 16-color named set as defined by HTML 3.2
#
$RGBDB{'black'} = '#000000';
$RGBDB{'green'} = '#008000';
$RGBDB{'silver'} = '#C0C0C0';
$RGBDB{'lime'} = '#00FF00';
$RGBDB{'gray'} = '#808080';
$RGBDB{'olive'} = '#808000';
$RGBDB{'white'} = '#FFFFFF';
$RGBDB{'yellow'} = '#FFFF00';
$RGBDB{'maroon'} = '#800000';
$RGBDB{'navy'} = '#000080';
$RGBDB{'red'} = '#FF0000';
$RGBDB{'blue'} = '#0000FF';
$RGBDB{'purple'} = '#800080';
$RGBDB{'teal'} = '#008080';
$RGBDB{'fuchsia'} = '#FF00FF';
$RGBDB{'aqua'} = '#00FFFF';
$currentDate = strftime ($opt_msg_date_format, localtime);
#
# Translate paths to physical paths (avoid symlink problems)
#
$opt_srcdir = lets_get_physical( $opt_srcdir );
print( "Physical srcdir : $opt_srcdir\n" ) if $opt_debug;
$opt_rootpath = lets_get_physical( $opt_rootpath );
print( "Physical rootpath : $opt_rootpath\n" ) if $opt_debug;
$icon_dir_path = "${opt_rootpath}$pathSep${opt_iconpath}";
print( "Physical icondir : $icon_dir_path\n" ) if $opt_debug;
# html_imgsize. Obtain image size and return HTML text (HEIGHT=foo
# WIDTH=bar) representing size.
sub html_imgsize {
my ($file) = @_;
use Image::Magick;
my (
$image,
$height,
$width,
@ping,
$retval,
$status
);
$retval = '';
if( -f $file ) {
$image = Image::Magick->new;
# Try PerlMagick 1.15 Ping method first
my $newfile = $file;
$newfile =~ s/\\/\\\\/g;
eval qq{\@ping = \$image->Ping("$newfile");};
if ( !$@ ) {
if ( $ping[0] =~ /,/ ) {
@ping = split (',',$ping[0]);
}
$width = $ping[0];
$height = $ping[1];
} else {
# If Ping fails to eval, do things the hard way
$status = $image->Read($file);
if( "$status" ) {
undef $image;
return( $retval );
}
($width, $height) = $image->[0]->Get("columns", "rows");
}
print( STDERR "Image \"$file\" has dimensions ",
"${width}x${height}\n") if $opt_debug;
$retval="HEIGHT=${height} WIDTH=${width}";
undef @$image; # Free up space
undef $image; # Ditto
} else {
print( STDERR "html_imgsize: no such file \"$file\"\n" );
}
return( $retval );
}
if( $opt_recurse && $opt_frames ) {
# Recurse depth-first under current directory, executing &wanted
# for each directory ignoring hidden directories
use File::Find;
print( "Processing directory tree $opt_srcdir ...\n" ) if $opt_debug;
find( \&wanted, $opt_srcdir );
} else {
print( "Processing directory $opt_srcdir ...\n" ) if $opt_debug;
$sourceDirectory = $opt_srcdir;
dodir( $sourceDirectory );
}
#
# Print run times if running in verbose mode
#
if( $opt_verbose ) {
my(
$user, # CPU time in user code for this process
$system, # CPU time in system code on behalf of this process
$cuser, # CPU time in user code of child processes
$csystem, # CPU time in system code on behalf of child processes
$total_user, # Total user time (parent + children)
$total_system, # Total system time (parent + children)
$total_time # Total elapsed time (wall clock)
);
my(
$user_m, # User time in minutes
$system_m, # System time in minutes
$cuser_m, # Child process user time in minutes
$csystem_m, # Child process system time in minutes
$total_user_m, # Total user time in minutes
$total_system_m,# Total system time in minutes
$total_time_m # Total elapsed time (wall clock) in minutes
);
($user, $system, $cuser, $csystem) = times;
$user_m = elapsedminutes( $user );
$system_m = elapsedminutes( $system );
$cuser_m = elapsedminutes( $cuser );
$csystem_m = elapsedminutes( $csystem );
$total_user = $user + $cuser; # Total user time
$total_user_m = elapsedminutes( $total_user );
$total_system = $system + $csystem; # Total system time
$total_system_m = elapsedminutes( $total_system );
$total_time = time - $startTime; # Total run time
$total_time_m = elapsedminutes( $total_time );
print( STDERR "Run time statistics:\n" );
print( STDERR "Detailed times: ${user_m} user, ${system_m} system,",
" ${cuser_m} child_user, ${csystem_m} child_system\n" );
print( STDERR "Summary times : ${total_time_m} total,",
" ${total_user_m} user, ${total_system_m} system\n" );
}
print( STDERR "Doing normal exit with code 0\n" ) if $opt_debug;
exit(0);
#####################
#####################
# Executed for each find operation
# Want:
# is directory
# not hidden directory
#
# Variables:
# $File::Find::dir current directory
# $File::Find::name current directory + file name
# $File::Find::prune set to true to prune tree
sub wanted {
my($dev,$ino,$mode,$nlink,$uid,$gid);
($dev,$ino,$mode,$nlink,$uid,$gid) = lstat($_);
if ( -d _ && -w _ && !/^\..+/ ) {
if( $_ ne '.' && get_rc_var('.', 'opt_prune', 0) ) {
$File::Find::prune=1;
# following funny logic is to avoid warnings about $prune
print( STDERR "Pruning $File::Find::name\n" ) if $File::Find::prune==1;
return;
}
#ignore special FrontPage directories (like /_vti_bin)
# lowercase names only, so _90-95 or _Covers is OK
if ( $opt_ignorefp && $File::Find::name =~ /\/_[a-z]/ )
{
return;
}
forking_dodir($File::Find::name);
}
}
# Execute dodir with the protection of a fork. This ensures that
# current directory and global webmagick configuration values are
# preserved between directories.
sub forking_dodir {
my $sourceDirectory = shift(@_); # Directory to process
my $inChild; # Set to one of we are child
my ($waitpid, # PID returned by wait
$childstat, # Status returned from child
$pid, # Child process PID
$waitpid, # PID waited on
$childstat # Child return status
);
FORK:
{
if( $pid = fork ) {
# parent here
# child process pid is available in $pid
$inChild=0;
$waitpid=wait();
$childstat=$?;
# If clean exit, then return 0
return 0 if ( $childstat == 0 );
syserror( $childstat ); # Print status from error
return 1;
} elsif ( defined $pid ) { # $pid is zero here if defined
# child here
# parent process pid is available with getppid
$inChild=1;
dodir( $sourceDirectory );
exit( 0 );
} elsif ( $! =~ /No more process/ ) {
# EAGAIN, supposedly recoverable fork error
sleep 5;
redo FORK;
} else {
# weird fork error
die( "Can't fork: $!\n$@\n" );
}
}
return(0); # Should never get here!
}
#
# Generate index files for directory specified by $sourceDirectory
#
sub dodir {
$sourceDirectory = shift(@_);
my $maxfiles = 0; # Maximum number of index links per page
$numPages = 0; # Number of index pages to be generated
my $numimages = 0; # Number of images in directory
my $numdirectories = 0; # Number of subdirectories in directory
$pageNumber = 1; # Current index page number (1 to N)
$haveReadme = 0; # Is there a readme file in this directory?
my $doIndexHtml=0; # Set to true if HTML index files must be generated
my $tmpstr; # Scratch string
my @tmplst; # Scratch list
#
# Regular expression to match supported file extensions
#
my $includeRegex='(\.avs$)|(\.bie$)|(\.bmp$)|(\.cgm$)|(\.dcm$)|(\.dcx$)' .
'|(\.dib$)|(\.dot$)|(\.dvi$)|(\.epdf$)|(\.epi$)|(\.eps$)' .
'|(\.eps2$)|(\.epsf$)|(\.epsi$)|(\.ept$)|(\.fax$)|(\.fig$)' .
'|(\.fits$)|(\.fpx$)|(\.g3$)|(\.gif$)|(\.gplt$)|(\.hdf$)' .
'|(\.hpgl$)|(\.ico$)|(\.im1$)|(\.im24$)|(\.im8$)|(\.jbg$)' .
'|(\.jbig$)|(\.jpeg$)|(\.jpg$)|(\.m2v$)|(\.man$)|(\.mif$)' .
'|(\.miff$)|(\.mng$)|(\.mpeg$)|(\.mpg$)|(\.mtv$)|(\.p7$)' .
'|(\.pbm$)|(\.pcd$)|(\.pcds$)|(\.pcx$)|(\.pdf$)|(\.pgm$)' .
'|(\.pic$)|(\.pict$)|(\.pix$)|(\.png$)|(\.pnm$)|(\.pov$)' .
'|(\.ppm$)|(\.ps$)|(\.psd$)|(\.rad$)|(\.rla$)|(\.rle$)' .
'|(\.sgi$)|(\.sun$)|(\.tga$)|(\.tif$)|(\.tiff$)|(\.tim$)' .
'|(\.ttf$)|(\.vicar$)|(\.viff$)|(\.wmf$)|(\.xbm$)|(\.xpm$)' .
'|(\.xwd$)';
#
# Regular expression for file and directory names we ignore
#
my $excludeRegex = '';
$excludeRegex .= "(^$opt_indexname)|"
if ("$opt_indexname" ne '');
$excludeRegex .= "(\\.s?html\$)|(\\.s?htm\$)|(\\.sht\$)|(^\\.)";
#
# Change current directory to $sourceDirectory
#
chdir( $sourceDirectory )
|| die("Can't cd to $sourceDirectory\n$@\n");
# Get current (absolute) directory
$currentDirectory=cwd();
# Eval per-directory rc files if they exist. Rc files are
# evaluated for each directory starting from $opt_rootdir until
# the current directory is reached. This supports "additive"
# behavior for a branch in the tree.
evaluateRcFiles();
# Decide if we want to process this directory or not based on the
# value of $opt_ignore. If not, then just return.
if( $opt_ignore ) {
# Skip this directory
print( STDERR "Skipping $sourceDirectory\n" );
return( 0 );
} else {
print( STDERR "Processing $sourceDirectory\n" );
}
# removed until I can find a way to do this
# that doesn't leave lockfiles on unsuccessful dodir attempts
#if (-e $opt_lockfile)
#{
# # Skip this directory because it's currently being processed
# print( STDERR "Skipping $sourceDirectory\n" );
# return( 0 );
#} else {
# open (LOCKFILE, ">$opt_lockfile");
# close LOCKFILE;
#}
# XXX: lowres implemented for javascript only
$opt_lowres = 0 if !$opt_javascript;
$currentDate = strftime ($opt_msg_date_format, localtime);
# Translate paths to physical paths (avoid symlink problems)
# Note: This duplicates code executed during initialization
$opt_srcdir = lets_get_physical( $opt_srcdir );
$opt_rootpath = lets_get_physical( $opt_rootpath );
$icon_dir_path = "${opt_rootpath}${pathSep}${opt_iconpath}";
#
# Set frame targets & frame naming
#
if( $opt_framefmt_frames{$opt_framestyle} == 2 ) {
# Two frame style & naming
$frameTargets{'default_dirview'}=$opt_frame_name_top; # Dir nav reloads entirely by default
$frameTargets{'default_thumbview'}=$opt_frame_name_top; # Thumbnail nav reloads entirely by default
$frameTargets{'dirview'}=$opt_frame_name_dirview; # Directory list displays in dirview frame
$frameTargets{'readmeview'}=$opt_frame_name_imageview; # Readme displays in imagemap frame
$frameTargets{'imageview'}=$opt_frame_name_imageview; # Images display in imagemap frame
$frameTargets{'thumbview'}=$opt_frame_name_imageview; # Imagemap displays in imagemap frame
} elsif ( $opt_framefmt_frames{$opt_framestyle} == 3 ) {
# Three frame style & naming
$frameTargets{'default_dirview'}=$opt_frame_name_top; # Dir nav reloads entirely by default
$frameTargets{'default_thumbview'}=$opt_frame_name_top; # Thumbnail nav reloads entirely by default
$frameTargets{'dirview'}=$opt_frame_name_dirview; # Directory list displays in dirview frame
$frameTargets{'readmeview'}=$opt_frame_name_imageview; # Readme displays in imageview frame
$frameTargets{'imageview'}=$opt_frame_name_imageview; # Images display in imageview frame
$frameTargets{'thumbview'}=$opt_frame_name_thumbview; # Imagemap displays in imagemap frame
} else {
die("Unsupported number of frames: $opt_framefmt_frames{$opt_framestyle}\n" );
}
#
# Ensure that certain options have correct case
#
$opt_cacheformat = "\U${opt_cacheformat}";
$opt_lowresformat = "\U${opt_lowresformat}";
#
# Default directory frame colors to page colors if not set
#
if ($opt_frames) {
$opt_dircolorback = $opt_colorback if ("$opt_dircolorback" eq '');
$opt_dircolorfore = $opt_colorfore if ("$opt_dircolorfore" eq '');
$opt_dircoloralink = $opt_coloralink if ("$opt_dircoloralink" eq '');
$opt_dircolorlink = $opt_colorlink if ("$opt_dircolorlink" eq '');
$opt_dircolorvlink = $opt_colorvlink if ("$opt_dircolorvlink" eq '');
}
#
# Convert all HTML colors to hex format
#
$opt_colorback = lookupRGBColor( $opt_colorback );
$opt_colorfore = lookupRGBColor( $opt_colorfore );
$opt_coloralink = lookupRGBColor( $opt_coloralink );
$opt_colorlink = lookupRGBColor( $opt_colorlink );
$opt_colorvlink = lookupRGBColor( $opt_colorvlink );
if ($opt_frames) {
$opt_dircolorback = lookupRGBColor( $opt_dircolorback );
$opt_dircolorfore = lookupRGBColor( $opt_dircolorfore );
$opt_dircoloralink = lookupRGBColor( $opt_dircoloralink );
$opt_dircolorlink = lookupRGBColor( $opt_dircolorlink );
$opt_dircolorvlink = lookupRGBColor( $opt_dircolorvlink );
}
# Calculate the maximum number of images per index page
$maxfiles=$opt_columns*$opt_rows;
# Convert renamed WebMagick options to new names for backward
# compatability
if( defined( $opt_thumbbordercolor ) ) {
$opt_thumbframebgcolor = $opt_thumbbordercolor;
}
if( defined( $opt_thumbmattecolor ) ) {
$opt_thumbframecolor = $opt_thumbmattecolor;
}
#
# Ensure that maptype is lower case
#
$opt_maptype = "\L${opt_maptype}";
if ($opt_iconbase) {
if ($opt_iconbase =~ !/^\//) {
die("$0: Iconbase must start with '/', use prefixpath to make it non-root related\n");
} else {
$icon_base_url = "${opt_prefixpath}${opt_iconbase}";
}
} else {
#
# Compute URL to top of icon directory
#
# Attempt to convert to relative URL
$icon_base_url = relative( $currentDirectory, $icon_dir_path);
if ( $icon_base_url =~ m\(^/)|(:)\ ) {
# If did not convert to relative URL then convert to absolute URL
$icon_base_url = escapeurl( abs_path_to_url($icon_dir_path));
}
}
#
# Source directory status file from last run
#
setFileNames(); # Set current file names
$pageStatusTime = 0;
if ( -f $fileNames{'pageStatus'} ) {
sourceRcFile($fileNames{'pageStatus'}) ;
# Obtain last modified date for status file
$pageStatusTime=fmtime($fileNames{'pageStatus'});
}
# Handle a directory name to title index file. Store alternative
# names in %dirTitles.
{
my $pos = 0;
my %tmp_dirTitles;
undef( %tmp_dirTitles );
if ( $opt_frames && -f $opt_dirindexname ) {
open( DIRINDEX, "<$opt_dirindexname" );
while( ) {
chop;
my($dirname, $dirtitle);
( $dirname, $dirtitle) = split( /[ \t]+/, $_, 2);
if(defined($dirname) && defined($dirtitle)) {
$tmp_dirTitles{$dirname} = escapehtml($dirtitle);
$dirOrder{$dirname} = $pos;
$pos++;
} elsif( defined($dirname) ) {
$dirOrder{$dirname} = $pos;
$pos++;
}
}
close( DIRINDEX );
}
if( compareHash(\%dirTitles,\%tmp_dirTitles) ) {
%dirTitles = %tmp_dirTitles;
if ($opt_frames) {
print( STDERR "Directory titles have changed, must re-do HTML indexes\n" )
if $opt_debug;
++$doIndexHtml;
}
} else {
print( STDERR "Directory titles not needed or unchanged from last run.\n")
if $opt_debug;
}
}
#
# Handle an image name to thumbnail label index file
# Store alternative names in %imageLabels
#
{
my $pos = 0;
my %tmp_imageLabels;
undef( %tmp_imageLabels );
my %tmp_imageCaptions;
undef( %tmp_imageCaptions );
if ( -f $opt_imgindexname ) {
open( IMGINDEX, "<$opt_imgindexname" );
while( ) {
chop;
my ( $imgname, $imgtitle, $imgcaption, $tmpstr);
( $imgname, $tmpstr) = split( /[ \t]+/, $_, 2);
( $imgtitle, $imgcaption ) = split( /,+/, $tmpstr, 2);
if(defined($imgname) && defined($imgtitle)) {
$tmp_imageLabels{$imgname} = $imgtitle;
$tmp_imageCaptions{$imgname} = $imgcaption;
$imageOrder{$imgname} = $pos;
$pos++;
} elsif( defined($imgname) ) {
$imageOrder{$imgname} = $pos;
$pos++;
}
}
close( IMGINDEX );
}
#
# This code is totally BOGUS since decision should be made on a per-page basis!!
#
if( compareHash(\%imageLabels,\%tmp_imageLabels) ) {
%imageLabels = %tmp_imageLabels;
print( STDERR "Image labels have changed, must re-do montages\n" )
if $opt_debug;
$opt_forcemontage=1;
} else {
print( STDERR "Image labels not needed or unchanged from last run.\n") if $opt_debug;
}
#BRAD: Added to record per image captions for perimage html page
if( $opt_pichtml &&
compareHash(\%imageCaptions,\%tmp_imageCaptions) ) {
%imageCaptions = %tmp_imageCaptions;
print( STDERR "Image captions have changed, must re-do perpage html\n" )
if $opt_debug;
$opt_forcehtml=1;
} else {
print( STDERR "Image captions not needed or unchanged from last run.\n")
if $opt_debug;
}
}
#
# Compute individual icon URLs.
#
{
my %tmp_iconImageUrls;
undef (%tmp_iconImageUrls);
print( "Icon URLs:\n" ) if $opt_debug;
my $icon;
for $icon ( keys %opt_icons ) {
if( $opt_icons{$icon} ) { # if defined
$tmp_iconImageUrls{$icon} = "$icon_base_url" . '/' . $opt_icons{$icon};
printf( " \$tmp_iconImageUrls%-20s = \"%s\"\n", "{'$icon'}", $tmp_iconImageUrls{$icon} )
if $opt_debug;
}
}
if( compareHash(\%iconImageUrls,\%tmp_iconImageUrls) ) {
%iconImageUrls = %tmp_iconImageUrls;
print( STDERR "Icon URLs have changed, must re-do all HTML\n" )
if $opt_debug;
$opt_forcehtml = 1;;
} else {
print( STDERR "Icon URLs not needed or unchanged from last run.\n")
if $opt_debug;
}
}
#
# Get icon image sizes
#
getIconImageSizes();
# Read source file names (if any). Filter out any names matching
# the exclude list.
opendir( SRCDIR, ".")
|| die("$0: Failed to open directory $sourceDirectory\n$@\n");
@allFiles = grep(!/$excludeRegex/io,readdir( SRCDIR ));
closedir( SRCDIR );
#
# Build list of image files
#
@allImageFiles = sort( sortImages grep( /$includeRegex/io, @allFiles));
print( STDERR " numfiles=", scalar(@allImageFiles), "\n") if $opt_debug;
# Find subdirectory names (if any) ignoring hidden directories and
# directories without index files. Directories should have index
# files since our find goes from the bottom up and we should have
# already processed the subdirectories.
#
# Only test files that are not in the allImageFiles list
{
my %tarray;
my @dirfiles;
my @tmp_dirNames = ();
if ($opt_frames) {
grep($tarray{$_}++, @allImageFiles);
foreach $_ ( grep(! $tarray{$_},@allFiles) ) {
if( -d "${_}" ) { # If directory exists
unless (get_rc_var(${_}, 'opt_ignore', 0) eq 1) { # and dir not ignored
unless ($opt_ignorefp && /^_[a-z]/) { # and we shouldn't ignore it
push(@dirfiles, $_); # then add it to the list
if ($opt_javascript) {
# Check which index file to use for JavaScript
if( -f "$_/$fileNames{'jsDirIndex'}" ) {
$dirJsLink{"$_"} = $fileNames{'jsDirIndex'};
} elsif ( -f "$_/$opt_indexname" ){
$dirJsLink{"$_"} = $opt_indexname;
} else {
$dirJsLink{"$_"} = '';
}
}
}
}
}
}
@tmp_dirNames = sort( sortDir @dirfiles);
}
if( "@dirNames" ne "@tmp_dirNames" ) {
@dirNames = @tmp_dirNames;
if ($opt_frames) {
print( STDERR "Subdirectories have changed, must re-do HTML indexes\n" )
if $opt_debug;
++$doIndexHtml;
}
}
if ($opt_javascript) {
# Check which parent-directory index file to use for JavaScript
if( -f "../$fileNames{'jsDirIndex'}" ) {
$dirJsLink{".."} = $fileNames{'jsDirIndex'};
} elsif ( -f "../$opt_indexname" ){
$dirJsLink{".."} = $opt_indexname;
} else {
$dirJsLink{".."} = '';
}
}
}
#
# Determine the number of index pages to be generated, etc.
#
$numimages=scalar(@allImageFiles); # Number of images
$numdirectories=scalar(@dirNames); # Number of subdirectories
$numPages=int($numimages/$maxfiles);
if ( $numimages%$maxfiles != 0 ) {
++$numPages;
}
#
# Check for README file and set haveReadme flag if exists
#
if("${opt_readme}" ne '' && -f "${opt_readme}") {
$haveReadme = 1;
}
# Set haveImages flag if there are images in directory. This
# effects the way the directory listing appears.
$haveImages = 0;
if( $numimages > 0 ) {
$haveImages = 1;
}
#
# Determine page title
#
if( "$opt_title" ne '' ) {
$pageTitle = $opt_title;
} else {
my $dirname=basename($sourceDirectory);
#BRAD: if cwd or pageTitle in imageLabels, use that for directory name
if( $imageLabels{$dirname} ne '') {
$pageTitle = $imageLabels{$dirname};
$imageLabels{'pageTitle'} = $imageLabels{$dirname};
$imageCaptions{'pageTitle'} = $imageLabels{$dirname};
} elsif ( $imageLabels{'pageTitle'} ne '') {
$pageTitle = $imageLabels{'pageTitle'};
} else {
$pageTitle = "${opt_msg_index_of_directory} \"$dirname\"";
}
}
#
# Put the PerlMagick Montage options together
#
$montageArguments = ''; #"\n ";
$montageArguments .= "background=>\'$opt_thumbbackground\',\n "
if $opt_thumbbackground ne 'false';
$montageArguments .= "borderwidth=>\'$opt_thumbborderwidth\',\n ";
$montageArguments .= "compose=>\'$opt_thumbcompose\',\n "
if $opt_thumbcompose ne 'false';
$montageArguments .= "font=>\'$opt_thumbfont\',\n "
if $opt_thumbfont ne 'false';
$montageArguments .= "fill=>\'$opt_thumbforeground\',\n "
if $opt_thumbforeground ne 'false';
$montageArguments .= "frame=>\'$opt_thumbframe\',\n "
if $opt_thumbframe ne 'false';
$montageArguments .= "geometry=>\'${opt_thumbgeometry}\',\n "
if $opt_thumbgeometry ne 'false';
$montageArguments .= "gravity=>\'$opt_thumbgravity\',\n "
if $opt_thumbgravity ne 'false';
$montageArguments .= "shadow=>\'$opt_thumbshadow\',\n "
if $opt_thumbshadow ne 'false';
$montageArguments .= "texture=>\'$opt_thumbtexture\',\n "
if $opt_thumbtexture ne 'false';
$montageArguments .= "tile=>\'${opt_columns}x${opt_rows}\',\n ";
$montageArguments .= "transparent=>\'$opt_thumbtransparent\'\n "
if $opt_thumbtransparent ne 'false';
# Compute a conglomeration of all parameters that effect the
# montage image to use for comparison with the parameters used in
# the last run.
{
my $tmp_montageParameters = "$montageArguments";
$tmp_montageParameters .= "bordercolor=>\'$opt_thumbframebgcolor\',\n "
if $opt_thumbframebgcolor ne 'false';
$tmp_montageParameters .= "mapnetscape=>\'$opt_mapnetscape\',\n ";
$tmp_montageParameters .= "mattecolor=>\'$opt_thumbframecolor\',\n "
if $opt_thumbframecolor ne 'false';
$tmp_montageParameters .= "label=>\'$opt_thumblabel\',\n "
if ($opt_thumblabel && $opt_thumblabel ne 'false');
$tmp_montageParameters .= "labelwidth=>\'$opt_thumblabelwidth\',\n ";
$tmp_montageParameters .= "\Lzoomfilter=>\'$opt_zoomfilter\'";
if( !defined($montageParameters) || ($tmp_montageParameters ne $montageParameters)) {
$montageParameters = $tmp_montageParameters;
print( STDERR "Montage parameters have changed, must re-do montages\n" )
if $opt_debug;
$opt_forcemontage=1;
}
}
#
# Store HTML options in associative array to make them easier to deal with
#
%htmlOpts =
(
'address' => $opt_address,
'anonymous' => $opt_anonymous,
'backgroundimg' => $opt_icons{'background'},
'cachedir' => !$opt_tables ? "" : $opt_cachedir,
'cacheformat' => !$opt_tables ? "" : $opt_cacheformat,
'centerfooter' => $opt_centerfooter,
'coloralink' => $opt_coloralink,
'colorback' => $opt_colorback,
'colorfore' => $opt_colorfore,
'colorlink' => $opt_colorlink,
'colorvlink' => $opt_colorvlink,
'columns' => $opt_columns,
'config' => !$opt_javascript ? 0 : $opt_allowconfig,
'dateText' => !$opt_date ? "" : "${opt_msg_page_updated_on} $currentDate",
'dirbackgroundimg' => !$opt_frames ? "" : $opt_icons{'dirbackground'},
'dircoloralink' => !$opt_frames ? "" : $opt_dircoloralink,
'dircolorback' => !$opt_frames ? "" : $opt_dircolorback,
'dircolorfore' => !$opt_frames ? "" : $opt_dircolorfore,
'dircolorlink' => !$opt_frames ? "" : $opt_dircolorlink,
'dircolorvlink' => !$opt_frames ? "" : $opt_dircolorvlink,
'dirfmt' => !$opt_frames ? "" : $opt_dirfmt,
'dirhtmlext' => !$opt_frames ? "" : $opt_dirhtmlext,
'dirindexname' => !$opt_frames ? "" : $opt_dirindexname,
'footer' => $opt_footer,
'forceuplink' => $opt_forceuplink,
'forcenouplink' => $opt_forcenouplink,
'frameddirfmt' => !$opt_frames ? "" : $opt_frameddirfmt,
'framemarginwidth' => !$opt_frames ? 0 : $opt_framemarginwidth,
'framemarginheight' => !$opt_frames ? 0 : $opt_framemarginheight,
'frameborder' => !$opt_frames ? 0 : $opt_frameborder,
'frames' => $opt_frames,
'framestyle' => !$opt_frames ? 1 : $opt_framestyle,
'header' => $opt_header,
'htimage' => !$opt_serversidemap ? "" : $opt_htimage,
'htmlext' => !$opt_frames ? "" : $opt_htmlext,
'iconbase' => $opt_iconbase,
'imgindexname' => $opt_imgindexname,
'indexinfo' => $opt_indexinfo,
'indexname' => $opt_indexname,
'javascript' => $opt_javascript,
'jsdirindex' => !$opt_javascript ? "" : $fileNames{'jsDirIndex'},
'jsfunctions' => !$opt_javascript ? "" : $fileNames{'jsFunctions'},
'jspageindex' => !$opt_javascript ? "" : $fileNames{'jsPageIndex'},
'jsvariables' => !$opt_javascript ? "" : $fileNames{'jsVariables'},
'lowres' => $opt_lowres,
'lowresdir' => !$opt_lowres ? "" : $opt_lowresdir,
'lowresformat' => !$opt_lowres ? "" : $opt_lowresformat,
'metaauthor' => $opt_metaauthor,
'metacharset' => $opt_metacharset,
'metaclassification' => $opt_metaclassification,
'metadescription' => $opt_metadescription,
'metaexpires' => $opt_metaexpires,
'metakeywords' => $opt_metakeywords,
'msg_copyright' => $opt_anonymous ? "" : $opt_msg_copyright,
'msg_directories' => !$opt_frames ? "" : $opt_msg_directories,
'msg_directory_navigator' => !$opt_frames ? "" : $opt_msg_directory_navigator,
'msg_images' => !$opt_frames ? "" : $opt_msg_images,
'msg_index_of_directory' => $opt_msg_index_of_directory,
'msg_index_of_files' => !$opt_indexinfo ? "" : $opt_msg_index_of_files,
'msg_index_through' => !$opt_indexinfo ? "" : $opt_msg_index_through,
'msg_next' => $opt_msg_next,
'msg_pause' => $opt_msg_pause,
'msg_page_navigator' => !$opt_frames ? "" : $opt_msg_page_navigator,
'msg_prev' => $opt_msg_prev,
'msg_produced_by' => $opt_anonymous ? "" : $opt_msg_produced_by,
'msg_readme' => !$haveReadme ? "" : $opt_msg_readme,
'msg_up' => $opt_msg_up,
'numpages' => $numPages,
'pageindexname' => $opt_pageindexname,
'pichtml' => $opt_pichtml,
'pichtmlaltend' => !$opt_pichtml ? "" : $opt_pichtmlaltend,
'pichtmlaltstart' => !$opt_pichtml ? "" : $opt_pichtmlaltstart,
'pichtmlbottom' => !$opt_pichtml ? "" : $opt_pichtmlbottom,
'pichtmlext' => !$opt_pichtml ? "" : $opt_pichtmlext,
'pichtmllink' => !$opt_pichtml ? '' : $opt_pichtmllink,
'pichtmlnav' => !$opt_pichtml ? 0 : $opt_pichtmlnav,
'pichtmlupfirst' => $opt_pichtmlupfirst,
'pichtmlputtitle' => !$opt_pichtml ? 0 : $opt_pichtmlputtitle,
'pichtmltitletop' => (!$opt_pichtml || !$opt_pichtmlputtitle) ? 0 : $opt_pichtmltitletop,
'pichtmltarget' => (!$opt_pichtml || !$opt_frames) ? "" : $opt_pichtmltarget,
'pichtmltitleend' => !$opt_pichtml ? "" : $opt_pichtmltitleend,
'pichtmltitlestart' => !$opt_pichtml ? "" : $opt_pichtmltitlestart,
'pichtmltop' => !$opt_pichtml ? "" : $opt_pichtmltop,
'edgelinksindex' => $opt_edgelinksindex,
'prefixpath' => $opt_prefixpath,
'readme' => !$haveReadme ? "" : $opt_readme,
'readmepresent' => $haveReadme,
'readmevisible' => !$haveReadme ? 0 : $opt_readmevisible,
'rows' => $opt_rows,
'serversidemap' => $opt_serversidemap,
'stylesheet' => $opt_stylesheet,
'subdirectories' => !$opt_frames ? "" : join(' ',@dirNames),
'tables' => $opt_tables,
'tablebackcolor' => !$opt_tables ? "" : $opt_tablebackcolor,
'fancytables' => !$opt_tables ? 0 : $opt_fancytables,
'fancytableheight' => !$opt_tables ? 0 : $opt_fancytableheight,
'tables_bottom' => !$opt_tables ? "" : $opt_tables_bottom,
'tables_params' => !$opt_tables ? "" : $opt_tables_params,
'tables_top' => !$opt_tables ? "" : $opt_tables_top,
'title' => $pageTitle,
'version' => $opt_anonymous ? "" : $webmagickInfo{'version'},
);
# Compute a conglomeration of all parameters that effect the HTML
# to use for comparison with the parameters used in the last run.
{
my $firstparam = 1;
my $tmp_htmlParams = '';
my $key;
foreach $key (sort(keys(%htmlOpts))) {
if(defined($htmlOpts{$key})) {
if( $firstparam ) {
$firstparam = 0;
} else {
$tmp_htmlParams .= ",\n ";
}
$tmp_htmlParams .= $key . '=>\'' . $htmlOpts{$key} . '\'';
}
}
if( !defined($htmlParams) || ($tmp_htmlParams ne $htmlParams)) {
$htmlParams = $tmp_htmlParams;
print( STDERR "HTML parameters have changed, must re-do HTML\n" )
if $opt_debug;
$opt_forcehtml=1;
}
}
#
# Print statistics message
#
print( STDERR " $numimages Images $numdirectories Directories",
" $numPages Pages --- " )
if $opt_verbose;
my @imgfiles = @allImageFiles; # Save full list of files for later
# Loop through file list, placing a maximum of $maxfiles images on
# each page. Do at least one page (there might not be any
# images).
while (scalar(@allImageFiles) > 0 || $pageNumber == 1) {
$doMontage=0; # Set to true if montage must be generated
$doPageHtml=0; # Set to true if per-page HTML files must be generated
print(STDERR " $pageNumber" ) if $opt_verbose;
#
# Get per-page image names
# @imageNames is a list of lists
{
my @tmp_imageNames = splice(@allImageFiles,0,$maxfiles);
if( !defined($imageNames[$pageNumber - 1]) ||
("@tmp_imageNames" ne "@{$imageNames[$pageNumber - 1]}") ) {
$imageNames[$pageNumber - 1] = [ @tmp_imageNames ];
print( STDERR "Need to do both montage and page HTML because",
" file list differs\n") if $opt_debug;
++$doMontage;
++$doPageHtml;
}
}
my $numfiles = $#{$imageNames[$pageNumber - 1]} + 1;
setFileNames(); # Set current file names
#
# Decide if we need to do HTML & montage
#
if ( $perlVarsVersion < $requiredPerlVarsVersion) {
print ( STDERR "Need to do montage, HTML and cache because",
" version has changed\n") if $opt_debug;
$opt_forcehtml = 1;
$opt_forcemontage = 1;
$opt_forcecache = 1;
$opt_forcelowres = 1;
}
# Montage specific checks
# Check for missing output files
# Check for new input files
if( $numfiles > 0 ) {
if( ! $opt_tables && (! -f $fileNames{'pageStatus'} ||
( ! -f $fileNames{'montageGIF'} && ! -f $fileNames{'montageJPEG'} ))) {
# If key file is missing then do montage
print(STDERR "Must do montage because a required output",
" file is missing\n")
if $opt_debug;
++$doMontage;
} else {
# If any file in file list is newer than status file,
# then do montage
my $file;
foreach $file (@{$imageNames[$pageNumber - 1]}) {
if( fmtime($file) > $pageStatusTime ) {
print( STDERR "Need to do both montage and HTML",
" because file has been updated\n")
if $opt_debug;
++$doMontage;
++$doPageHtml;
print(STDERR "\nMust do montage and html: file",
" updated\n") if $opt_debug;
}
}
}
}
die("Empty \$opt_indexname set with \$opt_frames\n$@\n")
if ($opt_frames && "$opt_indexname" eq '');
# HTML specific checks
# Check for missing files
if( ! -f $fileNames{'pageStatus'} ||
! -f $fileNames{'htmlCurrentIndex'} ||
($opt_frames && ! -f "$opt_indexname")) {
# If key file is missing then do HTML
print(STDERR "\n Must do page and index HTML: output file",
" missing\n") if $opt_debug;
++$doPageHtml;
++$doIndexHtml if ($opt_frames);
}
# Overrides
if( $opt_forcehtml ) {
++$doPageHtml;
++$doIndexHtml if ($opt_frames);
}
if( $opt_forcemontage ) {
++$doPageHtml; # Montage effects HTML output
++$doMontage;
}
my $errorstat = 1; # Cleared for non-error block exit
PAGES: {
#
# Build montage for current page
#
if( $doMontage && ( $numfiles > 0 ) ) {
doMontage(@{$imageNames[$pageNumber - 1]}) && last PAGES;
# Determine image name & size to use for imagemap
{
my $montageImage;
my $montageImageSize;
if( -f $fileNames{'montageGIF'} ) {
$montageImage = $fileNames{'montageGIF'}; # Use GIF
$montageImageSize = html_imgsize($fileNames{'montageGIF'});
} elsif ( -f $fileNames{'montageJPEG'} ) {
$montageImage = $fileNames{'montageJPEG'}; # Use JPEG
$montageImageSize = html_imgsize($fileNames{'montageJPEG'});
}
if(!defined($montageImages[$pageNumber - 1]) ||
( $montageImages[$pageNumber - 1] ne $montageImage )) {
$montageImages[$pageNumber - 1] = $montageImage;
print( STDERR "Need to re-do page HTML because montage image name ",
"has changed\n") if $opt_debug;
++$doPageHtml;
}
if(!defined($montageImageSizes[$pageNumber - 1]) ||
( $montageImageSizes[$pageNumber - 1] ne $montageImageSize )) {
$montageImageSizes[$pageNumber - 1] = $montageImageSize;
print( STDERR "Need to re-do page HTML because montage image size ",
"has changed\n") if $opt_debug;
++$doPageHtml;
}
}
}
#
# Write out page index files for current page
#
if( $doPageHtml ) {
writeIndexFiles();
}
# Write server-side imagemap file
if( $opt_serversidemap && $doPageHtml && ( $numfiles > 0 ) ) {
writeImageMap();
}
if ( $doPageHtml || $doIndexHtml || $doMontage ) {
#
# Save run status (source files and montage options)
#
writePerlIndexFiles();
if( $opt_javascript ) {
writeJavaScriptIndexFiles();
}
}
# Clear error flag
$errorstat = 0;
}
print( STDERR "Error encountered when creating page\n" )
if $errorstat;
++$pageNumber; # Next page
}
print( STDERR "\n" ) if $opt_verbose;
#
# Clean up old files
#
setFileNames();
while(
-f $fileNames{'htmlCurrentIndex'} ||
-f $fileNames{'montageGIF'} ||
-f $fileNames{'montageJPEG'} ||
-f $fileNames{'montageServerMap'}
) {
unlink(
$fileNames{'htmlCurrentIndex'},
$fileNames{'montageGIF'},
$fileNames{'montageJPEG'},
$fileNames{'montageServerMap'}
);
++$pageNumber; # Next page
setFileNames();
}
#
# Clean up cached thumbnails
#
if( ($opt_cache || $opt_tables) && -d $opt_cachedir ) {
my @extra;
my %tarray;
opendir( CACHEDIR, "$opt_cachedir")
|| die("$0: Failed to open directory $opt_cachedir\n$@\n");
@cacheFiles = grep(!/$excludeRegex/io,readdir( CACHEDIR ));
closedir( CACHEDIR );
grep( $tarray{"$_.\L${opt_cacheformat}"}++, @imgfiles );
@extra = grep( $_ = "$opt_cachedir/$_", grep( ! $tarray{$_}, @cacheFiles ));
if ($#extra >= 0) {
print( STDERR "Removing extra cache files @extra\n") if $opt_debug;
unlink( @extra );
}
}
#
# Clean up cached low resolution images
#
if( $opt_lowres && -d $opt_lowresdir ) {
my @extra;
my %tarray;
opendir( LOWRESDIR, "$opt_lowresdir")
|| die("$0: Failed to open directory $opt_lowresdir\n$@\n");
@lowresFiles = grep(!/$excludeRegex/io,readdir( LOWRESDIR ));
closedir( LOWRESDIR );
grep( $tarray{"$_.\L${opt_lowresformat}"}++, @imgfiles );
@extra = grep( $_ = "$opt_lowresdir/$_", grep( ! $tarray{$_}, @lowresFiles ));
if ($#extra >= 0) {
print( STDERR "Removing extra lowres files @extra\n") if $opt_debug;
unlink( @extra );
}
}
#
# Write out index files (Both main index and frames index files)
#
if( $doIndexHtml ) {
writeTopIndexes();
}
# remove lockfile
# unlink $opt_lockfile;
}
#
# Write out both top index and frame index files
#
sub writeTopIndexes {
die("Internal error: writeTopIndexes called when \$opt_frames is not set\n$@\n")
if (!$opt_frames);
die("Empty \$opt_indexname set with \$opt_frames\n$@\n")
if ("$opt_indexname" eq '');
print( STDERR "Writing Index Files ${opt_indexname} & ",
"${opt_pageindexname}dir${opt_dirhtmlext} ...\n" )
if $opt_debug;
#---- Generate the Variables for Format Options ----
#
# Generate HTML for up link
#
my $uphtml = '';
# get indexname of parent directory
my $upindexname =
get_rc_var('..', 'opt_indexname', "$opt_indexname");
unless ( "$upindexname" eq 'NOLINK' || "$opt_forcenouplink" || ( cwd() eq "$opt_rootpath" && ! "$opt_forceuplink" ) ) {
$uphtml = " " .
" ${opt_msg_up} \n";
}
#
# Generate HTML for help link
#
my $helphtml = '';
if( $haveReadme ) {
$helphtml .= " " .
" ${opt_msg_readme} \n";
}
#
# Compute HTML for link to first image page
#
my $nexthtml = '';
if( $haveReadme && $haveImages && $opt_framefmt_frames{$opt_framestyle}<=2 ) {
$nexthtml .= " " .
" ${opt_msg_images} ";
}
#
# Compute HTML for directory list
#
my $dirhtml = '';
if( !$opt_prune && scalar(@dirNames) > 0 ) {
$dirhtml = "${opt_msg_directories} \n";
my $subdir;
foreach $subdir (@dirNames) {
# ignore frontpage directories
if ($opt_ignorefp && $subdir =~ /^_[a-z]/)
{
next;
}
# If an alternative name is defined, then use it
my $dirtitle;
if( defined( $dirTitles{$subdir} ) ) {
$dirtitle=$dirTitles{$subdir};
} else {
$dirtitle=$subdir;
}
# get indexname for sub-directory (default as this directory)
my $subindexname =
get_rc_var($subdir, 'opt_indexname', "$opt_indexname");
unless ( "$subindexname" eq 'NOLINK' ) {
my $url = escapeurl("$subdir/${subindexname}");
# If a bullet icon is defined, then use it
# otherwise use plain text only
if( defined( $iconImageUrls{'ball'} ) ) {
$dirhtml .= " ";
}
$dirhtml .= "$dirtitle \n";
}
}
}
#
# Generate HTML for page index list
#
my $pageindexhtml = '';
if( $haveImages ) {
$pageindexhtml = "${opt_msg_page_navigator} \n";
my $i;
for( $i=1; $i <= $numPages; ++$i ) {
$pageindexhtml .=
" ${i} \n";
}
}
# ----- Evaluate the Format Options -----
#
# Evaluate the Top Index File Format Option
#
my $indexhtml;
$indexhtml = eval '"' . $opt_dirfmt . '"';
die( "Bad Eval of directory page template (\$opt_dirfmt)\n$@\n" )
if $@;
# Change header to plain bold text for framed directory file
$dirhtml =~
s|^${opt_msg_directories} \n|${opt_msg_directories} \n|;
$pageindexhtml =~
s|^${opt_msg_page_navigator} \n|${opt_msg_page_navigator} \n|;
#
# Evaluate the Framed Directory File Format Option
#
my ($pagedirhtml, $dirframelink, $pageframelink);
$pagedirhtml = eval '"' . $opt_frameddirfmt . '"';
die( "Bad Eval for directory page template (\$opt_frameddirfmt)\n$@\n" )
if $@;
#
# Pull README into thumbnail frame if it exists, and is
# either marked always visible or there are no images.
#
$dirframelink = "${opt_pageindexname}dir${opt_dirhtmlext}";
if( $opt_framefmt_frames{$opt_framestyle} <= 2 ) {
if( $haveReadme && ( $opt_readmevisible || ! $haveImages ) ) {
# Point to README.html
$pageframelink = $opt_readme;
} else {
# Point to first image page
$pageframelink = "${opt_pageindexname}1$opt_htmlext";
}
} else {
if( $haveReadme && $opt_readmevisible ) {
# Point to README.html
$pageframelink = "${opt_pageindexname}1$opt_htmlext";
$imageFrameLink = $opt_readme;
} else {
# Point to first image page
$pageframelink = "${opt_pageindexname}1$opt_htmlext";
$imageFrameLink = $fileNames{'htmlBlankPage'};
}
}
#
# Evaluate the Frame Format Option
#
my $framespechtml = eval '"' . $opt_framefmt{$opt_framestyle} . '"';
die( "Bad Eval for Frame template (\$opt_framefmt{$opt_framestyle})\n$@\n" )
if $@;
#
# Evaluate the JavaScript version of the Frame Format
#
# Override normal frame targets
if ($opt_javascript) {
$dirframelink = q/javascript:parent.returnDirectoryHTML();/;
$pageframelink = q/javascript:parent.returnThumbNailsHTML();/;
$imageFrameLink = q/javascript:parent.returnImageHTML(0);/;
my $framespecjshtml = eval '"' . $opt_framefmt{$opt_framestyle} . '"';
die( "Bad Eval for Frame template (\$opt_framefmt{$opt_framestyle})\n$@\n" )
if $@;
}
# ----- Output Top Index File (usually "index.html") -------
#
open( INDEX, ">${opt_indexname}")
|| die("$0: Failed to open file ${opt_indexname} for output\n$@\n");
print( INDEX "\n\n\n" );
# Charset is better before title
print( INDEX " \n" )
if( "$opt_metacharset" ne '' );
print( INDEX " ${pageTitle} \n" );
# Meta tags
print( INDEX " \n" )
if (!$opt_anonymous);
print( INDEX " \n" )
if( "$opt_metaauthor" ne '' );
print( INDEX " \n" )
if( "$opt_metadescription" ne '' );
print( INDEX " \n" )
if( "$opt_metakeywords" ne '' );
print( INDEX " \n" )
if( "$opt_metaclassification" ne '' );
# The value of $opt_metaexpires should be similar to:
# "Tue, 20 Aug 1996 14:25:27 GMT"
print( INDEX " \n" )
if( "$opt_metaexpires" ne '' );
print( INDEX " \n")
if ("$opt_stylesheet" ne '');
# If in JavaScript mode, output code to switch to JavaScript pages
# Currently knows about certain browsers.
if( $opt_javascript ) {
print( INDEX '\n" );
}
print( INDEX "\n" );
print( INDEX $framespechtml );
print( INDEX "\n" );
print( INDEX "\n" );
print( INDEX $indexhtml );
print( INDEX "\n \n \n" );
close( INDEX );
# ----- Output Top JavaScript Index File (usually "indexjs.html") -------
#
if( $opt_javascript ) {
open( INDEX, ">$fileNames{'jsDirIndex'}")
|| die("$0: Failed to open file $fileNames{'jsDirIndex'} for output\n$@\n");
print( INDEX "\n\n\n" );
print( INDEX "\n" );
print( INDEX q/! . "\n" );
print( INDEX q/! . "\n" );
print( INDEX "\n" );
print( INDEX "\n" );
close( INDEX );
}
# ----- Output Frame Directory File (usally ".indexdir.html") ------
#
open( INDEX, ">${opt_pageindexname}dir${opt_dirhtmlext}")
|| die("$0: Failed to open file \"${opt_pageindexname}dir${opt_dirhtmlext}\"",
" for output\n$@\n");
print( INDEX "\n\n\n" );
# Charset is better before title
print( INDEX " \n" )
if( "$opt_metacharset" ne '' );
print( INDEX " ${pageTitle} \n" );
# Default URL target
print( INDEX " \n" );
# Meta tags
print( INDEX " \n" )
if (!$opt_anonymous);
print( INDEX " \n" )
if( "$opt_metaauthor" ne '' );
print( INDEX " \n" )
if( "$opt_metadescription" ne '' );
print( INDEX " \n" )
if( "$opt_metakeywords" ne '' );
print( INDEX " \n" )
if( "$opt_metaclassification" ne '' );
# The value of $opt_metaexpires should be similar to:
# "Tue, 20 Aug 1996 14:25:27 GMT"
print( INDEX " \n" )
if( "$opt_metaexpires" ne '' );
print( INDEX " \n")
if ("$opt_stylesheet" ne '');
print( INDEX "\n" );
print( INDEX "\n");
print( INDEX $pagedirhtml );
print( INDEX "\n" );
close( INDEX );
return ( 0 );
}
#
# Write out page index files
#
sub writeIndexFiles {
my $indexbar; # HTML text representing numeric selection bar
my $errorstat = 0;
print( STDERR "Writing file $fileNames{'htmlCurrentIndex'} ...\n" )
if $opt_debug;
my $numimages = $#{$imageNames[$pageNumber - 1]} + 1;
my $pNumber = ($pageNumber == 1) ? "" : "$pageNumber";
# Calculate page index bar
# No link for current page
# Nothing at all when there is only one page.
$indexbar = "";
# Must be visible at each page, if no frames
if (!$opt_frames) {
# --- readme link ---
if ( $haveReadme ) {
$indexbar .= " \n";
}
# --- up link ---
my $upindexname = get_rc_var('..', 'opt_indexname', "$opt_indexname");
if ( "$upindexname" ne 'NOLINK' ) {
$indexbar .= " \n";
}
}
# --- prev link ---
if( $pageNumber == 1 ) {
if ($numPages > 1) {
# Print a grayed out arrow to maintain alignment
$indexbar .= " \n";
}
} else {
# Go to preceding page
$indexbar .= " \n";
}
# --- next link ---
if( $numPages > 1 ) {
if( $pageNumber < $numPages ) {
$indexbar .= " \n";
} else {
# Print a grayed out arrow to maintain alignment
$indexbar .= " \n";
}
}
# --- page links ---
if( $numPages > 1 ) {
my $page;
for ( $page = 1; $page <= $numPages; ++$page) {
if ( $page != $pageNumber ) {
if ($opt_frames) {
$indexbar .= "$fileNames{'htmlCurrentIndex'}")
|| die("$0: Failed to open file $fileNames{'htmlCurrentIndex'} for output\n$@\n");
print( INDEX "\n\n\n" );
# Charset is better before title
print( INDEX " \n" )
if( "$opt_metacharset" ne '' );
print( INDEX " ${pageTitle} \n" );
print( INDEX " \n" )
if ($opt_frames);
# Meta tags
print( INDEX " \n" )
if (!$opt_anonymous);
print( INDEX " \n" )
if( "$opt_metaauthor" ne '' );
print( INDEX " \n" )
if( "$opt_metadescription" ne '' );
print( INDEX " \n" )
if( "$opt_metakeywords" ne '' );
print( INDEX " \n" )
if( "$opt_metaclassification" ne '' );
# The value of $opt_metaexpires should be similar to:
# "Tue, 20 Aug 1996 14:25:27 GMT"
print( INDEX " \n" )
if( "$opt_metaexpires" ne '' );
print( INDEX " \n")
if ("$opt_stylesheet" ne '');
print( INDEX "\n" );
print( INDEX "\n");
print( INDEX "${opt_header}\n" ) if ("$opt_header" ne '');
# Leave page blank unless there is something to show
if( $numimages > 0 ) {
#BRAD: Added directory description
if( $imageCaptions{'pageTitle'} ne '') {
print( INDEX "$imageCaptions{'pageTitle'}
\n");
print( STDERR "Using custom PageDescription\n") if $opt_debug;
} else {
print( INDEX "\n" );
}
print( INDEX "$indexbar \n" );
if( $imageCaptions{'pageTitle'} eq '' &&
$opt_indexinfo && (!$opt_frames || $opt_framestyle == 1) ) {
my $desc1 = '';
my $desc2 = '';
if (defined($imageCaptions{$imageNames[$pageNumber -1][0]})) {
$desc1=escapehtml($imageCaptions{$imageNames[$pageNumber -1][0]});
} elsif (defined($imageLabels{$imageNames[$pageNumber -1][0]})) {
$desc1=escapehtml($imageLabels{$imageNames[$pageNumber -1][0]});
} else {
$desc1=escapehtml($imageNames[$pageNumber - 1][0]);
}
if (defined($imageCaptions{$imageNames[$pageNumber -1][$numimages-1]})) {
$desc2=escapehtml($imageCaptions{$imageNames[$pageNumber -1][$numimages-1]});
} elsif (defined($imageLabels{$imageNames[$pageNumber -1][$numimages-1]})) {
$desc2=escapehtml($imageLabels{$imageNames[$pageNumber -1][$numimages-1]});
} else {
$desc2=escapehtml($imageNames[$pageNumber - 1][$numimages-1]);
}
print( INDEX "${opt_msg_index_of_files}\"",
$desc1, "\" ${opt_msg_index_through}", " \"", $desc2,
"\" \n" );
}
if ($opt_tables)
{
if ( !$opt_fancytables ) {
print INDEX "
";
print INDEX "${opt_tables_top}"
if ($opt_tables_top ne '');
} else {
#BRAD added fancy tables based entirely on the Igal program
#This section prints the top of the table
my $cols = $opt_columns;
if ( $numimages < $cols) { $cols=$numimages; }
print INDEX "\n";
print INDEX " ";
}
}
else
{
#
# Add image map info to html file
#
my $mapname = "thumbnails";
if ($opt_serversidemap) {
if ( "${opt_htimage}" ne '' ) {
print( INDEX
"\n" );
} else {
print( INDEX
" \n");
}
}
print( INDEX
" " );
print( INDEX " " ) if ($opt_serversidemap);
print( INDEX "\n\n" );
} # unless ( $opt_tables )
my $imageNum;
my $maxNum = $#{$imageNames[$pageNumber-1]};
for( $imageNum = 0; $imageNum <= ${maxNum}; ++$imageNum ) {
my $pic = $imageNames[$pageNumber - 1][$imageNum];
my $pichtml;
my $altlabel;
my $target = '';
if ($opt_pichtml && $opt_frames && "$opt_pichtmltarget" ne '') {
$target = " TARGET=\"${opt_pichtmltarget}\"";
}
if (defined($imageLabels{$pic})) {
$altlabel = $imageLabels{$pic};
} else {
($altlabel = $pic) =~ s/(.*)\.\w+$/$1/i;
$altlabel =~ y/_/ /; # Usual space replacement in file name
}
$altlabel = escapehtml($opt_pichtmlaltstart . $altlabel . $opt_pichtmlaltend);
if ( $opt_pichtml ) {
$pichtml = $pic . $opt_pichtmlext;
open( PICHTML, ">$pichtml")
|| die("$0: Failed to open file $pichtml for output\n$@\n");
print( PICHTML "\n\n\n" );
# Charset is better before title
print( PICHTML " \n" )
if( "$opt_metacharset" ne '' );
print( PICHTML " ${altlabel} \n" );
# Meta tags
print( PICHTML " \n" )
if (!$opt_anonymous);
print( PICHTML " \n" )
if( "$opt_metaauthor" ne '' );
print( PICHTML " \n" )
if( "$opt_metadescription" ne '' );
print( PICHTML " \n" )
if( "$opt_metakeywords" ne '' );
print( PICHTML " \n" )
if( "$opt_metaclassification" ne '' );
# The value of $opt_metaexpires should be similar to:
# "Tue, 20 Aug 1996 14:25:27 GMT"
print( PICHTML " \n" )
if( "$opt_metaexpires" ne '' );
print( PICHTML " \n")
if ("$opt_stylesheet" ne '');
print( PICHTML "\n" );
print( PICHTML "\n" );
print( PICHTML "$opt_pichtmltop") if ("$opt_pichtmltop" ne '');
if ($opt_pichtmlnav) {
print ( PICHTML "");
# Must be visible at each page, if no frames
if (!$opt_frames) {
# --- readme link ---
if ( $haveReadme ) {
print (PICHTML " \n");
}
}
# up
if ( (!$opt_frames || $opt_framestyle == 1) && $opt_pichtmlupfirst ) {
if ($opt_frames) {
print ( PICHTML " \n");
}
# prev
if (($imageNum == 0) && ($pageNumber == 1)) {
#BRAD: Added edgelinks link back to index
if ( $opt_edgelinksindex ) {
if ($opt_frames) {
print ( PICHTML "");
} else {
print ( PICHTML " ");
}
}
print ( PICHTML " \n");
if ( $opt_edgelinksindex ) {
print ( PICHTML " ");
}
} else {
print ( PICHTML " \n");
}
# up if in middle (added by BRAD)
if ( (!$opt_frames || $opt_framestyle == 1) && !$opt_pichtmlupfirst ) {
if ($opt_frames) {
print ( PICHTML " \n");
}
#next
if (($pageNumber == $numPages) && ($imageNum == $#{$imageNames[$pageNumber - 1]})) {
#BRAD: Added edge links back to index
if ( $opt_edgelinksindex ) {
if ($opt_frames) {
print ( PICHTML "");
} else {
print ( PICHTML " ");
}
}
print ( PICHTML " \n");
if ( $opt_edgelinksindex ) {
print ( PICHTML " ");
}
} else {
print ( PICHTML " \n");
}
}
if ($opt_pichtmlputtitle && $opt_pichtmltitletop) {
print ( PICHTML "${opt_pichtmltitlestart}${altlabel}${opt_pichtmltitleend}");
} elsif ($opt_pichtmlnav) {
print ( PICHTML " ");
}
if ($pic =~ /\.(jpg|jpeg?|gif|xbm|png)$/i) {
print( PICHTML "")
if ($opt_pichtmllink ne '');
print( PICHTML " " );
print( PICHTML " ")
if ($opt_pichtmllink ne '');
} else {
print( PICHTML "", escapehtml($pic), " ", fsize($pic), "" );
}
if ($opt_pichtmlputtitle && !$opt_pichtmltitletop) {
print ( PICHTML "${opt_pichtmltitlestart}${altlabel}${opt_pichtmltitleend}");
}
print( PICHTML "$opt_pichtmlbottom\n") if ("$opt_pichtmlbottom" ne '');
print( PICHTML "\n" );
print( PICHTML "\n" );
close ( PICHTML );
unless ($opt_tables)
{
print( INDEX " \n" );
}
} else
{
unless ($opt_tables)
{
print( INDEX " \n" );
}
}
if ($opt_tables)
{
if ($imageNum%$opt_columns == 0)
{
print INDEX "
";
}
print INDEX "";
if ($opt_pichtml) {
print (INDEX "");
} else {
print (INDEX " ");
}
# TODO: make sure the thumbnails are created, and get some image sizes
# TODO: save the labels in a new array, maybe same with sizes
if ( $thumbImageSizes{$pic}) {
print (INDEX " ");
} else {
print (INDEX " ");
}
print (INDEX " ");
print (INDEX "",
$tableImageLabels{$imageNames[$pageNumber - 1][$imageNum]},
" ")
if ($opt_thumblabel && $opt_thumblabel ne 'false');
print (INDEX " \n");
if ($imageNum%$opt_columns == ($opt_columns - 1))
{
print INDEX " ";
#BRAD: Middle lines in a fancy tables
if ( $opt_fancytables && $imageNum != $maxNum) {
my $cols = $opt_columns;
if ( $maxNum - $imageNum < $opt_columns ) {
$cols = $maxNum%$opt_columns+1;
}
print INDEX " ",
" ",
" " ;
}
}
} # if ($opt_tables)
} # for each picture
if ($opt_tables)
{
unless ($imageNum%$opt_columns == ($opt_columns - 1))
{
print INDEX "";
}
#BRAD:The bottom of a fancy table
if ( $opt_fancytables ) {
my $cols = $maxNum%$opt_columns+1;
print INDEX " ";
}
print INDEX "${opt_tables_bottom}"
if ($opt_tables_bottom ne '');
print (INDEX "
\n")
} else {print( INDEX "\n" );}
}
print( INDEX "${opt_footer}\n" ) if ("$opt_footer" ne '');
# Print Copyright info on non-blank pages.
if( $numimages > 0 ) {
if( $opt_centerfooter ) {
print( INDEX "\n" );
}
if( "${opt_address}" ne '' ) {
print( INDEX "${opt_address} \n" );
}
if( "$htmlOpts{'dateText'}" ne '' || !$opt_anonymous) {
print( INDEX "" );
}
if( "$htmlOpts{'dateText'}" ne '' ) {
print( INDEX " $htmlOpts{'dateText'}\n" );
}
# If anonymous, don't show copyright and address info
if( ! $opt_anonymous ) {
print( INDEX " \n${opt_msg_produced_by} " );
print( INDEX "WebMagick " );
print( INDEX " $webmagickInfo{version}, ${opt_msg_copyright}© Bob Friesenhahn\n" );
}
if( "$htmlOpts{'dateText'}" ne '' || !$opt_anonymous) {
print( INDEX " \n" );
}
if( $opt_centerfooter ) {
print( INDEX " \n");
}
}
print( INDEX "\n" );
print( INDEX "\n" );
# Close current HTML index file
close( INDEX );
return ( $errorstat );
}
#
# Write out JavaScript index files
#
sub writeJavaScriptIndexFiles {
print("Writing JavaScript status file: $fileNames{'jsPageIndex'}\n") if $opt_debug;
#
# Write JavaScript "index" page.
# This page loads JavaScript source files and ensures that windows are drawn
#
open( JSINDEX, ">$fileNames{'jsPageIndex'}")
|| die("$0: Failed to open file $fileNames{'jsPageIndex'} for output\n$@\n");
print( JSINDEX "\n\n\n" );
print( JSINDEX "\n");
print( JSINDEX "\n");
print( JSINDEX "\n");
print( JSINDEX "\n");
print( JSINDEX "\n");
print( JSINDEX "\n");
print( JSINDEX "\n");
close( JSINDEX );
#
# JavaScript Variable definitions
#
open( JSVARS, ">$fileNames{'jsVariables'}")
|| die("$0: Failed to open file $fileNames{'jsVariables'} for output\n$@\n");
print( JSVARS "//\n// WebMagick Run Status File -- JavaScript Format\n//\n" );
#
# Directory global variables
#
print( JSVARS "//\n// Directory-global definitions\n//\n\n" );
# Subdirectory names
print( JSVARS "\n// subdirectory names\n",
jsArray( 'dirNames', @dirNames ) );
# Subdirectory titles
print( JSVARS "\n// subdirectory titles\n",
jsHash( 'dirTitles', \%dirTitles ) );
# Subdirectory links
print( JSVARS "\n// subdirectory links\n", jsHash( 'dirLinks', \%dirJsLink ) );
# Image labels
print( JSVARS "\n// image titles\n", jsHash( 'imageLabels', \%imageLabels ) );
# Image captions
print( JSVARS "\n// image captions\n", jsHash( 'imageCaptions', \%imageCaptions ) );
# Image labels
#print( JSVARS "\n// table image titles\n", jsHash( 'tableImageLabels', \%tableImageLabels ) );
print( JSVARS "\n// table image titles\n",
jsHashToDouble( 'imLabels', \%tableImageLabels ) );
# Montage options ($montageParameters)
# print( JSVARS "\n// montage parameters\n",
# jsVariable( 'montageParameters', \$montageParameters) );
# HTML options
print( JSVARS "\n// HTML options\n",
jsHash( 'htmlOpts', \%htmlOpts ) );
# Icon URLs
print( JSVARS "\n// icon URLs\n",
jsHash( 'iconImageUrls', \%iconImageUrls ) );
# Icon sizes
print( JSVARS "\n// icon sizes\n",
jsHash( 'iconImageSizes', \%iconImageSizes ) );
# Thumbnail image sizes
#print( JSVARS "\n// thumb sizes\n",
# jsHash( 'thumbImageSizes', \%thumbImageSizes ) );
print ( JSVARS "\n// thumb sizes \n",
jsSizes( 'thumb', \%thumbImageSizes ) );
#
# Page specific variables
#
print( JSVARS "\n//\n// Page-Specific variable definitions\n//\n" );
# Generated File names
# print( JSVARS "\n// file names\n",
# jsHash( 'fileNames', \%fileNames ) );
# Image names
print( JSVARS "\n// image names (imageNames[page number][image number])\n",
jsDoubleArray( 'imageNames', @imageNames) );
# Image thumbnail map (co-ordinate) information (@imageThumbCoords)
print( JSVARS "\n// thumbnail coordinates (imageThumbCoords[page number])\n",
jsDoubleArray( 'imageThumbCoords', @imageThumbCoords ) );
# Montage image names (@montageImages) already in per-page array form
print( JSVARS "\n// montage image names (montageImages[page number])\n",
jsArray( 'montageImages', @montageImages) );
# Montage image sizes (@montageImageSizes) already in per-page array form
print( JSVARS "\n// montage image sizes (montageImageSizes[page number])\n",
jsArray( 'montageImageSizes', @montageImageSizes) );
# Set flag to indicate this file completely loaded
print( JSVARS "\nvar jsVarsLoaded = 1;\n" );
close( JSVARS );
print("Done writing JavaScript\n") if $opt_debug;
}
#
# Write out PERL-format run-status file
#
sub writePerlIndexFiles {
open( PERLVARS, ">$fileNames{'pageStatus'}" )
|| die( "Unable to open file $fileNames{'pageStatus'}!\n$@\n" );
print(STDERR "Writing PERL status file: $fileNames{'pageStatus'}\n") if $opt_debug;
print( PERLVARS "#\n# WebMagick Run Status File -- PERL Format\n#\n\n" );
#
# Directory global variables
#
print( PERLVARS "#\n# Directory-global definitions\n#\n" );
# Subdirectory names (@dirNames)
print( PERLVARS "\n# subdirectory names\n",
plArray( 'dirNames', @dirNames ) );
# Subdirectory titles
print( PERLVARS "\n# subdirectory titles\n",
plHash( 'dirTitles', \%dirTitles ) );
# Image labels
print( PERLVARS "\n# image titles\n", plHash( 'imageLabels', \%imageLabels ) );
# Image captions
print( PERLVARS "\n# image captions\n", plHash( 'imageCaptions', \%imageCaptions ) );
# Table image labels
print( PERLVARS "\n# table image titles\n", plHash( 'tableImageLabels', \%tableImageLabels ) );
# Montage options ($montageParameters)
print( PERLVARS "\n# montage parameters\n",
plVariable( 'montageParameters', \$montageParameters) );
# HTML options ($htmlParams)
print( PERLVARS "\n# HTML options\n",
plVariable( 'htmlParams', \$htmlParams ) );
# Icon URLs
print( PERLVARS "\n# icon URLs\n",
plHash( 'iconImageUrls', \%iconImageUrls ) );
# Icon sizes
print( PERLVARS "\n# icon sizes\n",
plHash( 'iconImageSizes', \%iconImageSizes ) );
# Thumb sizes
print( PERLVARS "\n# thumb sizes\n",
plHash( 'thumbImageSizes', \%thumbImageSizes ) );
#
# Page-Specific variable definitions
#
print( PERLVARS "\n#\n# Page-specific variables\n#\n" );
# Image names (@imageNames)
print( PERLVARS "\n# image names (\$imageNames[page number][image number])\n",
plDoubleArray( 'imageNames', @imageNames) );
# Image thumbnail map (co-ordinate) information (@imageThumbCoords)
print( PERLVARS "\n# thumbnail coordinates (\$imageThumbCoords[page number][thumb number])\n",
plDoubleArray( 'imageThumbCoords', @imageThumbCoords ) );
# Montage image names (@montageImages) already in per-page array form
print( PERLVARS "\n# montage image names (\$montageImages[page number])\n",
plArray( 'montageImages', @montageImages ) );
# Montage image sizes (@montageImageSizes) already in per-page array form
print( PERLVARS "\n# montage image sizes (\$montageImageSizes[page number])\n",
plArray( 'montageImageSizes', @montageImageSizes ) );
# Indicate the version used for processing
# This way we can regenerate things if we need a newer version
print (PERLVARS "\n\$perlVarsVersion = $requiredPerlVarsVersion;\n" );
# Set flag to indicate this file completely loaded
print( PERLVARS "\n\$perlVarsLoaded = 1;\n" );
close( PERLVARS );
}
#
# Build montage using PerlMagick
#
sub doMontage {
my $errorstat = 1; # Started with "failed" status
use Image::Magick;
my (
$imagename, # Image name
$image, # An individual image
$montage, # Montage of images
# $newthumb, # Set to 1 if new thumbnail
$status, # Return status
$thumbs # Thumbnail array
);
# If we need to, then do the expensive stuff Build index
# files via PerlMagick's Montage operation. Go out of our
# way to avoid problems with multi-image files. JPEG does not
# support transparency but we fudge by setting the
# background color in the JPEG file to the page color.
# Hopefully browsers that support JPEG also support
# setting the background
unlink(
$fileNames{'montageGIF'},
$fileNames{'montageJPEG'},
);
#
# If caching thumbnails then ensure that directory exists
#
mkdir( $opt_cachedir, 0755 ) if ($opt_cache || $opt_tables) && ! -d $opt_cachedir;
#
# If caching low resolution images then ensure that directory exists
#
mkdir( $opt_lowresdir, 0755 ) if $opt_lowres && ! -d $opt_lowresdir;
# Read images into PerlMagick object
print( STDERR "\nReading images: ", join(' ', @{$imageNames[$pageNumber - 1]}), "\n" )
if $opt_debug;
# Allocate thumbnail image
$thumbs = Image::Magick->new;
# Allocate scratch image
$image = Image::Magick->new;
# Allocate and read Netscape map image (Netscape 216 color cube)
# No need to do an allocation if we are not doing the mapping.
if ($opt_mapnetscape) {
$netscapeColormap = Image::Magick->new;
$status = $netscapeColormap->Read('netscape:');
handleMagickError( __FILE__, __LINE__, 'netscape:', $status) if "$status";
}
MONTAGE:
{
READ:
foreach $imagename (@{$imageNames[$pageNumber - 1]}) {
my ($rc, #return code
$width, # Image width
$height, # Image height
$filesize, # Image file size
$magick);
if ($opt_lowres) {
#PMF: resize images using createLowResolutionImage()
#first do the low resolution image
($rc, $filesize, $width, $height, $magick) =
&createLowResolutionImage ($image, $opt_lowresdir, $imagename, 0, 1, 0,
$opt_forcelowres, $opt_lowresgeom,
$opt_lowresformat, $opt_lowresmin,
0, 0);
undef @$image; # Only delete image data, not object
if ($rc == -1) {
print("Trying next image...\n");
next READ;
}
}
#then do the thumbnail
($rc, $filesize, $width, $height, $magick) =
&createLowResolutionImage ($image, $opt_cachedir, $imagename, $opt_cache, 0, $opt_tables,
$opt_forcecache, $opt_thumbgeometry,
$opt_cacheformat, $opt_cachemin,
$opt_thumbprehook, $opt_thumbposthook);
if ($rc == -1) {
undef @$image; # Only delete image data, not object
print("Trying next image...\n");
next READ;
}
#
# Add thumbnail to thumbs array
#
push(@$thumbs, @$image);
# Only delete image data, not object
undef @$image;
}
# READ end block
#
# Set common image attributes
#
if( $opt_thumbframebgcolor ne 'false' ) {
$status = $thumbs->Set( bordercolor=>$opt_thumbframebgcolor );
if( "$status" ) {
handleMagickError( __FILE__, __LINE__, "", $status);
last MONTAGE;
}
}
if( $opt_thumbframecolor ne 'false' ) {
$status = $thumbs->Set( mattecolor=>$opt_thumbframecolor );
if( "$status" ) {
handleMagickError( __FILE__, __LINE__, "", $status);
last MONTAGE;
}
}
# New-style way to set label text foreground color
# Somewhere along the way 'foreground' started being ignored by montage
if( $opt_thumbforeground ne 'false' ) {
$status = $thumbs->Set( pen=>$opt_thumbforeground );
if( "$status" ) {
handleMagickError( __FILE__, __LINE__, "", $status);
last MONTAGE;
}
}
unless ($opt_tables)
{
#
# Do the montage
#
print( STDERR "Creating montage using options:\n $montageArguments\n" )
if $opt_debug;
eval "\$montage = \$thumbs->Montage( $montageArguments ) ;";
if( $@ ) {
handleMagickError( __FILE__, __LINE__, "", $@);
last MONTAGE;
}
handleMagickError( __FILE__, __LINE__, "", $montage) unless ref($montage);
last MONTAGE unless ref($montage);
#
# Obtain imagemap info (thanks to Cristy for the relevant code)
#
{
my @thumbCoords;
my $montageWidth = $montage->Get('width');
my $montageHeight = $montage->Get('height');
$montage->Get('montage')=~/(\d+)x(\d+)\+(\d+)\+(\d+)/;
my $thumbWidth=$1;
my $thumbHeight=$2;
my $x=$3;
my $y=$4;
my $directory = $montage->Get('Directory');
print( STDERR "Montage directory = $directory\n" ) if $opt_debug;
for (split(/\n/,$directory))
{
my $x1 = $x;
my $y1 = $y;
my $x2 = $x+$thumbWidth-1;
my $y2 = $y+$thumbHeight-1;
push(@thumbCoords, "$x1,$y1,$x2,$y2");
$x+=$thumbWidth;
if ($x >= $montageWidth)
{
$x=0;
$y+=$thumbHeight;
}
}
if( !defined($imageThumbCoords[$pageNumber - 1]) ||
("@{$imageThumbCoords[$pageNumber - 1]}" ne "@thumbCoords") ) {
$imageThumbCoords[$pageNumber - 1] = [ @thumbCoords ];
print( STDERR "Thumbnail coordinates have changed, must re-do HTML page\n" )
if $opt_debug;
++$doPageHtml;
}
}
#
# Process & Write GIF file
#
# Copy image so we can play with it without effecting original
print( STDERR "Copying montage to scratch ...\n" )
if $opt_debug;
$image = $montage->Copy();
handleMagickError( __FILE__, __LINE__, "", $image) unless ref($image);
last MONTAGE unless ref($image);
if ($opt_mapnetscape) {
print( STDERR "Mapping $fileNames{'montageGIF'} to Netscape 216 color cube...\n" )
if $opt_debug;
$status = $image->Map(image=>$netscapeColormap, dither=>'True');
handleMagickError( __FILE__, __LINE__, "", $status) if "$status";
}
if( ! $opt_forcejpeg ) {
print( STDERR "Writing $fileNames{'montageGIF'} ...\n" ) if $opt_debug;
$status = $image->Write(
dither=>'True',
filename=>"GIF:$fileNames{'montageGIF'}",
interlace=>'Line'
);
handleMagickError( __FILE__, __LINE__, $fileNames{'montageGIF'}, $status) if "$status";
last MONTAGE if "$status";
undef @$image;
}
# If not doing GIF only, do JPEG
if( ! $opt_forcegif ) {
# Only do JPEG if GIF is large.
# Most reasonable GIFs are under 30K
if( $opt_forcejpeg || fsize( $fileNames{'montageGIF'} ) > $opt_maxgif ) {
# Write JPEG file
print( STDERR "Writing $fileNames{'montageJPEG'} ...\n" )
if $opt_debug;
$status = $montage->Write(
filename=>"JPEG:$fileNames{'montageJPEG'}",
interlace=>'Plane',
quality=>$opt_jpegquality
);
handleMagickError( __FILE__, __LINE__, $fileNames{'montageJPEG'}, $status) if "$status";
last MONTAGE if "$status";
} else {
print( STDERR "Avoiding JPEG image since GIF is small enough\n" )
if $opt_debug;
}
} else {
print( STDERR "Avoiding JPEG image due to forcegif option\n" )
if $opt_debug;
}
# Decide to use GIF or JPEG version of output depending on size.
# If there is only one type then no need.
if( -f $fileNames{'montageGIF'} && -f $fileNames{'montageJPEG'} ) {
if( fsize($fileNames{'montageGIF'}) > fsize($fileNames{'montageJPEG'}) ) {
print( STDERR "Choosing JPEG since it is smaller\n" )
if $opt_debug;
unlink($fileNames{'montageGIF'}); # Use JPEG
} else {
print( STDERR "Choosing GIF since it is smaller\n" )
if $opt_debug;
unlink($fileNames{'montageJPEG'}); # Use GIF
}
}
} # unless ($opt_tables)
$errorstat = 0; # If it made it this far, then no error
}
# MONTAGE end block
# Delete montage image
#print( STDERR "Freeing montage image ...\n" ) if $opt_debug;
undef @$montage; # FIXME: Can't use string ("Warning 310: No images to montag") as an ARRAY ref while "strict refs" in use
undef $montage;
# Delete thumbnails
#print( STDERR "Freeing thumbnail images ...\n" ) if $opt_debug;
undef @$thumbs;
undef $thumbs;
# Delete scratch image
#print( STDERR "Freeing scratch image ...\n" ) if $opt_debug;
undef @$image;
undef $image;
# Delete Netscape map image
if ($opt_mapnetscape) {
#print( STDERR "Freeing Netscape map image ...\n" ) if $opt_debug;
undef @$netscapeColormap;
undef $netscapeColormap;
}
unlink(
$fileNames{'montageJPEG'},
$fileNames{'montageGIF'}
) if $errorstat;
return( $errorstat );
}
#
# Write out server-side imagemap data
#
sub writeImageMap {
my $errorstat = 0;
my $pindexname;
my $pNumber;
# Write out server-side imagemap (CERN or NCSA)
# This uses the absolute path as the URL or a relative one
# from the referring URL
# The server must map URLs specified with filesystem paths
# or support relative URLs from the referrer (Apache &
# latest NCSA do).
print( STDERR "Writing file $fileNames{'montageServerMap'} ...\n" ) if $opt_debug;
open( IMAGEMAP, ">$fileNames{'montageServerMap'}" )
|| die("$0: Failed to open file $fileNames{'montageServerMap'} for output\n$@\n");
# default URL
if (!$opt_frames) {
$pNumber = ($pageNumber == 1) ? "" : "$pageNumber";
$pindexname = "${pNumber}${opt_indexname}";
} else {
$pindexname = "${opt_pageindexname}${pageNumber}${opt_htmlext}";
}
if ( "${opt_htimage}" ne '' ) {
print( IMAGEMAP "default "
. abs_path_to_url("${sourceDirectory}/${pindexname}")
. "\n" );
} else {
print( IMAGEMAP "default ${pindexname}\n" );
}
my $imageNum;
for( $imageNum = 0; $imageNum <= $#{$imageNames[$pageNumber - 1]}; ++$imageNum ) {
my $url = escapeurl($imageNames[$pageNumber - 1][$imageNum]);
my($x1,$y1,$x2,$y2);
($x1,$y1,$x2,$y2) = split(',', $imageThumbCoords[$pageNumber - 1][$imageNum]);
if( $opt_pichtml ) {
$url .= $opt_pichtmlext;
}
if( $opt_maptype eq 'ncsa' ) {
if ( "${opt_htimage}" ne '' ) {
print( IMAGEMAP "rect "
. abs_path_to_url("${sourceDirectory}/${url}")
. " $x1,$y1 $x2,$y2\n" );
} else {
print( IMAGEMAP "rect ${url} $x1,$y1 $x2,$y2\n" );
}
} elsif ( $opt_maptype eq 'cern' ) {
if ( "${opt_htimage}" ne '' ) {
print( IMAGEMAP "rect ($x1,$y1) ($x2,$y2) "
. abs_path_to_url("${sourceDirectory}/${url}")
. "\n" );
} else {
print( IMAGEMAP "rect ($x1,$y1) ($x2,$y2) ${url}\n" );
}
} else {
die( "\nError: \$opt_maptype must be \"cern\"",
" or \"ncsa\".\n" );
}
}
close( IMAGEMAP );
$errorstat=0;
return( $errorstat );
}
#
# Return string to represent JavaScript array
# Usage: jsArray('arrayName', @array)
#
sub jsArray {
my($arrayName, @elements) = @_;
my($result) = "var ${arrayName} = new Array(\n";
my $i;
for $i (0 .. $#elements) {
$result .= "\t\'" . escapejs($elements[$i]) . "\'";
$result .= ',' if $i < $#elements;
$result .= "\n";
}
$result .= ");\n";
return $result;
}
#
# Return string to represent JavaScript double-dimensioned array
# Usage: jsDoubleArray('arrayName', @array)
# .
sub jsDoubleArray {
my($arrayName, @elements) = @_;
my($result) = "var ${arrayName} = new Array(\n";
my $i;
for $i (0 .. $#elements) {
$result .= "\tnew Array(\n";
my $j;
for $j (0 .. $#{$elements[$i]}) {
$result .= "\t\t\'" . escapejs($elements[$i][$j]) . "\'";
$result .= ',' if $j < $#{$elements[$i]};
$result .= "\n";
}
$result .= "\t)";
$result .= ',' if $i < $#elements;
$result .= "\n";
}
$result .= ");\n";
return $result;
}
#
# Return string to represent Javascript array
# from a hash
# Usage: jsHashToDouble('objectName', \%hashName)
#
sub jsHashToDouble {
my ( $name, $hash) = @_;
my $result = "var ${name} = new Array(\n";
my $i;
for $i (0 .. $#imageNames) {
$result .= "\tnew Array(\n";
my $j;
for $j (0 .. $#{$imageNames[$i]}) {
$result .= "\t\t'";
if ($$hash{$imageNames[$i][$j]}) {
$result .= escapejs($$hash{$imageNames[$i][$j]});
} else {
$result .= "0";
}
$result .= "\'";
$result .= ',' if $j < $#{$imageNames[$i]};
$result .= "\n";
}
$result .= "\t)";
$result .= ',' if $i < $#imageNames;
$result .= "\n";
}
$result .= ");\n";
return $result;
}
#
# Return string to represent 2 Javascript double
# arrays representing width and height
# Usage: jsSizes('objectNamePrefix', \%hashName)
#
sub jsSizes {
my ( $nameprefix, $hash) = @_;
my $result = "var ${nameprefix}widths = new Array(\n";
my $i;
for $i (0 .. $#imageNames) {
$result .= "\tnew Array(\n";
my $j;
for $j (0 .. $#{$imageNames[$i]}) {
if ($$hash{$imageNames[$i][$j]} =~ /WIDTH=([0-9]+)/) {
$result .= "\t\t'" . $1 . "\'";
$result .= ',' if $j < $#{$imageNames[$i]};
$result .= "\n";
} else {
$result .= "\t\t'0\'";
$result .= ',' if $j < $#{$imageNames[$i]};
$result .= "\n";
}
}
$result .= "\t)";
$result .= ',' if $i < $#imageNames;
$result .= "\n";
}
$result .= ");\n";
$result .= "\nvar ${nameprefix}heights = new Array(\n";
for $i (0 .. $#imageNames) {
$result .= "\tnew Array(\n";
my $j;
for $j (0 .. $#{$imageNames[$i]}) {
if ($$hash{$imageNames[$i][$j]} =~ /HEIGHT=([0-9]+)/) {
$result .= "\t\t'" . $1 . "\'";
$result .= ',' if $j < $#{$imageNames[$i]};
$result .= "\n";
} else {
$result .= "\t\t'0\'";
$result .= ',' if $j < $#{$imageNames[$i]};
$result .= "\n";
}
}
$result .= "\t)";
$result .= ',' if $i < $#imageNames;
$result .= "\n";
}
$result .= ");\n";
return $result;
}
#
# Return string to represent JavaScript associative array
# Usage: jsHash('objectName', \%hashName)
#
sub jsHash {
my( $name, $hash) = @_;
my $result = '';
$result .= "var ${name} = new Object();\n";
my $key;
foreach $key (sort(keys(%$hash))) {
if(defined($$hash{$key})) {
if($$hash{$key} =~ /^\d+$/) {
# numeric
$result .= "${name}" . '["' . $key . '"] = ' . escapejs($$hash{$key}) . ";\n";
} else {
# text string gets quoted
$result .= "${name}" . '["' . $key . '"] = \'' . escapejs($$hash{$key}) . "\';\n";
}
}
}
return $result;
}
#
# Return string to represent JavaScript variable
# Usage: jsVariable('variableName', \$variableName)
#
sub jsVariable {
my( $name, $variable) = @_;
my $result = "${name} = \'" . escapejs($$variable) . "\';\n";
return $result;
}
#
# Return string to represent PERL list
# Usage: plArray('arrayName', @array)
#
sub plArray {
my($arrayName, @elements) = @_;
my($result) = "\@${arrayName} = (\n";
my $elem;
foreach $elem (@elements) {
if(defined($elem)) {
$result .= "\t\'" . escapeperl($elem) . "\',\n";
} else {
$result .= "\t\'\',\n";
}
}
$result .= ");\n";
return $result;
}
#
# Return string to represent PERL list of lists
# Usage: plDoubleArray('arrayName', @array)
#
sub plDoubleArray {
my($arrayName, @elements) = @_;
my($result) = "\@${arrayName} = (\n";
my $slow;
for $slow (0 .. $#elements) {
$result .= " [\n";
my $fast;
for $fast (0 .. $#{$elements[$slow]}) {
#print( "element $slow $fast is $elements[$slow][$fast]\n");
$result .= "\t\'" . escapeperl($elements[$slow][$fast]) . "\',\n";
}
$result .= " ],\n";
}
$result .= ");\n";
return $result;
}
#
# Return string to represent PERL associative array
# Usage: plHash('objectName', \%hashName)
#
sub plHash {
my( $name, $hash) = @_;
my $result = "\%${name} = (\n";
my $key;
foreach $key (sort(keys(%$hash))) {
if(defined($$hash{$key})) {
$result .= "\t\'" . escapeperl($key) . "\' => \'" . escapeperl($$hash{$key}) . "\',\n";
}
}
$result .= ");\n";
return $result;
}
#
# Return string to represent PERL variable
# Usage: plVariable('variableName', \$variableName)
#
sub plVariable {
my( $name, $variable) = @_;
my $result = "\$${name} = \'" . escapeperl($$variable) . "\';\n";
return $result;
}
#
# Routine used by 'sort' to sort directories
# %dirOrder # Order directories are listed in dirindex file
sub sortDir {
if(defined($dirOrder{$a}) && defined($dirOrder{$b})) {
$dirOrder{$a} <=> $dirOrder{$b}
} elsif(defined($dirOrder{$a})) {
return -1;
} elsif(defined($dirOrder{$b})) {
return 1;
} else {
lc($a) cmp lc($b);
}
}
#
# Routine used by 'sort' to sort images
# %imageOrder # Order that images occur in imgindex file
sub sortImages {
if(defined($imageOrder{$a}) && defined($imageOrder{$b})) {
$imageOrder{$a} <=> $imageOrder{$b}
} elsif(defined($imageOrder{$a})) {
return -1;
} elsif(defined($imageOrder{$b})) {
return 1;
} else {
lc($a) cmp lc($b);
}
}
#
# Return current directory
#
sub cwd {
local($_);
chomp($_ = getcwd());
# fix path name for Win32
if ($^O eq "MSWin32") { s:/:\\:g; };
return $_;
}
#
# Return size of file in bytes (size)
#
sub fsize {
my($name) = @_;
return ((stat($name))[7]);
}
#
# Return file modification time (mtime)
#
sub fmtime {
my($name) = @_;
return ((lstat($name))[9]);
}
#
# Return file name portion of path
#
sub basename {
my($name) = @_;
$name =~ s:([^\/]*/)+::;
$name =~ s:([^\\]*\\)+::;
return($name);
}
#
# Return directory name portion of path
#
sub dirname {
my($name) = @_;
$name =~ s:(/[^\/]+$)::g;
return($name);
}
#
# Compare two associative arrays
#
sub compareHash {
my( $hash1, $hash2) = @_;
if (defined(%$hash1) != defined(%$hash2)) {
return( 1 );
}
if(scalar(keys(%$hash1)) != scalar(keys(%$hash2))) {
return( 1 ); # different length
}
my $key;
foreach $key (keys(%$hash1)) {
if(( defined($$hash1{$key}) && !defined($$hash2{$key})) ||
( !defined($$hash1{$key}) && defined($$hash2{$key}))) {
return( 1 ); # different
}
if( defined($$hash1{$key}) && defined($$hash2{$key}) ) {
if($$hash1{$key} ne $$hash2{$key}) {
return( 1 ); # different
}
}
}
return(0);
}
#
# Generic error handler routine to handle Magick reported errors
# Numeric error codes are currently used to aid backward compatability
# in spite of the fact that Magick.pm exports these constants
#
# Returns 0 when normal processing may continue
# Returns 1 when alternative processing (e.g. skip defective image) is recommended
# Exits process for serious problems
#
# Use similar to:
# $status = $image->Read("${imagename}\[0\]");
# handleMagickError( __FILE__, __LINE__, $imagename, $status) if "$status";
#
sub handleMagickError {
my ($file, $line, $argument, $error) = @_;
$error =~ /(\d+)/;
my $errorCode = $1;
# Benign warnings
if (
( $errorCode == 300 ) || # ResourceLimitWarning
( $errorCode == 305 ) || # XServerWarning
( $errorCode == 310 ) || # OptionWarning
( $errorCode == 315 ) || # PluginWarning
( $errorCode == 320 ) ) # MissingPluginWarning
{
warn('PerlMagick:"', $file, '", line ', $line, ', ', $error, "\n");
return 0;
}
# Corrupt image problem
elsif (
( $errorCode == 325 ) || # CorruptImageWarning
( $errorCode == 430 ) # getting this on bad symlinks
)
{
my $imagename = $argument;
warn("Warning: Image $imagename is defective\n");
# Evaluate contents of $opt_readfailhook if image fails to
# read A typical action here would be to unlink the image file
if( $opt_readfailhook ) {
print("Evaluating read-failure hook ...\n$opt_readfailhook\n" )
if $opt_debug;
eval $opt_readfailhook;
}
return 1;
}
# Errors we consider fatal (until proven otherwise)
# Presumably the user can rectify the problem
elsif (
( $errorCode == 330 ) || # FileOpenWarning
( $errorCode == 400 ) || # ResourceLimitError
( $errorCode == 405 ) || # XServerError
( $errorCode == 410 ) # OptionError
)
{
die('PerlMagick fatal error:"', $file, '", line ', $line, ', ', $error, "\n");
}
# Other problems
warn('PerlMagick:"', $file, '", line ', $line, ', ', $error, "\n");
return 0;
}
#
# Get icon image sizes
# Sets or updates value of %iconImageSizes hash
# Sets the value of $opt_forcehtml to true if existing hash is altered
#
sub getIconImageSizes {
my %tmp_iconImageSizes;
my $icon;
for $icon ( keys %opt_icons ) {
if( $opt_icons{$icon} ) { # if defined
my $icon_path = $icon_dir_path . ${pathSep}. $opt_icons{$icon};
if( !defined( $icon_paths{$icon} ) || ( $icon_paths{$icon} ne $icon_path )) {
$icon_paths{$icon} = $icon_path;
$ tmp_iconImageSizes{$icon} = html_imgsize( $icon_path );
}
}
}
if( !defined(%iconImageSizes) || ( compareHash(\%iconImageSizes,\%tmp_iconImageSizes) ) ) {
%iconImageSizes = %tmp_iconImageSizes;
print( STDERR "Icon sizes have changed, must re-do all HTML\n" )
if $opt_debug;
$opt_forcehtml = 1;;
}
}
#
# Get the physical path for a specified directory/file path
#
sub lets_get_physical {
my( $path ) = @_;
my $physical=$path;
if( -d $path ) {
my( $savedir ) = cwd();
chdir( $path );
$physical=cwd();
chdir( $savedir );
}
if( -f $path ) {
my($dir)=dirname($path);
my($fname)=basename($path);
my( $savedir ) = cwd();
chdir( $dir );
$physical=cwd();
chdir( $savedir );
$physical .= "/$fname";
}
return( $physical );
}
######################################################################
# PMF: Create a low resolution of the image
#returns 0 if everything went fine, -1 if the image does not exist
sub createLowResolutionImage () {
my ($image, $a_dir, $imagename, $a_cache, $a_lowres, $a_tables,
$a_force, $a_geometry, $a_cacheformat, $a_cachemin,
$a_prehook, $a_posthook) = @_;
my (
$newthumb, # Set to 1 if new thumbnail
$status # Return status
);
my (
$width, # Image width
$height, # Image height
$base_columns, # Original width
$base_rows, # Original height
$class, # Image class
$comment, # Image comment
$depth, # Image color depth
$filesize, # Image file size
$magick # Image magick
);
#
# Handle thumbnail/lowres cache
#
my $cachename = "${a_dir}/${imagename}.\L${a_cacheformat}";
$newthumb = 1; # Start presuming that thumbnail is new
# If we are caching, and cache thumbnail exists and is newer then use it
# always make cache if doing tables, or if version is not correct
if ( ($a_cache || $a_tables || $a_lowres) && ! $a_force && -f $cachename
&& (fmtime($cachename) >= fmtime($imagename))) {
# Read image
print( STDERR "Reading $cachename ...\n" ) if $opt_debug;
$status = $image->Read("$cachename");
if ("$status") {
handleMagickError( __FILE__, __LINE__, $cachename, $status);
return -1; # Try to read next image
}
# Obtain original image parameters
$comment = $image->Get("comment");
if ($comment =~
# xv 3.00 & 3.10 format
/IMGINFO:(\d+)x(\d+) (\S+) file\s+\((\d+) bytes\)/ ) {
$width = $1;
$height = $2;
$magick = $3;
$filesize = $4;
} else {
print( STDERR "Failed to grock image info from thumbnail ${cachename}!\n",
"Removing cache file ...\n" );
print( STDERR "Run WebMagick again to re-generate the thumbnail.\n" );
print( STDERR "If problem continues then your ImageMagick is out of date.\n" );
unlink( $cachename );
}
# Indicate that thumbnail came from cache
$newthumb = 0;
} else {
# Otherwise, read and scale image
# Set desired image read size. The JPEG library will
# read and return a reduced image which is at least
# the size specified (it returns a number of standard
# scaled sizes) but not smaller.
# This uses a feature available in PerlMagick 1.12 and beyond
$status = $image->Set(size=>$a_geometry);
if ("$status") {
handleMagickError( __FILE__, __LINE__, "$a_geometry", $status);
return -1; # Try to read next image }
}
# Read image
print( STDERR "Reading ${imagename}\[0\] with geometry ${a_geometry}...\n" ) if $opt_debug;
$status = $image->Read("${imagename}\[0\]");
if ("$status") {
handleMagickError( __FILE__, __LINE__, $imagename, $status);
return -1; # Try to read next image }
}
# Scale image and obtain original parameters if not from cache
if ( $newthumb ) {
#
# Apply any PerlMagick operations specified by $a_prehook
#
if ( $a_prehook ) {
print("Evaluating thumbnail pre-hook ...\n$a_prehook\n" )
if $opt_debug;
eval $a_prehook;
}
# Obtain image parameters
( $width, $height, $filesize, $magick, $class, $depth ) =
$image->Get(
'width',
'height',
'filesize',
'magick',
'class',
'depth');
if ( $opt_debug ) {
print("Image: ${width}x${height} $class $filesize bytes $magick $depth bits\n");
}
# Obtain original image size. This uses a feature
# available in PerlMagick 1.12 and beyond. If the
# feature is not supported then undefined values
# should be returned.
($base_columns, $base_rows) = $image->Get('base-columns', 'base-rows');
if ( defined($base_columns) && defined($base_rows) ) {
$width = $base_columns;
$height = $base_rows;
print("Saving original image size ${base_columns}x${base_rows}\n")
if $opt_debug;
}
my $geometry;
if ($a_cache && !$a_tables && !$a_lowres) {
$geometry = $opt_cachegeom;
} else {
$geometry = $a_geometry;
}
my $a_sampling = 0; # Set to 1 to enable sampling
if ( $class eq 'PseudoClass' && $a_sampling ) {
print( STDERR "Sampling $imagename to geometry \"${geometry}>\" ...\n")
if $opt_debug;
$status = $image->Sample(geometry=>"${geometry}>");
} else {
print( STDERR "Zooming $imagename with geometry \"${geometry}>\" ...\n")
if $opt_debug;
$status = $image->Zoom(filter=>"${opt_zoomfilter}",
blur=>0.6,
geometry=>"${geometry}>" );
}
if ("$status") {
handleMagickError( __FILE__, __LINE__, $imagename, $status);
return -1; # Try to read next image
}
}
#
# Apply any PerlMagick operations specified by $a_posthook
#
if ( $a_posthook ) {
print("Evaluating thumbnail post-hook ...\n$a_posthook\n" ) if $opt_debug;
eval $a_posthook;
}
# If we are caching, thumbnail is new, and image is
# large enough, then write it to thumbnail cache
# if we are using tables or lowres, then we cache as long as it's new
if ( ($a_cache || $a_tables || $a_lowres) && $newthumb && ((($width*$height) > $a_cachemin) || ($a_tables || $a_lowres ))) {
my $comment="IMGINFO:${width}x${height} ${magick} file (${filesize} bytes)";
print( STDERR "Applying image comment:\n${comment}\n") if $opt_debug;
# Apply comment to thumbnail image
$status = $image->Comment( $comment );
if ("$status") {
handleMagickError( __FILE__, __LINE__, $cachename, $status);
return -1;
}
print( STDERR "Writing ${cachename} ...\n" )
if $opt_debug;
#
# Give JPEG files special treatment
#
if ( $a_cacheformat eq 'JPEG' || $a_cacheformat eq 'JPG' ) {
$status = $image->Write(
filename=>"${a_cacheformat}:${cachename}",
interlace=>'None',
quality=>85
);
} else {
$status = $image->Write(
filename=>"${a_cacheformat}:${cachename}"
);
}
if ("$status") {
handleMagickError( __FILE__, __LINE__, $cachename, $status);
return -1;
}
if (! $a_lowres) {
# TODO: for some reason, the output looks like these are getting put in twice, once with .cache/
$thumbImageSizes{$imagename} = html_imgsize($cachename);
}
}
}
#
# Set image label
#
my $label = '';
if( $opt_thumblabel && $opt_thumblabel ne 'false' ) {
if( defined( $imageLabels{$imagename} ) ) {
# Set image specific label
$label = $imageLabels{$imagename};
} else {
# Set default label
$label = $opt_thumblabel;
}
}
if ($label ne '') {
my $sizestr;
my $kb = 1024;
my $mb = $kb * $kb;
if( $filesize <= 9999 ) {
# print as bytes
$sizestr = "${filesize}b";
} elsif( $filesize <= 9999999 ) {
# print as kilobytes
my $size = int($filesize/$kb);
$sizestr = "${size}kb";
} else {
# print as megabytes
my $size = int($filesize/$mb);
$sizestr = "${size}Mb";
}
#
# Truncate label down to width $opt_thumblabelwidth
#
my $imagebase;
($imagebase = $imagename) =~ s/\.[^\.]*$//g;
# %b = file size
# %d = directory (not implemented)
# %e = extension (not implemented)
# %f = full filename
# %h = height
# %m = magick
# %n = filename minus extension
# %s = scene number (not implemented)
# %t = top of filename (not implemented)
# %w = width
$label =~ s/%b/$sizestr/g;
$label =~ s/%f/$imagename/g;
$label =~ s/%h/$height/g;
$label =~ s/%m/$magick/g;
$label =~ s/%n/$imagebase/g;
$label =~ s/%w/$width/g;
my @llines = split(/\\n/, $label);
grep($_ = substr( $_, 0, $opt_thumblabelwidth), @llines);
$label = join("\n", @llines);
# put our label into the table image hash
$tableImageLabels{$imagename} = escapehtml($label);
$tableImageLabels{$imagename} =~ s/\n/ /g;
print( STDERR "Applying image label: \"${label}\"\n" )
if $opt_debug;
$status = $image->Label( $label );
if ("$status") {
handleMagickError( __FILE__, __LINE__, $imagename, $status);
return -1;
}
}
return 0;
}
######################################################################
#
# Attempt to build a relative path from specified directory
# to a file given the specified absolute physical path
#
# Usage: relative($dir,$path);
#
# Example: $relative_icon_path = relative($cwd, $absolute_path);
#
sub relative {
my($dir, $path) = @_;
my(@path,@dir);
my $savepath;
my $result;
# Return value from cache if defined
my $index = $dir . '|' . $path;
if( defined($relativePathCache{$index}) ) {
return( $relativePathCache{$index} );
}
$savepath=$path;
# for Win32, just return absolute for now
if ($^O eq "MSWin32") { return $savepath; }
# If not rooted then we are hosed
if ( ( $path !~ m|^/| ) || ($dir !~ m|^/|) ) {
print( "ERROR: The path \"${savepath}\" is not absolute.\n" );
die( "Fix the \$opt_rootpath value and try again.\n" );
}
if( ! -f $path && ! -d $path ) {
print( "ERROR: The specified path \"${savepath}\" does not exist.\n" );
die( "Fix the \$opt_rootpath and \opt_iconpath values and try again.\n" );
}
@path=split('/', $path); # Array form
shift(@path);
@dir=split('/', $dir); # Array form
shift(@dir);
# If roots are not the same, then it is not possible to compute a relative path
# Just return absolute path
if ( $path[0] ne $dir[0] ) {
$result = $savepath;
# Cache and return result
$relativePathCache{$index} = $result;
return( $result );
}
# If the current dir is not inside the document root, just return
# the absolute path
if ( index ($dir,$opt_rootpath) == -1 ) {
$result = $savepath;
# Cache and return result
$relativePathCache{$index} = $result;
return( $result );
}
# Remove common start directories
while( scalar(@path) && scalar(@dir) ) {
last if( $path[0] ne $dir[0] );
shift(@path);
shift(@dir);
}
# Prepend any ../ part
grep($_='..',@dir);
# Return results
if( scalar(@dir) ) {
$result = join('/',@dir,@path) ;
} else {
if( scalar(@path) ) {
$result = './' . join('/',@path);
} else {
$result = '.';
}
}
# Cache and return result
$relativePathCache{$index} = $result;
return $result;
}
#
# Build a relative path to a file given the absolute physical path
# Uses the option variables $opt_rootpath and $opt_prefixpath
#
sub abs_path_to_url {
($_) = @_;
# Remove root prefix if absolute
my $newfile = ${opt_rootpath};
$newfile =~ s/\\/\\\\/g;
s|^$newfile||;
# Tack on prefix (if any)
$_ = "${opt_prefixpath}${_}";
return( $_ );
}
#
# Subroutine to print version information
#
sub version {
print( STDOUT
qq|webmagick $webmagickInfo{version}
| );
}
#
# Subroutine to print help message
#
# WARNING: help2man not understand multi-line option description!
#
sub help {
print( STDOUT
qq|WebMagick `webmagick' recurses through directories of images and builds HTML
pages and image-maps to display those images in a web browser. Options may be
specified on the command line as --option or in .webmagickrc files as \$opt_option.
By default WebMagick processes files in the current directory. See --srcdir for
a way to process files in a different directory.
Usage: webmagick [OPTIONS]
General:
--[no]debug Print debug messages (default off)
--[no]forcecache Force cached thumbnails to be generated (default off)
--[no]forcelowres Force cached low resolution images to be generated (default off)
--[no]forcehtml Force HTML files to be generated (default off)
--[no]forcemontage Force montage (default off)
--[no]ignorefp Ignore directories with names like _vti (FrontPage directories) (default on)
--[no]indexinfo Put "Index of files" (default on)
--[no]help Display usage message (default off)
--[no]recurse Recurse directory tree (default off)
--srcdir Image directory to process
--[no]verbose Tell us more ... (default off)
--[no]version Print version and exit (default off)
Paths:
--iconpath Relative path under rootdir to webmagick icons
--iconbase Global base URL for webmagick icons
--prefixpath Path to prepend to generated URLs (e.g. /~username)
--rootpath Absolute path to server root (NCSA DocumentRoot)
Server-side imagemaps:
--htimage Imagemap CGI program URL (set to '' for none)
--maptype Server-side map type ("ncsa" or "cern")
--[no]serversidemap Enable server-side map writting (default off)
Filenames:
--dirindexname Directory-name to title cross-reference file name
--imgindexname Image-name to thumbnail label cross-reference file name
Line Format: [, ]
or: pageTitle [, ]
--indexname Name of master index files (default server index)
--pageindexname Base name of page-related index files
--readme Name of directory info file
Caching:
--[no]cache Cache thumbnails (default on)
--cachedir Subdirectory name to cache thumbnails in (default .cache)
--cacheformat Format of cached thumbnails (default JPEG)
--cachegeom Cache thumbnail geometry (default thumbgeom)
--cachemin Smallest image to cache in pixels. (default 300*200)
Low resolution images:
--[no]lowres Cache low resolution images (default on for Javascript, off otherwise)
--lowresdir Subdirectory name to cache low resolution images in (default .640x480)
--lowresformat Format of cached low resolution images (default JPEG)
--lowresgeom Cache low resolution geometry (default 640x480+2+2)
--lowresmin Smallest image to resize in pixels. (default 640*480)
Montage:
--[no]forcegif Force imagemap to be in GIF format (default off)
--[no]forcejpeg Force imagemap to be in JPEG format (default off)
--jpegquality Quality of JPEG imagemaps
--maxgif Maximum size of GIF imagemap before trying JPEG
--columns Montage columns
--rows Montage rows (max)
--[no]mapnetscape Map generated image files to Netscape 216-color cube (default off)
--thumbbackground Montage background color
--thumbframebgcolor Background color inside of Frame (unused if no Frame)
--thumbborderwidth Thumbnail border width (pixels)
--thumbcompose Thumbnail image composition operation (default Replace) Over, In, Out, Atop, Xor, Plus, Minus, Add, Subtract, Difference, Bumpmap, Replace, MatteReplace, Mask, Blend, Displace
--thumbfont Thumbnail title font
--thumbforeground Montage foreground color (effects label color)
--thumbframe Geometry of frame around thumbnail (default no frame)
--thumbgeometry Thumbnail geometry (widthxheight)
--thumbgravity Direction thumbnail gravitates to (default Center) NorthWest, North, NorthEast, West, Center, East, SouthWest, South, SouthEast. North is up.
--thumblabel Format for default thumbnail text label
--thumblabelwidth Label width (in characters) to truncate to.
--thumbframecolor Frame color (if thumbnail frames enabled)
--thumbshadow Enable decorative shadow under thumbnail
--thumbtexture Texture to tile onto the image background
--thumbtransparent Transparent color
--zoomfilter Zoom filter algorithm (Box/Triangle/Mitchell)
HTML Colors & Appearance:
--address Optional user address info
--[no]centerfooter Center the footer text (default no)
--[no]anonymous Don't show WebMagick address and copyright info on pages (default off)
--coloralink Link (active) color
--colorback Background color (also applied to JPEG montage background)
--colorfore Foreground text color
--colorlink Link (unvisited) color
--colorvlink Link (visited) color
--dircoloralink Link (active) color (directory frame)
--dircolorback Background color (directory frame)
--dircolorfore Foreground color (directory frame)
--dircolorlink Link (unvisited) color (directory frame)
--dircolorvlink Link (visited) color (directory frame)
--dirhtmlext Extension for directory frame
--forceuplink Force there to be a link to "../index.html" in directory list even if we didn't generate the file
--forcenouplink Force there to be no linke to "../index.hml" in directory list even if we did generate the file
--stylesheet URL to stylesheet (overrides other color options)
--[no]date Output updates date (default on)
--footer Page footer (imagemap frame) (default to )
--header Page header (imagemap frame) (default to )
--[no]javascript Enable JavaScript output (default off)
--[no]readmevisible Show README.html on first page rather than just linking (default off)
--[no]tables Use HTML tables instead of imagemaps for thumbnails (default off)
--tables_params Table HTML parameters
--tables_top HTML before table contents
--tables_bottom HTML after table contents
--title Page title
Per-image HTML options:
--[no]pichtml Per-image HTML file generation (default off)
--pichtmlaltend Some words to append to ALT= (default "")
--pichtmlaltstart Some words to prepend to ALT= (default "")
--pichtmlbottom Per-image HTML, extra HTML to display below image (default to )
--pichtmlext Per-image HTML file extension (default .html)
--[no]pichtmlnav Per-image HTML, show navigation buttons (default off)
--[no]pichtmlupfirst Put Up icon before prev, next icons (default on)
--[no]pichtmlputtitle Put per-image HTML picture title (default on)
--[no]pichtmltitletop Put per-image picture title above image (default on)
--[no]edgelinksindex Edge-links on per-image HTML link back to index (default off)
--pichtmltarget Per-image HTML default frame target
--pichtmltitleend End tags for per-image HTML picture title (default )
--pichtmltitlestart Start tags for per-image HTML picture title (default )
--pichtmltop Per-image HTML, extra HTML to display above image (default to
)
--[no]fancytables Use a fancier HTML table (default off). Caution, the default
colors do not look good with this option.
Frame Options:
--[no]frames Use frames, if no - single directory collection assumed (default on)
--framemarginwidth Pixels allocated to frame margin in horizontal direction (default 1)
--framemarginheight Pixels allocated to frame margin in vertical direction (default 1)
--frameborder Enable (1, default) or disable (0) decorative frame borders
--framestyle Frame style to use (out of those available)
--[no]allowconfig Allow user to configure framestyle, columns and rows (requires javascript and tables) (default off)
Messages Replacement:
--msg_copyright "Copyright "
--msg_date_format "\%B \%e, \%Y" (see strftime(3))
--msg_directories "Directories"
--msg_directory_navigator "Directory Navigator"
--msg_images "Images"
--msg_index_of_directory "Index of directory"
--msg_index_of_files "Index of files "
--msg_index_through "through"
--msg_next "Next"
--msg_pause "Pause"
--msg_page_navigator "Page Navigator"
--msg_page_updated_on "Page updated on"
--msg_prev "Prev"
--msg_produced_by "Produced by"
--msg_readme "ReadMe"
--msg_up "Up"
Report bugs to .
Visit the WebMagick web page at http://webmagick.sourceforge.net/
| );
}
#
# Subroutine to calculate per-page file names
# This is so names can be defined in one place
#
sub setFileNames {
my $nextPageNumber=$pageNumber + 1;
my $previousPageNumber=$pageNumber - 1;
my $pNumber;
if ($opt_javascript) {
# HTML file to load JavaScript code into hidden Frame
$fileNames{'jsPageIndex'} = "${opt_pageindexname}js.html";
# Javascript master index "indexjs.html"
$fileNames{'jsDirIndex'} = 'indexjs.html';
# JavaScript variable definitions
$fileNames{'jsVariables'} = "${opt_pageindexname}.js";
# Shared WebMagick JavaScript source file
$fileNames{'jsFunctions'} = "${icon_base_url}${pathSep}webmagick.js";
}
# Run status file
$fileNames{'pageStatus'} = "${opt_pageindexname}.pl";
# Generated GIF file
$fileNames{'montageGIF'} = "${opt_pageindexname}${pageNumber}.gif";
# Generated JPEG file
$fileNames{'montageJPEG'} = "${opt_pageindexname}${pageNumber}.jpg";
# Generated server-side imagemap file
$fileNames{'montageServerMap'} = "${sourceDirectory}${pathSep}${opt_pageindexname}${pageNumber}.map";
# Name for current HTML index page
if (!$opt_frames) {
$pNumber = ($pageNumber == 1) ? "" : "$pageNumber";
$fileNames{'htmlCurrentIndex'} = "${pNumber}${opt_indexname}";
} else {
$fileNames{'htmlCurrentIndex'} = "${opt_pageindexname}${pageNumber}$opt_htmlext";
}
# Name for next HTML index page
if($pageNumber == $numPages) {
$fileNames{'htmlNextIndex'} = '';
} else {
if (!$opt_frames) {
$pNumber = ($nextPageNumber == 1) ? "" : "$nextPageNumber";
$fileNames{'htmlNextIndex'} = "${pNumber}${opt_indexname}";
} else {
$fileNames{'htmlNextIndex'} = "${opt_pageindexname}${nextPageNumber}$opt_htmlext";
}
}
# Name for previous HTML index page
if($pageNumber == 1) {
$fileNames{'htmlPrevIndex'} = '';
} else {
if (!$opt_frames) {
$pNumber = ($previousPageNumber == 1) ? "" : "$previousPageNumber";
$fileNames{'htmlPrevIndex'} = "${pNumber}${opt_indexname}";
} else {
$fileNames{'htmlPrevIndex'} = "${opt_pageindexname}${previousPageNumber}$opt_htmlext";
}
}
if ($opt_javascript) {
# Name for next JavaScript HTML index page
if($pageNumber == $numPages) {
$fileNames{'htmlNextJsIndex'} = '';
} else {
$fileNames{'htmlNextJsIndex'} = "${opt_pageindexname}${nextPageNumber}js.html";
}
# Name for previous Javascript HTML index page
if($pageNumber == 1) {
$fileNames{'htmlPrevJsIndex'} = '';
} else {
$fileNames{'htmlPrevJsIndex'} = "${opt_pageindexname}${previousPageNumber}js.html";
}
}
# Location of blank HTML page for use in Frame target
$fileNames{'htmlBlankPage'} = "${icon_base_url}/blank.html";
}
#
# Escape special characters in HTML text
#
sub escapehtml {
local($_) = @_;
s/&/&/g;
s/>/>/g;
s/</g;
s/\"/"/g; # because we use "xxx" form sometimes
return( $_ );
}
#
# Escape characters in strings so they may be eval'ed later in PERL
#
sub escapeperl {
local($_) = @_;
s/\'/\\'/g;
return( $_ );
}
#
# Escape characters in strings so they may be evaluated by JavaScript
#
sub escapejs {
local($_) = @_;
s/\'/\\'/g;
#$_ = join(' + \'', split(/^/));
#s/\n/\\n\'\n/g;
s/\n/\\n\'\n + \'/g;
return( $_ );
}
#
# Escape unsafe characters in URLs
#
sub escapeurl {
no locale;
local($_) = @_;
# RFC 2396
# unreserved + some reserved (no query, allow path chars): "$+,/:;=@"
s/([^0-9a-zA-Z_.!~*'()\$+,\/:;=\@-])/sprintf("%%%02x", ord($1))/eg;
return( $_ );
}
#
# Convert time in seconds to minutes:seconds.hundreths
#
sub elapsedminutes {
my($seconds) = @_;
my $min = int($seconds/60);
my $sec = int($seconds%60);
my $hund = ($seconds - int($seconds)) * 100;
return( "${sec}s" ) if $min == 0;
return( "${min}:" . sprintf( "%02d", $sec ) ) if $hund == 0;
return( "${min}:" . sprintf( "%02d.%02d", $sec, $hund ) );
}
#
# PERL-based RC file handlers
#
#
# Search for and return the contents of an rc file
# The file handle will be auto-close for next file.
#
sub get_rc {
my ($rc) = @_;
my $result = '';
my $bytes = 0;
open( RC, "<${rc}" ) || warn("Failed to open file ${rc}\n") && return '';
$bytes = read( RC, $result, fsize($rc) );
#print( STDERR "Read ${bytes} bytes from file ${rc}\n" ) if $opt_debug;
close( RC );
return $result;
}
#
# Eval .webmagickrc files with specified path. If the file does not
# exist or is not readable, then return silently. If an error occurs,
# then print message and return zero to caller (who can die if deemed
# necessary). This allows statements like:
# $sourceRcFile( $rcfile) || die( "Failed to source $rcfile\n" );
#
sub sourceRcFile {
my $rc;
foreach $rc (@_) {
next if ( ! -r $rc || ! -f $rc );
eval ( get_rc($rc) );
if( $@ ) {
print( STDERR "Bad Eval for file \"${rc}\"...\n$@\n" );
return( 0 );
}
}
return( 1 );
}
#
# Look in the .webmagickrc file for the given directory and return
# the variable requested, or the default value given. this tries to
# be a bit more intelligent than previous eval.
# -- added by Anthony Thyssen
#
# Use as: get_rc_var( directory, variable name, default value)
sub get_rc_var {
my($dir, $var, $def) = @_;
my($rc) = "$dir/$opt_webmagickrc";
return $def if ( ! -r $rc || ! -f $rc );
my($val) = ';' . get_rc( $rc );
$val =~ s/#.*//g; # remove comments to avoid confusion
if ( $val =~ /\$$var\b/ > 1 ) {
print STDERR "Var \"\$$var\" is not simple in \"$rc\" -- using default.\n";
return $def;
}
# find variable assignment if pressent and remove stuff before it
unless ( $val =~ s/(.|\n)*;\s*\$$var\s*=\s*// ) {
# print("DB: \$$var not found in \"$rc\"\n") if $opt_debug;
return $def; # variable assignment was not found
}
$val =~ s/;(.|\n)*//; # remove stuff after assignment expression
# print("Assignment for \$$var = \"$val\"\n") if $opt_debug;
$val = eval ( $val );
if ( $@ ) {
warn("Bad Eval for variable \"\$$var\" in \"$rc\"...\n$@\n");
$val = $def;
}
# print("DB: \$$var found in \"$rc\" with value of \"$val\"\n")
# if $opt_debug;
return $val;
}
#
# Eval PERL-format rc files in order from $opt_rootpath to
# $currentDirectory directory. Values are added to global variables
#
sub evaluateRcFiles {
my($dir) = $currentDirectory; # current directory
my(@top,@dir);
my $rcpath ;
my $top;
my $direlem;
# Decide how far to look for .webmagickrc files
# Support the case where processing outside of the server
# root directory. In that case, use the sourceDirectory instead.
if( $currentDirectory =~ m|^$opt_rootpath| ) {
$top = $opt_rootpath; # Use server root directory
} else {
$top = $opt_srcdir; # Use specified source directory
}
@top=split('/', $top); # Array form
shift(@top);
@dir=split('/', $dir); # Array form
shift(@dir);
splice(@dir, 0, scalar(@top) ); # Leave only subdirectory part
#
# Build up path starting at top sourcing any .webmagickrc as we go.
#
my $path=$top;
$direlem='';
do {
# Certain values must only be valid in the last
# current directory webmagickrc file.
$opt_ignore=0; # Ignore -- do not process this directory
if( $direlem ) {
$path = "$path/$direlem";
}
$rcpath = "$path/$opt_webmagickrc";
sourceRcFile( $rcpath );
} while( $direlem = shift(@dir) );
return( 0 );
}
#
# Lookup color in RGB hash table
#
sub lookupRGBColor {
my($color) = @_;
# If already in hex format, don't translate
if( $color =~ /^\#/ ) {
return( "\U$color" ); # just uppercase the color hex value
}
if( defined($RGBDB{"\L$color"}) ) {
return( $RGBDB{"\L$color"} );
} else {
print( STDERR "No such color \"$color\" found\n" );
return("#BEBEBE"); # Return grey as default in case of error
}
}
#
# Print details regarding executing child process
# Takes return from system() command or $? as input
# Borrowed from example provided in the Camel book
# (PERL 5) page 230
#
sub syserror {
my($rc) = @_;
print("Process exited: ");
$rc = 0xffff & $rc;
if($rc == 0) {
print("normal exit\n");
}
elsif ($rc == 0xff00) {
print("command failed: $!\n");
}
elsif ($rc > 0x80) {
$rc >>= 8;
print("ran with non-zero exit status $rc\n");
}
else {
print("ran with ");
if ($rc & 0x80) {
$rc &= ~0x80;
print("coredump from ");
}
print("signal $rc\n");
}
}