#!/bin/sh
#
# Usage:
#     script/lossless_JPEG_compress [-m bbb] file.jpg { file2.jpg ...}
#
# Losslessly compress in-place the specified JPEG file(s).
# Any compression done may be reported as an INFO line on stderr.
# The files must be valid writable JPEGs.
#
# By default no compression is done and the source files are left as-is.


# Maximum size to consider potentially targeted to a mobile device.
# Below this size try to avoid many-scan progressive as CPU-intensive.
#
# Size threshold is overridden by -m size.
#
# A threshold of 0 effectively removes the limit.
#
# Possibly override this restriction if big (10%?) savings are to be had.
# TODO: allow override/removal of this limit from the command-line.
MOBSIZEMAX=10240
if [ "-m" = "$1" ]; then
    MOBSIZEMAX="$2"
    # Discard the -m bbb args.
    shift
    shift
fi

# Tries various plausible output formats to reduce size,
# including progressive, even for small files.

# Look at possible alternative scans as in:
#     https://cloudinary.com/blog/progressive_jpegs_and_green_Martians

# Uses jpegtran: gives up immediately if not available.
JT=/usr/local/bin/jpegtran
if [ ! -x $JT ]; then
    JT=/usr/bin/jpegtran
    if [ ! -x $JT ]; then
        echo "WARNING: jpegtran not available" 1>&2
        # Quit immediately leaving files untouched.
        exit 1
    fi
fi



# Writes to an intermediate file with a temporary suffix.
# Some files already have very long names,
# so making this suffix too long may make some tasks fail.
TMPSUFFIX="U.tmp"


# Process the files.
for f in $*;
    do
    if [ ! -s "$f" ]; then
        echo "WARNING: missing or zero-length file $f" 1>&2
        continue
    fi

    TMPFILE=$f.$TMPSUFFIX
    rm -f $TMPFILE
    ISIZE="`wc -c < $f`"
    #echo "INFO: file $ISIZE $f" 1>&2

    # Earlier encodings are preferred,
    # eg fewer passes to save mobile CPU and battery,
    # or easier for users to know when complete,
    # or more likely to be compatible with all browsers,
    # or less likely to produce transient 'green Martians'.

    # In any case, replace immediately if smaller,
    # and report against original size.
    # First conversion with smallest/equal size will win.

    # Baseline, ie non-progressive.
    # Most mobile-friendly: least CPU and memory to decode.
    $JT -copy none -optimize <$f >$TMPFILE
    NPSIZE="`wc -c < $TMPFILE`"
    if [ -s $TMPFILE -a "$NPSIZE" -lt "`wc -c < $f`" ]; then
        mv -f $TMPFILE $f
        echo "INFO: file $ISIZE shrunk to $NPSIZE (non-progressive) $f" 1>&2
    fi

#    # "Two-pass progressive" scans file.
#    # DHD20180409: doesn't provide any optimisation on current hero set.
#    # Just two passes, all DC first, so very steep improvement.
#    # Should be easier on mobile battery as fewer scans.
#    SCANSTWO=$0.twopass.scans
#    if [ ! -s $SCANSTWO ]; then
#        echo "WARNING: $SCANSTWO scans file not available" 1>&2
#        # Can continue, just won't be able to try this scan type.
#    else
#        # Suppress "Invalid scan script at entry 1" for grayscale images.
#        $JT -copy none -optimize -scans $SCANSTWO <$f >$TMPFILE 2>/dev/null
#        TPSIZE="`wc -c < $TMPFILE`"
#        if [ -s $TMPFILE -a "$TPSIZE" -lt "`wc -c < $f`" ]; then
#            mv -f $TMPFILE $f
#            echo "INFO: file $ISIZE shrunk to $TPSIZE (two-pass progressive) $f" 1>&2
#        fi
#    fi

    # "Semi-semi-progressive" scans file.
    # Fewer passes (4) than the "Semi-progressive" scans file.
    # Should be easier on mobile battery as fewer scans.
    SCANSSSEMI=$0.semisemiprog.scans
    if [ ! -s $SCANSSSEMI ]; then
        echo "WARNING: $SCANSSSEMI scans file not available" 1>&2
        # Can continue, just won't be able to try this scan type.
    else
        # Suppress "Invalid scan script at entry 1" for grayscale images.
        $JT -copy none -optimize -scans $SCANSSSEMI <$f >$TMPFILE 2>/dev/null
        SSSIZE="`wc -c < $TMPFILE`"
        if [ -s $TMPFILE -a "$SSSIZE" -lt "`wc -c < $f`" ]; then
            mv -f $TMPFILE $f
            echo "INFO: file $ISIZE shrunk to $SSSIZE (semi-semi-progressive) $f" 1>&2
        fi
    fi

    # "Semi-progressive" scans file.
    # Fewer passes (5) than the default progressive scans file.
    # Should be easier on mobile battery as fewer scans.
    SCANSSEMI=$0.semiprog.scans
    if [ ! -s $SCANSSEMI ]; then
        echo "WARNING: $SCANSSEMI scans file not available" 1>&2
        # Can continue, just won't be able to try this scan type.
    else
        # Suppress "Invalid scan script at entry 1" for grayscale images.
        $JT -copy none -optimize -scans $SCANSSEMI <$f >$TMPFILE 2>/dev/null
        SESIZE="`wc -c < $TMPFILE`"
        if [ -s $TMPFILE -a "$SESIZE" -lt "`wc -c < $f`" ]; then
            mv -f $TMPFILE $f
            echo "INFO: file $ISIZE shrunk to $SESIZE (semi-progressive) $f" 1>&2
        fi
    fi

#    # "Steep-progressive" scans file.
#    # DHD20180408: doesn't provide any optimisation on current hero set.
#    SCANSSTEEP=$0.steepprog.scans
#    if [ ! -s $SCANSSTEEP ]; then
#        echo "WARNING: $SCANSSTEEP scans file not available" 1>&2
#        # Can continue, just won't be able to try this scan type.
#    else
#        # Suppress "Invalid scan script at entry 1" for grayscale images.
#       $JT -copy none -optimize -scans $SCANSSTEEP <$f >$TMPFILE 2>/dev/null
#       STSIZE="`wc -c < $TMPFILE`"
#       if [ -s $TMPFILE -a "$STSIZE" -lt "`wc -c < $f`" ]; then
#           mv -f $TMPFILE $f
#           echo "INFO: file $ISIZE shrunk to $STSIZE (steep-progressive) $f" 1>&2
#       fi
#    fi

    # "Three-pass progressive" scans file.
    # Three passes, all luma (0) then all 2 then all 1.
    # Small number of passes kinder to mobile CPU/battery.
    # Some risk of green Martians, so try late.
    SCANSTHREE=$0.threepass.scans
    if [ ! -s $SCANSTHREE ]; then
        echo "WARNING: $SCANSTHREE scans file not available" 1>&2
        # Can continue, just won't be able to try this scan type.
    else
        # Suppress "Invalid scan script at entry 1" for grayscale images.
        $JT -copy none -optimize -scans $SCANSTHREE <$f >$TMPFILE 2>/dev/null
        TPSIZE="`wc -c < $TMPFILE`"
        if [ -s $TMPFILE -a "$TPSIZE" -lt "`wc -c < $f`" ]; then
            mv -f $TMPFILE $f
            echo "INFO: file $ISIZE shrunk to $TPSIZE (three-pass progressive) $f" 1>&2
        fi
    fi

    ### BELOW HERE NOT FOR MOBILE (~10k) UNLESS FORCED (OR >10% SAVINGS?)
    ### Attempt to avoid huge numbers of scans to save mobile battery life.
    if [ "`wc -c < $f`" -gt "$MOBSIZEMAX" ]; then

        # Default (ten-pass) progressive.
        # Lots of extra CPU time for mobiles, so not good.
        $JT -copy none -optimize -progressive <$f >$TMPFILE
        PSIZE="`wc -c < $TMPFILE`"
        if [ -s $TMPFILE -a "$PSIZE" -lt "`wc -c < $f`" ]; then
            mv -f $TMPFILE $f
            echo "INFO: file $ISIZE shrunk to $PSIZE (progressive) $f" 1>&2
        fi

        # "Six-pass progressive" scans file.
        # Six passes, all DC first separately, then all AC afterwards.
        # Some risk of green Martians, so try late.
        # Order is 0, 2, 1 for DC then 2, 1, 0 for AC, to try to reduce Martians.
        SCANSSIX=$0.sixpass.scans
        if [ ! -s $SCANSSIX ]; then
            echo "WARNING: $SCANSSIX scans file not available" 1>&2
            # Can continue, just won't be able to try this scan type.
        else
            # Suppress "Invalid scan script at entry 1" for grayscale images.
            $JT -copy none -optimize -scans $SCANSSIX <$f >$TMPFILE 2>/dev/null
            SPSIZE="`wc -c < $TMPFILE`"
            if [ -s $TMPFILE -a "$SPSIZE" -lt "`wc -c < $f`" ]; then
                mv -f $TMPFILE $f
                echo "INFO: file $ISIZE shrunk to $SPSIZE (six-pass progressive) $f" 1>&2
            fi
        fi

        # "Seven-pass progressive" scans file.
        # Seven passes, all DC first separately, then AC with extra luma split.
        # Some risk of green Martians, so try late.
        SCANSSEVEN=$0.sevenpass.scans
        if [ ! -s $SCANSSEVEN ]; then
            echo "WARNING: $SCANSSEVEN scans file not available" 1>&2
            # Can continue, just won't be able to try this scan type.
        else
            # Suppress "Invalid scan script at entry 1" for grayscale images.
            $JT -copy none -optimize -scans $SCANSSEVEN <$f >$TMPFILE 2>/dev/null
            SPSIZE="`wc -c < $TMPFILE`"
            if [ -s $TMPFILE -a "$SPSIZE" -lt "`wc -c < $f`" ]; then
                mv -f $TMPFILE $f
                echo "INFO: file $ISIZE shrunk to $SPSIZE (seven-pass progressive) $f" 1>&2
            fi
        fi

    fi

    rm -f $TMPFILE
    done

exit 0
