JPEG-Optimierung mit jpegoptim in Projekten automatisieren
Führen Sie jpegoptim auf Kopien Ihrer Bilder in einem Build-Verzeichnis aus. So erhalten Sie optimierte JPEGs zur Veröffentlichung, während Ihre Originale und der Staging-Bereich von Git unverändert bleiben. Diese Anleitung erstellt unter Linux ein Verzeichnis mit verlustfrei optimierten JPEGs und bricht mit einem Fehler ab, wenn die Verarbeitung eines Bildes fehlschlägt.
jpegoptim unter Ubuntu installieren
Sie benötigen Bash, GNU coreutils und findutils sowie ein vorhandenes Verzeichnis mit JPEG-Dateien.
Das folgende Skript nutzt Optionen von GNU realpath; es ist ein Linux-Beispiel,
kein natives Skript für macOS oder Windows. Es wurde mit dem Paket jpegoptim 1.4.7 aus Ubuntu 24.04
und mit jpegoptim 1.5.6 unter Linux getestet.
Installieren Sie unter Ubuntu 24.04 das jpegoptim-Paket:
sudo apt-get update &&
sudo apt-get install -y jpegoptim &&
jpegoptim --version
Der Paketmanager installiert die Laufzeitbibliotheken. Sie benötigen libjpeg-dev
nicht, um das Programm aus dem Paket auszuführen.
Optimierung für ein Bild vorab prüfen
Ersetzen Sie photo.jpg durch eine Datei in Ihrem Verzeichnis mit Bilddateien:
jpegoptim --noaction --strip-none --nofix -- assets/images/photo.jpg
--noaction zeigt eine mögliche Ergebnisgröße an, ohne die Datei zu schreiben.
Ohne --max oder --size optimiert jpegoptim das
JPEG-Encoding verlustfrei. Das Handbuch unterscheidet dies vom
Verringern der Bildqualität. Die komprimierten Bytes können sich ändern, während die decodierten
Pixel gleich bleiben. Ein Ergebnis von skipped kann schlicht bedeuten, dass
das mögliche Ergebnis nicht kleiner war.
Ein separates Verzeichnis mit optimierten JPEGs erstellen
Speichern Sie dies als optimize-jpegs.sh im Stammverzeichnis Ihres Projekts. Das Skript
kopiert reguläre Dateien mit den Endungen .jpg und
.jpeg, auch bei großgeschriebenen Endungen und in verschachtelten
Verzeichnissen. Anschließend optimiert es die Kopien. Andere Dateien und symbolische Links werden
ausgeschlossen. Lassen Sie den Quellverzeichnisbaum unverändert, während das Skript läuft.
#!/usr/bin/env bash
set -euo pipefail
if (( $# != 2 )); then
printf 'Usage: bash optimize-jpegs.sh SOURCE NEW_OUTPUT\n' >&2
exit 1
fi
command -v jpegoptim >/dev/null || {
printf 'Install jpegoptim first.\n' >&2
exit 1
}
IFS= read -r -d '' source_dir < <(realpath -e -z -- "$1")
[[ -d "$source_dir" ]] || { printf 'Source must be a directory.\n' >&2; exit 1; }
IFS= read -r -d '' output_dir < <(realpath -m -z -- "$2")
if [[ "$source_dir" == / || "$output_dir/" == "$source_dir/"* ]]; then
printf 'Output must be outside the source tree.\n' >&2
exit 1
fi
if [[ -e "$2" || -L "$2" ]]; then
printf 'Output already exists; choose a new directory.\n' >&2
exit 1
fi
mkdir -- "$output_dir"
find "$source_dir" -type f \( -iname '*.jpg' -o -iname '*.jpeg' \) -print0 |
while IFS= read -r -d '' file; do
relative=${file#"$source_dir"/}
target="$output_dir/$relative"
mkdir -p -- "${target%/*}"
cp -- "$file" "$target"
jpegoptim --strip-none --nofix -- "$target"
done
printf 'JPEG build ready: %s\n' "$output_dir"
Führen Sie es vom Projektstammverzeichnis aus aus und geben Sie ein Ausgabeverzeichnis an, das noch nicht existiert. Dessen übergeordnetes Verzeichnis muss bereits vorhanden sein. Dieses Beispiel schreibt neben Ihr Projektverzeichnis:
bash optimize-jpegs.sh assets/images ../optimized-images
Zum Beispiel wird aus assets/images/products/front.JPG die Datei
../optimized-images/products/front.JPG. Das vorherige Kopieren erhält auch Dateien, die nicht mehr kleiner
werden können: Die Option --dest von jpegoptim allein kann solche Dateien
auslassen. Das Skript überschreibt nie ein vorhandenes Ausgabeverzeichnis. Ein zweiter Durchlauf
benötigt daher ein neues Ziel.
Die durch Nullzeichen getrennte Dateiliste und die Pfade in Anführungszeichen berücksichtigen
Leerzeichen, Zeilenumbrüche, führende Bindestriche und literale Zeichen vom Typ
% in Dateinamen. Sowohl die Suche als auch das Kopieren verwenden
denselben aufgelösten Quellpfad, auch wenn das Verzeichnisargument einen symbolischen Link enthält,
auf den .. folgt.
--nofix weist Bilder zurück, die beim Decodieren Warnungen erzeugen, statt
Reparaturen zu versuchen. Schlägt das Kopieren oder Optimieren fehl, stoppt die Schleife. Die
Bash-Option pipefail gibt auch einen Fehler von find
weiter. Ein Fehler nach dem Erstellen des Ausgabeverzeichnisses kann ein unvollständiges Verzeichnis
hinterlassen. Prüfen oder entfernen Sie diesen fehlgeschlagenen Build, bevor Sie es erneut versuchen.
Veröffentlichen Sie erst nach einem Exit-Status von null und der abschließenden Erfolgsmeldung.
Ein leeres Quellverzeichnis führt erfolgreich zu einem leeren Ausgabeverzeichnis.
Die vorgemerkten Änderungen für den Commit unverändert lassen
Vermeiden Sie einen Pre-Commit-Hook, der Arbeitsdateien optimiert und dann
git add assets/images ausführt.
Git fügt den aktuellen Zustand dieses gesamten Verzeichnisses hinzu,
einschließlich nicht zugehöriger Änderungen, neuer Dateien und Löschungen. Dabei kann auch eine
bewusst vorgemerkte Version eines Bildes durch die abweichende Version in Ihrem Arbeitsverzeichnis
ersetzt werden.
Nutzen Sie das Build-Skript als separate Aufgabe. Es führt keine Git-Befehle aus und überschreibt keine Quellbilder. Vorgemerkte, teilweise vorgemerkte, nicht vorgemerkte und nicht versionierte Änderungen bleiben daher unverändert. Lokal liest es das Arbeitsverzeichnis einschließlich nicht versionierter JPEGs; seine Ausgabe ist kein Abbild Ihres vorgemerkten Commits. Verwenden Sie in CI einen sauberen Checkout, wenn die Ausgabe einem Commit entsprechen muss.
Dasselbe Skript in CI ausführen
Checken Sie in einem Ubuntu-CI-Job das Projekt aus, führen Sie den obigen Installationsbefehl aus
und rufen Sie dann das Skript vom Projektstammverzeichnis aus auf. Verwenden Sie für einen
Shell-Schritt in GitHub Actions ein neues Verzeichnis unter
RUNNER_TEMP
als zweites Argument. Konfigurieren Sie den Artefakt-Upload oder das Deployment so, dass dieses
Verzeichnis erst nach erfolgreichem Abschluss des Skripts verwendet wird. Das Skript erzeugt
JPEG-Dateien, keine vollständige Website. Ihr Build muss weiterhin die übrigen Dateien
bereitstellen und auf die optimierten Bilddateien verweisen.
Regeln für Metadaten und Qualität bewusst wählen
Das Skript verwendet --strip-none, um Metadatenmarker zu erhalten, darunter
EXIF-Ausrichtung, ICC-Farbprofile und Kommentare. JFIF- und Adobe-Marker können von der
JPEG-Bibliothek dennoch neu erzeugt werden. Dies ist weder ein bytegetreues Archiv noch eine
Datenschutzbereinigung: Standort- und Kamerainformationen können erhalten bleiben.
Ersetzen Sie die Option nicht durch --strip-all, ohne zu berücksichtigen, wie Ihre
Bilder diese Metadaten nutzen. Das Entfernen von Ausrichtungs- oder Farbinformationen kann ihre
Darstellung beeinflussen, selbst wenn die decodierten Pixelwerte unverändert bleiben. Die
Metadatenoptionen beschreiben, welche Marker die einzelnen Optionen
erhalten oder entfernen.
Für kleinere Dateien auf Kosten der Bildqualität aktiviert --max=80, wo
anwendbar, eine verlustbehaftete Optimierung. Es ist eine Qualitätsobergrenze, kein Größenziel von
80 %. Auch --size aktiviert verlustbehaftete Optimierung und strebt eine Größe
an, ohne sie zu garantieren. Bewerten Sie solche Änderungen anhand neuer Kopien Ihrer Originale;
das Build-Skript bleibt bewusst verlustfrei.
Eigene Bilder messen
Vergleichen Sie für ein Bild aus Ihrem Build die Byteanzahl des Originals mit der Ausgabe:
wc -c -- assets/images/photo.jpg ../optimized-images/photo.jpg
Es gibt keinen festen Prozentsatz für die Einsparung. Ein bereits optimiertes Bild kann gleich groß bleiben, und kleinere Dateien allein belegen noch keine Verbesserung der Seitenladezeit. Prüfen Sie Ihre tatsächliche Build-Ausgabe und messen Sie die Seite, nachdem sie diese Dateien ausliefert. Bewahren Sie die Originale auf, damit Sie Qualitäts- oder Metadateneinstellungen später neu bewerten können, ohne von einem zuvor erneut komprimierten Bild ausgehen zu müssen.
