Legen Sie einen 80 MB großen eingescannten Bericht hinter einen Link, öffnen Sie ihn in einem Browser und beobachten Sie, was passiert: Der Viewer verharrt auf einer leeren Fläche, bis ein großer Teil dieser Bytes angekommen ist, und zeichnet dann Seite eins auf einmal auf den Bildschirm. Springen Sie zu Seite 40 und bei einer schlecht erstellten Datei kann der gesamte Download von vorne beginnen. Das Frustrierende daran ist, dass der Leser immer nur die erste Seite wollte. Linearisierung ist die strukturelle Antwort auf dieses Problem. Sie ordnet ein PDF so um, dass ein Viewer die Startseite aus einem kleinen Präfix der Datei rendern und den Rest bei Bedarf abrufen kann – weshalb Adobe die Funktion als „Fast Web View“ (schnelle Web-Ansicht) vermarktet
Nichts davon ist ein anderes Dateiformat. Ein linearisiertes PDF ist ein gewöhnliches PDF, das ein konformer Reader ohne besondere Behandlung öffnet. Der Trick liegt vollständig darin, wie die Bytes geordnet sind und in zwei zusätzlichen Strukturen, die die Datei mitführt. ISO 32000-1 spezifiziert das gesamte Layout in Anhang F, und wenn man dieses Layout einmal gesehen hat, wirkt das Verhalten nicht mehr wie Magie, sondern wie ein bewusster Tausch von Dateireihenfolge gegen First-Paint-Latenz
Was die Linearisierung tatsächlich umordnet
Ein normales PDF kann seine Objekte in fast beliebiger Reihenfolge verstreuen. Die Querverweistabelle (Cross-Reference Table) am Ende der Datei ist das, was dies möglich macht: Ein Reader sucht das Ende, liest den startxref-Zeiger, lädt die Xref und kann von dort aus jedes Objekt anhand seines Offsets lokalisieren. Dieses Design eignet sich hervorragend für lokale Dateien, bei denen die Suche nach dem Ende nichts kostet, und schlecht für eine Datei, die über ein Netzwerk gestreamt wird, bei der das Ende genau der Teil ist, der zuletzt ankommt. Um Seite eins zu rendern, benötigt ein herkömmlicher Reader das Seitenobjekt, seinen Content-Stream, die von ihm referenzierten Schriftarten und alle Bilder, die es zeichnet, und in einer ungeordneten Datei können diese überall liegen, einschließlich des letzten Megabytes
Linearisierung fixiert die Reihenfolge. Die Objekte, die zur Anzeige der ersten Seite benötigt werden, werden in einem zusammenhängenden Block nahe dem Anfang, direkt nach einem kleinen Header-Abschnitt, gesammelt, sodass sie früh im Bytestream eintreffen. Alles andere, die verbleibenden Seiten und die von ihnen geteilten Ressourcen, folgt in einer vorhersehbaren Sequenz. Eine zweite, vollständige Querverweistabelle existiert weiterhin am Ende für Reader, die die Optimierung ignorieren, aber eine linearisierte Datei platziert auch einen Querverweis für die erste Seite und die Parameter, die ein streamender Reader benötigt, ganz nach vorn. Der Reader muss nicht mehr das Ende erreichen, bevor er etwas zeichnen kann
Das Objekt-Set der ersten Seite und das Linearisierungs-Parameterwörterbuch
Das allererste Objekt in einer linearisierten Datei nach dem %PDF-Header ist das Linearisierungs-Parameterwörterbuch (Linearization Parameter Dictionary). Dies ist es, wonach ein streamender Reader sucht, um zu entscheiden, ob die Optimierung vorhanden ist und wie er sie nutzen kann. Das Wörterbuch verzeichnet die Länge der gesamten Datei, den Byte-Offset, an dem der Haupt-Querverweisabschnitt beginnt, die Objektnummer der ersten Seite sowie Position und Länge des folgenden Hint-Streams. Mit diesen Zahlen weiß ein Reader allein aus den ersten Kilobytes, wie viel er abrufen muss, um Seite eins anzuzeigen, und wo er nach dem Index suchen muss, der ihm Sprünge an andere Stellen erlaubt
Anhang F ist streng, was „erste Seite“ hier bedeutet. Der Abschnitt für die erste Seite muss das Seitenobjekt selbst, seine Content-Streams und die von diesen Streams referenzierten Ressourcen enthalten, damit die Seite autark ist, sobald dieses Präfix heruntergeladen wurde. Gemeinsam genutzte Ressourcen (Shared Resources) – eine Schriftart, die auf jeder Seite verwendet wird, ein Logo, das sich in einer Kopfzeile wiederholt – werden besonders behandelt: Sie erscheinen früh genug, um der ersten Seite zu dienen, sind aber als gemeinsam genutzt (shared) markiert, sodass der Reader sie nicht erneut abruft, wenn er später Seite 30 rendert. Diese Unterscheidung zwischen seitenprivaten und gemeinsam genutzten Objekten ist der Teil, den die meisten selbstgestrickten „Optimierer“ falsch machen, und dieses Falschmachen ist es, was eine Datei erzeugt, die vorgibt, linearisiert zu sein, aber dennoch ins Stocken gerät
Hint-Streams: Der Index, der Seitensprünge billig macht
Die schnelle Anzeige von Seite eins ist nur der halbe Wert. Die andere Hälfte ist der Sprung zu einer beliebigen Seite, ohne alles dazwischen herunterladen zu müssen, und das ist es, was die Hint-Streams bieten. Eine linearisierte Datei führt eine Hint-Tabelle für Seiten-Offsets (Page Offset Hint Table) und eine Hint-Tabelle für gemeinsam genutzte Objekte (Shared Object Hint Table) mit sich, gespeichert als Stream, der vom Parameterwörterbuch referenziert wird. Die Seiten-Offset-Tabelle verzeichnet für jede Seite, wo ihre Objekte in der Datei beginnen und wie lang sie sind. Die Tabelle für gemeinsam genutzte Objekte tut dasselbe für Ressourcen, die über mehrere Seiten hinweg verwendet werden
Mit diesen Tabellen parst ein Reader, der Seite 40 möchte, die Datei nicht sequenziell. Er konsultiert die Hint-Tabelle, um den Byte-Bereich zu erfahren, den Seite 40 belegt, bittet den Server um exakt diesen Bereich und rendert die Seite, sobald diese Bytes ankommen, wobei er alle noch nicht vorliegenden gemeinsamen Ressourcen über denselben Mechanismus abruft. Der Hint-Stream ist praktisch eine Direktzugriffskarte (Random-Access Map), die über das Dokument gelegt wird, und er ist der Grund, warum sich eine gut linearisierte 500-Seiten-Datei über eine langsame Verbindung reaktionsschnell anfühlt, während dies bei einer unoptimierten Datei gleicher Größe nicht der Fall ist
Warum der Server kooperieren muss
Linearisierung geht davon aus, dass der Transport beliebige Slices (Scheiben) der Datei liefern kann, und diese Annahme sollte man überprüfen, bevor man dem Format die Schuld für schlechte Ergebnisse gibt. Der Mechanismus ist HTTP-Byte-Serving: Der Reader sendet Range-Anfragen (Range Requests), und der Server beantwortet sie mit 206 Partial Content-Antworten. Wenn der Server nicht Accept-Ranges: bytes annonciert, oder wenn ein davor geschalteter Proxy oder ein CDN Range-Anfragen zu vollständigen Übertragungen zusammenfasst, hat der Reader keine Möglichkeit, Seite 40 isoliert abzurufen, und fällt auf das Herunterladen der gesamten Datei zurück. Die Struktur innerhalb des PDFs ist dann vollkommen korrekt und völlig verschwendet
Dies ist der Fehler, der am häufigsten fälschlicherweise als „Linearisierung funktioniert nicht“ fehldiagnostiziert wird. Die Datei ist in Ordnung; der Auslieferungsweg ist es nicht. Bevor Sie ein Dokument neu aufbauen, bestätigen Sie mit einer bedingten Anfrage (Conditional Request), dass der Host tatsächlich Partial Content für die URL zurückgibt, auf die der Reader zugreift. Viele statische Hosts tun dies standardmäßig, und viele falsch konfigurierte Anwendungsserver und Caching-Schichten tun es nicht
Inkrementelle Updates machen Linearisierung stillschweigend kaputt
Hier ist die Einschränkung, die Leute überrascht, die linearisierte Dateien korrekt generieren und sich dann wundern, warum sich die Optimierung in Luft auflöst. Linearisierung beruht auf einem einzigen, sorgfältig geordneten Layout mit seinem Index am Anfang. Ein inkrementelles Update verletzt dies per Design. Wenn ein Tool eine Signatur hinzufügt, ein Formularfeld ausfüllt oder eine Anmerkung durch einen inkrementellen Speichervorgang (Incremental Save) anhängt, wird die Datei nicht neu geschrieben. Es hängt die geänderten Objekte, einen neuen Querverweisabschnitt und einen neuen Trailer an das Ende an, wobei die ursprünglichen Bytes unberührt bleiben. Dieses Anhängen ist der ganze Sinn inkrementeller Updates: Es ist schnell und bewahrt die frühere Revision für Audits oder Signaturprüfungen
Der Nebeneffekt ist, dass die Datei ihre neuesten Querverweisdaten jetzt am Ende hat, nach dem sorgfältig platzierten Erstseiten-Block, und das Linearisierungs-Parameterwörterbuch am Anfang ein Layout beschreibt, das nicht mehr mit der Datei übereinstimmt. Ein konformer Reader erkennt die Diskrepanz und behandelt das Dokument wie ein normales, nicht linearisiertes PDF. Fast Web View ist verschwunden, obwohl die ursprüngliche linearisierte Struktur immer noch in der ersten Hälfte der Datei sitzt. Wenn Sie mehrere Updates anhängen, stapelt jedes eine weitere Revision an das Ende und die Kluft zwischen dem veralteten Front-Index und dem tatsächlichen Zustand wächst
Wenn Ihr Workflow sowohl Bearbeitungen als auch Fast Web View erfordert, folgt die Regel direkt aus der Struktur: Bearbeiten Sie inkrementell, solange das Dokument im Fluss ist, und re-linearisieren Sie es dann einmal am Ende. Ein vollständiges Neuschreiben (Full Rewrite) stellt das Layout wieder her. In HotPDF-Begriffen bedeutet das, dass eine laufende Bearbeitung durch BeginIncrementalUpdate und SaveIncrementalUpdate geht, welche ein Delta anhängen, während der abschließende Schritt das gesamte Dokument lädt und mit LoadFromFile gefolgt von SaveLoadedDocument frisch serialisiert, was die angesammelten alten Revisionen verwirft und ein sauberes Layout ausgibt. Derselbe Kompromiss zeigt sich bei Objekt-Streams: Die Aktivierung von UseObjectStreams zusammen mit UseXRefStream komprimiert den Querverweis und packt Objekte eng zusammen, was der Dateigröße zugutekommt, aber wie jede strukturelle Entscheidung während dieses abschließenden Neuschreibens angewendet werden muss, anstatt auf eine angehängte Revision aufgeschraubt zu werden
// In-flight edits: append a delta, keep prior revisions intact.
// This leaves the file NOT linearized.
Pdf.BeginIncrementalUpdate('report.pdf');
Pdf.AddPage;
Pdf.CurrentPage.TextOut(72, 760, 0, 'Addendum');
Pdf.SaveIncrementalUpdate('report.pdf');
// Finishing step: full re-serialization produces one clean layout,
// dropping the stacked revisions. Re-run your linearizer on the output.
Pdf.LoadFromFile('report.pdf');
Pdf.SaveLoadedDocument('report-final.pdf');
HotPDF stellt keine Ein-Aufruf-„Linearisieren“-Routine bereit, daher ist das praktische Muster, eine saubere, vollständig neu geschriebene Datei zu produzieren und einen dedizierten Optimierer darüberlaufen zu lassen. Kommandozeilentools kümmern sich direkt um das Umordnen. qpdf schreibt eine Datei mit einem einzigen Flag in eine linearisierte Form um:
qpdf --linearize report-final.pdf report-web.pdf
Wie man erkennt, ob eine Datei linearisiert ist
Vertrauen Sie nicht dem Dateinamen oder dem Tool, das behauptet, sie erstellt zu haben; überprüfen Sie die Bytes. Die direkteste Prüfung ist der Kopf (Head) der Datei: Öffnen Sie sie und suchen Sie nach dem Linearisierungs-Parameterwörterbuch als erstes Objekt nach dem Header, das den Schlüssel /Linearized trägt. Eine anwenderfreundliche Abkürzung ist der Dokumenteigenschaften-Dialog von Acrobat, der „Schnelle Web-Ansicht: Ja“ (Fast Web View: Yes) nur meldet, wenn die Struktur tatsächlich vorhanden und aktuell ist
Für skriptgesteuerte Prüfungen meldet qpdf sowohl das Vorhandensein als auch die Integrität der Struktur, was wichtig ist, da eine Datei ein Linearisierungs-Wörterbuch mit sich führen kann, das ihr Layout nicht mehr widerspiegelt – exakt der Zustand, den ein inkrementelles Update hinterlässt:
# Reports "File is linearized" and validates hint tables against the layout
qpdf --check report-web.pdf
# Dumps the linearization parameters and hint data in detail
qpdf --show-linearization report-web.pdf
Der Validierungsschritt ist derjenige, der sein Geld wert ist. Ein Durchlauf, der nur bestätigt, dass das Wörterbuch existiert, wird freudig eine Datei absegnen, deren Index auf die falschen Offsets zeigt; eine Prüfung, die die Hint-Tabellen mit den tatsächlichen Objektpositionen abgleicht, sagt Ihnen, ob die Optimierung echten Range-Anfragen eines Readers standhält
Linearisierung bleibt für jedes große Dokument, das über das Web ausgeliefert wird, anwendungswürdig, insbesondere für mobile Leser mit unbeständigen Verbindungen, und sie kostet ein paar Prozent der Dateigröße für den vorgezogenen Index. Die beiden Dinge, die man im Kopf behalten muss, sind, dass sowohl die Struktur innerhalb des PDFs als auch das Byte-Serving außerhalb stimmen müssen und dass jede nachträgliche Bearbeitung die Optimierung zunichtemacht, bis man die Datei neu schreibt. Behandeln Sie die Re-Linearisierung als den letzten Schritt in der Pipeline, nachdem jede andere Änderung abgeschlossen ist. Das hier beschriebene Verhalten bezüglich Querverweisen, Objekt-Streams und inkrementellen Updates ist Teil des Strukturmodells, das die HotPDF-Komponente für Delphi und C++Builder implementiert; für den breiteren Hintergrund zum Dateilayout siehe wie ein PDF aufgebaut ist, und für den Workflow bei inkrementellen Updates und großen Dateien im Code siehe Verarbeitung großer PDFs in Delphi