#!/usr/bin/env nix #! nix shell nixpkgs#optipng nixpkgs#jpegoptim nixpkgs#nodePackages.svgo nixpkgs#dash --command dash # shellcheck shell=dash # source: https://github.com/stride-tasks/stride/blob/148d513297c8ae66d79fc287769adfe5e711c93c/scripts/optimize-images PROJECT_DIR="$(git rev-parse --show-toplevel)" cd "$PROJECT_DIR" || { echo "No '$PROJECT_DIR' ?!" exit 1 } PNG_OPITMIZE_COMMAND='optipng --quiet -o7 -preserve' JPG_OPITMIZE_COMMAND='jpegoptim --quiet --strip-all -m76' SVG_OPITMIZE_COMMAND='svgo --multipass --quiet --input' # The extension is the part after the first dot in the filename: # # For example: # file.png => png # file.tar.gz => tar.gz find_files_by_extension() { wanted_extension="$1" tmp="$(mktemp)" git ls-files --cached --modified --other --exclude-standard --deduplicate | while IFS= read -r file; do file_basename="$(basename "$file")" extension="${file_basename#*.}" if [ "$extension" = "$wanted_extension" ]; then echo "$file" else : # echo "'$file' with extension: '$extension' does not match filter: '$wanted_extension'" 1>&2 fi done >"$tmp" echo "$tmp" } size_of() { du -b "$1" | cut -f1 } bytes_human() { number="$1" numfmt --to=iec-i --suffix=B --format="%9.2f" "$number" } # https://stackoverflow.com/questions/44695878/how-to-calculate-percentage-in-shell-script # Native POSIX solution using string manipulation (assumes integer inputs). percent() { DP="$1" SDC="$2" # Special case when DP is zero. [ "$DP" = "0" ] && echo "0.00" && return # # e.g. round down e.g. round up # # DP=1 SDC=3 DP=2 SDC=3 Percent=$((DP * 100000 / SDC + 5)) # Percent=33338 Percent=66671 Whole=${Percent%???} # Whole=33 Whole=66 Percent=${Percent#"$Whole"} # Percent=338 Percent=671 Percent=$Whole.${Percent%?} # Percent=33.33 Percent=66.67 echo "$Percent" } TOTAL=0 TOTAL_SAVED=0 optimize_files() { FILTER="$1" PROGRAM="$2" printf "%s" "Processing $FILTER files:" FILES="$(find_files_by_extension "$FILTER")" COUNT=$(wc -l <"$FILES") if [ "$COUNT" -eq 0 ]; then echo " no files found!" return fi echo "" I=1 TOTAL_INNER=0 TOTAL_SAVED_INNER=0 while IFS= read -r f; do printf "%s/${COUNT} $f ... " "$I" SIZE="$(size_of "$f")" $PROGRAM "$f" NEW_SIZE="$(size_of "$f")" DIFF=$((SIZE - NEW_SIZE)) echo "saved: $(bytes_human "$DIFF") ($(percent $DIFF "$SIZE")%)" TOTAL_INNER=$((TOTAL_INNER + SIZE)) TOTAL_SAVED_INNER=$((TOTAL_SAVED_INNER + DIFF)) I=$((I + 1)) done <"$FILES" rm "$FILES" echo "Total saved for $FILTER: $(bytes_human "$TOTAL_SAVED_INNER") ($(percent $TOTAL_SAVED_INNER $TOTAL_INNER)%)" echo "" TOTAL=$((TOTAL + TOTAL_INNER)) TOTAL_SAVED=$((TOTAL_SAVED + TOTAL_SAVED_INNER)) } optimize_files 'png' "$PNG_OPITMIZE_COMMAND" optimize_files 'jpg' "$JPG_OPITMIZE_COMMAND" optimize_files 'jpeg' "$JPG_OPITMIZE_COMMAND" optimize_files 'svg' "$SVG_OPITMIZE_COMMAND" echo "Total saved: $(bytes_human "$TOTAL_SAVED") ($(percent $TOTAL_SAVED $TOTAL)%)"