#!/bin/sh

# Usage:
#     $0 source-image-name output-image-name [ultimate-source [maxsize]]
#
#     source-image-name  can be as-is under img or autogenerated under img/a
#         Must be an acceptable primary image format.
#
#     output-image-name  target output filename
#         Must be under img/a/ or out/ and
#         must have a known alternate format suffix
#
#     maxsize  if present then the maximum allowed size for the alternate
#         If not supplied then a maximum will be computed
#         which is sufficiently smaller to be worthwhile.
#
#     ultimate-source  ultimate source image with original extension
#         Used to determine lossy or lossless handling.
#         If unset, source-image-name is used.

# This will *remove* the output image target if the input does not exist.

# This generates no output other than informational, on stderr.
# This script will:
#   * do nothing (with no output image generated)
#   * leave an existing output image in place as up to date
#   * atomically create or replace the specified output image
#   * remove the output image if extant and the input not
#
# This may use/create flags under the .flags directory next to the output file.

#echo "INFO: $0 $@" 1>&2

# Capture inputs.
SRCIMGNAME=$1
OUTIMGNAME=$2
ULTIMATESRC=${3:-$1}
MAXSIZE=$4

# Build an alternate format compact image on demand if needed and possible.
# Any creation or update of the output image will be atomic.
# Any created or updated output image will globally readable, user writable.
# This may use a flag to cache a DONE or FAIL state.
# Such flags will be ignored if this script is newer than the flag.
# Such flags will be ignored if the rebuild flag is newer.

# The output image must be within the autogen area.

# The output image suffix determines the output format.
# An unknown format will cause immedate return without making flags, etc.

# The input image format must be an acceptable/known primary image format.
# FOR NOW only PNG (.png) input is acceptable.

# This can be used to build compact alternate images
#   * from autoscaled images while they are being built
#   * on demand from source hero and body images being used as-is


# VARIABLES MATCHING FROM get_hero_img_inline.
# TODO: they can be in future sourced from a common config file.
# Until then, keep them in step.
#
# AUTOGEN cache locations.
CACHEDIRAG=img/a
# If the rebuild flags exists and is newer than any cached result flag,
# unconditionally try to rebuild/refresh everything (carefully, under a lock).
# Else return immediately on cached positive or negative results.
# Assumes that a cached positive result is the most likely.
# Should be touched after any substantive change to image selection/generation.
REBUILDFLAG=$CACHEDIRAG/.rebuild.flag
# Ceiling size (%) of alternate format image to use.
MAXALTIMGPC=95
# Approximate uncompressed HTML overhead of an extra picture source tag.
PICTURESOURCEOH=101

# ImageMagick seems not to work well as a wrapper on RPi with cwebp 0.5.2
# DHD20210802: use locally-built (cut-down) cwebp if available, not distro.
CWEBP=cwebp
if [ -x /usr/local/bin/cwebp ]; then CWEBP=/usr/local/bin/cwebp; fi


# Input image validation.
# Input image must be of acceptable primary type.
case $SRCIMGNAME in
    *.png) ;; # Good!
    *.jpg) ;; # Good!
    *)
        echo "ERROR: input image type not acceptable" 1>&2
        exit 1;;
esac

# Output image validation.
# Output image must be of an acceptable alternative type.
case $OUTIMGNAME in
    *.webp) ;; # Good!
    *.avif|*.jxl) 
        #echo "INFO: output image type not yet available" 1>&2
        exit 0;; # Not an error, just does nothing.
    *)
        echo "ERROR: output image type not acceptable" 1>&2
        exit 1;;
esac
#
# Output image path must be in the autogenerated image directory or out/.
case $OUTIMGNAME in
    out/*) ;; # Good!
    $CACHEDIRAG/*) ;; # Good!
    *)
        echo "ERROR: output image path not acceptable: not under out/ nor $CACHEDIRAG" 1>&2
        exit 1;;
esac

# If input image does not exist and output does, remove the output and stop.
# Not an error.
if [ ! -s "$SRCIMGNAME" -a -f "$OUTIMGNAME" ]; then
    rm -f  "$OUTIMGNAME"
    echo "INFO: input image file missing or zero length, output removed." 1>&2
    exit 0
fi

# Mode selection.
case $ULTIMATESRC in
    *.png) MODE=lossless;; # Good!
    *.jpg) MODE=lossy;; # Good!
    *)
        echo "ERROR: cannot determine processing mode from ultimate source name" 1>&2
        exit 1;;
esac


# Create a maximum output size if not provided.
if [ "" = "$MAXSIZE" ]; then
    srcsize="`wc -c < $SRCIMGNAME | awk '{print $1}'`"
    # Allow for the HTML overhead of a new source tag.
    # Then enforce a mimimum % saving.
    MAXSIZE="`expr \( $srcsize \* $MAXALTIMGPC \) / 100`"
    outsizelessoh="`expr $srcsize - $PICTURESOURCEOH`"
    if [ "$outsizelessoh" -lt "$MAXSIZE" ]; then
        MAXSIZE=$outsizelessoh
    fi
    #echo "INFO: computed MAXSIZE=$MAXSIZE from input size $srcsize" 1>&2
fi


# Temporary output filename, parallel safe, removed on error exit.
OUTTMPNAME=$OUTIMGNAME.$$.tmp
trap "rm -f $OUTTMPNAME; exit 1" 1 2 15


# Handle lossless alternative formats first.
if [ "lossless" = "$MODE" ]; then
    case $OUTIMGNAME in
        *.webp)
            $CWEBP -quiet -mt -q 100 -lossless -m 6 $SRCIMGNAME -o $OUTTMPNAME
            ;;
        *) echo "ERROR: output image type invalid" 1>&2; exit 1;;
    esac
fi # LOSSLESS

# Handle lossy.
if [ "lossy" = "$MODE" ]; then
    case $OUTIMGNAME in
        *.webp)
            # Assume that cwebp does a reasonable job automatically.
            $CWEBP -quiet -mt -m 6 $SRCIMGNAME -o $OUTTMPNAME
            ;;
        *) echo "ERROR: output image type invalid" 1>&2; exit 1;;
    esac
fi # LOSSLESS


# Atomically move new file into place if:
#   * It exists and is non-zero length.
#   * It is different to something already there.

# If no alternate was produced or was zero length or too large
# then remove new tmp *and any extant result* are removed.
# This is not an error.
#if [ -s "$OUTTMPNAME" ]; then echo "INFO: MADE alternate `ls -l $OUTTMPNAME`" 1>&2; fi
if [ ! -s "$OUTTMPNAME" ]; then
    echo "INFO: alternate not made or zero-length" 1>&2
    rm -f $OUTTMPNAME $OUTIMGNAME
    exit 0
fi
if [ "`wc -c < $OUTTMPNAME`" -gt "$MAXSIZE" ]; then
    #echo "INFO: alternate too large" 1>&2
    rm -f $OUTTMPNAME $OUTIMGNAME
    exit 0
fi

# Only move valid new alternate into place if different from any extant.
# If there is an extant identical result in place, discard the new tmp.
if [ -s "$OUTIMGNAME" ]; then
    if cmp -s $OUTTMPNAME $OUTIMGNAME; then
        echo "INFO: leaving alone unchanged alternate $OUTIMGNAME" 1>&2
        rm -f $OUTTMPNAME
        exit 0
    fi
    chmod u+w $OUTIMGNAME
fi

# Make new tmp globally readable.
chmod a+r $OUTTMPNAME
# Atomic move into place.
mv -f $OUTTMPNAME $OUTIMGNAME
echo "INFO: moved into place new alternate $OUTIMGNAME" 1>&2

# Clean up any residual temporary file and exit without error.
rm -f $OUTTMPNAME
exit 0










# Code from the future...


if false; then
# WEBP lossy
                if [ "webp" = "$fmt" ]; then
                    # Attempt to build a temporary alternate
                    # to move into place later.
                    # TARGETPSNR includes a fudge factor from ImageMagick to WEBP.
                    TARGETPSNR=`$COMPARE -metric PSNR $NOLOSSTMP ${imain} null: 2>&1 | awk '{print ($1 + 4.5)}'`
                    #echo "INFO: TARGETPSNR $TARGETPSNR" | tee -a $AGHBINFO 1>&2
                    # If it is zero length or not enough smaller, zap it.
                    # NOTE: always generate from the *lossless* version.
    $CWEBP -quiet -mt -psnr $TARGETPSNR -pass 10 -m 6 -af $NOLOSSTMP -o $itmp
                    if [ ! -f "$itmp" ]; then continue; fi
                    if [ ! -s "$itmp" ]; then rm -f "$itmp"; continue; fi
                    imainsize="`wc -c < $imain | awk '{print $1}'`"
                    itmpsize="`wc -c < $itmp | awk '{print $1}'`"
                    # Allow for the HTML overhead of a new source tag.
                    # Then enforce a mimimum % saving.
                    maxtmpsize="`expr \( $imainsize \* $MAXALTIMGPC \) / 100`"
                    #echo "INFO: imainsize=$imainsize maxtmpsize=$maxtmpsize itmpsize=$itmpsize" | tee -a $AGHBINFO 1>&2
                    if [ "$itmpsize" -gt "$maxtmpsize" ]; then rm -f "$itmp"; continue; fi
echo "INFO: MADE smaller alternate $itmp $itmpsize cf $imainsize" | tee -a $AGHBINFO 1>&2
                fi
