#!/users/fdc/bin/wermit +
#!/net/u/1/f/fdc/bin/wermit +
#!/usr/local/bin/kermit +
#
.version = 3.15                         # Version of this script
.date = 2023/01/26                      # Date of this version
forward :START                          # Jump around all the comments

# Creates a photo gallery from a collection of JPG images.
# Requires C-Kermit 9.0 or later (free):
# http://www.kermitproject.org/ckermit.html
#
# TO USE: EDIT THE TOP LINE TO SHOW THE FULL PATH OF C-KERMIT ON YOUR COMPUTER
# (FOLLOWED BY SPACE AND PLUS SIGN) AND GIVE THIS FILE EXECUTE PERMISSION.
# OR (easier) INSTALL IT USING THE getkermitscript SCRIPT:
# http://www.kermitproject.org/getkermitscript.html
#
# Author:        Frank da Cruz, Bronx NY
# Email:         fdc@columbia.edu
# License:       https://www.kermitproject.org/scriptlicense.html
# Documentation: https://www.kermitproject.org/photogallery.html
#
# Makes an index page with thumbnails and then a page for each image with
# forward, back, and index links, with an button to click to see the original
# image in full size.  Pages can be in Spanish or English.
#
# To use, put the desired image files in an empty directory,
# cd to the directory, and run this script with the desired options
# (you can also make a gallery in a directory that has other files in
# it but for that you need to read read the documentation).
#
# Usage: photogallery [ keyword=value [ keyword=value [ ... ] ] ]
#
# If a PARAMS file exists, runs with those parameters.
# If an IMAGES file exists, creates the gallery from the given list.
# Otherwise, and no parameters are given on command line, a help message 
# is printed.  Command-line parameters override PARAMS file parameters.
#
#############################################################################
# THUMBNAILS AND RESIZING:
#
# If ImageMagick 'convert' is available and you have not specified otherwise,
# it is used to generate thumbnails for the index page.  Otherwise the 
# thumbnails are the original images, scaled by the browser to the default or
# specified thumbnail height.  ImageMagick can be found here:
#
#   http://www.imagemagick.org/
#
# Alternatively if you can make thumbnails some other way; they will be used
# if they are already there.  For each image file xxx.jpg, the corresponding
# thumbnail must be called xxx-t.jpg; all thumbnails should be the same height.
#
# Image Magick is also used, if available and desired, to resize the original
# images so the sub-pages fit browser windows of the target size and don't
# take forever to download.  Or the originals can be shown as is, with scaling
# by the browser.  Resized images are named xxx-r.jpg.
#
# NOTE: 'convert' geometry (e.g. 1600x1200) is width x height.
#
#############################################################################
#
# EDIT HISTORY
# xx Dec 2001: Initial creation for private use.
# 09 Jul 2006: Converted for general use and installed as photoalbum.ksc.
# 10 Jul 2006: Fixed some typos and fixed the test for Windows.
# 11 Jul 2006: Added RESIZE option (RESIZE=n, pixels, default=760).
# 11 Jul 2006: Reduced disk size of thumbnails by factor of 10.
# 12 Jul 2006: Don't give HTML HEIGHT or WIDTH attributes for resized images.
# 12 Jul 2006: Keep and link to original when resizing rather than replacing.
# 15 Sep 2006: Fix NOSCALE result; add "arrows" option for navigation links.
# 16 Nov 2006: Colors for links; fix help text; allow "-help".
# 12 Dec 2009: Nicer default colors; give usage message if no arguments.
# 07 Aug 2010: Put alts and better titles on images; new default colors
# 05 Oct 2010: Change defaults for most common usage
# 01 Oct 2011: Kermit Project becomes independent of Columbia University.
# 07 Aug 2012: Custom version for parades
# 14 Aug 2012: Changes to allow editing of pictures and captions while
#              waiting for more pictures to arrive:
#              . Create resized file only if original is newer
#              . Take captions from external files
#              . Read index text from index.txt file.
#              . Fix permissions on index.html.
# 09 Sep 2012: Allow importation of head and tail HTML.
# 16 Sep 2012: Make caption same width as picture and underline URLs.
# xx Jul 2013: Add tool tips for arrows; take parameters from PARAMS file.
# 30 Jul 2013: Allow for deletion of originals.
# 07 Aug 2013: Merge the different versions of this script into one.
#              Supply head and tail code if no external head or tail files.
#              Allow for BASE and non-BASE linking.
#              Polish for general use.  Call this Photogallery 1.00.
# 07 Sep 2013: 1.01: Allow image names to be taken from a file named IMAGES.
# 08 Sep 2013: 1.02: Normalize image filenames if asked; allow image sorting.
# 09 Sep 2013: 1.03: Fixed some bugs in adding new images to gallery.
# 14 Sep 2013: 1.04: Added Javascript to make image scaling work in IE.
# 15 Sep 2013: 1.05: Make Javascript optional
# 18 Sep 2013: 1.06: IMAGES file can specify images in other directories.
#                    Allow specificaton of permissions for gallery files.
#                    Allow specificaton of names of PARAMS and IMAGES files.
#                    Allow specificaton of name for index file.
# 27 Sep 2013: 1.07: Fix bug in finding index.txt file.
# 29 Sep 2013: 1.08: Fix a typo in the previous fix.
# 16 Oct 2013: 1.09: Fix duplicate thumbnail after editing an image.
# 20 Oct 2013: 1.10: Fix the previous fix which broke adding new images.
# xx Nov 2013: 1.11: Change Uplink on main page to .. if ../index.html exists.
# 12 Jan 2014: 1.12: Allow uplink to be a parameter.
#                    Exit if images file list specified but no images found.
#                    Add "dontenlarge" parameter for small originals.
# 07 Feb 2014: 1.13: Add index2 parameter (text to put below thumbnails).
#                    Don't assume return code of \fpictureinfo() is index
#                    into array element holding length of longer side because
#                    new third element is "date taken".
# 23 Jul 2014: 1.14  Fix a bug when image is square (return code of \fpicture);
#                    Allow specification of subsections and subtitles.
# 13 Aug 2014: 1.15  Allow specification of labels for subsections.
# 24 Apr 2015: 2.00  Make it "mobile friendly" (viewport, fluid design, etc).
#                    Allow specification of stylesheet and favicon.
# 18 May 2015: 2.01  Handle thumbnails that are too wide for screen.
# 19 May 2015: 2.02  Click on image always goes to next image;
#                    there's a new Enlarge button to enlarge the image.
#                    Change default for dontenlarge from 0 to 1.
# 27 May 2015: 2.03  Eliminate space after top subtitle.
# 20 Jun 2015: 2.04  Make Enlarge button optional
# 25 Jun 2015: 2.05  Fix glitch in identifying non-default index.txt file
# 18 Jul 2015: 2.06  Fix typo in stylesheet code (writing to wrong channel)
# 16 Aug 2015: 2.07  Resize portrait images smaller than landscape to
#                    increase the chances that the caption will be visible.
# 18 Aug 2015: 2.08  Found a better way to scale portrait images.
# 19 Aug 2015: 2.09  Added a way to put some text after a subtitle.
# 25 Feb 2016: 2.10  Allow for misbehaving 'convert' version that always
#                    returns a failure code even when it works right.
#                    Also don't assume that \v(tmpdir) directory exists.
#                    Don't execute CHANGE command unless it's available.
#                    Take scale=n out of help text because we always scale now.
# 30 Apr 2016: 2.11  Fix a typo in APPENDFILE (extraneous closing brace)
# 25 May 2017: 2.12  Fluid design improvements for main gallery page:
#                    Don't put width attributes with thumbnails because
#                    it inhibits the use of @media scaling in CSS done in
#                    external 'head' file.  When no head file is specified,
#                    add @media statements to generated <style> section to do
#                    automatic thumbnail scaling for narrow screens.
# 26 May 2017: 2.13  Removed Javascript scaling hack for IE.
#                    Made Enlarge button more manageable (previously it was
#                    a form and its size and appearance couldn't be changed).
#                    Added option for Pinterest "Pin it" buttons.
#                    Made stylesheet parameter work for subpages too.
#                    Made default colors a bit subtler.
# 21 Jul 2017: 2.14  Portrait images from certain cameras would be shown as
#                    landscape if they were not processed first by a photo
#                    editor.  This happened when the ImageWidth and ImageLength
#                    Exif fields were reversed.  Fixed by having ImageMagick
#                    "auto-orient" each image based on its Orientation Exif
#                    value.
# 15 Aug 2017: 2.15  For some reason subpages stopped having a margin; 
#                    added margin:12 to subpage body style.
# 24 Aug 2017: 2.16  Put title (tooltip) on Enlarge button.
#                    Fix alignment of Enlarge and Pinit buttons.
#                    Minor code cleanups.
# 14 Oct 2017: 2.17  Fix squeezing of portrait images on narrow screens.
# 04 Dec 2017: 2.18  Allow for lowercase IMAGES and PARAMS files, for example
#                    if Kermit transferred with SET FILE NAMES CONVERTED.
#                    Also put specify 'px' as units for all image dimensions,
#                    required by HTML5.  Also, fix language tag for Spanish.
# 19 Dec 2017: 2.19  Generate HTML5 (DOCTYPE, units, windows-1252, etc)
# 26 Dec 2017: 2.20  New maxwidth parameter for subpage images;
#                    tighter vertical spacing on index page.
# 27 Dec 2017: 2.21  Improved method for scaling portrait images.
# 28 Dec 2017: 2.22  Improved handling of large portrait images.
# 30 Dec 2017: 2.23  Allow for lowercase-named PARAMS and IMAGES files;
#                    put 1px solid grey borders back on all images.
#  7 Jan 2018: 2.23  Slight adjustment to aspect ratio trigger;
#                    images were coming out smaller than necessary.
# 16 Jan 2018: 2.24  Make sure original image has read permission.
# 10 Feb 2018: 2.25  Replace portrait image-scaling from 2.21, 2.22, and 2.24;
#                    use vmin instead of math to scale images in subpages and
#                    then display:table/display:table-caption to size caption
#                    to scaled image.  Also, make index page obey maxwidth.
#                    Also, put image file basename as Alt text rather than
#                    just a number.
# 05 Mar 2018: 2.26  Fix glitch if maxwidth not specified in PARAMS;
#                    add "text" id to subpage image captions so they can be
#                    linked to.
# 24 Mar 2018: 2.27  Minor tweak to dynamic scaling.
# 21 Apr 2018: 2.28  Add banner file feature for headers/menus.
# 04 May 2018: 2.29  One more scaling fix needed only for Chrome.
#                    Also, print warning if image from IMAGES files not found.
#                    Also, if both strip and bannerfile are specified,
#                    do the bannerfile (typically a menu and/or site title)
#                    first, then the strip beneath it.  Important: Menu
#                    is specified in local file-system notation but Strip
#                    is specified in URL notation.
# 22 May 2018: 2.30  Fix bug: if a head file was specified but an index.txt
#                    was not present, index.html is never opened.  Also
#                    fix a bug in Pinterest button code.
# 26 May 2018: 2.31  Fix typo in previous edit that suppressed all thumbnails!
#                    Make maxwidth apply also to index2 and copyright text.
# 04 Jun 2018: 2.32  Changed max-height for landscape images from 80vh to 72vh.
#                    This allows a bit more of the text to be visible.
# 25 Sep 2018: 2.33  The style section in the generated page head was missing
#                    a closing brace.  Main gallery-page section headings
#                    needed a space beween the ID clause and style clause.
# 02 Dec 2018:       A couple other minor typos fixed.
# 16 Jul 2019:       Report total images and sections upon exit.
# 17 Aug 2019: 2.34  Print subtitles during execution;
#                    Allow .charset = xxx in PARAMS file;
#                    Ignore warning about non-JPG files in IMAGES list;
#                    Ignore and warn about duplicate imagefilenames in list;
#                    Warn about problematic filenames and skip them;
#                    Process imagenames correctly even if they include hyphens
#                    (this might still need some work).
# 08 Oct 2019: 2.35  Add SUPERTITLE parameter, change ENLARGEBUTTON and
#                    DONTENGLARGE defaults from 0 to 1; highlight the section
#                    names a bit more in the runtime progress report.  Also,
#                    add a "validate" link, bottom right, main page.
# 06 Nov 2019: 2.36  Fix margin around thumbnails.
# 10 Nov 2019: 2.37  Ignore leading blanks in IMAGES filenames.
# 22 Nov 2019: 2.38  Allow trailing comments on IMAGES file entries.
#                    Allow Validate link to be controlled by .validate = {0,1}
#                    in PARAMS file.  Thumbnail margins adjusted again.
# 26 Nov 2019: 2.39  Allow definition of ATEND macro in PARAMS to be
#                    executed after the gallery is built.  Truncate progress
#                    report lines to terminal-screen width.
# 27 Jan 2020: 3.00  . Allow PNG and GIF images as well as JPGs.  Including 
#                      animated  GIFs.
#                    . Allow building of galleries without ImageMagick.
#                    . If encoding (charset) of text files is not specified,
#                      try to detect it; this applies to the index page as
#                      well as subpages.
#                    . New summary messages are shown at the end
#                      (after they normally might have scrolled away).
#                    . Be more conservative about overwriting existing
#                      index.htm/html.
#                    . Ability to handle filenames that contain spaces.
#                    . Fix a long-standing bug in the treatment of file
#                      names that contain hyphens.
#                    . Fix a problem building with resize=0 when there are
#                      still some resized images hanging around.
# 01 Feb 2020: 3.01  . Suppressed some spurious syntax error messages when
#                      executed by C-Kermit 9.0.301 through 9.0.304 Dev.22.
# 01 Feb 2020: 3.02  . Fixed a last-minute glitch in passing filenames
#                      containing spaces as arguments.
# 28 Jun 2020: 3.03  . Fixed a glitch that was causing thumbnails to be
#                      rebuilt unnecessarily.
# 29 Jun 2020: 3.04  . Improved handling of 'charset' definition vs
#                      automatic detection of character sets for subpages; 
#                      Improved formatting of footer and 'Validate' link.
#                      Improved vertical spacing around index.txt.
# 13 Jul 2020: 3.05  . Allow arrow-key navigation for Next, Previous, and Up.
#                      Uses Javascript, no harm is done if Javascript not
#                      enabled.  Works for main gallery page (Up only) and 
#                      each subpage (Next, Previous, Up).
# 10 Sep 2020: 3.06  . Right-arrow on last subpage goes up;
#                      Left-arrow on first subpage goes up.
#                      "Included xxx images from (directory name)" message
#                      shortened if too long to fit on one line.
# 15 Sep 2020: 3.07  . Changes over the last 18 months broke the ability to
#                      create a gallery from an IMAGES file that included
#                      images that were not in the current directory, fixed.
#                      The fixes aren't exactly elegant but are intended to not
#                      disturb the code that works for the more common case.
# 24 Mar 2021: 3.08  . The bannerfile directive wasn't working; changed
#                      it to use something more straightforward that works.
#                      Also, added a titlestyle parameter.
# 04 Apr 2021: 3.09  . Fixed a problem when images file is called something
#                      other than IMAGES.  Caught the dangerous case when
#                      when a subpage would wind up with the same name
#                      as the index file.  Fixed slightly bogus reporting
#                      of the index2 file when there isn't one.
# 12 Jul 2021: 3.10  . Simplify charset declaration in head.
# 29 Sep 2021: 3.11  . Prevent empty charset="" declaration in subpages.
# 16 Oct 2021: 3.12  . If convertpath specified, actually use it!
# 26 May 2022: 3.13  . Changed 2 occurrences of "if not llt \v(version) 900304"
#                      to "if not lt \v(version) 900304" to accommodate 
#                      C-Kermit 10.0, which has a more digits in its numeric
#                      version number (1000000) than 9.0.304 (900304).
# 24 Jul 2022: 3.14  . Changed "if [not] lt \v(version)" to "if < \v(version)"
#                      because "if lt" is not a C-Kermit command, oops!
# 26 Jan 2023: 3.15  . Changed "Created by" legend to link from the word
#                      Photogallery alone, not including the version number
#                      because the link goes the the page for the latest
#                      version but the gallery might have been created by
#                      an earlier version.
#>>>
# *****************************************************************************

:START
# "set variable-eval simple" works in 9.0.304 Dev.23 and later but makes no 
# difference.  However, it causes big problems in earlier C-Kermit versions:
# set variable-eval simple     # so don't uncomment this

# Image filetypes we handle... "extensions pattern"
.extp = {{jpg,gif,png,Jpg,Gif,Png,JPG,GIF,PNG,jpeg,Jpeg,JPEG}}
void \fsplit(\fstripb(\m(extp)),&e,\44,CSV)
.extensions := \fjoin(&e)               # (for summary message at end)

.myname := \fbasename(\%0)              # Filename of this script
.thisdir := \fword(\v(dir),-1,/,-)      # Name of current directory
.pinterest_js = http://kermitproject.org/ftp/kermit/scripts/pinterest.js
.unix = 0
if eq "\v(system)" "unix" .unix = 1     # Platform we're running on

# Default parameter values before trying to parse command line or PARAMS file

.doarrowkeys = 1
.defheight = 160                        # Default height for thumbnails
.thumbhgt := \m(defheight)              # Default thumbnail height
.resize = 740                           # Default width for subpage images
.defsize = 740                          # Default resize length of longer side
.language = English                     # Default text language
.color = black                          # Default foreground color
.linkcolor = darkorchid                 # Default link color
.background = white                     # Default background color
.defcset = utf-8                        # Default text encoding
.arrows = 1                             # Navigation arrows by default
.have_images = 0                        # We don't have any images yet
.have_imagefile = 0                     # Image names come from a file
.titlestyle = border-bottom:1px solid grey  # Title style

# For summary messages at end of Photogallery run...
#
declare \&m 100                         # Message array
.mx = 0                                 # Message array index
define ADDMSG {                         # Add a message to the message array
    incr mx
    if >= mx \fdim(&m) {                # If array fills up...
        array resize &m \fdim(&m)+100   # Make it bigger
        if fail exit 1 "Memory allocation failure"
    }
    .\&m[mx] := \%1
}
# Check text file character set
#
define CHECKCSET {
    local fn tmp
    if not def \%1 return
    .fn := \fcontents(\%1)              # Inhibit recursion
    if not exist \m(fn) return
    local filetype tmp &z[] i
    dcl \&z[] UTF-8 ISO-8859-* US-ASCII WINDOWS-* 
    if not  < "\v(version)" "900304" {
        if not text \m(filetype) {      # This is a new Kermit command
            addmsg {WARNING: \m(fn) does not seem to be a text file}
        }
    } else {
        .filetype := \fcommand(file \m(fn)) # See what 'file' says about it
        if \v(pexitstat) {
            addmsg {WARNING: \m(fn) file type could not be determined}
        }
        if not match {\m(filetype)} {*{text,html}*} { # Is it text?
            addmsg {WARNING: \%1 does not seem to be a text file}
        }
    }
    # Seems to be text - what about the encoding?
    .filetype := \fcommand(file --mime-encoding \m(fn))
    if == \v(pexitstat) 0 {
        .tmp := \fword(\m(filetype),2,\fchar(32):)                
        if not def tmp .tmp := \m(charset)
        if equ "\m(tmp)" "us-ascii" .tmp := \m(charset)
        if equ "\m(tmp)" "unknown-8bit" .tmp = windows-1252
        return \m(tmp)
    }
    .tmp = bi
    if match "\v(osversion)" "*Mac OS X*" .tmp := bI
    .filetype := \fcommand(file -\m(tmp) \m(fn))
    if == \v(pexitstat) 0 {
        .tmp := \fword(\m(filetype),2,=,ALL)
        for i 1 \fdim(&z) 1 {
            if match {\m(tmp)} {\&z[i]} {
                addmsg {File \m(fn) character set detected: \m(tmp)}
                return \m(tmp)
            }
        }
    }
    return
}
.sttl =                                 # Section title / subtitle
.nsttl = 0                              # Number of subsections
.stylesheet =                           # Stylesheet filespec
.favicon =                              # Favicon filespec
.changewarning = 0                      # CHANGE warning has been issued
.dopinterest = 0                        # Only put Pinit buttons if asked.
.subpages = 0                           # Subpage counter
.noimagemagick = 0                      # Don't use IM even if it's available

# CHECKIMAGENAME
# Warn user about problematic image file names
#
def CHECKIMAGENAME {      # Screen filenames that won't pass through the shell
    local name i          # Not a complete list but catches common cases
    .name := \fcontents(\%1)
    if \findex(.jpg.jpg,\m(name)) end 1         # ".jpg.jpg"
    if \findex(.gif.jpg,\m(name)) end 1         # etc...
    if \findex(.jpg.gif,\m(name)) end 1
    if \findex(.gif.gif,\m(name)) end 1
    else if \findex(\fchar(40),\m(name)) end 1  # paren
    else if \findex(\fchar(41),\m(name)) end 1  # paren
    else if \findex(\fchar(60),\m(name)) end 1  # angle bracket
    else if \findex(\fchar(91),\m(name)) end 1  # square bracket
    else if \findex(\fchar(123),\m(name)) end 1 # curly brace
    else if \findex(\fchar(127),\m(name)) end 1 # DEL/RUBOUT
    for \%i 1 31 1 {
        if \findex(\fchar(\%i),\m(name)) end 1  # C0 control characters
    }
    end 0
}
# Super-careful front end for chmod mainly for the development cycle.
# None of these errors should occur in released version.  For example
# "chmod 644 .", which would remove execute permssion from current
# directory.
#
def DOCHMOD {
    local fn perms
    if not def \%1 end 1 \%0: called with no arguments
    .perms := \fcontents(\%1)
    if not def perms exit 1 "DOCHMOD \f(fn) CALLED WITHOUT PERMISSIONS"
    if not numeric \m(perms) {
        exit 1 "DOCHMOD \f(fn) PERMISSIONS [\m(perms)] NOT NUMERIC"
    }
    if not equ \flen(\m(perms)) 3 {
        exit 1 "DOCHMOD \m(fn) INVALID PERMISSIONS (length): \m(perms)"
    }
    if not \fverify(\m(perms,0123457)) {
        exit 1 "DOCHMOD \m(fn) INVALID PERMISSIONS (digits): \m(perms)"
    }
    .fn := \fcontents(\%2)              # Get value with no recursion
    if not def fn end 1 \%0: called with no filename
    if not \ffiles(\m(fn)) exit 1 "DOCHMOD file not found: \m(fn)"
    if equ "." "\m(fn)" exit 1 "DOCHMOD CALLED WITH '.'"
    if directory \m(fn) exit 1 "DOCHMOD CALLED WITH DIRECTORY NAME \f(fn)"
    if not unix end 1 "DOCHMOD \m(fn) \m(perms) DOESN'T WORK ON \v(system)"
    if link \f(fn) end 0 "DOCHMOD \m(perms) \m(fn) SKIPPED (symlink)"
    chmod \m(perms) {\m(fn)}
    if fail exit 1 { DOCHMOD \m(perms) \m(fn) FAILED }
    end 0
}
# PARSENAME
# Breaks a filename up into its parts:
# Name part, Photogallery suffix (-r or -t), extension, backup version
# Call with complete filename 
# Returns failure if called with empty string
# On success returns with the following variables set:
# namepart - filename exclusive of suffix, extension, or backup version
# suffix   - Photogallery suffix (if any): -r or -t
# ext      - extension such as jpg or gif
# backup   - EMACS backup version number like ~23~ or simple number
# to       - Original name of this file
# tr       - Resized name
# tt       - Thumbnail name
# imgtype  - The type of image: 'original', 'resized', or 'thumbnail'.
#
define PARSENAME {                      # Break filename into its parts
    local fn tmp
    undef namepart suffix ext backup to tr tt ht imgtype # Clear results
    if not def \%1 end 1 \%0: called with no argument
    .fn := \fcontents(\%1)              # Get value with no recursion
    if not exist \m(fn) end 1 \%0 - file not found: \m(fn)
    .\%9 := \frindex(.,\m(fn))          # Find rightmost '.'
    if not \%9 {                        # String has no '.'
        .namepart := \m(fn)
    } else {
        .tmp := \s(fn[\%9+1])           # Part of string after last '.'
        if ( match "\m(tmp)" "~*~" || numeric \m(tmp) ) {
            parsename {\s(fn[1_\%9-1])}
            .backup := \m(tmp)
            end 0
        }
        .ext := \s(fn[\%9+1])            # Extension
        .namepart := \s(fn[1_\%9-1])     # Name part
        .\%9 := \frindex(-,\m(namepart)) # Rightmost '-' in namepart
        if \%9 {
            .tmp := \s(namepart[\%9])  # Possible PG suffix
            if \findex(|\m(tmp)|,|-r|-t|) {
                .suffix := \m(tmp)
                .namepart := \fstripx(\m(namepart),-)
                if equ "suffix" "-r" .imgtype = resized
                else if equ "suffix" "-t" .imgtype = thumbnail
            } else .imgtype = original
        }
    }
    # The original filename and its two prefixed derivatives
    # \fbasename() is for IMAGES-files that are in other directories.
    .tmp := \fbasename(\m(namepart))
    .to := \m(tmp).\m(ext)                  # Original name of this file
    .tr := \m(tmp)-r.\m(ext)                # Resized name
    .tt := \m(tmp)-t.\m(ext)                # Thumbnail name
    .subpagename := \m(tmp).html            # Filename of HTML subpage
    if equ "\m(subpagename)" "\m(indexfile)" {
        exit 1 -
        "FATAL - Subpage \m(subpagename) would have same name as index file."
    }
    .subpagetext := \m(tmp).txt             # Filename supbage caption
    .ht := \m(tmp).html                     # Same (for brevity)
    .url := \freplace(\m(tmp).html,\32,%20) # Web page name as URL
}

def CHECKANIMATED {
    .animated = 0
    if not def \%1 end
    if not match "\%1" "*.{gif,GIF,Gif}" end 0
    void \fcommand(grep $'NETSCAPE2.0\fchar(92)03\fchar(92)01' \%1;)
    if not \v(pexitstat) {
        .animated = 1
    }
}
# GETDIMENSIONS
# Tries to get width and height of image in pixels.  Returns them as nonzero
# 'wid' and 'hgt' if it succeeds, otherwise zeros.  Tries Kermit's built-in
# \fpictureinfo() function first, and if that fails uses the external 'file'
# command and tries to parse the results.  Does not care about the file
# extension or how it is spelled or capitalized.  As of C-Kermit 9.0.304
# \fpictureinfo() works only for JPG and GIF images.  If support for other
# images type are added, this routine will need no changes.
#
# Image orientation is returned as 'orientation', which can be 'portrait'
# 'landscape', or 'unknown'.
#
# Note dimensions can also be obtained using the ImageMagick command-line
# tool 'identify': identify image.jpg
# and then scan for nnnnxnnnn as we do below.
#
def GETDIMENSIONS {                     # Get the dimensions of an image.
    local fn buf &d[]
    .wid = 0                            # Result 1: width
    .hgt = 0                            # Result 2: height
    .buf =
    .fn := \fcontents(\%1)
    if not def fn end
    .\%9 := \fpictureinfo(\m(fn),&d)    # Try to get dimensions
    if == \%9 3 .\%9 = 2                # In case image is square
    switch \%9 {
      :1, .orientation = "landscape", break
      :[23], .orientation = "portrait", break
      :default, .\orientation = "unknown"
    }
    if \%9 {                            # This works for JPG and GIF
        .wid := \&d[1]
        .hgt := \&d[2]
    }
    if > \m(wid) 0  {                   # If we have a width we're done
        return
    } else {                            # Something else e.g. PNG
        .buf := \fcommand(file \m(fn))  # Use the system 'file' command
        if \v(pexitstat) return         # Return 0's if 'file' failed
        .\%8 := \findex({ x },\m(buf))
        if > \%8 6 {                    # It might report width x height
           .buf := \s(buf[\%8-8_\%8+8]) # Try to bracket it
            void \fsplit(\m(buf),&y,\fchar(32)\fchar(44),ALL) 
            for y 1 \fdim(&y) 1 {       # search segment for n* x n*
                if equ "\&y[y]" "x" {   # where n* is sequence of digits
                    if > y 1 {
                        .wid := \&y[y-1]
                        if numeric \m(wid) {
                            .hgt := \&y[y+1]
                                if numeric \m(hgt) {
                                if > \m(wid) 0 return
                            }
                        }
                    }
                }
            }
        }
        # If we add some other image type e.g. TIFF we might also want to look
        # for nnnxnnnn (without spaces) which 'file' produces for JPG files.
    }
}
dcl \&t[200] # Global array for image files (expands automatically as needed)

def DOIMAGESFILE {
# Get list of gallery filenames from IMAGES file
# Resulting list is returned in array &t[].
    local \%c                           # Images file channel number
    .\%n = 0                            # Image counter
    fopen /read \%c \m(imagesfile)      # Open the images file on channel \%c
    if fail exit 1
    echo READING IMAGE FILENAMES from \m(imagesfile)
    .commentstart := \fchar(32)\fchar(35) # Trailing comment indicator
    while 1 {                           # Loop for each image file name
        fread /line /untabify /trim \%c name
        if fail break
        .name := \fltrim(\m(name))
        if equ "\s(name[1:1])" "#" continue  # Full-line comment
        if not def name continue             # Blank line or comment
#        .name := \fltrim(\m(name))           # Have name
        .\%5 := \findex(\m(commentstart),\m(name)) # Check for trailing comment
        if \%5 .name := \ftrim(\s(name[1:\%5]))
        .\%8 := \findex([SUBTITLE,\m(name)) # Check for subsection title
        if \%8 {
            local tmp1 tmp2 tmp3 tmp4
            .\%9 ::= \%n + 1
            .\%7 := \findex(],\m(name),\%8+1)
            if \%7 {
                .tmp1 := \s(name[\%8_\%7]) # Extract the SUBTITLE directive
                .tmp2 := \fstripb(\m(tmp1)) # Remove brackets
                .tmp3 := \fword(\m(tmp2),2,:) # Get label if any
                .tmp4 := \fword(\m(tmp2),3,:) # Get name of text file if any
                _asg SUBTTL<\%9> \freplace(\m(name),\m(tmp1),)
                _asg SUBTXT<\%9> \m(tmp4) # Name of file with subsection text
                _asg LABEL<\%9> \m(tmp3)  # Label for this subsection
                incr nsttl                # Count it
            }
            continue
        }
        checkimagename \m(name)
        if fail {
            addmsg {WARNING: image "\m(name)" has problematic name (skipping)}
            continue
        }
        if not exist {\m(name)} {
            addmsg {WARNING: image "\m(name)" not found}
            continue
        }
        # Supported filetype?
        if not match "\fword(\m(name),-1)" "\m(extp)" {
          addmsg {WARNING: -
\m(name).. Image filetype must match \m(extp) (skipping)}
            continue
        }
        if > \farraylook(\m(name),&t) 0 {
           addmsg {WARNING: \m(name) already seen in \m(imagesfile) (skipping)}
            continue
        }
        incr \%n
        if >= \%n \fdim(&t) {             # If array fills up...
            array resize &t \fdim(&t)+100 # Make it bigger
            if fail exit 1 "Memory allocation failure"
        }
        .\&t[\%n] := \m(name)
    }
    if > \%n 0 {                        # If we got any image names...
        array resize &t \%n             # Set array size
        .have_images = 1                # We have some images
        echo {\%n image file names loaded from file: \m(imagesfile)}
        addmsg {\%n image file names loaded from file: \m(imagesfile)}
    } else exit 1 "Imagefile \m(imagesfile): No images found"
}
# Default values for settable parameters
if not def scale .scale = 0               # Don't scale unless asked to
if not def sort .sort = 0                 # Sort images by Date Taken.
if not def permissions .permissions = 644      # Permissions for gallery files
if not def paramsfile .paramsfile = PARAMS     # Name for PARAMS file
if not def indexfile .indexfile = index.html   # Name for index file
if not def validate .validate = 0              # Include W3C validatator link

if not def noimagesfile .noimagesfile = 0      # Not suppressing IMAGES files
if not def imagesfile .imagesfile = IMAGES     # Name for IMAGES file
.have_imagefile = 0                            # but we don't have one yet

# VERSION DEPENDENCIES
# PG with 9.0.300, 301, 302, 303, 304, and 305.
# 9.0.304 required for Spanish dates (Lun, Mar, Mie, etc)
#
if not unix exit 1 "Sorry\, this version of Photogallery works only in Unix."
if < \v(version) 900300 exit 1 "FATAL - C-Kermit 9.0.300 or later required."

.have_locale = 0                        # For generating dates in Spanish
.have_datetaken = 0                     # For sorting by Date Taken

if not < \v(version) 900304 {          # C-Kermit 9.0.304 or later features
    .have_locale = 1
    .have_datetaken = 1
}
if sort if not have_datetaken {
    echo C-Kermit 9.0.304 or later required for sorting.
    echo Proceeding with sort=0...
    .sort = 0
}
# Attempt to avoid clobbering website home page...
.ignorerobots = 0
.doindextests = 0

if not def indexfile exit 1 FATAL - indexfile undefined
.\%6 := \fword(\m(indexfile),-1,.)
if ( not equ "html" "\%6" && not equ "htm" "\%6" ) {
  exit 1 "ERROR: Index file \m(indexfile) not HTML"
}
# If the gallery page will be called index.html or index.htm
# check for conflict with an existing file of that name.
if equ "\fword(\m(indexfile),1)" "index" .doindextests = 1

if not doindextests .ignorerobots = 1

.indexname =
if exist index.html .indexname = index.html
else if exist index.htm .indexname = index.htm

def USAGE {
    echo
    echo { \m(myname) \m(version) \m(date) ...}
    echo { Makes a Web gallery in a directory containing .jpg, .gif,}
    echo { and/or .png images.  Index page shows thumbnails of the images.}
    echo { Each image has a subpage that shows a larger version of the image.}
    echo { Text and captions can be included in the index and the subpages.}
    echo
    echo { Usage: \m(myname) keyword=value [ keyword=value [ ... ] ]}
    echo {  Or put parameters in PARAMS file in the gallery directory.}
    echo
    echo { Options (spell out option names in full):}
    echo {   title="Title of the gallery"}
    echo {   color=xxx      Foreground text color, default black}
    echo {   background=yyy Background color, default white}
    echo {   language=zzz   English or spanish, default english}
    .\%9 := \m(defheight)
    echo {   height=h       Height for thumbnails, default \%9 pixels}
    .\%9 := \m(defsize)
    echo {   resize=w       Width for images shown in subpages.}
    echo {                  Nonzero w means resize originals to n pixels}
    echo {                  resize=0 means don't resize the originals}
    echo {                  Default is to resize originals to \%9 pixels}
    echo {   arrows=n       1 to use arrows for navigation, 0 to use words}
    echo {   help           Print this message}
    echo {   (many more..)  (see http://kermitproject.org/photogallery.html)}
    echo
    echo { Parameters can be given in Kermit-script format in the PARAMS file:}
    echo
    echo {   .title = "This is the title"}
    echo {   .color = gold}
    echo {   .background = black}
    echo
    echo { This allows the script to be run multiple times without having}
    echo { to remember or re-enter the parameters on the command line, which}
    echo { is useful when expanding or modifying a gallery.}
    echo
    echo { Full instructions:  http://kermitproject.org/photogallery.html}
    echo
    exit 0
}
if not defined indexname .indexname = index.html
if ( doindextests && exist indexname ) {
    grep /nolist PHOTOGALLERYINDEX \m(indexname)
    if fail {
        echo "*********************************************************"
        echo "WARNING: \v(dir)"
        echo "An \m(indexname) file exists in this directory that does not"
        echo "seem to be for this gallery.  To create a gallery in this"
        echo "directory, you can either give it a different name \(see the"
        echo "Script Parameters section of the Photogallery documentation)"
        echo "or delete or rename the existing index file.  Documentation:"
        echo "http://kermitproject.org/photogallery.html"
        echo "*********************************************************"
        echo
        echo For help\, cd to another directory and type "\m(myname) help"
        echo
        exit 1
    }
}
if < \v(argc) 2 {
    if ( not exist ./PARAMS && not exist ./params ) { do usage }
}
# Prescan args for "help"
.args := \%0 \fjoin(&_,\32)
if \findex({\32-help},\m(args)) usage  # If keyword was "help" give help
if \findex({\32help},\m(args)) usage   # If keyword was "help" give help
if \findex({\32-h},\m(args)) usage     # If keyword was "help" give help

if def \$(IGNORE_ROBOTS) if not equ "\$(IGNORE_ROBOTS)" "0" .ignorerobots = 1
if not equ "\m(paramsfile)" "index.html" .ignorerobots = 1
if ( not ignorerobots && exist robots.txt ) {
    echo "WARNING: Your current directory:"
    echo
    echo "  \v(dir)"
    echo
    echo "seems to be the top-level directory of a website because it" 
    echo "contains a robots.txt file.  If you run this script here," 
    echo "you will overwrite the website's home page.  If the current" 
    echo "directory is not the top-level directory of a website and" 
    echo "just happens to contain a robots.txt file, you can run this" 
    echo "script if (a) you delete or rename the robots.txt file, or" 
    echo "(b) define the environment variable IGNORE_ROBOTS=1." 
    exit
}
define APPENDFILE {
# \%1 = name of file to append
# \%2 = tag to be replaced
# \%3 = string to replace it with
# \%4 = name of file to be appended to (not currently open)
    local tmpfile
    if def \v(tmpdir) if not dir \v(tmpdir) set temp-directory . # For CHANGE 
    .tmpfile = ./__APPEND.TMP
    grep /nolist "\%2" \%1              # If it contains the tag
    if success {                        # copy and substitute given value
        copy \%1 \m(tmpfile)
        if fail exit 1 APPENDFILE error[1] \%1 \%4
        if command change {
            change /case:on \m(tmpfile) "\%2" "\%3"
            if fail exit 1 APPENDFILE error[2] \%1 \%4
        } else if not changewarning {
            echo "WARNING: CHANGE command not present in:"
            echo \v(herald)
            echo "Some text substitutions will not be made."
            echo "C-Kermit 9.0.304 Dev.06 or later required."
            incr changewarning
        }
        copy /append \m(tmpfile) \%4
        if fail exit 1 APPENDFILE error[3] \%1 \%4
        delete /quiet \m(tmpfile)
    } else {                            # Otherwise just append it
        copy /append \%1 \%4
        if fail exit 1 APPENDFILE error[4] \%1 \%4
    }
}

# This is cheating but we have to peek ahead at the command line
# arguments to see if a different PARAMS file was specified.
# But leave other command-line arguments for after executing the PARAMS file.
#
for \%i 1 \v(argc)-1 1 {                # Look for params file
    if match "\&_[\%i]" "paramsfile=*" {
        echo ALTERNATIVE PARAMS FILE: \&_[\%i]
        void \fkeywordvalue(\&_[\%i])
        break
    }
}
if equ "\m(paramsfile)" "PARAMS" {      # This is the default name
    if not exist PARAMS {
        if exist params {               # Maybe lowercase?
             rename /list params PARAMS # Convert it
             if fail .paramsfile = params
        }
    } else if exist params {
        if newer params PARAMS {
             rename /list params PARAMS # Convert it
             if fail .paramsfile = params
        }
    }    
} else if def paramsfile {
    if not exist \m(paramsfile) exit 1 "PARAMS file \m(paramsfile) not found"
}

.maxwidth = 1920                        # Maximum display width for subpage
.minwidth = 220                         # Minimum width for index.html
if exist \m(paramsfile) {
    take \m(paramsfile)                 # It only contains Kermit commands
    if fail exit 1 PARAMS file error [\m(paramsfile)]
    addmsg {Parameters set from file: \m(paramsfile)}
    if def resize {
        if not numeric \m(resize) exit 1 FATAL: resize value not numeric
        if ( > resize 0 && < resize  80 ) {
            echo FATAL: resize value (\m(resize)) in \m(paramsfile) too small.
            echo To resize images specify a value of 80 (pixels) or greater.
            echo To disable resizing specify a value of 0.
            exit 1 
        }
    }
    if def maxwidth {                
        if not numeric \m(maxwidth) fatal "maxwidth not numeric: \m(maxwidth)"
    } else {
        .maxwidth = 1920
    }
    if def minwidth .mw := min-width:\m(minwidth)px
    if def maxwidth .mw := \m(mw); max-width:\m(maxwidth)px;
    if def scale {
        if not numeric \m(scale) fatal "scale not numeric: \m(scale)"
        if scale { .noscale = 0 } else { .noscale = 1 }
    } else if def noscale {
        if not numeric \m(noscale) fatal "noscale not numeric: \m(noscale)"
        if noscale { .scale = 0 } else { .scale = 1 }
    }
    if def arrows {
        if not numeric \m(arrows) fatal "arrows not numeric: \m(arrows)"
        if arrows { .noarrows = 0 } else { .noarrows = 1 }
    } else if def noarrows {
        if not numeric \m(noarrows) fatal "noarrows not numeric: \m(noarrows)"
        if noarrows { .arrows = 0 } else { .arrows = 1 }
    }
    if def pinterest {
        if not def myurl .myurl := \m(pinterest)
        if match \m(myurl) http*://* {
            if not equ "\fright(\m(myurl),1)" "/" .myurl := \m(myurl)/
            .dopinterest = 1
        } else {
            fatal "Pinterest requires full URL of this website"
        }
    }
}
.indextxt := \fstripx(\m(indexfile)).txt # Text at top of main gallery page
undef index2txt                          # Optional text below thumbnails
if def index2 .index2txt := \fstripx(\m(index2)).txt
if not exist \m(index2txt) undef index2txt # specified but doesn't exist
if def charset {
    addmsg {Character encoding declared as \m(charset)}
} else {
    .charset := \m(defcset)
    addmsg {WARNING: charset not defined, using \m(charset)}
}
if exist \m(indextxt) {             # Encoding of index.txt file
    checkcset \m(indextxt)
    if not equ "\v(return)" "\m(charset)" {
        addmsg { -
WARNING: \m(indextxt) charset mismatch: \v(return) vs \m(charset) }
    }
} else if def \m(index2txt) {           # or if none, the index2.txt file
    checkcset \m(index2txt)
    if not equ "\v(return)" "\m(charset)" {
        addmsg { -
WARNING: \m(index2txt) charset mismatch: \v(return) vs \m(charset) }
    }
}

.kerbang = 0                            # How we exit depends on how invoked
if kerbang incr kerbang                 # (This only works at top level)
define FATAL {                          # Fatal error macro
    fclose all                          # Close all open files
    echo                                # and exit or stop with given message
    if \m(kerbang) exit 1 FATAL - \%*
    else stop 1 FATAL - \%*
}
def STYLE {                             # Add <style> stanza
    fwrite /line \%1 <style>
    fwrite /line \%1 "  a:link { color:\m(linkcolor) }"
    fwrite /line \%1 "  a:visited { color:\m(linkcolor) }"
    fwrite /line \%1 "  a:hover { color:\m(hover) }"
    fwrite /line \%1 "  a:active { color:\m(hover) }"
    fwrite /line \%1 "  .nowrap  { white-space:nowrap }"      
    fwrite /line \%1 "  img { border:1px solid grey; }"
    if equ "\m(what)" "SUBPAGE" -
    fwrite /line \%1 "  td.pinit img { border:0 }"
    fwrite /line \%1 "  .button \m(lb) background: \#eeeeee; margin:0;"
    fwrite /line \%1 "    border: 1px solid; white-space:nowrap;"
    fwrite /line \%1 "    font-family:sans-serif; font-size:15px;"
    fwrite /line \%1 "    border-color: grey; padding:0 4px 0 4px;"
    fwrite /line \%1 "  \m(rb)"
    fwrite /line \%1 "  .button a { text-decoration:none }"
    fwrite /line \%1 "  .button a:link { color:purple }"
    fwrite /line \%1 "  .button a:visited { color:purple }"
    fwrite /line \%1 "  .button a:hover { color:purple; font-weight:bold }"
    fwrite /line \%1 "  .button a:active { color:purple; font-weight:bold }"
    fwrite /line \%1 -
"  span.button:hover { background:#f5f5f5; border-color:purple }"
    fwrite /line \%1 -
"  td.button:hover { background:#f5f5f5; border-color:purple }"
    fwrite /line \%1 "  div.thumbnails a img { margin:0 6px 6px 0 }"
    if def \%2 if equ "\%2" "INDEX" {   # If doing the index page...
        fwrite /line \%1 "  @media screen and (max-width: 390px) {-
\v(newline)    img { margin-top:6px }-
\v(newline)    blockquote { margin-left:1em } }"
        if > \m(thumbhgt) 140 {         # Large thumbnails - scale them
            fwrite /line \%1 {  @media screen and (max-width: 660px) {-
\v(newline)    body { font-size:15px; }-
\v(newline)    div.thumbnails img { height:100px; width:auto; }-
\v(newline)    blockquote { margin-left:24px } } }
            fwrite /line \%1 {  @media screen and (max-width: 360px) {-
\v(newline)    body { font-size:14px; }-
\v(newline)    div.thumbnails img { height:100px; width:auto; }-
\v(newline)    blockquote { margin-left:16px } } }
        }
    }
    fwrite /line \%1 </style>
}
def PINTERESTJS {                       # Include Javascript pinit() function
    local src
    if dopinterest {
        .src := \m(pinterest_js)
        fwrite /line \%1 <script src="\m(src)"></script>
    }
}
# Command-line processing - title and options

.lp := \fchar(40)                       # Left paren
.rp := \fchar(41)                       # Right paren
.lb := \fchar(123)                      # Left bracket
.rb := \fchar(125)                      # Right bracket

.ncmdline = 0

for \%i 1 \v(argc)-1 1 {                # Parse each keyword option
    void \fkeywordvalue(\&_[\%i])       # This function does it
    if eq "\v(lastkwval)" "help" usage  # If keyword was "help" give help
    if eq "\v(lastkwval)" "-help" usage # If keyword was "-help" give help
    if eq "\v(lastkwval)" "-h" usage    # If keyword was "-h" give help
    if \findex(|\v(lastkwval)|,|-version|version|-v|) {
        echo \m(myname) \m(version) \m(date)
        incr ncmdline
        exit 0
    }
    if eq "\v(lastkwval)" "resize" {    # If "resize" given without argument
        if not def resize .resize := \m(defsize) # supply default
        incr ncmdline
    }    
    if \m(resize) if < \m(resize) 80 {
        echo RESIZE TOO SMALL: \m(resize)
        echo Minumum resize size: 80
        echo Or 0 to not resize
        exit 1
    } else incr ncmdline

    if eq "\v(lastkwval)" "noscale" {   # If "noscale" given without argument
        if not def noscale .scale = 1   # supply default.
        if noscale { .scale = 0 } else { .scale = 1 }
    }
    if eq "\v(lastkwval)" "arrows" {    # If "arrows" given without argument
        if not def arrows .arrows = 1   # supply default.
        if arrows { .noarrows = 0 } else { .noarrows = 1 }
        incr ncmdline
    }
    if eq "\v(lastkwval)" "noarrows" {
        if not def noarrows .noarrows = 1 # supply default.
        if noarrows { .arrows = 0 } else { .arrows = 1 }
        incr ncmdline
    }
    if eq "\v(lastkwval)" "pinterest" {
        if not def pinterest exit 1 -
{Usage: pinterest=http://www.thiswebsite.com/ (full URL for this website)}
        if not def myurl .myurl := \m(pinterest)
        if match \m(myurl) http*://* {
            if not equ "\fright(\m(myurl),1)" "/" .myurl := \m(myurl)/
            .dopinterest = 1
            .javascript = 1
            incr ncmdline
        } else {
            fatal "Pinterest requires full URL of this website"
        }
    }
}

if \m(ncmdline) addmsg {Parameters set from command line: \m(ncmdline)}
echo Photogallery \m(version) \m(date)

if def height .thumbhgt := \m(height)

if not def dontenlarge .dontenlarge = 1
if not numeric \m(dontenlarge) {
  exit 1 Fatal - Dontenlarge not numeric: \m(dontenlarge)
}
if not def enlargebutton .enlargebutton = 1
if not numeric \m(enlargebutton) {
  exit 1 Fatal - Enlargebutton not numeric: \m(enlargebutton)
}
if not def noscale .noscale = 1
if not numeric \m(resize) exit 1 Fatal - Resize not numeric: \m(resize)
if not numeric \m(thumbhgt) exit 1 Fatal - Thumbhgt not numeric: \m(thumbhgt)
if not numeric \m(noscale) exit 1 Fatal - Noscale not numeric: \m(noscale)
if match english \m(language)* .language = English
else if match spanish \m(language)* .language = Spanish
else exit 1 Fatal - Language "\m(language)" not supported

if not def title {
   .title = "Image Gallery"
   if equ "\m(language)" "Spanish" .title = "Galer&iacute;a de im&aacute;genes"
}
if not def shorttitle .shorttitle := \m(title)

if not def hover {
    .hover := \m(color)
    switch \m(color) {
      :darkmagenta, .hover = fuchsia, break
      :deeppink,    .hover = pink, break
      :gold,  .hover = yellow, break
      :black, .linkcolor = purple, .hover = fuchsia, break
      :blue,  .hover = lightblue, break
      :red,   .hover = pink
    }
}
if not def uplink {                     # Uplink from gallery main page
    if exist ../index.html .uplink = ../index.html
    else .uplink = /
}
echo
echo title = \m(title)
echo shorttitle = \m(shorttitle)
show macro -
 convertpath -
 uplink -
 arrows -
 bannerfile -
 imagesfile -
 copyright -
 dontenlarge -
 dopinterest -
 enlargebutton -
 favicon -
 hover -
 indexfile -
 index2 -
 javascript -
 language -
 maxwidth -
 permissions -
 resize -
 sort -
 strip -
 stylesheet -
 thumbhgt

pwd

# Check for IMAGES file, which contains a list of the images to be
# included in the gallery.  If it doesn't exist, all images in the
# current directory will be included.
#
if not \m(noimagesfile) {               # Unless suppressed for testing
    if def imagesfile {                 # If imagesfile parameter defined
        if exist \m(imagesfile) {
            .have_imagefile = 1 
        } else {
            if equ "\m(imagesfile)" "IMAGES" {
                if not exist IMAGES {
                    if exist images {               # Maybe lowercase?
                         rename /list images IMAGES # Convert it.
                         if fail .imagesfile = images
                    }
                } else if exist images {
                    if newer images IMAGES {
                         rename /list images IMAGES # Convert it.
                         if fail .imagesfile = images
                    }
                }
                if exist \m(imagesfile) .have_imagefile = 1
            } else if not exist \m(imagesfile) {
                exit 1 "IMAGES file \m(imagesfile) not found"
            }
        }
    } else if exist IMAGES .have_imagefile = 1
}
# If there was no IMAGES file get filenames from reading disk directory
#
if not def have_images exit 1 "INTERNAL ERROR: have_images not defined"
if have_imagefile {
    do DOIMAGESFILE
} else {
    # Make a list of original images.
    # Note: Even if we are not making thumbnails with IM we still have to 
    # skip *-t.* and *-r.* files in case we used IM on a previous run.
    #
    .ndiskimages = 0
    dir /nolinks /array:&q *.\m(extp)   # Array Q has ALL image files
    dcl \&t[\fdim(&q)]                  # Array T has only originals
    .q = 0                              # with only the original files
    for i 1 \fdim(&q) 1 {
        .thisname := \fcontents(\&q[i]) # Suppress any recursion on filename
        parsename {\m(thisname)}        # Parse the name into its pieces
        if def backup continue          # Skip backup files
        if equ "\m(suffix)" "-t" continue # Skip thumbnails
        if equ "\m(suffix)" "-r" {        # Resized file
            if exist \m(namepart).\m(ext) continue
        }
        incr q                          # Add original image to list
        .\&t[q] := \m(thisname) 
    }
    if not \m(q) exit 1 NO IMAGES FOUND: \v(dir)
    array resize &t q                   # Remove empty elements from end
    .ndiskimages := \fdim(&t)           # How many images we're doing
    .showdir := \v(directory)           # Direct name might be loooong
    if > \flen(\m(showdir)) \v(cols)-40 { # so truncate it to fit on one line
        .\%9 := \fright(\m(showdir),\v(cols)-35)
        .\%8 := \findex(/,\%9)
        .showdir := ...\fsubstr(\%9,\%8)
    }
    addmsg {Included \m(ndiskimages) images from \m(showdir)}
}

if sort {                               # If sorting by Date Taken...
    dcl \&x[\fdim(&t)]
    xecho Sorting by date taken...
    if == sort 1 echo [chronological]
    if > sort 1 echo [reverse chronological]
    # Note: can also use ImageMagick 'identify' for this:
    # identify -verbose image.jpg | grep "exif:DateTime:"
    # But it's sloooooow...
    for i 1 \fdim(&x) 1 {               # Make parallel array of photo dates
        void \fpictureinfo(\&t[i],&d)
        if not def \&d[3] {
            echo "Date Taken not available for \&t[i] - Sorting not possible"
            addmsg {Images not sorted because \&t[i] lacks Date Taken}
            .sort = 0
            undeclare &x
            break
        }
        .\&x[i] := \&d[3]
    }
    if \fdim(&x) {                      # Sort names array by date taken
        if == sort 1 array sort &x &t   # Ascending
        else array sort /reverse &x &t  # Descending
        undecl &x                       # Dispose of date-taken array
    }
    undeclare &d
    if sort addmsg {Images sorted by Date Taken}
}

.need_thumbnails = 1                    # Assume we want to make thumbnails
.have_convert = 0                       # Do we have Image Magick convert?

if noimagemagick {                      # IM not wanted
    .need_thumbnails = 0                # so we don't make thumbnails..
    .have_convert = 0                   # we don't have 'convert'..
    .resize = 0                         # and we don't resize originals
    addmsg {ImageMagick Convert was not used}
} else {
    if def convertpath {                # User supplied path for convert
        if exist \m(convertpath) {
            .have_convert = 1
            addmsg {ImageMagick Convert path given as \m(convertpath)}
        } else {
            addmsg {\m(convertpath) not found - will proceed without it}
        }
    } else {
        .convertpath := \fcommand(which convert) # Try to find it
        if \v(pexitstat) undefine convertpath    # Not found
        if ( not def convertpath || not exist \m(convertpath) ) {
            .convertpath = convert
        }
        if exist \m(convertpath) {
            .ignoreconverterrors = 0
            # Some versions of 'convert' return a spurious failure code
            !\m(convertpath) -version > /dev/null 2> /dev/null
            if success {
                .have_convert = 1
            } else {
                .cversion := \fcommand(\m(convertpath) -version)
                if  \findex(ImageMagick,\m(cversion)) {
                    .ignoreconverterrors = 1 
                    .have_convert = 1
                }
            }
        } else {
            .have_convert = 0
        }
        if have_convert {
            addmsg {ImageMagick Convert was found at \m(convertpath)}
        } else {
            .resize = 0                 # Don't do any requested resizing
            .need_thumbnails = 0        # Don't try to make thumbnails
            addmsg {ImageMagick Convert not found}
        }
    }
}

# IF WE ARE RESIZING and *-r.xxx does not exist, we create one.  If a
# *-r.xxx file already exists then either it's an orphan (the original has
# been deleted), or the original still exists.  In the latter case, the
# original might have been updated, in which case we need to resize again.

.nresize = 0                            # How many were resized
if resize {                             # If resizing originals...
    local fn buf &y[] y
    echo
    echo RESIZING...
    addmsg {Resize width: \m(resize) pixels}

    # The &t[] array contains original image names except in the case
    # where a resized image exists and the original is gone so, for
    # example, foo.jpg, bar.jpg, baz-r.jpg (if baz.jpg doesn't exist).

    for i 1 \fdim(&t) 1 {               # Go through non-thumbnail images...
        .fn := \fcontents(\&t[i])        
        if not def fn continue
        checkimagename \m(fn)
        if fail {
            addmsg {WARNING: "\m(fn)" has problematic name (skipped)}
            continue
        }
        parsename {\m(fn)}              # Parse the filename
        if exist \m(tr) {               # If resized version already exists 
            getdimensions {\m(tr)}      # Get dimensions of resized image
            .width := \m(wid)           # Its width
            .height := \m(hgt)          # Its height
            .alreadyexists = 1		# remember that it does
            if exist \m(to) {           # If original still exists
                # If original hasn't been edited and resizing to the same size
                if ( newer \m(tr) \m(fn) && == \m(resize) \m(width) ) {
                    echo "SKIPPING: \m(tr) (already desired size)"
                    continue            # Go on to next image.
                }
            }
        } else {                        # Resized version doesn't exist
            # Or it wasn't resized because it's already too small...
            getdimensions {\m(to)}      # Get dimensions of original image
            if ( dontenlarge && < \m(wid) \m(resize) ) {
                .tr := \m(to)
                .width := \m(wid)
            }
        }
        # Don't try to resize an animated GIF - it doesn't work

        .animated = 0                   # Nonzero indicates animited GIF
        if equ "\m(ext)" "gif" {        # Gif file?
            checkanimated \m(to)        # Animated?
            if animated {               # If animated don't try to resize
                echo "SKIPPING \m(to) (animated GIF) "
                .tr := \m(to)
                continue
            }
        }
        # Not animated GIF...
        .doresize = 0
        if exist \m(tr) { 
            if dontenlarge {                # If "don't enlarge"
                if < \m(width) \m(resize) { # Original too small
                    echo "SKIPPING: \m(fn) (dontenlarge)" # don't resize it
                    continue
                }
            }
            if newer \m(to) \m(tr) .doresize = 1
            else if != \m(resize) \m(width) .doresize = 1
            else if not animated  .doresize = 1
        } else .doresize = 1
        if not doresize continue

        if doresize {
          xecho \m(fn): \fsize(\m(fn))... # Resize the original
          # Quotes are in case the filenames contain spaces
          !\m(convertpath) "\m(fn)" -resize \m(resize)x\m(resize) -auto-orient "\m(tr)"
          if fail {
              echo {CONVERT FAILED: \m(fn)=>\m(tr)}
              .tr := \m(fn)
          } else incr nresize           # Count resized image
        }
        echo \fsize(\m(tr))
    }
    echo                                # Resizing complete.
    if nresize {
        .\%9 = images
        if == \m(nresize) 1 .\%9 = image
        addmsg {Used ImageMagick 'convert' to resize \m(nresize) subpage \%9}
    } else {
        addmsg {No images needed resizing}
    }
} else {
    if \m(noimagemagick) {
        addmsg{Subpage images were not resized because noimagemagick = 1}
    } else {
        addmsg {Subpage images were not resized because resize = 0}
    }
}

.have_thumbnails := \m(need_thumbnails) # (two names for same thing)

# MAKE THUMBNAILS
if not \m(need_thumbnails) {            # Not making thumbnails
    addmsg {Browser-scaled originals will serve as thumbnails}
} else {                                # Need to and can make thumbnails...
    addmsg {Thumbnail height: \m(thumbhgt) pixels}
    echo Doing thumbnails (\fdim(&t))...

# \&t[] = array of originals and -r's (e.g. foo.jpg or foo-r.jpg)
# t  = image filename without extension (e.g. foo or foo-r)
# tt = thumbnail filename (e.g. foo-t.jpg)
# tr = name of image file to be converted to thumbnail

    .nthumbs = 0                        # Count how many we make
    for i 1 \fdim(&t) 1 {               # Go through non-thumbnail images...
        .fn := \fcontents(\&t[i])       # Original images's filename
        .thisname := \fcontents(\&t[i]) # Suppress any recursion on filename
        parsename {\m(thisname)}        # Get the parts of the name (sets 'to')
        if not have_convert {           # No ImageMagick?
            incr nthumbs
            continue
        }
        # tr is the source image to make the thumbnail from.
        # If we are resizing the subpage images we use the resized image
        # because in most cases it is smaller than the original.  If we are
        # not resizing we make the thumbnail from the original.
        if resize {                           # Resizing?
            if not exist \m(tr) .tr := \m(to) # Use original if none
        } else {                        # Not resizing
            .tr := \m(to)               # Use original
        }
       if not def tr exit 1 -
"INTERNAL ERROR: tr not defined for thumbnail \m(tt)"
       if not exist \m(tr) {
           # This can happen if we're using an IMAGES file that contains
           # files with pathnames.
           .tr := \m(fn)
       }
       if not exist \m(tr) {
            exit 1 "NO SOURCE IMAGE \m(tr) FOR THUMBNAIL \m(tt)"
        }
        xecho "\m(tr) => "
        if equ "\m(ext)" "gif" {        # Animated GIFs can't be resized
            checkanimated \m(to)        # If it's animated
            if animated {               # use the original as the thumbnail
                echo " (animated GIF)"
                .tt := \m(to)
                continue
            }
        }
        # Not animated and not GIF...
        if exist \m(tt) {               # Thumbnail already exists?
            # See if a new thumbnail is needed (e.g. if original changed)
            getdimensions {\m(tt)}      # Get its dimensions
            .ttwid := \m(wid)
            .tthgt := \m(hgt)
            if == \m(thumbhgt) \m(tthgt) { # Height same as requested height?
                if newer \m(tt) \m(tr) {   # Yes and if thumbnail is newer
                    echo (Thumbnail \m(tt) up to date)
                    continue        # this one is OK - go check next one
                }
            }
            del /quiet \m(tt)           # Need new one - delete current
        }
        # Quotes are in case the filenames contain spaces
        !\m(convertpath) "\m(tr)" -thumbnail x\m(thumbhgt) -auto-orient "\m(tt)"
        if fail {
            copy /list \m(tr) \m(tt)    # Just use the original
        } else {
            incr nthumbs
            echo \m(tt)                 # Create new thumbnail
        }
        dochmod \m(permissions) {\m(tt)}
    }
    if nthumbs {
        .\%9 = thumbnails
        if == \m(nthumbs) 1 .\%9 = thumbnail
        addmsg {Used ImageMagick 'convert' to create or update \m(nthumbs) \%9}
    } else addmsg {All thumbnails were already up to date}
    echo                                # Done with thumbnails
}
dochmod \m(permissions) {*.\m(extp)}    # Set image permissions

# Localization (Spanish or English)...

switch \m(language) {                   # Text messages for selected language
  :spanish
    .langtag = { lang="es"}             # HTML language tag
    if not def title .title = Fotos     # Default title
    .enlarge = Agrandar                 # Enlarge button label
    .enlargelegend = "Haz clic para ampliar la imagen"
    .pinitlegend = "Pinear esta foto en Pinterest"
    .photo = Foto                       # Individual page title
    .next  = Adelante                   # Forward
    .nexttitle  = Adelante              # Forward tool tip
    .prev  = Atr&aacute;s               # Back
    .prevtitle  = Atr&aacute;s          # Back tool tip
    .index = Ver todas                  # Index
    .indextitle = Ver todas             # Index tool tip
    .up = Arriba
    .uptitle = Arriba
    .msg1 = Haz clic en cualquier foto para entrar
    .createdby = Creado por
    .tooltip1 = Haz clic para seguir adelante
    break
  :english
    .langtag = { lang="en"}             # HTML language tag
    if not def title .title = Photos    # Default title
    .enlarge = Enlarge                  # Enlarge button label
    .enlargelegend = "Click to enlarge the image"
    .pinitlegend = "Pin this photo on Pinterest"
    .photo = Photo                      # Individual page title
    .next  = Next                       # Forward
    .nexttitle  = Next                  # Forward tool tip
    .prev  = Prev                       # Back
    .prevtitle  = Prev                  # Back tool tip
    .index = See all                    # Index
    .indextitle = See all               # Index tool tip
    .up      = Up
    .uptitle = Up
    .msg1 = Click on any photo to enter
    .createdby = Created by
    .tooltip1 = Click to go to next image
    break
  :default
    fatal "No language!"
}
.td = ""
if arrows {
    undef lp rp
    .index = <span style="font-size:40px;padding-top:16px">&#9650;</span>
    .up := \m(index)
    .next = <span style="font-size:36px;padding-top:16px">&#9654;</span>
    .prev = <span style="font-size:36px;padding-top:16px">&#9664;</span>
    .td = style="text-decoration:none"
}
echo Creating Web pages...

# Copy HTML prologue...

if not def font {
  .font = "font-family:calibri,arial narrow,arial,sans-serif; font-size:15px"
}
if not def head .head := \$(HEAD_HTML)

if ( def head && exist \m(head) ) {     # If external head file exists...
    if exist \m(indexfile) delete /quiet \m(indexfile)
    if fail fatal "Can't replace \m(indexfile)"
    appendfile \m(head) "_PAGETITLE_" "\m(title)" \m(indexfile) # append it
    fopen /append \%o \m(indexfile)
    if fail fatal "FOPEN \m(indexfile) failed[1]"
} else {                                # Otherwise supply standard head
    fopen /write \%o \m(indexfile)
    if fail fatal "FOPEN \m(indexfile) failed[2]"
    .what = INDEX
    fwrite /line \%o {<!DOCTYPE HTML>}
    fwrite /line \%o {<html \m(langtag)>}
    fwrite /line \%o {<head>}
    if def charset fwrite /line \%o {<META charset="\m(charset)">}
    else fwrite /line \%o {<META charset="utf-8">}
    if def stylesheet fwrite /line \%o -
{<LINK REL="stylesheet" TYPE="text/css" HREF="\m(stylesheet)">}
    if def favicon fwrite /line \%o -
{<LINK REL="shortcut icon" href="\m(favicon)">}
    fwrite /line \%o -
{<META name="viewport" content="width=device-width, initial-scale=1.0">}
    fwrite /line \%o {<title>\m(title)</title>}
    do STYLE \%o
    fwrite /line \%o {</head>}
    .bodystyle := margin:0; background:\m(background); color:\m(color);
    fwrite /line \%o <body style=\fchar(34)\m(bodystyle)
    fwrite /line \%o {  \m(font);\fchar(34)>}
    # Banner file to be included e.g. site title and menu
    if ( def bannerfile && exist \m(bannerfile) ) {
        fopen /read \%b \m(bannerfile)
        if fail exit 1 \m(bannerfile)
        while 1 {
            fread /line \%b line
            if fail break
            fwrite /line \%o \m(line)
        }
        fclose \%b
    }
    if def strip {
        if not exist \m(strip) exit 1 {Strip '\m(strip)' not found}
        if not match \m(strip) *.\m(extp) {
            exit 1 {Unsupported image filetype for strip '\m(strip)'}
        }
        getdimensions {\m(strip)}       # Get dimensions of strip
        .stwid := \m(wid)
        .sthgt := \m(hgt)
        if sthgt {
            fwrite /line \%o {<div -
style="background-image:url('\m(strip)'); height:\m(sthgt)px; -
border-bottom:1px solid grey">&nbsp;</div>}
        }
    }
    fwrite /line \%o {<div style="margin:0 12px 12px 10px">}
    if def supertitle {
        fwrite /line \%o {<span -
 style="font-size:15px"><i>\m(supertitle)</i></span>}
       fwrite /line \%o -
 {<h2 style="margin-top:0; \m(titlestyle)">\m(title)</h2>}
    } else {
        fwrite /line \%o {<h2 style="\m(titlestyle)">\m(title)</h2>}
    }
}
.sep =

if exist \m(indextxt) {                 # If index.txt exists
    fwrite /line \%o {<div -
style="width:100%;max-width:\m(maxwidth)px; margin:10px 0 1em 0">} 
    fclose \%o
    copy /append \m(indextxt) \m(indexfile) # append it to index file.
    fopen /append \%o \m(indexfile)         # (re)open index file.
    if fail fatal "FOPEN \m(indextxt) failed[3]"
    .sep = { style="border-top:1px solid grey"}
    fwrite /line \%o {</div>}
}

# The first line is to allow us to identify our own index.html files.
#
fwrite /line \%o {<!--PHOTOGALLERYINDEX v.\m(version)[\v(timestamp)]-->}
fwrite /line \%o {<div\m(sep)>}         # And write the contents
fwrite /line \%o {<a style="text-decoration:none"}
fwrite /line \%o { title="\m(uptitle)"}
fwrite /line \%o { href="\m(uplink)">\m(up)</a> }
fwrite /line \%o { &nbsp; }
fwrite /line \%o {<i>(\m(msg1))</i>}
fwrite /line \%o {</div>}
fwrite /line \%o {<div class="thumbnails">}

.\%n := \fdim(&t)                       # How many non-thumbnail JPGs

# MAKE SUBPAGES
#
# We can have original images, resized images, and thumbnail images.
# It is possible, however, to build a gallery from originals and then 
# delete them.  The following code allows the gallery to be rebuilt
# even after the originals have been deleted by treating the resized
# images as originals.

def DOSUBTITLE {
    if nsttl {                          # If we have any subtitles
        .tmpsttl := \m(SUBTTL<\%i>)     # Check for associated subtitle
        .tmplbl := \m(LABEL<\%i>)       # and label
        .tmptxt := \m(SUBTXT<\%i>)      # and text file
        if def tmpsttl {                # If we have one for this image
            local tmpline tmpstyle
            .sttl := \m(tmpsttl)        # Put a subheading in the index page
            if def tmplbl .tmplbl := { id="\m(tmplbl)" }
            .tmpstyle = {style="margin:8px 0 0px 0; border-top:1px solid grey"}
            if == \%i 1 .tmpstyle = { style="margin:0"}
            .tmpline := <h3 \m(tmplbl)\m(tmpstyle)>\m(sttl)</h3>
            fwrite /line \%o "\m(tmpline)"
            echo "---------------------------------"
            echo SUBTITLE \m(tmpsttl)
            echo "---------------------------------"
        }
        if def tmptxt {                 # Have some text to put here?
            if not exist \m(tmptxt) {   # Specified file exists?
                echo SUBTITLE text file not found: \m(tmptxt)
            } else {
                local tmpline
                fopen /read \%9 \m(tmptxt)   # Open the specified file
                if success {                 # If OK
                    fwrite /line \%o {<div style="margin:0 0 2px 0">} # <div>
                    while 1 {                # Copy text to the index file
                        fread /line \%9 tmpline
                        if fail break
                        fwrite /line \%o \m(tmpline)
                    }
                    fclose \%9                # Close subtext file
                    fwrite /line \%o {</div>} # Close div
                }
            }
        }
    }
}
# Put Back, Next, and Up links on a subpage, plus an Enlarge button.
#
define PUTLINKS {
    local \%i \%n \%c
    .\%i := \%1
    .\%n := \%2
    .\%c := \%3

    undef nextpage
    if == \%i \%n {                     # Last subpage...
        .x := \m(indexfile)             # Has only Up and Prev links
        .x := \freplace(\m(x),\32,%20)  # No spaces allowed
        .whatsnext := \m(x) 
        fwrite /line \%c \m(lp) <a -
title="\m(indextitle)" \m(td) -
href="\m(x)">\m(up)</a> \m(rp)
    } else {                            # Not last image
        .x := \fstripx(\fbasename(\&t[\%i+1])).html
        .x := \freplace(\m(x),\32,%20) # No spaces allowed
        .nextpage := \m(x)
        fwrite /line \%c -
      {\m(lp) <a \m(td) title="\m(nexttitle)" href="\m(x)">\m(next)</a> \m(rp)}
    }
    .xnext := \m(x)                     # Remember this for later
    undef prevpage
    if != \%i 1 {                       # Not first image?
        .prevpage = 1
        .x := \fstripx(\fbasename(\&t[\%i-1])).html # Not 1 so link to previous
        .x := \freplace(\m(x),\32,%20) # No spaces allowed
        .prevpage := \m(x)
        fwrite /line \%c {&nbsp; \m(lp) <a \m(td) title="\m(prevtitle)" -
href="\m(x)">\m(prev)</a> \m(rp) &nbsp;}
    }
    if != \%i \%n {                     # If not last subpage
        fwrite /line \%c \m(lp) <a \m(td) title="\m(indextitle)" -
href="\m(indexfile)">\m(index)</a> \m(rp)
    }
    .original := \m(namepart).\m(ext)
    if ( exist \m(original) && \m(enlargebutton) ) { # Enlarge button
        fwrite /line \%c <td style="padding:0 0 0 12px; vertical-align:middle">
        fwrite \%c {<span title="\m(enlargelegend)" }
        fwrite \%c {class="button"><a href="\m(original)">}
        fwrite /line \%c \m(enlarge)</a></span>
    }
    if dopinterest {
        fwrite /line \%c <td class="pinit" -
 style="padding:0 0 0 12px; vertical-align:middle" title="\m(pinitlegend)">
        fwrite /line \%c {<script>}
        echo pinit('\m(myurl)','\m(to)','\freplace(\m(title),\39,&#39;)')
        fwrite /line \%c -
{document.writeln(pinit('\m(ht)','\m(to)','\freplace(\m(title),\39,&#39;)'));}
        fwrite /line \%c {</script>}
    }
    fwrite /line \%c </table>           # End of "navigation bar"
    fwrite /line \%c <div -
style="padding-bottom:10px; border-bottom:1px solid grey">
}
# DO THE SUBPAGE IMAGES

if not have_convert addmsg -
 {Browser-scaled originals will serve as subpage images}

for \%i 1 \%n 1 {                       # Loop through all non-thumbnails
    dosubtitle \%i                      # Handle any subtitles
    .animated = 0                       # Unset this in case set (per file)
    .fn := \fcontents(\&t[\%i])         # Suppress any recursion on filename
    parsename {\m(fn)}                  # Get the pieces of the name
    if resize .subpageimage := \m(tr)
    if ( not exist \m(subpageimage) || not resize ) {
        .subpageimage := \m(to)
    }
    if not exist \m(subpageimage) {
        .subpageimage := \m(fn)
    }
    if not exist \m(subpageimage) {
        exit 1 SUBPAGE IMAGE \m(subpageimage) not found.
    }
    .filemsg := "\m(fn) => "            # Beginning of subpage message
    getdimensions {\m(subpageimage)}    # Get subpage image width and height
    .width := \m(wid)                   # Copy 'em
    .height := \m(hgt)
    if == 0 height .height := 1         # Prevent divide by zero below
    .captionfile := \m(subpagetext)     # Caption file
    if not exist \m(captionfile) .captionfile := default.txt
    if exist \m(captionfile) {          # If it exists
        checkcset \m(captionfile)       # detect its character set
        .subcharset := \v(return)       # and declare it for this subpage
        if not def subcharset .subcharset := \m(charset)
        if equ "\m(subcharset)" "us-ascii" .subcharset = utf-8
    }

# Until version 2.21, portrait images would often have their bottoms truncated.
# You'd have to scroll down to see the rest of the image and to see if there
# was a caption.  In 2.22-2.24 I tried various math tricks based on the image's
# aspect ratio, but they were not satisfying.  In version 2.25 I use the vmin
# viewport-scaling unit to do the job, but that works only for the image
# itself, so I still need to apply the aspect ratio to the caption text.
# I'm not worrying about old browsers because these days most browsers
# update themselves automatically.  -fdc 2018/02/10

    .dimensions := \m(width)&times;\m(height)
    .realwidth := \m(width).0           # Width as floating-point number
    .realheight := \m(height).0         # Height as floating-point number

    # Make width fit in minwidth..maxwidth range
    if maxwidth if > \m(width) \m(maxwidth) .width := \m(maxwidth)
    if minwidth if < \m(width) \m(minwidth) .width := \m(minwidth)
    # Get aspect ratio... See how we do floating-point arithmetic in Kermit:
    .hscale = 0
    (setq ratio (/ realwidth realheight)) # Ratio of width to height
    if < \m(ratio) 1.2 {
        # 0.72 = Leave space for the top matter and (some of) the caption.
        # (setq width (truncate (* width ratio 0.72)))
        .hscale = 1                     # Narrow image needs horizontal scaling
    }
    .titlefile := \m(namepart).ttl      # Title file for this image if any
    undef titleline                     # Default title line for this subpage
    if def sttl .titleline := \m(sttl)  # Use this if given
    if exist \m(titlefile) {            # Title file for this image
        local \%d                       # takes precedence.
        fopen /read \%d \m(titlefile)
        if success {
            fread /line \%d titleline
            fclose \%d
        }
    }
    if def titleline {
        .thistitle := \m(shorttitle) - \m(photo) \#\%i - \m(titleline)
    } else {
        .thistitle := \m(shorttitle) - \m(photo) \#\%i
    }
    .filemsg := \m(filemsg)\m(url) (\m(orientation)) # Finish progress message
    echo \fleft(\m(filemsg),\v(cols)-1) # Echo so it fits on screen
    fopen /write \%c \m(subpagename)    # Create page for this image
    if fail exit 1 OPEN failed: \m(subpagename)
    .what = SUBPAGE                     # (for STYLE macro)
    fwrite /line \%c <!DOCTYPE HTML>    # Write HTML prologue
    fwrite /line \%c <html\m(langtag)>
    fwrite /line \%c <head>
    fwrite /line \%c -
<META name="viewport" content="width=device-width, initial-scale=1.0">
    if def subcharset fwrite /line \%c {<META charset="\m(subcharset)">}
    else fwrite /line \%c {<META charset="utf-8">}
    if def stylesheet fwrite /line \%c -
<LINK REL="stylesheet" TYPE="text/css" HREF="\m(stylesheet)">
    if def favicon fwrite /line \%c -
<LINK REL="shortcut icon" href="\m(favicon)">
    fwrite /line \%c <title>\m(thistitle)</title>
    do STYLE \%c                        # Write out style section
    do pinterestjs \%c                  # Include Pinterest Javascript
    fwrite /line \%c </head>            # Close the <head> section
    .bodystyle := margin:12px; background:\m(background); color:\m(color);
    fwrite /line \%c <body style=\fchar(34)\m(bodystyle)
    fwrite /line \%c {  \m(font);\fchar(34)>}
    fwrite /line \%c <h3>\m(thistitle)</h3>

    fwrite /line \%c {<table><tr><td>}
    putlinks \%i \%n \%c                # Put next/prev/up links on subpage
    .whatsnext := \m(xnext)             # What the image itself links to

    .nexttooltip := \m(tooltip1)
# NOTE: Chrome 66 ignores the max-width clause and wrecks the aspect ratio.
    fwrite /line \%c {<div style="display:table; max-width:\m(width)px">}
    fwrite /line \%c {<a href="\m(whatsnext)"><img }
    fwrite /line \%c {title="\m(thistitle) - \m(dimensions) - \m(nexttooltip)"}
    if hscale {                         # Scaling by height (portrait)
        .\%q := style="height:76vmin; max-height:\m(realheight)px"
    } else {                            # Scaling by width (landscape)
        .\%9 := \fmin(\m(realwidth),\m(maxwidth))
        .\%q := style="width:96%; max-width:\m(width)px; max-height:72vh"
    }
    fwrite /line \%c {\%q alt="\fbasename(\m(namepart))" -
src="\m(subpageimage)"></a>}

# This sets the width for any and all text written below the image.

    fwrite /line \%c {<div id="text" -
style="display:table-caption; caption-side:bottom">}

# Captions are in separate .txt files.  Doing it this way allows the content
# of the gallery to change during construction without having to edit the
# .html files, which would be destroyed in the next run (e.g. when inserting
# or deleting photos, because all the previous/next links have to be
# recalculated).
#
# If a caption file does not exist for particular image, a default
# caption will be used if a default.txt file exists.

    if exist \m(captionfile) {          # Insert caption if any 
        fopen /read \%d \m(captionfile)
        if success {                    # Have caption file
            fwrite /line \%c            # (cosmetic)
            while true {                # Copy the text line by line
                fread /line \%d textline
                if fail { fclose \%d, break }
                fwrite /line \%c \m(textline)
            }
            fwrite /line \%c            # (cosmetic)
        }
    }
    .have_copyright = 0
    if not def copyright .copyright := \$(COPYRIGHT_HTML)
    if ( def copyright && exist \m(copyright) ) {
        .have_copyright = 1
    }
    .footer = 0
    if ( have_copyright || validate ) .footer = 1
    if footer {
        fwrite /line \%c {<table -
 style="width:100%; margin-top:12px; -
   border-top:1px solid gray; font-size:90%; ">}
        fwrite /line \%c {<tr>}
        fwrite /line \%c {<td>}
        if have_copyright {
            fclose \%c                      # Close page so we can append to it
            appendfile \m(copyright) "_YEAR_" "\fword(\v(date),3)" \m(ht)
            fopen /append \%c \m(ht)        # Reopen the page
        }
        fwrite /line \%c {<td style="text-align:right">}
        if validate {
          fwrite /line \%c {<script>}
          fwrite /line \%c { -
            var url = 'http://validator.w3.org/check?uri=' -
 + escape(window.location.href);}
            fwrite /line \%c { -
 var href = '<a href="' + url + '">Validate<\/a>';}
            fwrite /line \%c { -
 document.writeln('\m(sp)[&nbsp;' +  href + '&nbsp;]');}
            fwrite /line \%c {</script>}
                if footer { fwrite /line \%c </table> }
        }
    }
    fwrite /line \%c </div>
    fwrite /line \%c </div>
    fwrite /line \%c </div>             # End of image-caption section
    if dopinterest {
        fwrite /line \%c {<script>}
        fwrite /line \%c {  document.writeln(loadpinitjs());}
        fwrite /line \%c {</script>}
    }
# Insert Javascript to allow navigation by arrow keys 

    if ( doarrowkeys && equ "\m(what)" "SUBPAGE" ) {
        if not def prevpage .prevpage := \m(indexfile)
        if not def nextpage .nextpage := \m(indexfile)
        fwrite /line \%c "<script>"
        fwrite /line \%c "document.onkeydown = function(event) \m(lb)"
        fwrite /line \%c "  switch (event.keyCode) \m(lb)"
        fwrite /line \%c "    case 37:"
        fwrite /line \%c "      window.open('\m(prevpage)','_self')"
        fwrite /line \%c "      break;"
        fwrite /line \%c "    case 38:"
        fwrite /line \%c "      window.open('\m(indexfile)','_self')"
        fwrite /line \%c "      break;"
        fwrite /line \%c "    case 39:"
        fwrite /line \%c "      window.open('\m(nextpage)','_self')"
        fwrite /line \%c "      break;"
        fwrite /line \%c "    case 40:"
        fwrite /line \%c "/* No-op because browser intercepts this */"
        fwrite /line \%c "      window.open('\m(original)','_self')"
        fwrite /line \%c "      break;"
        fwrite /line \%c "    \m(rb)"
        fwrite /line \%c "\m(rb);"
        fwrite /line \%c </script>
    }
    fwrite /line \%c </body>            # End of subpage body
    fwrite /line \%c </html>            # End of html
    fclose \%c                          # Close it the subpage
    increment subpages                  # Count it
    dochmod \m(permissions) {\m(subpagename)} # Give it the desired permissions

# ADD THUMBNAIL TO INDEX PAGE...

    if not have_convert .tt := \m(namepart).\m(ext) # Use original image
    checkanimated \m(subpageimage)                  # Animated GIF?
    if animated .tt := \m(subpageimage)             # Use original
    if exist \m(tt) {                               # Have thumbnail image?
        # Make entry in index page.        
        fwrite /line \%o -
{<a href="\m(url)"><img -
title="\m(thistitle)" -
alt="\m(namepart)" -
style="height:\m(thumbhgt)px; width:auto" -
src="\m(tt)"></a>}
    } else {                            # No thumbnail - put text link
       fwrite /line \%o [&nbsp;<a href="\m(url)">\m(ht)</a>&nbsp;]
    }
}
# Finish and close Index page

fwrite /line \%o {</div><!--THUMBNAILS-->}

if def index2 {
    if exist \m(index2) {
        fwrite /line \%o <div style="max-width:\m(maxwidth)px;">
        fclose \%o
        copy /append \m(index2) \m(indexfile)
        fopen /append \%o \m(indexfile)
        fwrite /line \%o </div>
    } else {
        addmsg {WARNING: index2 \m(index2) not found - skipping...}
    }
}
if have_locale {                        # Get today's date
    local day
    .day := \fword(\v(date),1)
    if equ "\m(language)" "Spanish" {
        set locale es_ES.UTF-8
        .fulldate := el \m(day) de \fmonthname(\v(nmonth),0) del \v(year)
    } else {
        set locale en_US.UTF-8
        if fail set locale
        .fulldate := \fmonthname(\v(nmonth),0) \m(day)\, \v(year)
    }
} else {
    .fulldate := \v(date)
}
if not def tail .tail := \$(TAIL_HTML)
if ( def tail && exist \m(tail) ) {     # If external tail file exists...
    fclose \%o                          # Close index file
    appendfile \m(tail) "_PAGEDATE_" "\m(fulldate)" \m(indexfile) # append tail
} else {
    .pgurl = http://www.kermitproject.org/photogallery.html
    fwrite /line \%o {<p>}
    fwrite /line \%o {<div style="border-top:1px solid grey">} # End of page
    fwrite /line \%o {<table style="width:100%">}
    fwrite /line \%o {<tr>}
    fwrite /line \%o {<td>}
    fwrite /line \%o {<i style="font-size:86%">\m(createdby) -
 <a href="\m(pgurl)">C-Kermit Photogallery</a> \m(version)}
    fwrite /line \%o { \m(fulldate)}
    fwrite /line \%o {</i>}
    if validate {
      fwrite /line \%o {<td style="text-align:right">}
      fwrite /line \%o {<script>}
      fwrite /line \%o { var url -
= 'http://validator.w3.org/check?uri=' + escape(window.location.href);}
        fwrite /line \%o { -
var href = '<a href="' + url + '">Validate<\/a>';}
        fwrite /line \%o { -
document.writeln('\m(sp)[&nbsp;' +  href + '&nbsp;]');}
        fwrite /line \%o {</script>}
    }
    fwrite /line \%o {</table>}
    fwrite /line \%o {</div>}
    fwrite /line \%o {</div>}

    if doarrowkeys  { 
        fwrite /line \%o "<script>"
        fwrite /line \%o "document.onkeydown = function(event) \m(lb)"
        fwrite /line \%o "  switch (event.keyCode) \m(lb)"
        fwrite /line \%o "    case 38:"
        fwrite /line \%o "      window.open('\m(uplink)','_self')"
        fwrite /line \%o "      break;"
        fwrite /line \%o "    \m(rb)"
        fwrite /line \%o "\m(rb);"
        fwrite /line \%o </script>
    }

    fwrite /line \%o {</body>}
    fwrite /line \%o {</html>}
    fclose \%o
}
dochmod \m(permissions) {\m(indexfile)}

addmsg {Images in gallery: \m(subpages)}
! echo \m(subpages) > imgcount
if nsttl addmsg {Sections: \m(nsttl)}

echo "---------------------------------"
echo "SUMMARY \fcvtdate(,2)..."
.testversion := \v(test)
if equ "\m(testversion)" "0" undef testversion
echo "Interpreter: \v(program) version \v(version) \m(testversion)"
if def convertpath {
    echo Convert path: \m(convertpath)
} else if not \m(have_convert) {
    echo "Convert not found - no resizing was done"
} else {
    echo "Convert from default path used for resizing"
}
echo "Supported graphics file extensions:"
echo "\m(extensions)"
xecho "This directory:"
if > \flen(\v(dir)) 63 echo ""
echo " \v(dir)"
echo "Title: \m(title)"
echo "Index file name: \m(indexfile)"

for i 1 mx 1 {                          # Show accumulated messages at end
  echo \&m[i]                           # (summary of Photogallery session)
}
echo "---------------------------------"
if defined atend do atend               # Execute ATEND macro if defined
else if exist imgcount del /quiet imgcount

echo "\m(myname): \m(thisdir)/\m(indexfile) OK"
exit

; Local Variables:
; comment-column:40
; comment-start:"# "
; End:
