#! /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 "<BODY\n" ); print( INDEX " TEXT=\"${opt_colorfore}\"\n" ); print( INDEX " BGCOLOR=\"${opt_colorback}\"\n" ) if $opt_colorback ne 'false'; print( INDEX " BACKGROUND=\"$iconImageUrls{background}\"\n" ) if defined $iconImageUrls{background}; print( INDEX " LINK=\"${opt_colorlink}\"\n" ); print( INDEX " VLINK=\"${opt_colorvlink}\"\n" ); print( INDEX " ALINK=\"${opt_coloralink}\""); print( INDEX ">\n" ); print( INDEX $indexhtml ); print( INDEX "</BODY>\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 "\"${mapname}\"" ); 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 "\"${opt_msg_up}\"\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 "\"${opt_msg_prev}\"\n"); } # up if in middle (added by BRAD) if ( (!$opt_frames || $opt_framestyle == 1) && !$opt_pichtmlupfirst ) { if ($opt_frames) { print ( PICHTML "\"${opt_msg_up}\"\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 "\"${opt_msg_next}\"\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 "\"${altlabel}\"" ); 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 " \"${altlabel}\"\n" ); } } if ($opt_tables) { if ($imageNum%$opt_columns == 0) { print INDEX "

"; } 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 "
 
"; 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 "\"${altlabel}\""); } else { print (INDEX "\"${altlabel}\""); } print (INDEX ""); print (INDEX "
", $tableImageLabels{$imageNames[$pageNumber - 1][$imageNum]}, "") if ($opt_thumblabel && $opt_thumblabel ne 'false'); 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/ # # 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"); } }