Zum Inhalt springen
100 % lokal · 0 KB hochgeladenPDF komprimieren

Wie PDFs Text und Bilder speichern (unter der Haube)

Ein PDF ist eine Textdatei mit binären Blobs darin. Der Aufbau ist überraschend lesbar: ein Header, eine Liste nummerierter Objekte, eine Cross-Reference-Tabelle und ein Trailer. Diese Seite führt durch diesen Aufbau und zeigt, wo Text, Schriften und Bilder tatsächlich leben. Geschrieben für Entwickler und jeden, der verstehen will, was ein PDF-Werkzeug tut, wenn es eine Datei liest oder schreibt.

Überblick

Die vier Teile eines PDFs

Jede PDF-Datei hat denselben vierteiligen Aufbau:

  1. Header — eine Zeile, z. B. %PDF-1.7, die die Version deklariert.
  2. Body — eine Folge nummerierter indirekter Objekte. Hier lebt alles: Seiten, Schriften, Bilder, Metadaten.
  3. Cross-Reference-Tabelle (xref) — Byte-Offsets jedes Objekts, sodass ein Reader sie findet, ohne die ganze Datei zu durchsuchen.
  4. Trailer — verweist auf das Wurzelobjekt (den Dokumentkatalog), die xref-Position und optionale Verschlüsselungsinformationen. Der Reader liest den Trailer zuerst und springt dann zur Wurzel.

Das Trailer-zuerst-Design ist der Grund, warum ein PDF in konstanter Zeit gelesen werden kann, ohne die ganze Datei zu laden — wichtig für riesige Dokumente und Streaming-Reader.

Body

Indirekte Objekte

Jedes Objekt im Body ist nummeriert und sieht so aus:

3 0 obj
<< /Type /Page /MediaBox [0 0 612 792] /Contents 4 0 R /Resources << /Font << /F1 5 0 R >> >> >>
endobj

Das 3 0 obj besagt „dies ist Objekt 3, Generation 0". Der Body innerhalb von << ... >> ist ein Dictionary — eine Liste von Schlüssel/Wert-Paaren. Werte können Zahlen, Strings, Namen (mit /-Präfix), Arrays, andere Dictionaries oder Referenzen wie 4 0 R („sieh Dir Objekt 4 an") sein. So verweist eine Seite auf ihren Inhaltsstrom und ihre Schriften, ohne sie einzubetten.

Die Generationsnummer ist normalerweise 0. Sie wird inkrementiert, wenn ein inkrementelles Update ein Objekt löscht und neu schreibt — ein Feature, das PDFs das Bearbeiten erlaubt, indem Änderungen an das Dateiende angehängt werden, ohne alles neu zu schreiben. Die meisten modernen Writer schreiben die ganze Datei neu, sodass die Generation bei 0 bleibt.

Inhalt

Wie Text gespeichert wird

Seiteninhalt lebt in einem Inhaltsstrom — einem Objekt, dessen Wert ein Strom von Bytes (oft Flate-komprimiert) ist, der PDF-Zeichenoperatoren enthält. Text wird mit Operatoren wie BT (Begin Text), Tf (Schrift und Größe setzen), Td (Position verschieben), Tj (Text anzeigen) und ET (End Text) gezeichnet. Ein einfaches „Hello" sieht grob so aus:

BT
/F1 24 Tf
100 700 Td
(Hello) Tj
ET

Der String (Hello) verwendet die Kodierung der Schrift. Für einfachen lateinischen Text ist das oft WinAnsiEncoding oder die eingebaute Kodierung der Schrift. Für Unicode-Text ist der String eine 16-Bit-kodierte Bytefolge und die Schrift hat eine /ToUnicode-Abbildung, die Readern das Wiederherstellen der tatsächlichen Codepunkte für Kopieren-Einfügen und Suche erlaubt. Wenn ein PDF beim Kopieren-Einfügen Zeichensalat hat, der angezeigte Text aber korrekt ist, fehlt die /ToUnicode-Abbildung oder ist falsch — ein häufiger Export-Bug.

Text wird nicht als HTML oder Absätze gespeichert. Es gibt kein semantisches „Absatz"-Objekt. Zeilen, Zeilenumbrüche und Positionierung sind alles explizite Zeichenbefehle. Deshalb ist das Reflowen eines PDFs auf eine andere Seitenbreite schwer: der Reader müsste das Layout aus den Zeichenbefehlen zurückentwickeln.

Schriften

Schrift-Einbettung

Ein Schrift-Objekt in PDF hat zwei Teile: ein Schrift-Dictionary, das die Schrift benennt und auf ihre Daten verweist, und das Schrift-Programm selbst (Type 1, TrueType oder OpenType), das als Strom eingebettet ist. Die PDF-Spezifikation verlangt, dass Schriften eingebettet werden, damit das Dokument überall identisch rendert — aber sie erzwingt es nicht, weshalb manche PDFs auf Maschinen ohne die Schriften Ersatzschriften verwenden.

Subsetting bettet nur die im Dokument tatsächlich verwendeten Glyphen ein. Eine 250 KB große Schrift für eine einzelne Überschrift wird zu einem 8 KB-Subset. Die meisten modernen Exporter subsetten standardmäßig. Ältere Exporter oder bestimmte „Print to PDF"-Pfade betten manchmal die volle Schrift ein, was eine häufige Ursache für aufgeblähte Dateien ist. Die vollständige Aufschlüsselung finden Sie in unseremDateigrößen-Leitfaden.

Bilder

Wie Bilder gespeichert werden

Bilder werden als XObjects (externe Objekte) gespeichert — Ströme aus rohen oder komprimierten Pixeldaten mit einem Dictionary, das Breite, Höhe, Farbraum, Bits pro Komponente und Filter beschreibt. Der Seiten-Inhaltsstrom zeichnet das Bild dann mit dem Operator Do.

PDF unterstützt mehrere Bildfilter (Kompression):

  • DCTDecode — JPEG. Verlustbehaftet, gut für Fotos. Die häufigste Quelle der Größe in bildlastigen PDFs.
  • FlateDecode — zlib/deflate. Verlustfrei, gut für Linienkunst und Bilder mit wenigen Farben.
  • JPXDecode — JPEG2000. Bessere Kompression als JPEG bei hoher Qualität, aber langsamer und weniger universell unterstützt.
  • JBIG2Decode — für bitonale (1-Bit) gescannte Text. Kann gescannte Seiten dramatisch verkleinern.
  • CCITTFaxDecode — klassische Fax-Kompression für bitonale Bilder.

Ein bildlastiges PDF ist hauptsächlich eine Folge komprimierter Bildströme. Das Neukodieren dieser Ströme mit einer aggressiveren JPEG-Qualität ist der einzelne größte Hebel für die Größe bei gescannten Dokumenten.

Index

xref-Tabelle und Trailer

Die xref-Tabelle listet den Byte-Offset jedes indirekten Objekts. Ein Reader öffnet die Datei, liest den Trailer (der sich an einem bekannten Offset vom Dateiende befindet), findet die xref und nutzt sie, um direkt zu jedem Objekt zu springen, ohne die ganze Datei zu parsen. Das macht PDFs random-access-fähig.

PDF 1.5 fügte Cross-Reference-Ströme hinzu, die die xref-Tabelle selbst komprimieren. Kombiniert mit Objektströmen (viele kleine Objekte in einem komprimierten Strom) ist dies die strukturelle Kompression, die moderne PDFs kleiner macht als ihre 1.4-Äquivalente. Was dies in der Praxis bewirkt, sehen Sie in unseremKompression-Erklärer.

Der Trailer verweist außerdem auf /Root (den Dokumentkatalog, der den Seitenbaum auflistet), das /Info-Dictionary (Title, Author, CreationDate — die Metadaten) und optional das /Encrypt-Dictionary, wenn die Datei verschlüsselt ist.

Kompression

Ströme und Filter

Jedes Objekt, dessen Wert binäre Daten sind (ein Inhaltsstrom, ein Bild, eine eingebettete Schrift), ist ein Strom: ein Dictionary, gefolgt von stream, rohen Bytes und endstream. Der /Filter-Eintrag des Dictionaries teilt dem Reader mit, wie die Bytes zu dekodieren sind — FlateDecode für zlib, DCTDecode für JPEG und so weiter. Mehrere Filter können verkettet werden, z. B. ein Bild, das dekodiert und dann downsampeled wird.

Deshalb ist „ein PDF komprimieren" keine einzelne Operation. Jeder Strom ist unabhängig mit seinem eigenen Filter komprimiert. Ein Kompressionswerkzeug, das mit Objektströmen neu speichert, verkleinert den strukturellen Overhead; das Neukodieren von Bildern mit aggressiverer JPEG-Qualität verkleinert die Bildströme. Sie sind unabhängige Hebel.

In der Praxis

Warum dies für PDF-Werkzeuge wichtig ist

Wenn ein Werkzeug wie IXPDF ein PDF zusammenführt, aufteilt oder dreht, parst es die xref, durchwandert den Seitenbaum, kopiert oder ordnet die Seitenobjekte um und schreibt die xref und den Trailer neu. Die Inhaltsströme (Text und Bilder) werden byte-für-byte kopiert — kein Neukodieren, kein Qualitätsverlust. Deshalb sind strukturelle Operationen schnell und verlustfrei: sie mischen Objektreferenzen um, sie rendern die Seite nicht neu.

Kompression ist die Ausnahme: sie serialisiert die Struktur mit Objektströmen neu. Aber auch dann werden Bild- und Schriftströme unverändert kopiert, es sei denn, der Benutzer fordert explizit ein Neukodieren.

All dies geschieht in Ihrem Browser über einen Web Worker — die Datei wird lokal geparst, modifiziert und neu serialisiert. Ihr PDF verlässt nie Ihr Gerät.

Weiterlesen

Verwandte Ressourcen