diff options
| author | sillylaird <sillyfanboy@gmail.com> | 2026-09-03 00:33:59 +0000 |
|---|---|---|
| committer | sillylaird <sillyfanboy@gmail.com> | 2026-09-03 00:33:59 +0000 |
| commit | 898b52edcb47bcb3e9d6106e74ca73e74ea01e70 (patch) | |
| tree | 85c6ee5ad58b860144551184d4cf86b560c62b91 /tools/optimize_images.sh | |
| download | www-898b52edcb47bcb3e9d6106e74ca73e74ea01e70.tar.gz www-898b52edcb47bcb3e9d6106e74ca73e74ea01e70.zip | |
Diffstat (limited to '')
| -rwxr-xr-x | tools/optimize_images.sh | 93 |
1 files changed, 93 insertions, 0 deletions
diff --git a/tools/optimize_images.sh b/tools/optimize_images.sh new file mode 100755 index 0000000..6538448 --- /dev/null +++ b/tools/optimize_images.sh @@ -0,0 +1,93 @@ +#!/usr/bin/env bash +# Optimize site images in place. Lossy but visually conservative. +# +# - JPEG : strip metadata, progressive, quality 82 +# - PNG : strip metadata, max zlib recompression (lossless) +# - GIF : gifsicle -O3 (lossless frame optimization); --lossy on big ones +# - A short list of oversized tile PNGs is downscaled to a sane max width, +# since the layout never displays them larger than ~320px. +# +# Originals are tarred to "$BACKUP_DIR" before anything is touched. +# Re-running is safe: already-small files are left alone. +# +# Env: +# BACKUP_DIR where to write the pre-run tarball (default /tmp) +# DRY_RUN=1 print what would change, touch nothing +set -u +cd "$(dirname "$0")/.." +ROOT="$(pwd)" +BACKUP_DIR="${BACKUP_DIR:-/tmp}" +DRY="${DRY_RUN:-0}" + +have() { command -v "$1" >/dev/null 2>&1; } +have convert || { echo "need ImageMagick (convert)"; exit 1; } + +# Tile PNGs the layout caps at ~320px wide; 640 keeps a 2x retina buffer. +# Section heroes are capped wider (display size rarely exceeds ~960px). +declare -A MAXW=( + [assets/img/runescape.png]=640 + [assets/img/soldierfront.png]=640 + [assets/img/multibox.png]=640 + [assets/img/stepmania.png]=640 + [startpage/videogame.jpg]=720 + [computers/laptop-compaq.jpg]=960 + [gaming/runescape/runescape.png]=640 +) + +fmt() { numfmt --to=iec "$1" 2>/dev/null || echo "$1"; } +size() { stat -c%s "$1"; } + +if [ "$DRY" != "1" ]; then + ts="$(date +%Y%m%d-%H%M%S)" + tar -czf "$BACKUP_DIR/images-pre-optimize-$ts.tar.gz" \ + assets/img images startpage computers gaming vblog mstartpage 2>/dev/null \ + && echo "backup: $BACKUP_DIR/images-pre-optimize-$ts.tar.gz" +fi + +total_before=0; total_after=0 +process() { + local f="$1" before after; before="$(size "$f")"; total_before=$((total_before+before)) + local tmp="$f.opt.$$" + local fl + fl="$(printf '%s' "$f" | tr '[:upper:]' '[:lower:]')" + case "$fl" in + *.jpg|*.jpeg) + convert "$f" -strip -interlace Plane -quality 82 "$tmp" 2>/dev/null ;; + *.png) + local w="${MAXW[$f]:-}" + [ -z "$w" ] && w="${MAXW[$fl]:-}" + if [ -n "$w" ]; then + convert "$f" -strip -resize "${w}x${w}>" -define png:compression-level=9 -define png:compression-filter=5 "$tmp" 2>/dev/null + else + convert "$f" -strip -define png:compression-level=9 -define png:compression-filter=5 "$tmp" 2>/dev/null + fi ;; + *.gif) + if ! have gifsicle; then total_after=$((total_after+before)); return; fi + if [ "$before" -gt 400000 ]; then + gifsicle -O3 --lossy=60 "$f" -o "$tmp" 2>/dev/null + else + gifsicle -O3 "$f" -o "$tmp" 2>/dev/null + fi ;; + *) total_after=$((total_after+before)); return ;; + esac + if [ ! -s "$tmp" ]; then rm -f "$tmp"; total_after=$((total_after+before)); return; fi + after="$(size "$tmp")" + if [ "$after" -lt "$before" ]; then + if [ "$DRY" = "1" ]; then + printf ' %-40s %8s -> %8s\n' "$f" "$(fmt "$before")" "$(fmt "$after")"; rm -f "$tmp" + else + mv "$tmp" "$f" + fi + total_after=$((total_after+after)) + else + rm -f "$tmp"; total_after=$((total_after+before)) + fi +} + +while IFS= read -r -d '' f; do process "$f"; done < <( + find assets/img images startpage computers gaming vblog mstartpage \ + -type f \( -iname '*.jpg' -o -iname '*.jpeg' \ + -o -iname '*.png' -o -iname '*.gif' \) -print0 2>/dev/null +) + +echo "total: $(fmt "$total_before") -> $(fmt "$total_after")" |
