Die Anatomie einer PDF-Datei
Auf einen Blick
Abschnitt betitelt „Auf einen Blick“Öffnen Sie ein beliebiges PDF in einem einfachen Texteditor, und das Erste, was
Sie sehen, ist beruhigend: ein %PDF-1.x- oder %PDF-2.0-Header. Das Letzte, was
Sie sehen, ist %%EOF. Alles zwischen diesen beiden Zeilen ist eine adrette
kleine Maschine, um Objekte nach Nummer zu finden. Diese Seite ist eine
Sezierung. Wir öffnen die Datei, benennen jedes Organ und zeigen, wie sie
zusammenhängen.
Es ist der strukturelle Begleiter zweier Nachbarn. Was ein PDF wirklich ist behandelt die Datei als Objektgraphen; inkrementelle Aktualisierungen decken ab, wie sie im Laufe der Zeit wächst. Diese Seite bleibt nah an den Bytes — den physischen Regionen, die ein Parser durchläuft, in der Reihenfolge, in der sie auf der Festplatte liegen.
Warum das wichtig ist
Abschnitt betitelt „Warum das wichtig ist“Sie brauchen das fast nie, um ein PDF zu verwenden. Sie brauchen es an dem Tag, an dem eines schiefgeht. Eine Datei öffnet sich in einem Viewer und in einem anderen nicht; ein Validator meldet eine „beschädigte Querverweistabelle”; ein signiertes Dokument lässt sich plötzlich nicht mehr verifizieren. Keines davon ist ein Rätsel, sobald Sie die Anatomie lesen können. Sie sind eine Zahl, die nicht mehr zu einer Position passt, eine Region am falschen Ort oder ein Ende, das ins Leere zeigt.
Das Layout zu kennen, verwandelt „das PDF ist beschädigt” in eine Diagnose, nach der Sie handeln können. Es ist der Unterschied zwischen dem Achselzucken vor einer Blackbox und dem Zeigen auf genau das Byte, das lügt.
Die Kurzfassung
Abschnitt betitelt „Die Kurzfassung“Ein konformes PDF hat vier physische Teile, in dieser Dateireihenfolge (Spec: ISO 32000-2, §7.5.1ISO 32000-2 §7.5.1):
- Einen Header — eine Zeile,
%PDF-2.0, die die Version benennt. - Einen Rumpf — der Großteil der Datei: eine Folge nummerierter indirekter Objekte.
- Einen Querverweisabschnitt — einen Index von der Objektnummer zum Byte-Offset, an dem dieses Objekt liegt. Klassische PDFs verwenden eine Text-Tabelle; PDF 2.0 verwendet einen komprimierten Querverweis-Stream.
- Einen Trailer — ein kleines Dictionary, das den Einstiegspunkt benennt,
gefolgt von
startxref, einem Offset und%%EOF.
Die Wendung: Ein Reader beginnt nicht oben. Er beginnt unten, liest
startxref, um den Index zu finden, und nutzt diesen Index, um jedes Objekt
direkt zu erreichen. Die Datei wird von vorne nach hinten geschrieben, aber von
hinten nach vorne gelesen.
Wie NextPDF es angeht
Abschnitt betitelt „Wie NextPDF es angeht“Gehen wir die vier Regionen der Reihe nach durch, mit den Bytes vor uns.
Der Header ist eine Zeile. NextPDF schreibt %PDF-2.0 und üblicherweise eine
zweite Kommentarzeile aus High-Bit-Bytes, damit naive Übertragungswerkzeuge die
Datei als binär und nicht als Text behandeln. Diese zweite Zeile ist der Grund,
warum ein als reiner Text geöffnetes PDF gleich nach der Version ein wenig
Kauderwelsch zeigt.
Der Rumpf ist, wo das Dokument lebt. Jedes indirekte Objekt ist eine Zahl,
eine Generation, das Schlüsselwort obj, ein Wert und endobj
(Spec: ISO 32000-2, §7.3.10ISO 32000-2 §7.3.10). Der Wert ist eine von wenigen
Gestalten — aber zwei tragen fast das gesamte Gewicht:
- Ein Dictionary,
<< /Key value … >>, ist eine Zuordnung von Namen zu Werten. Der Seitenbaum, der Katalog, die Schriftdeskriptoren: alles Dictionaries. - Ein Stream ist ein Dictionary, gefolgt von
stream, einem Block beliebiger Bytes undendstream. Seiteninhalt, eingebettete Schriften und Bilder sind Streams, fast immer komprimiert. (Ihre Filter sind eine Geschichte für sich, erzählt in Streams und Filter.)
Objekte zeigen aufeinander per indirekter Referenz — 2 0 R bedeutet „Objekt 2,
Generation 0.” Das ist die Verdrahtung, die aus einer flachen Liste von Objekten
einen Graphen macht.
Der Querverweisabschnitt ist der Teil, den die meisten Menschen nie korrekt
vor sich sehen. In der klassischen Form ist er reiner Text: das Schlüsselwort
xref, dann Unterabschnitte aus festbreiten 20-Byte-Zeilen
(Spec: ISO 32000-2, §7.5.4ISO 32000-2 §7.5.4). Jede Zeile ist ein
zehnstelliger Byte-Offset, eine fünfstellige Generation und ein einzelnes Flag —
n für in Verwendung, f für frei — auf genau zwanzig Bytes aufgefüllt, damit
ein Reader allein durch Arithmetik zu jedem Eintrag springen kann. PDF 2.0 ersetzt
dies durch einen Querverweis-Stream: derselbe Index, aber binär und
komprimiert innerhalb eines Stream-Objekts, das mit /Type /XRef markiert ist
(Spec: ISO 32000-2, §7.5.8ISO 32000-2 §7.5.8). Kleiner und in der Lage,
Objekte zu beschreiben, die in Objekt-Streams gepackt sind.
Der Trailer ist das Inhaltsverzeichnis der Datei
(Spec: ISO 32000-2, §7.5.5ISO 32000-2 §7.5.5). Er benennt /Root — den
Dokumentkatalog, das einzige Objekt, an dem alles andere hängt — und /Size, die
Objektanzahl. Dann kommt der Handschlag, der das Rückwärtslesen möglich macht:
startxref, ein Byte-Offset in einer eigenen Zeile und %%EOF. Ein Reader springt
ans Ende, liest diesen Offset, springt direkt zum Querverweisabschnitt und ist
unterwegs.
- HeaderOne line, %PDF-2.0, naming the version. A binary-marker comment usually follows.
- BodyNumbered indirect objects — dictionaries and streams — referenced by N G R.
- Cross-reference sectionA text table of 20-byte entries, or a compressed /Type /XRef stream in PDF 2.0.
- TrailerNames /Root and /Size, then startxref + offset + %%EOF.
- Read orderA reader starts at %%EOF, follows startxref to the index, then reaches each object directly.
Es gibt eine fünfte Region, die eine langlebige Datei wachsen lässt: eine
inkrementelle Aktualisierung. Eine Änderung wird nicht an Ort und Stelle
geschrieben. Die geänderten Objekte, ein frischer Querverweisabschnitt und ein
neuer Trailer werden nach dem ersten %%EOF angehängt, und dieser neue Trailer
trägt /Prev — den Offset des vorherigen Querverweisabschnitts
(Spec: ISO 32000-2, §7.5.6ISO 32000-2 §7.5.6). Die Abschnitte bilden eine
rückwärts gerichtete Kette; für jede Objektnummer gewinnt der neueste Eintrag.
Weil sich die ursprünglichen Bytes nie bewegen, hält die kryptografische Prüfung
über den Byte-Bereich, den eine Signatur tatsächlich abdeckt, auch nach einer
Aktualisierung noch. Eine spätere inkrementelle Aktualisierung kann immer noch
ändern, was ein Validator über das Dokument als Ganzes meldet — ob die Änderungen
nach der Signatur erlaubt sind und was die Signatur zu zertifizieren gilt — aber
sie kann die signierten Bytes selbst nicht verändern. Diese Eigenschaft ist das
ganze Thema von inkrementellen
Aktualisierungen.
Praktisches Beispiel
Abschnitt betitelt „Praktisches Beispiel“Hier ist die gesamte Anatomie in einer minimalen Datei. Die Zahlen unter xref
sind Byte-Offsets, und sie müssen genau sein — zeigen Sie ein Zeichen hinter den
Beginn eines Objekts, und ein strikter Reader gibt auf.
%PDF-2.01 0 obj<< /Type /Catalog /Pages 2 0 R >>endobj2 0 obj<< /Type /Pages /Kids [3 0 R] /Count 1 >>endobj3 0 obj<< /Type /Page /Parent 2 0 R /MediaBox [0 0 612 792] >>endobjxref0 40000000000 65535 f0000000009 00000 n0000000058 00000 n0000000115 00000 ntrailer<< /Size 4 /Root 1 0 R >>startxref186%%EOFLesen Sie es so, wie ein Parser es tut. Letzte Zeile: %%EOF. Darüber:
startxref 186, also springen Sie zu Byte 186, wo xref beginnt. Die Tabelle
sagt, Objekt 1 liegt bei Byte 9. Das /Root 1 0 R des Trailers zeigt dorthin —
den Katalog — und vom Katalog aus folgen Sie /Pages zum Seitenbaum und finden
die einzelne Seite. Objekt 0 ist immer der Kopf der Freiliste mit Generation
65535, ein Fossil aus dem ersten Entwurf des Formats, das jeder Reader noch
immer zu sehen erwartet.
Verbreitetes Missverständnis
Abschnitt betitelt „Verbreitetes Missverständnis“Die Falle besteht darin, ein PDF wie eine Geschichte zu lesen — von oben nach
unten, der Reihe nach. Es ist keine Geschichte; es ist ein Index mit einem
Rückwärtszeiger. Objektnummern müssen in der Datei nicht fortlaufend sein, Objekte
können in beliebiger physischer Reihenfolge auftreten, und ein Reader verlässt
sich nie auf ihre Position. Die einzige maßgebliche Karte ist der
Querverweisabschnitt, und der einzige Weg, diese Karte zu finden, ist der
startxref-Offset ganz am Ende.
Die Folge überrascht die Leute. Ein PDF mit einem makellosen Rumpf und einer
falschen Ziffer in startxref ist unlesbar — der Reader kann den Index nicht
finden. Ein PDF mit seinen Objekten in durcheinandergewürfelter Reihenfolge, aber
einem korrekten Querverweisabschnitt ist vollkommen in Ordnung. Die physische
Position trägt keine Bedeutung. Die aufgezeichnete Position trägt sie ganz.
Grenzen und Abgrenzungen
Abschnitt betitelt „Grenzen und Abgrenzungen“Diese Seite beschreibt die physische Struktur, nicht den Seiteninhalt. Wie Marken
auf einer Seite landen — Inhaltsstrom-Operatoren, Textausgabe, Grafikzustand — ist
ein eigenes Thema. Sie beschreibt außerdem eine wohlgeformte Datei. PDFs aus der
echten Welt sind häufig ein wenig kaputt und überleben nur, weil nachsichtige
Viewer die Querverweistabelle wiederaufbauen, indem sie nach obj-Schlüsselwörtern
suchen. Diese Rettung ist ein Verhalten des Viewers, nicht etwas, das das Format
garantiert.
| Edition | Availability |
|---|---|
| Core | NextPDF ist ein Writer. Er zeichnet jeden Offset aus dem Ausgabepuffer in dem Moment auf, in dem jedes Objekt ausgegeben wird, sodass die von ihm erzeugten Dateien einen Querverweisabschnitt haben, der konstruktionsbedingt zum Rumpf passt. |
| Pro | Das Parsen, Rekonstruieren oder Reparieren einer beschädigten Querverweistabelle in einer Datei, die NextPDF nicht geschrieben hat, liegt in jeder Edition außerhalb des Umfangs. |
| Enterprise | Für die Inspektion der Struktur einer bestehenden Datei verwenden Sie einen dedizierten Parser oder Validator; NextPDF garantiert Korrektheit für das, was es schreibt, nicht für das, was es liest. |
Mini-FAQ
Abschnitt betitelt „Mini-FAQ“Warum hat ein PDF nach dem Header eine Binärmarkierungszeile? Manche älteren Übertragungswerkzeuge würden eine Datei verstümmeln, die sie für reinen Text hielten. Der High-Bit-Kommentar lässt die Datei unmissverständlich binär aussehen, sodass sie die Reise unverändert übersteht.
Ist der Querverweis-Stream einfach eine kleinere Tabelle? Größtenteils, mit einer zusätzlichen Fähigkeit. Über das Komprimiertsein hinaus kann ein Querverweis-Stream Objekte beschreiben, die innerhalb von Objekt-Streams gespeichert sind — Einträge, die die klassische 20-Byte-Texttabelle nicht ausdrücken kann.
Kann ich in einer Datei sowohl eine Tabelle als auch einen Stream haben? Eine einzelne Revision verwendet das eine oder das andere. Aber eine Hybriddatei kann eine klassische Tabelle für alte Reader mit einem Querverweis-Stream für neue paaren, sodass jede Art von Reader einen Index findet, den sie versteht.
Verwandte Dokumente
Abschnitt betitelt „Verwandte Dokumente“- Was ein PDF wirklich ist — dieselben vier Teile, gesehen als Objektgraph statt als physisches Layout.
- Inkrementelle Aktualisierungen und warum sie wichtig sind — wie die angehängte fünfte Region eine Datei wachsen lässt und Signaturen schützt.
- Streams und Filter — was sich in den Stream-Objekten des Rumpfes befindet und wie sie komprimiert werden.
- PDF 2.0: was sich geändert hat — warum der Querverweis-Stream die Standardstruktur ist, die NextPDF schreibt.
Glossar
Abschnitt betitelt „Glossar“- Header — die erste Zeile,
%PDF-2.0, die die Version benennt; meist gefolgt von einem Binärmarkierungskommentar. - Indirektes Objekt — ein nummeriertes Objekt im Rumpf, geschrieben
N G obj … endobj, wobeiNdie Objektnummer undGdie Generation ist. - Dictionary — eine
<< /Key value … >>-Zuordnung von Namen zu Werten; die häufigste Objektgestalt. - Stream — ein Dictionary plus ein Block von Bytes zwischen
streamundendstream, verwendet für Inhalt, Schriften und Bilder. - Querverweistabelle (xref) — der Index von der Objektnummer zum Byte-Offset;
klassisch eine Texttabelle mit 20 Byte pro Eintrag, in PDF 2.0 ein
/Type /XRef-Stream. - Trailer — das Dictionary, das
/Rootund/Sizebenennt, lokalisiert über denstartxref-Offset am Ende der Datei. - Inkrementelle Aktualisierung — geänderte Objekte, ein neuer
Querverweisabschnitt und ein neuer Trailer, die nach
%%EOFangehängt werden, wobei/Prevzum vorherigen Abschnitt zurückverkettet.