#!/usr/bin/env nix-shell #! nix-shell -i bash --pure #! nix-shell -p bash coreutils imagemagick libjpeg optipng ffmpeg diffutils # vim: filetype=sh set -euo pipefail # Optimizes everything the script can find in a folder, # meaning it will compress files as much as possible, # without losing any data (verification will be done # in order to verify that no data has been done) # (executable) # TODO Run in parallel # TODO Lots of dupplicated code there # TODO Maybe replace part with https://github.com/toy/image_optim? dir=${1:-$PWD} total=$(mktemp) echo -n 0 > "$total" function showtotal { echo "Total saved: $(cat "$total") bytes" rm "$total" exit } trap showtotal SIGTERM SIGINT SIGFPE function doReplace { # candidate original mv "$c" "$o" saved=$((os - cs)) perc=$((100 * saved / os)) echo "→ $os ⇒ $cs (saved $saved bytes, or ${perc}%)" newtotal=$(($(cat "$total") + saved)) echo -n $newtotal > "$total" } function replace { # candidate original c="$1" o="$2" # File verifications if [ ! -f "$o" ]; then echo "→ Original is inexistant, skipping!" return fi if [ ! -f "$c" ]; then echo "→ Candidate is inexistant, skipping!" return fi # Size verifications cs=$(wc -c "$c" | cut -d' ' -f1) os=$(wc -c "$o" | cut -d' ' -f1) if [ "$cs" -le 0 ]; then echo "→ Candidate is empty, skipping!" rm "$c" return fi if [ "$cs" -eq "$os" ]; then echo "→ Candidate weight the same, skipping." rm "$c" return fi if [ "$cs" -gt "$os" ]; then echo "→ Candidate is larger, skipping." rm "$c" return fi doReplace "$c" "$o" } # function replaceImg { # candidate original # # With bitmap verification # # c="$1" # o="$2" # # # File verifications # if [ ! -f "$o" ]; then # echo "→ Original is inexistant, skipping!" # return # fi # if [ ! -f "$c" ]; then # echo "→ Candidate is inexistant, skipping!" # return # fi # # # Size verifications # cs=$(wc -c "$c" | cut -d' ' -f1) # os=$(wc -c "$o" | cut -d' ' -f1) # if [ $cs -le 0 ]; then # echo "→ Candidate is empty, skipping!" # rm "$c" # return # fi # if [ $cs -eq $os ]; then # echo "→ Candidate weight the same, skipping." # rm "$c" # return # fi # if [ $cs -gt $os ]; then # echo "→ Candidate is larger, skipping." # rm "$c" # return # fi # # # Bitmap verification # ppmc="$(mktemp --suffix .ppm)" # ppmo="$(mktemp --suffix .ppm)" # convert "$c" "$ppmc" # convert "$o" "$ppmo" # # if cmp --silent "$ppmo" "$ppmc"; then # doReplace "$c" "$o" # else # echo "→ Candidate don't have the same bit map as original, skipping!" # fi # rm -f "$ppmc" "$ppmo" "$c" # # } # JPEG (requires jpegtran) while read -r image do if [ -z "$image" ]; then continue; fi echo Processing "$image" prog=$(mktemp --suffix .jpg) jpegtran -copy all -progressive "$image" > "$prog" echo "→ Progressive done" replace "$prog" "$image" done <<< "$(find "$dir/" -type f -iregex ".+.jpe?g$")" # PNG (requires optipng) while read -r image do if [ -z "$image" ]; then continue; fi echo Processing "$image" temp=$(mktemp --suffix .png) cp "$image" "$temp" optipng -quiet "$temp" echo "→ Optimize done" replace "$temp" "$image" done <<< "$(find "$dir/" -type f -iname "*.png")" # FLAC (requires ffmpeg) while read -r music do if [ -z "$music" ]; then continue; fi echo "Processing $music" temp=$(mktemp --suffix .flac) ffmpeg -nostdin -y -i "$music" -compression_level 8 "$temp" echo "→ Optimize done" replace "$temp" "$music" done <<< "$(find "$dir/" -type f -iname "*.flac")" # # SVG (requires scour) # while read image # do # if [ -z "$image" ]; then continue; fi # echo Processing $image # # temp=$(mktemp --suffix .svg) # scour --quiet "$image" "$temp" --no-line-breaks # echo "→ Optimize done" # # replaceImg "$temp" "$image" # # done <<< "$(find "$dir/" -type f -iname "*.svg")" # NOTE Explicitely disabled since: # - I only have ~50 MiB of SVG in TOTAL # - Most conversions are not image losseless # - Even when they are losseless, they are mostly worthless # - I might want to keep editor data and/or ids for some of them # So rather use scour explicitely when needed cleandev showtotal