Die Ökonomie der PDF-Dateigröße
Spec: ISO 32000-2, §7.5.7ISO 32000-2 §7.5.7
Auf einen Blick
Abschnitt betitelt „Auf einen Blick“Zwei PDFs können auf dem Bildschirm Pixel für Pixel identisch aussehen und sich auf der Platte um das Zehnfache unterscheiden. Der Unterschied ist fast nie der Inhalt, den Sie sehen; es ist, wie die Datei darunter zusammengesetzt wurde. Diese Seite ist eine Tour durch die Größenökonomie: wohin die Bytes eines PDF tatsächlich gehen und die vier Hebel, auf die ein Autor ein Byte-Budget verwendet.
Es ist der Warum-Dateien-groß-sind-Begleiter zu Streams und Filter, das behandelt, wie ein Filter dekodiert. Diese hier bleibt beim Budget.
Warum das wichtig ist
Abschnitt betitelt „Warum das wichtig ist“Dateigröße ist selten eine Eitelkeitskennzahl. Sie ist Bandbreite bei jedem Download, Speicher bei jedem Archiv und Latenz bei jeder Vorschau. Eine 12 MB große Rechnung, die 400 KB hätte sein sollen, ist kein kosmetisches Problem, wenn Sie eine Million davon im Monat erzeugen – es ist eine dreißigfache Rechnung.
Das Frustrierende daran ist, dass die Aufblähung gewöhnlich unsichtbar ist. Das Dokument rendert korrekt, öffnet sich problemlos, druckt problemlos. Nichts sagt Ihnen, dass dasselbe Artefakt ein Bruchteil der Größe hätte sein können, weil die verschwendeten Bytes strukturell sind, nicht visuell. Um sie zu finden, müssen Sie auf das Budget schauen, nicht auf die Seite.
Die Kurzfassung
Abschnitt betitelt „Die Kurzfassung“Stellen Sie sich ein PDF als ein Budget vor, das Sie auf vier Posten verwenden.
- Overhead pro Objekt. Jedes indirekte Objekt trägt eine
N G obj- /endobj-Hülle und wird durch einen Querverweiseintrag verfolgt. Ein seitenlastiges Dokument hat Tausende winziger Objekte, und die Hüllen summieren sich. Objektstreams lassen diese Hülle für eine ganze Gruppe von Objekten weg; jedes gepackte Objekt behält weiterhin seinen eigenen Querverweiseintrag, aber als kompakten Typ-2-Eintrag. - Bild-Bytes. Für jedes Dokument mit Fotografien oder Scans dominieren die Bilder, und der mit Abstand größte Hebel ist die Wahl des Filters – ein verlustfreier Codec gegenüber einem verlustbehafteten Bildcodec ist der Unterschied zwischen Megabyte und Kilobyte.
- Font-Bytes. Eine vollständige eingebettete Schrift sind Hunderte Kilobyte Glyphen, die Sie nie verwenden. Subsetting behält nur die Glyphen, die das Dokument tatsächlich zeichnet.
- Der Index. Die Querverweistabelle, die einen Reader jedes Objekt finden lässt, kann selbst ein komprimierter Stream sein statt Klartext.
Bekommen Sie alle vier richtig hin, und die Datei ist klein. Verfehlen Sie einen, und er dominiert alles andere, was Sie gut gemacht haben.
Wie NextPDF dabei vorgeht
Abschnitt betitelt „Wie NextPDF dabei vorgeht“NextPDFs Writer ist ein einstufiger Streaming-Serialisierer: Er hängt die Bytes jedes Objekts an, sobald sie erzeugt werden, und erfasst für jedes einen klassischen In-Use-Querverweiseintrag. Diese Voreinstellung ist schnell, vorhersehbar und erzeugt eine byte-stabile Datei – aber sie ist nicht das kleinstmögliche Layout, und NextPDF ist darüber ehrlich.
Hebel 1 – Objektstreams (ObjStm)
Abschnitt betitelt „Hebel 1 – Objektstreams (ObjStm)“Ein PDF ist ein Graph indirekter Objekte. Die meisten von ihnen sind kleine
Dictionarys: Seitenknoten, Annotations-Dictionarys, Strukturbaum-Elemente,
Gliederungseinträge. Jedes zahlt eine feste Steuer – die obj- / endobj-Schlüsselwörter,
die Objekt- und Generationsnummern und einen Querverweiseintrag, der es lokalisiert.
Bei einem Dokument mit Tausenden kleiner Objekte ist diese Steuer ein bedeutsames Stück
der Datei.
Ein Objektstream sammelt viele dieser kleinen Nicht-Stream-Objekte in einen Stream und
komprimiert sie zusammen (Spec: ISO 32000-2, §7.5.7ISO 32000-2 §7.5.7). Die
obj- / endobj-Hülle wird für die ganze Gruppe weggelassen; die Werte darin werden
Rücken an Rücken ohne Schlüsselwörter pro Objekt gespeichert und dann als ein einzelner
Block deflatiert – was auch besser komprimiert, weil der deduplizierende Kompressor
nun all diese ähnlichen Dictionarys auf einmal sieht. Der Querverweiseintrag verschwindet
nicht – jedes gepackte Objekt braucht weiterhin einen –, aber er schrumpft zu einem
kompakten binären Typ-2-Eintrag im Querverweis-Stream (mehr dazu in Hebel 2).
In NextPDF wird das von ObjectStreamPacker geliefert, einem eigenständigen
Nachbearbeiter, der ein fertiges PDF mit Querverweis-Stream nimmt und die in Frage
kommenden Objekte in einen einzigen /Type /ObjStm umschreibt. Die Regeln, die er
befolgt, kommen direkt aus dem Standard: Ein in Frage kommendes Objekt ist ein
Nicht-Stream-Objekt der Generation null, nachdem die speziellen Objekte ausgeschlossen
wurden, die direkt adressierbar bleiben müssen. §7.5.7 verbietet, ein Stream-Objekt in
einem Objektstream zu speichern, sodass Stream-Objekte – Inhalt, Schriften, Bilder –
ihre eigenen Einträge behalten; und ObjectStreamPacker lehnt zusätzlich das eigene
Querverweis-Stream-Objekt des Dokuments (es wird umgeschrieben) und das
/Encrypt-Dictionary ab, die beide direkt adressierbar bleiben müssen. Alles andere
Nicht-Stream-Objekt der Generation null wird gepackt.
| Edition | Availability |
|---|---|
| Core | Volle Unterstützung im Open-Source-Core über ObjectStreamPacker. Es ist opt-in: Die Voreinstellung des einstufigen Writers gibt klassische In-Use-Einträge aus, sodass die Ausgabe byte-identisch bleibt, sofern Sie das Packen nicht aktivieren. Der Packer ist deterministisch, mit seiner eigenen reproduzierbaren Golden-Baseline. |
| Pro | Not in this edition |
| Enterprise | Not in this edition |
Opt-in ist eine bewusste Haltung, keine versteckte Einschränkung. Die voreingestellte Ausgabe ist byte-stabil und passt zu den bestehenden Golden-Baselines; das Packen zu aktivieren entscheidet sich für ein anderes, kleineres, gleichermaßen deterministisches Layout. Sie wählen den Kompromiss, und die Engine trifft ihn nie hinter Ihrem Rücken.
Hebel 2 – der Index kann auch ein Stream sein
Abschnitt betitelt „Hebel 2 – der Index kann auch ein Stream sein“Sobald Objekte in einem Objektstream leben, ändert der Index, der auf sie zeigt, seine
Form. Ein Reader findet ein gepacktes Objekt über einen komprimierten
Querverweiseintrag – einen Typ-2-Eintrag, der den Objektstream und den Index darin
benennt (Spec: ISO 32000-2, §7.5.8.3ISO 32000-2 §7.5.8.3). Weil der gesamte
Querverweis selbst ein /Type /XRef-Stream ist, ist der Index für Tausende von
Objekten binär gepackt und deflatiert statt als Klartextzeilen geschrieben. Die Karte
schrumpft neben dem Territorium.
ObjectStreamPacker baut genau dies neu auf: Er gibt den einzelnen Objektstream aus,
dann einen umgeschriebenen Querverweis-Stream, der einen kompakten Typ-1-Eintrag für
jedes beibehaltene Objekt und einen Typ-2-Eintrag für jedes gepackte trägt, wobei jede
Objektnummer bewahrt wird, damit bestehende Referenzen gültig bleiben.
Hebel 3 – Wahl des Bildfilters
Abschnitt betitelt „Hebel 3 – Wahl des Bildfilters“Für jedes Dokument mit echten Bildern stellt dieser Hebel die anderen in den Schatten. Die Bytes sind dasselbe Bild; der Codec ist das Budget. Die Filter-Namen leben im Standard-Filtersatz (Spec: ISO 32000-2, §7.4ISO 32000-2 §7.4), und die Wahl zwischen ihnen ist eine Größenentscheidung:
- FlateDecode ist verlustfrei. Perfekt für Strichzeichnungen, Screenshots und alles mit flacher Farbe – und ruinös für eine Fotografie, wo verlustfrei jedes Byte des Originals bedeutet.
- DCTDecode ist JPEG: verlustbehaftet, und für Fotografien mit weitem Abstand die richtige Wahl, oft eine zehnfache Reduktion bei einem Qualitätsverlust, den niemand bemerkt.
- JPXDecode ist JPEG 2000: Wavelet-Komprimierung mit einer anderen Qualität/Größe-Kurve, aber uneinheitlicher Unterstützung und von manchen Archivierungsprofilen verboten.
Das ist genau dort, wo wie ein Filter dekodiert wichtig wird, und das ist die Aufgabe des Artikels Streams und Filter. Der ökonomische Punkt ist enger: Eine verlustfrei gespeicherte Fotografie ist die häufigste einzelne Ursache eines unnötig riesigen PDF, und kein Maß an Objektstream-Packen wird eine Datei retten, deren echtes Gewicht ein un-JPEG’ter Scan ist.
Hebel 4 – Font-Subsetting
Abschnitt betitelt „Hebel 4 – Font-Subsetting“Eine eingebettete Schrift ist ein Programm. Eine vollständige kann mehrere hundert Kilobyte groß sein, weil sie jede Glyphe trägt, die der Schriftgestalter je gezeichnet hat – Tausende von Zeichen über Schriftsysteme hinweg, die Sie in diesem Dokument nie verwenden werden. Subsetting bettet nur die Glyphen ein, die das Dokument tatsächlich zeichnet, und verwandelt dieses Programm in einen kleinen Bruchteil seiner selbst. Ein einseitiger Brief braucht nicht die gesamte einer CJK-fähigen Schrift; er braucht die paar Dutzend Glyphen, die er setzt. Die Mechanik, wie Glyphen ausgewählt und neu indiziert werden, ist ihr eigenes Thema – siehe Schriften: der schwierige Teil.
- Image bytesFor media-heavy files, the largest line item. The filter choice — lossless Flate vs a lossy image codec like DCT (or JPX in a lossy mode) — is the dominant size lever.
- Font bytesA full embedded font is mostly glyphs you never draw. Subsetting keeps only the used glyphs, often shrinking the program by an order of magnitude.
- Per-object overheadThousands of small dictionaries each pay an obj/endobj envelope plus a cross-reference entry. Object streams (ObjStm) drop the envelope for the whole group; each object keeps a compact type-2 cross-reference entry.
- The indexA compressed cross-reference stream with type-2 entries binary-packs and deflates the map of every object, replacing plaintext index rows.
Praktisches Beispiel
Abschnitt betitelt „Praktisches Beispiel“Es gibt hier keine erfundene API zu zeigen, denn die wichtigsten Größenentscheidungen werden getroffen, bevor die Bytes den Writer erreichen – und der eine strukturelle Hebel, den NextPDF freilegt, ist ein einziges Opt-in. Konzeptionell liest sich das Budget so:
- Speisen Sie Fotografien als JPEG ein, sodass sie unter
DCTDecodelanden und nicht verlustfrei neu kodiert werden. Der größte Gewinn ist eine Entscheidung über die Quelldaten, kein Writer-Flag. - Lassen Sie den Writer eingebettete Schriften subsetten, sodass nur gezeichnete Glyphen ausgeliefert werden.
- Für ein Dokument mit vielen kleinen Objekten entscheiden Sie sich für
Objektstream-Packen, das die fertige Datei durch
ObjectStreamPackerleitet, um die kleinen Nicht-Stream-Objekte zu gruppieren und den Querverweis-Stream umzuschreiben.
Der Standardpfad – klassische In-Use-Einträge, kein ObjStm – ist die richtige Grundlinie: deterministisch, byte-stabil und leicht zu verifizieren. Das Packen ist das durchdachte Upgrade, wenn die Objektanzahl, nicht das Bildgewicht, das ist, was die Datei aufbläht.
Häufiges Missverständnis
Abschnitt betitelt „Häufiges Missverständnis“Die Falle ist, nach einem „das PDF komprimieren”-Knopf zu greifen und zu erwarten, dass
er alles behebt. Komprimierung ist nicht ein Hebel; sie sind vier, und sie ersetzen
einander nicht. Objektstream-Packen kann eine Fotografie nicht schrumpfen – das ist die
Aufgabe des Bildfilters. Ein perfektes JPEG kann eine Schrift nicht aufwiegen, die Sie
zu subsetten vergessen haben. Und nichts davon hilft, wenn die echte Aufblähung ein
10 MB großer Scan ist, der verlustfrei gespeichert wird, weil niemand DCTDecode
dafür gewählt hat.
Das zweite Missverständnis ist, dass kleiner immer streng besser ist. Ist es nicht. Objektstreams sind mit Linearisierung unvereinbar – dem Fast-Web-View-Layout, das die absolute Objektplatzierung fixiert, damit die erste Seite früh streamt. Und manche Archivierungsprofile schränken ein, welche Bildfilter überhaupt erlaubt sind. Größe ist eine Achse. Sie steht im Tausch mit Streaming, Archivkonformität und Reproduzierbarkeit, und der richtige Punkt auf der Kurve hängt davon ab, wofür das Dokument da ist.
Grenzen und Abgrenzungen
Abschnitt betitelt „Grenzen und Abgrenzungen“Die vier Hebel sind die strukturelle Ökonomie der Dateigröße. Sie sind keine universelle „mach es kleiner”-Garantie, und NextPDF gibt nicht vor, ein Re-Optimierer für beliebige eingehende PDFs zu sein.
ObjectStreamPacker ist eine Best-Effort-Optimierung, die nie die Korrektheit aufs
Spiel setzt. Er lehnt ab – und gibt die Eingabe unverändert zurück –, wenn die Datei
kein PDF mit Querverweis-Stream ist, wenn sie verschlüsselt ist, wenn sie eine digitale
Signatur trägt (das Neuanordnen von Objekten würde die Byte-Bereiche verschieben, die
eine Signatur schützt), wenn sie bereits Objektstreams enthält oder wenn es kein in
Frage kommendes Objekt zu packen gibt. Er gibt genau einen Objektstream für das gesamte
Dokument aus; er teilt nicht in eine /Extends-Sammlung auf, was außerhalb des
Geltungsbereichs liegt und für die Dokumentgrößen, die NextPDF erzeugt, konform ist.
Die Bild- und Font-Hebel sind weitgehend Entscheidungen über die Eingabe. NextPDFs
Writer transkodiert nicht implizit eine verlustfreie Bitmap in einen verlustbehafteten
Bildstream – eine Fotografie zu DCTDecode oder JPXDecode neu zu kodieren, ist eine
explizite vorgelagerte Bildkodierungsentscheidung, nichts, was der Serialisierer hinter
Ihrem Rücken tut – noch gewinnt er Glyphen aus einer Schrift zurück, die der Aufrufer
vollständig einzubetten verlangt hat. Die größten Größengewinne werden vor dem
Byte-Serialisierer getroffen; die Aufgabe der Engine ist es, das Budget, das Sie ihr
bringen, nicht zu verschwenden.
Verwandte Dokumente
Abschnitt betitelt „Verwandte Dokumente“- Streams und Filter – der Wie-ein-Filter-dekodiert-Begleiter; diese Seite ergänzt ihn bewusst, dupliziert ihn nicht.
- Was ein PDF wirklich ist – das Modell der indirekten Objekte, dessen Overhead pro Objekt der Objektstream-Hebel reduziert.
- Die Anatomie einer PDF-Datei – die Querverweisstruktur, die zu einem komprimierten Stream wird.
- Schriften: der schwierige Teil – wie Subsetting die Glyphen auswählt und neu indiziert, die ein Dokument zeichnet.
Glossar
Abschnitt betitelt „Glossar“- Objektstream (ObjStm) – ein einzelner Stream, der viele kleine
Nicht-Stream-indirekte-Objekte enthält, zusammen komprimiert, sodass die
obj- /endobj-Hülle für die Gruppe weggelassen wird. Jedes gepackte Objekt behält weiterhin seinen eigenen Querverweiseintrag, als kompakten Typ-2-Eintrag. Opt-in in NextPDF. - Indirektes Objekt – ein nummeriertes Objekt im Graphen eines PDF, eingehüllt in
eine
obj- /endobj-Hülle und durch den Querverweisindex verfolgt. Die Hülle ist der Overhead pro Objekt. - Querverweis-Stream – der
/Type /XRef-Stream, der jedes Objekt indiziert, binär gepackt und deflatiert statt als Klartextzeilen geschrieben. - Komprimierter (Typ-2-)Eintrag – ein Querverweiseintrag, der auf ein Objekt zeigt, das in einem Objektstream lebt, und den Stream und den Index darin benennt.
- Font-Subsetting – das Einbetten nur der Glyphen, die ein Dokument tatsächlich zeichnet, statt der vollständigen Schriftart, was das eingebettete Font-Programm schrumpfen lässt.
- Verlustfreier vs. verlustbehafteter Filter – ein verlustfreier Codec (FlateDecode) reproduziert jedes Byte; ein verlustbehafteter Bildcodec (DCTDecode oder JPXDecode in einem verlustbehafteten Modus) verwirft nicht wahrnehmbares Detail für ein weitaus kleineres Ergebnis. (JPEG 2000 / JPX kann auch verlustfrei konfiguriert werden.) Die Wahl ist der dominante Hebel bei einer medienlastigen Datei.