Bilder machen bis zu 50% der Gesamtgröße einer durchschnittlichen Webseite aus. Und wenn Bilder nicht optimiert sind, laden Benutzer zusätzliche Bytes herunter. Und wenn sie zusätzliche Bytes herunterladen, dauert die Ladezeit der Seite nicht nur länger, sondern Benutzer verbrauchen auch mehr Daten. Beides kann, zumindest teilweise, gelöst werden, indem die Bilder optimiert werden, bevor sie heruntergeladen werden.
Forscher auf der ganzen Welt entwickeln eifrig neue Bildformate, die trotz hoher visueller Qualität kleiner sind als andere Formate wie PNG oder JPG. Obwohl diese neuen Formate noch in der Entwicklung sind und im Allgemeinen nur begrenzte Browserunterstützung haben, gewinnt eines davon, WebP, viel Aufmerksamkeit. Und obwohl sie nicht wirklich in der gleichen Klasse wie Rasterbilder spielen, sind SVGs ein weiteres Format, das viele von uns in den letzten Jahren aufgrund ihres inhärent leichten Gewichts verwendet haben.
Es gibt unzählige Möglichkeiten, kleinere und optimierte Bilder zu erstellen. In diesem Tutorial schreiben wir Bash-Skripte, die Bilder in verschiedenen Bildformaten erstellen und optimieren, und zielen auf die gängigsten Formate ab, darunter JPG, PNG, WebP und SVG. Die Idee ist, die Bilder vor dem Ausliefern zu optimieren, damit die Benutzer das visuell großartigste Erlebnis ohne den gesamten Byte-Overhead erhalten.


Dieses GitHub-Repository enthält alle Bilder, die wir verwenden, und Sie können sie gerne herunterladen und mitmachen.
Einrichtung
Bevor wir beginnen, bringen wir alle unsere Abhängigkeiten in Ordnung. Wir schreiben wieder Bash-Skripte, also werden wir Zeit auf der Kommandozeile verbringen.
Hier sind die Befehle für alle Abhängigkeiten, die wir benötigen, um mit der Optimierung von Bildern zu beginnen
sudo apt-get update
sudo apt-get install imagemagick webp jpegoptim optipng
npm install -g svgexport svgo
Es ist ratsam zu wissen, womit wir arbeiten, bevor wir mit der Verwendung beginnen
- ImageMagick: Arbeitet mit allen Arten von Rasterbildern.
- webp optimiert WebP-Dateien.
- JPEGoptim optimiert JPG/JPEG-Dateien.
- OptiPNG optimiert PNG-Dateien.
- SVGO und svgexport sind Node-Pakete, die SVG-Assets optimieren.
OK, wir haben unsere Bilder im Verzeichnis original-images aus dem GitHub-Repository. Sie können dem Commit 3584f9b folgen.
Hinweis: Es wird dringend empfohlen, Ihre Bilder zu sichern, bevor Sie fortfahren. Wir werden Programme ausführen, die diese Bilder ändern, und obwohl wir die Originale unverändert lassen wollen, könnte ein falscher Befehl sie auf eine Weise ändern, die nicht rückgängig gemacht werden kann. Sichern Sie also alles, was Sie für ein echtes Projekt verwenden möchten, um sich späteres Fluchen zu ersparen.
Bilder organisieren
OK, wir sind technisch eingerichtet. Aber bevor wir uns dem Optimieren aller Dinge widmen, sollten wir unsere Dateien etwas organisieren. Lassen Sie uns sie nach ihrem MIME-Typ in verschiedene Unterverzeichnisse aufteilen. Tatsächlich können wir ein neues Bash-Skript erstellen, das dies für uns erledigt!
Der folgende Code erstellt ein Skript namens organize-images.sh
#!/bin/bash
input_dir="$1"
if [[ -z "$input_dir" ]]; then
echo "Please specify an input directory."
exit 1
fi
for img in $( find $input_dir -type f -iname "*" );
do
# get the type of the image
img_type=$(basename `file --mime-type -b $img`)
# create a directory for the image type
mkdir -p $img_type
# move the image into its type directory
rsync -a $img $img_type
done
Das mag verwirrend aussehen, wenn Sie neu im Skriptschreiben sind, aber was es tut, ist eigentlich ziemlich einfach. Wir geben dem Skript ein Eingabeverzeichnis, in dem es nach Bildern sucht. Das Skript durchsucht dann dieses Eingabeverzeichnis, sucht nach Bilddateien und identifiziert ihren MIME-Typ. Schließlich erstellt es Unterverzeichnisse im Eingabeordner für jeden MIME-Typ und legt eine Kopie jedes Bildes in das jeweilige Unterverzeichnis.
Lassen Sie es uns ausführen!
bash organize-images.sh original-images
Super. Das Verzeichnis sieht jetzt so aus. Jetzt, da unsere Bilder organisiert sind, können wir mit der Erstellung von Varianten jedes Bildes fortfahren. Wir werden uns jeweils einen Bildtyp vornehmen.
Konvertieren in PNG
Wir werden in diesem Tutorial drei Arten von Bildern in PNG konvertieren: WebP, JPEG und SVG. Beginnen wir mit dem Schreiben eines Skripts namens webp2png.sh, das ziemlich selbsterklärend ist: Konvertieren von WebP-Dateien in PNG-Dateien.
#!/bin/bash
# directory containing images
input_dir="$1"
if [[ -z "$input_dir" ]]; then
echo "Please specify an input directory."
exit 1
fi
# for each webp in the input directory
for img in $( find $input_dir -type f -iname "*.webp" );
do
dwebp $img -o ${img%.*}.png
done
Hier ist, was passiert
input_dir="$1": Speichert die Eingabe der Befehlszeile im Skript.if [[ -z "$input_dir" ]]; then: Führt die nachfolgende Bedingung aus, wenn das Eingabeverzeichnis nicht definiert ist.for img in $( find $input_dir -type f -iname "*.webp" );: Schleift durch jede Datei im Verzeichnis, die die Erweiterung.webphat.dwebp $img -o ${img%.*}.png: Konvertiert das WebP-Bild in eine PNG-Variante.
Und los geht's
bash webp2png.sh webp
Wir haben jetzt unsere PNG-Bilder im Verzeichnis webp. Als nächstes konvertieren wir JPG/JPEG-Dateien mit einem weiteren Skript namens jpg2png.sh in PNG.
#!/bin/bash
# directory containing images
input_dir="$1"
if [[ -z "$input_dir" ]]; then
echo "Please specify an input directory."
exit 1
fi
# for each jpg or jpeg in the input directory
for img in $( find $input_dir -type f -iname "*.jpg" -o -iname "*.jpeg" );
do
convert $img ${img%.*}.png
done
Dies verwendet den convert-Befehl, der vom installierten ImageMagick-Paket bereitgestellt wird. Wie das letzte Skript geben wir ein Eingabeverzeichnis an, das JPEG/JPG-Bilder enthält. Das Skript durchsucht dieses Verzeichnis und erstellt für jedes passende Bild eine PNG-Variante. Wenn Sie genau hinschauen, haben wir -o -iname "*.jpeg" in find hinzugefügt. Dies bezieht sich auf die logische ODER-Verknüpfung, die das Skript alle Bilder findet, die entweder die Erweiterung .jpg oder .jpeg haben.
So führen wir es aus
bash jpg2png.sh jpeg
Jetzt, da wir unsere PNG-Varianten aus JPG haben, können wir dasselbe auch für SVG-Dateien tun.
#!/bin/bash
# directory containing images
input_dir="$1"
# png image width
width="$2"
if [[ -z "$input_dir" ]]; then
echo "Please specify an input directory."
exit 1
elif [[ -z "$width" ]]; then
echo "Please specify image width."
exit 1
fi
# for each svg in the input directory
for img in $( find $input_dir -type f -iname "*.svg" );
do
svgexport $img ${img%.*}.png $width:
done
Dieses Skript hat eine neue Funktion. Da SVG ein skalierbares Format ist, können wir die width-Direktive angeben, um unsere SVGs zu vergrößern oder zu verkleinern. Wir verwenden das zuvor installierte Paket svgexport, um jede SVG-Datei in eine PNG-Datei zu konvertieren.
bash svg2png.sh svg+xml
Commit 76ff80a zeigt das Ergebnis im Repository.
Wir haben hier viel gute Arbeit geleistet, indem wir eine Reihe von PNG-Dateien basierend auf anderen Bildformaten erstellt haben. Wir müssen noch dasselbe für die restlichen Bildformate tun, bevor wir zur eigentlichen Aufgabe der Optimierung übergehen.
Konvertieren in JPG
In Anlehnung an die Erstellung von PNG-Bildern werden wir WebP, JPEG und SVG in JPG konvertieren. Beginnen wir mit dem Schreiben eines Skripts namens png2jpg.sh, das PNG in SVG konvertiert.
#!/bin/bash
# directory containing images
input_dir="$1"
# jpg image quality
quality="$2"
if [[ -z "$input_dir" ]]; then
echo "Please specify an input directory."
exit 1
elif [[ -z "$quality" ]]; then
echo "Please specify image quality."
exit 1
fi
# for each png in the input directory
for img in $( find $input_dir -type f -iname "*.png" );
do
convert $img -quality $quality% ${img%.*}.jpg
done
Sie bemerken vielleicht schon ein Muster in diesen Skripten. Aber dieses führt eine neue Funktion ein, bei der wir eine -quality-Direktive festlegen können, um PNG-Bilder in JPG-Bilder zu konvertieren. Der Rest ist derselbe.
Und so führen wir es aus
bash png2jpg.sh png 90
Wow. Wir haben jetzt JPG-Bilder in unserem png-Verzeichnis. Machen wir dasselbe mit einem webp2jpg.sh-Skript.
#!/bin/bash
# directory containing images
input_dir="$1"
# jpg image quality
quality="$2"
if [[ -z "$input_dir" ]]; then
echo "Please specify an input directory."
exit 1
elif [[ -z "$quality" ]]; then
echo "Please specify image quality."
exit 1
fi
# for each webp in the input directory
for img in $( find $input_dir -type f -iname "*.webp" );
do
# convert to png first
dwebp $img -o ${img%.*}.png
# then convert png to jpg
convert ${img%.*}.png -quality $quality% ${img%.*}.jpg
done
Auch hier ist es dasselbe wie bei der Konvertierung von WebP nach PNG. Es gibt jedoch einen Haken. Wir können das WebP-Format nicht direkt in das JPG-Format konvertieren. Daher müssen wir hier etwas kreativ werden und WebP mit dwebp in PNG konvertieren und *dann* PNG mit convert in JPG konvertieren. Deshalb haben wir in der for-Schleife zwei verschiedene Schritte.
Lassen Sie es uns jetzt ausführen
bash webp2jpg.sh jpeg 90
Voilà! Wir haben JPG-Varianten für unsere WebP-Bilder erstellt. Jetzt widmen wir uns SVG zu JPG.
#!/bin/bash
# directory containing images
input_dir="$1"
# jpg image width
width="$2"
# jpg image quality
quality="$3"
if [[ -z "$input_dir" ]]; then
echo "Please specify an input directory."
exit 1
elif [[ -z "$width" ]]; then
echo "Please specify image width."
exit 1
elif [[ -z "$quality" ]]; then
echo "Please specify image quality."
exit 1
fi
# for each svg in the input directory
for img in $( find $input_dir -type f -iname "*.svg" );
do
svgexport $img ${img%.*}.jpg $width: $quality%
done
Sie denken vielleicht, dass Sie dieses Skript schon einmal gesehen haben. Das haben Sie! Wir haben dasselbe Skript verwendet, um PNG-Bilder aus SVG zu erstellen. Die einzige Ergänzung zu diesem Skript ist, dass wir die quality-Direktive unserer JPG-Bilder angeben können.
bash svg2jpg.sh svg+xml 512 90
Alles, was wir gerade getan haben, ist im Commit 884c6cf im Repository enthalten.
Konvertieren in WebP
WebP ist ein Bildformat, das für moderne Browser entwickelt wurde. Zum Zeitpunkt der Abfassung dieses Textes hat es eine weltweite Browserunterstützung von etwa 90 %, einschließlich teilweiser Unterstützung in Safari. Der größte Vorteil von WebP ist seine deutlich kleinere Dateigröße im Vergleich zu anderen Bildformaten, ohne Kompromisse bei der visuellen Qualität einzugehen. Das macht es zu einem guten Format für Benutzer.
Aber genug geredet. Schreiben wir ein png2webp.sh, das – Sie haben es erraten – WebP-Bilder aus PNG-Dateien erstellt.
#!/bin/bash
# directory containing images
input_dir="$1"
# webp image quality
quality="$2"
if [[ -z "$input_dir" ]]; then
echo "Please specify an input directory."
exit 1
elif [[ -z "$quality" ]]; then
echo "Please specify image quality."
exit 1
fi
# for each png in the input directory
for img in $( find $input_dir -type f -iname "*.png" );
do
cwebp $img -q $quality -o ${img%.*}.webp
done
Dies ist einfach die Umkehrung des Skripts, das wir zum Erstellen von PNG-Bildern aus WebP-Dateien verwendet haben. Anstatt dwebp zu verwenden, verwenden wir cwebp.
bash png2webp.sh png 90
Wir haben unsere WebP-Bilder. Jetzt konvertieren wir JPG-Bilder. Das Schwierige ist, dass es keine Möglichkeit gibt, eine JPG-Datei direkt in WebP zu konvertieren. Daher werden wir in unserem jpg2webp.sh-Skript zuerst JPG in PNG konvertieren und dann das Zwischen-PNG in WebP konvertieren.
#!/bin/bash
# directory containing images
input_dir="$1"
# webp image quality
quality="$2"
if [[ -z "$input_dir" ]]; then
echo "Please specify an input directory."
exit 1
elif [[ -z "$quality" ]]; then
echo "Please specify image quality."
exit 1
fi
# for each webp in the input directory
for img in $( find $input_dir -type f -iname "*.jpg" -o -iname "*.jpeg" );
do
# convert to png first
convert $img ${img%.*}.png
# then convert png to webp
cwebp ${img%.*}.png -q $quality -o ${img%.*}.webp
done
Jetzt können wir es so verwenden, um unsere WebP-Varianten von JPG-Dateien zu erhalten.
bash jpg2webp.sh jpeg 90
Commit 6625f26 zeigt das Ergebnis.
Alles in einem Verzeichnis zusammenführen
Nachdem wir nun mit der Konvertierung fertig sind, sind wir einen Schritt näher an der Optimierung unserer Arbeit. Aber zuerst bringen wir alle unsere Bilder wieder in ein einziges Verzeichnis, damit es einfacher ist, sie mit weniger Befehlen zu optimieren.
Hier ist der Code, der ein neues Bash-Skript namens combine-images.sh erstellt.
#!/bin/bash
input_dirs="$1"
output_dir="$2"
if [[ -z "$input_dirs" ]]; then
echo "Please specify an input directories."
exit 1
elif [[ -z "$output_dir" ]]; then
echo "Please specify an output directory."
exit 1
fi
# create a directory to store the generated images
mkdir -p $output_dir
# split input directories comma separated string into an array
input_dirs=(${input_dirs//,/ })
# for each directory in input directory
for dir in "${input_dirs[@]}"
do
# copy images from this directory to generated images directory
rsync -a $dir/* $output_dir/
done
Das erste Argument ist eine durch Kommas getrennte Liste von Eingabeverzeichnissen, die Bilder in ein Zielverzeichnis übertragen. Das zweite Argument definiert dieses kombinierte Verzeichnis.
bash combine-images.sh jpeg,svg+xml,webp,png generated-images
Das Endergebnis ist im Repository zu sehen.
SVG optimieren
Lassen Sie uns damit beginnen, unsere SVG-Bilder zu optimieren. Fügen Sie den folgenden Code zu optimize-svg.sh hinzu.
#!/bin/bash
# directory containing images
input_dir="$1"
if [[ -z "$input_dir" ]]; then
echo "Please specify an input directory."
exit 1
fi
# for each svg in the input directory
for img in $( find $input_dir -type f -iname "*.svg" );
do
svgo $img -o ${img%.*}-optimized.svg
done
Wir verwenden hier das SVGO-Paket. Es hat viele Optionen, die wir verwenden können, aber um die Dinge einfach zu halten, bleiben wir beim Standardverhalten der Optimierung von SVG-Dateien.
bash optimize-svg.sh generated-images

Das Ergebnis ist im Commit 75045c3 im Repository zu sehen.
PNG optimieren
Machen wir weiter und optimieren unsere PNG-Dateien, indem wir diesen Code verwenden, um einen optimize-png.sh-Befehl zu erstellen.
#!/bin/bash
# directory containing images
input_dir="$1"
if [[ -z "$input_dir" ]]; then
echo "Please specify an input directory."
exit 1
fi
# for each png in the input directory
for img in $( find $input_dir -type f -iname "*.png" );
do
optipng $img -out ${img%.*}-optimized.png
done
Hier verwenden wir das OptiPNG-Paket zur Optimierung unserer PNG-Bilder. Das Skript sucht im Eingabeverzeichnis nach PNG-Bildern und erstellt für jedes eine optimierte Version, wobei -optimized an den Dateinamen angehängt wird. Es gibt ein interessantes Argument, -o, mit dem wir den Optimierungsgrad festlegen können. Der Standardwert ist 2, **und die Werte reichen von 0 bis 7. Um unsere PNGs zu optimieren, führen wir
bash optimize-png.sh generated-images

Wie wir sehen können, leistet OptiPNG hervorragende Arbeit bei der Optimierung der Bilder. Wir können mit dem -o-Argument experimentieren, um einen geeigneten Wert zu finden, indem wir zwischen Bildqualität und Größe abwägen. Sehen Sie sich die Ergebnisse in Commit 4a97f29 an.
JPG optimieren
Wir sind beim letzten Teil angekommen! Wir schließen das Ganze ab, indem wir JPG-Bilder optimieren. Fügen Sie den folgenden Code zu optimize-jpg.sh hinzu.
#!/bin/bash
# directory containing images
input_dir="$1"
# target image quality
quality="$2"
if [[ -z "$input_dir" ]]; then
echo "Please specify an input directory."
exit 1
elif [[ -z "$quality" ]]; then
echo "Please specify image quality."
exit 1
fi
# for each jpg or jpeg in the input directory
for img in $( find $input_dir -type f -iname "*.jpg" -o -iname "*.jpeg" );
do
cp $img ${img%.*}-optimized.jpg
jpegoptim -m $quality ${img%.*}-optimized.jpg
done
Dieses Skript verwendet JPEGoptim. Das Problem mit diesem Paket ist, dass es keine Option zur Angabe der Ausgabedatei hat. Wir können die Bilddatei nur vor Ort optimieren. Wir können dies umgehen, indem wir zuerst eine Kopie des Bildes erstellen, es beliebig benennen und dann die Kopie optimieren. Das Argument -m wird verwendet, um die Bildqualität anzugeben. Es ist gut, damit ein wenig zu experimentieren, um die richtige Balance zwischen Qualität und Dateigröße zu finden.
bash optimize-jpg.sh generated-images 95

Die Ergebnisse sind im Commit 35630da zu sehen.
Zusammenfassung
Sehen Sie das? Mit ein paar Skripten können wir umfangreiche Bildoptimierungen direkt über die Befehlszeile durchführen und sie in jedem Projekt verwenden, da sie global installiert sind. Wir können CI/CD-Pipelines einrichten, um verschiedene Varianten jedes Bildes zu erstellen und sie mithilfe von gültigem HTML, APIs oder sogar durch Einrichtung eigener Bildkonvertierungs-Websites auszuliefern.
Ich hoffe, Sie haben das Lesen und Lernen aus diesem Artikel genauso genossen wie ich das Schreiben für Sie. Viel Spaß beim Coden!
Gibt es eine Windows-Version dieses Beitrags irgendwo?
Die meisten verwendeten Werkzeuge (vielleicht alle, aber ich habe nicht jedes einzelne überprüft) haben Windows-Binärdateien oder können darauf laufen. Bash-Skripte müssen entweder neu geschrieben werden oder Sie können Bash von WSL oder Cygwin verwenden. Vielleicht kann jemand das Repository forken und .ps1-Dateien hinzufügen, die den .sh-Dateien entsprechen.
Wowww!
Ich benutze https://squoosh.app im Allgemeinen viel für Komprimierung und Konvertierung, aber das sieht großartig aus.
Nur ein paar Zeilen Befehl und ich bin fertig.
Das ist etwas, das ich gerne ausprobieren würde.
Danke für diesen großartigen Beitrag.
Avif hinzufügen
Wenn Sie Ruby installiert haben, gibt es https://github.com/toy/image_optim, das viel Arbeit für Sie erledigt.