2026-06-27 · Aktualisiert am 2026-07-26

Bilder mit Pillow, WebP und mozjpeg in Python komprimieren

Komprimieren Sie JPEG-, PNG- und WebP-Bilder in Python mithilfe von Pillow, cwebp und mozjpeg. Nutzen Sie Qualitäts-Einstellungen, Zielgrößen-Schleifen und ein schnelles Batch-Skript.

Bilder mit Pillow, WebP und mozjpeg in Python komprimieren

Zuletzt aktualisiert: July 26, 2026

Sie haben einen Ordner mit kameraformatgroßen JPEGs, einen Build-Schritt, der sie an die Benutzer liefert, und ein Seitengewichtsbudget, das ständig überzogen wird. Die manuelle Komprimierung dieser Dateien in einem Bildbearbeiter skaliert nicht. Dieser Leitfaden zeigt genau das Python, das Sie benötigen, um JPEG-, PNG- und WebP-Dateien nach Plan, in einem CI-Job oder innerhalb eines Upload-Handlers zu verkleinern.

Kurzantwort: Wie komprimiert man Bilder in Python?

Öffnen Sie das Bild mit Pillow und speichern Sie es dann mit den richtigen Format-Flags. Für Fotos speichern Sie als JPEG mit quality=80, optimize=True und progressive=True. Für die kleinsten modernen Dateien speichern Sie als WebP mit quality=80, method=6. Für flache Grafiken und Screenshots behalten Sie PNG bei und übergeben optimize=True.

from PIL import Image

def compress_jpeg(src, dst, quality=80):
    img = Image.open(src)
    if img.mode in ("RGBA", "P"):
        img = img.convert("RGB")
    img.save(dst, "JPEG", quality=quality, optimize=True, progressive=True)

Diese vierzeilige Funktion reduziert die meisten Smartphone- und DSLR-JPEGs bereits um 40 bis 70 Prozent. Der Rest dieses Leitfadens fügt Zielgrößen, WebP, mozjpeg und einen Batch-Runner hinzu, sodass Sie ihn auf ein Verzeichnis richten und nichts mehr tun müssen.

Was benötigen Sie vor dem Start?

Sie benötigen Python 3.9 oder neuer sowie Pillow, das gewartete Fork von PIL. Pillow unterstützt JPEG, PNG und WebP direkt auf jeder gängigen Plattform.

pip install Pillow

Für die kleinstmögliche Ausgabe möchten Sie auch zwei Kommandozeilen-Encoder, die Python aufrufen kann: cwebp aus libwebp und cjpeg aus mozjpeg.

brew install webp mozjpeg   # macOS; Linux: apt install webp, build mozjpeg

Überprüfen Sie vor dem Schreiben von Code, wofür jedes Stück verwendet wird:

  • Pillow liest und schreibt jedes Format und führt das Skalieren durch.
  • cwebp erzeugt die kleinsten WebP-Dateien und bietet mehr Tuning als Pillow.
  • mozjpeg re-encodiert JPEGs, die kleiner sind als der Standard-libjpeg von Pillow.
  • Ein Berichtshilfe damit jeder Lauf ausgibt, wie viele Bytes Sie gespart haben.

Hier ist die Hilfsfunktion, die im gesamten Leitfaden verwendet wird:

import os

def report(src, dst):
    before, after = os.path.getsize(src), os.path.getsize(dst)
    saved = (1 - after / before) * 100
    print(f"{before/1024:.0f} KB -> {after/1024:.0f} KB ({saved:.0f}% smaller)")

Wenn Sie nur eine einmalige Komprimierung benötigen und nichts installieren möchten, erledigt der browserbasierte Bildkompressor denselben Job für eine Handvoll Dateien.

Wie komprimiert man ein JPEG mit Pillow?

Die drei Flags, die für JPEG wichtig sind, sind quality, optimize und progressive. quality steuert, wie viele Details der Encoder verwirft. optimize=True führt einen zweiten Durchlauf durch, um eine kleinere Huffman-Tabelle zu erstellen. progressive=True ordnet die Datei neu an, sodass sie bei niedriger Auflösung zuerst von oben nach unten gezeichnet wird, was auf langsamen Verbindungen schneller erscheint und in der Regel die Datei noch etwas verkleinert.

Laptop on a wooden desk showing source code open in an editor

Wählen Sie einen Qualitätswert basierend darauf, wo das Bild verwendet wird, nicht eine einzige globale Zahl:

Qualitäts-Wert Typische Verwendung Was zu erwarten ist
90-95 Hero-Bilder, Druck-Proofs Nah am Original, deutlich größere Dateien
75-85 Die meisten Web-Fotos Der sichere Standard, große Ersparnis
60-70 Thumbnails und Vorschauen Sichtbares Weichzeichnen feiner Details
Unter 50 Für Fotos vermeiden Blockige Artefakte an Kanten

Ein häufiger Fehler fällt fast jedem auf: JPEG hat keinen Alpha-Kanal. Wenn Sie einen PNG-Screenshot mit Transparenz öffnen und ihn direkt als JPEG speichern, gibt Pillow die Fehlermeldung cannot write mode RGBA as JPEG aus. Der Aufruf convert("RGB") in der früheren Funktion flacht die Transparenz zuerst auf einen soliden Hintergrund, weshalb er vor jedem JPEG-Speichern ausgeführt wird.

PNG komprimieren und nach WebP konvertieren

PNG ist verlustfrei (lossless), daher können Sie Qualität nicht gegen Größe eintauschen, wie es bei JPEG der Fall ist. Was Sie tun können, ist, Pillows Optimizer auszuführen und für alles, was wirklich ein Foto ist, das Format komplett zu wechseln.

def compress_png(src, dst):
    Image.open(src).save(dst, "PNG", optimize=True, compress_level=9)

def to_webp(src, dst, quality=80):
    img = Image.open(src)
    img.save(dst, "WEBP", quality=quality, method=6)

method=6 weist den WebP-Encoder an, mehr Zeit mit der Suche nach einer kleineren Datei zu verbringen. Es ist pro Bild langsamer, aber in einem Build-Schritt wertvoll. Für ein Foto, das als 2 MB PNG begann, landet WebP bei Qualität 80 routinemäßig unter 200 KB und sieht dabei bei normaler Betrachtungsgröße identisch aus. Googles eigene Messungen zeigen, dass WebP im Vergleich zu vergleichbarem JPEG etwa 25 bis 35 Prozent kleiner ist, wie in der WebP documentation beschrieben.

Verwenden Sie diese Tabelle, um ein Format zu wählen, anstatt zu raten:

Quell-Inhalt Bestes Format Warum
Fotografie WebP oder JPEG Glatte Verläufe komprimieren verlustbehaftet gut
Logo, Icon, flache UI PNG oder verlustfreies WebP Scharfe Kanten bleiben knackig
Screenshot mit Text PNG oder verlustfreies WebP Vermeidet verschwommenen Text durch verlustbehaftete Durchläufe
Bild mit Transparenzbedarf WebP oder PNG JPEG kann keinen Alpha-Kanal speichern

Wenn Sie immer noch zwischen Formaten für eine ganze Website entscheiden, behandelt der Überblick in WebP vs JPEG vs PNG die Browserunterstützung und die Kompromisse detaillierter.

Ein Ziel-Dateigröße in einer Schleife erreichen

„Macht es unter 200 KB“ ist eine häufige Anforderung von E-Mail-Tools, Marktplätzen und CMS-Uploadlimits. Sie können keine Qualitätszahl wählen, die bei einem Byte-Ziel trifft, da dieselbe Qualität für ein belebtes Foto im Vergleich zu einem flachen Bild völlig unterschiedliche Größen erzeugt. Schleifen Sie von hoher Qualität abwärts, bis Sie unter dem Limit landen:

def compress_to_target(src, dst, target_kb=200, q=90, floor=35):
    img = Image.open(src).convert("RGB")
    while q >= floor:
        img.save(dst, "JPEG", quality=q, optimize=True, progressive=True)
        if os.path.getsize(dst) <= target_kb * 1024:
            return q
        q -= 5
    return q

Das Argument floor stoppt die Schleife, bevor die Qualität in den Verschmierungsbereich fällt. Wenn ein Bild das Ziel über dem Floor nicht erreichen kann, gibt die Funktion trotzdem einen Wert zurück, damit Sie es protokollieren und stattdessen das Bild skalieren können, anstatt weiter zu komprimieren. Für feste Byte-Budgets wie 100 KB oder 50 KB funktioniert dieselbe Schleife; der Leitfaden in compress images without losing quality erklärt, wann Skalierung besser ist als das Senken der Qualität.

Wie verkleinert man JPEGs mit mozjpeg und cwebp?

Pillow speichert JPEGs mit dem Standard-libjpeg-Encoder. mozjpeg ist ein Drop-in-Encoder von Mozilla, der bei gleicher visueller Qualität kleinere Dateien erzeugt, normalerweise 5 bis 15 Prozent kleiner. Da Pillow es nicht bündelt, rufen Sie das cjpeg-Binary über subprocess auf. Mozjeggs cjpeg liest PPM zuverlässig, daher flachen Sie das Bild zuerst mit Pillow ab:

import subprocess

def mozjpeg(src, dst, quality=80):
    Image.open(src).convert("RGB").save("_tmp.ppm")
    subprocess.run(["cjpeg", "-quality", str(quality), "-progressive",
                    "-optimize", "-outfile", dst, "_tmp.ppm"], check=True)
    os.remove("_tmp.ppm")

Für WebP gibt es den direkten Aufruf von cwebp, der Ihnen Regler bietet, die Pillow nicht freigibt, wie -m 6 für maximale Anstrengung und -sharp_yuv für sauberere Farbränder:

def cwebp(src, dst, quality=82):
    subprocess.run(["cwebp", "-q", str(quality), "-m", "6",
                    "-sharp_yuv", src, "-o", dst], check=True)

So sieht der Vergleich der Optionen aus, damit Sie entscheiden können, was Sie installieren möchten:

Tool Best for Trade-off
Pillow Allgemeines Skripting, jedes Format Nicht das kleinste JPEG
mozjpeg Kleinstes progressives JPEG Zusätzliches Binary, PPM-Roundtrip
cwebp (libwebp) Feinste WebP-Kontrolle Separates Binary zur Installation
pillow-simd Schnelleres Skalieren auf x86-Servern Schwerer zu bauen und zu pinnen

Das mozjpeg-Projekt dokumentiert seinen Encoder und Benchmarks im mozjpeg repository, und die vollständige Liste der Pillow-Speicheroptionen befindet sich in der Pillow image file formats reference.

Wie komprimiert man einen Ordner schnell?

Ein einzelnes Bild ist einfach. Die eigentliche Aufgabe ist ein Verzeichnis mit Hunderten von Bildern. Skalieren Sie alles, was breiter ist als Ihre Layout-Anforderungen, dann komprimieren und führen Sie die Arbeit über Threads aus, damit ein 500-Bild-Ordner in Sekunden statt Minuten fertig wird.

Developer at a multi-monitor workstation running code while wearing headphones

from pathlib import Path
from concurrent.futures import ThreadPoolExecutor

def batch(in_dir, out_dir, quality=80, max_width=1920):
    out = Path(out_dir); out.mkdir(parents=True, exist_ok=True)
    files = [p for p in Path(in_dir).iterdir()
             if p.suffix.lower() in {".jpg", ".jpeg", ".png"}]
    def work(p):
        img = Image.open(p)
        if img.width > max_width:
            h = round(img.height * max_width / img.width)
            img = img.resize((max_width, h), Image.LANCZOS)
        img.convert("RGB").save(out / f"{p.stem}.jpg", "JPEG",
                                quality=quality, optimize=True, progressive=True)
    with ThreadPoolExecutor() as pool:
        list(pool.map(work, files))
    return len(files)

Einige praktische Anmerkungen aus dem Betrieb in der Produktion:

  1. Skalieren Sie vor der Komprimierung. Das Bereitstellen eines 6000 px Fotos für eine 1200 px Spalte verschwendet Bytes, die keine Qualitäts Einstellung wiederherstellen kann.
  2. Pillow gibt das GIL während des Encodes frei, daher sorgen Threads hier für einen echten Geschwindigkeitszuwachs; Sie benötigen für die meisten Ordner kein Multiprocessing.
  3. Schreiben Sie in ein separates Ausgabeverzeichnis, damit ein fehlerhafter Lauf niemals Ihre Originaldateien überschreibt.
  4. Verwenden Sie Image.LANCZOS zum Downscaling; es hält Kanten besser scharf als der Standardfilter.
  5. Protokollieren Sie jede Datei mit der report-Hilfe und behalten Sie die Originale, bis Sie eine Stichprobe visuell geprüft haben.

Wenn Ihre Aufgabe wiederkehrend statt einmalig ist, behandeln die Muster in batch image processing Warteschlangen, Wiederholungen und Namenskonventionen. Für einen No-Code-Lauf über ein Zip von Dateien übernehmen die Stapelverarbeitung und der Formatkonverter die Formatänderungen ohne Skript.

Welchen Ansatz sollten Sie wählen?

Passen Sie die Methode an die Aufgabe an, anstatt immer das schwerste Werkzeug zu greifen:

  • Webfotos in einem Build-Schritt: Pillow WebP bei Qualität 80 oder cwebp mit -m 6, wenn Sie die letzten paar Prozent wollen.
  • Ein striktes Byte-Budget: die compress_to_target-Schleife, die auf Skalierung zurückfällt, wenn der Floor erreicht wird.
  • Legacy JPEG Pipelines, die Sie nicht ändern können: Re-encodieren Sie die Ausgabe mit mozjpeg für kostenlose Einsparungen.
  • Screenshots und Diagramme: Behalten Sie PNG bei optimize=True oder WebP verlustfrei, falls Ihre Browser dies unterstützen.

Für die Theorie dahinter, warum diese Einstellungen funktionieren, erklärt der image compression guide verlustbehaftet versus verlustfrei und wie Quantisierungstabellen das Ergebnis beeinflussen.

Häufige Fehler und Behebungen

Eine Handvoll Ausnahmen sind für die meisten fehlgeschlagenen Läufe verantwortlich:

  • cannot write mode RGBA as JPEG — rufen Sie vor dem Speichern als JPEG img.convert("RGB") auf.
  • Image.DecompressionBombError — Pillow schützt vor riesigen Bildern; erhöhen Sie das Limit nur für Dateien, denen Sie vertrauen, mit Image.MAX_IMAGE_PIXELS = 200_000_000.
  • OSError: broken data stream — die Quelldatei ist abgeschnitten; setzen Sie ImageFile.LOAD_TRUNCATED_IMAGES = True, um sie zu retten, und laden Sie dann bei Möglichkeit neu herunter.
  • Ausgabe größer als Eingabe — Sie haben ein bereits komprimiertes JPEG erneut gespeichert; komprimieren Sie vom Original, nicht von einem vorherigen Export.
  • Farben sehen ausgewaschen aus — eine CMYK-Quelle wurde ohne Konvertierung gespeichert; rufen Sie zuerst convert("RGB") auf.
from PIL import Image, ImageFile
Image.MAX_IMAGE_PIXELS = 200_000_000
ImageFile.LOAD_TRUNCATED_IMAGES = True

Wichtigste Erkenntnis

Pillow übernimmt 90 Prozent der Bildkomprimierung in Python mit drei JPEG-Flags und einem WebP-Speichern. Greifen Sie zu mozjpeg und cwebp, wenn Sie die kleinstmöglichen Dateien benötigen, verpacken Sie alles in die Zielgrößen-Schleife, wenn ein Byte-Budget fest ist, und führen Sie einen Ordner durch die Thread-Batch-Funktion, wenn das Volumen wächst. Behalten Sie Ihre Originale, skalieren Sie vor der Komprimierung und drucken Sie die Einsparungen bei jedem Lauf aus, damit Sie immer wissen, was die Pipeline tatsächlich tut.

Nutze die kostenlosen Werkzeuge, während du der Anleitung folgst.