Skip to content

Instantly share code, notes, and snippets.

@johan
Created March 9, 2012 20:30

Revisions

  1. johan created this gist Mar 9, 2012.
    61 changes: 61 additions & 0 deletions jpopt.sh
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,61 @@
    #! /bin/sh

    # Lossless repacking of JPEG images, to save disk space
    # Keeps EXIF tags and comments on digital camera images, otherwise wipes them
    # Requires the "jhead" program to function properly
    # Keeps file timestamps, or sets file time to EXIF timestamp if present
    # Fredrik Mellström <traal@chalmers.se>, Aug 2005

    # Usage examples:
    # jpopt *.jpg
    # find . -type f -iname '*.jpg' -print0 | xargs -0 jpopt

    siz() { ls -l "$1" | awk '{print $5}'; }

    if type jhead >/dev/null 2>&1; then
    jhead=1 copy=none
    else
    jhead= copy=all
    echo >&2 WARNING: jhead not found, cannot optimize comments or EXIF data
    fi

    trap exit 1 2 3 13 15
    oldsum=0 newsum=0

    for f do
    [ -f "$f" ] || { echo >&2 "no file '$f'"; continue; }
    mydir=`dirname "$f"`
    [ "$mydir" -a -d "$mydir" ] || { echo >&2 "no dir '$mydir'"; continue; }
    a=$mydir/_${$}_a.jpg b=$mydir/_${$}_b.jpg
    trap 'rm -f "$a" "$b"' 0
    rm -f "$a" "$b"

    printf "'%s' ... " "$f"
    jpegtran -copy "$copy" -opt "$f" >"$a" 2>/dev/null && touch -r "$f" "$a"
    jpegtran -copy "$copy" -prog "$f" >"$b" 2>/dev/null && touch -r "$f" "$b"
    [ -f "$a" -a -s "$a" -a -f "$b" -a -s "$b" ] ||
    { rm -f "$a" "$b"; trap 0; echo FAILED; continue; }
    [ "$jhead" ] && jhead "$f" 2>/dev/null | grep '^Camera ' >/dev/null && {
    [ -f "$a" ] && jhead -te "$f" -dt -ft "$a" >/dev/null 2>&1 &&
    [ -f "$b" ] && jhead -te "$f" -dt -ft "$b" >/dev/null 2>&1 &&
    printf 'exif ' ||
    { rm -f "$a" "$b"; trap 0; echo EXIF_FAILED; continue; }
    }

    oldsize=`siz "$f"` optsize=`siz "$a"` progsize=`siz "$b"`
    if [ $progsize -lt $oldsize -a $progsize -lt $optsize ]; then
    mv -f "$b" "$f"
    printf prog
    elif [ $optsize -lt $oldsize ]; then
    mv -f "$a" "$f"
    printf opt
    fi
    rm -f "$a" "$b"; trap 0; echo
    oldsum=`expr $oldsum + $oldsize`
    oldsize=`siz "$f"`
    newsum=`expr $newsum + $oldsize`
    done

    [ $oldsum -gt 0 -a $newsum -gt 0 ] &&
    echo $oldsum bytes total, saved `expr $oldsum - $newsum` bytes \
    \(`expr 100 \* \( $oldsum - $newsum \) / $oldsum`%\)