Læg en 80 MB scannet rapport bag et link, åbn den i en browser, og se, hvad der sker: fremviseren sidder på et tomt vindue, indtil en stor brøkdel af disse bytes er ankommet, hvorefter den maler side et på én gang. Spring til side 40, og for en dårligt bygget fil kan hele overførslen starte forfra. Det frustrerende er, at læseren altid kun ønskede den første side. Linearisering er det strukturelle svar på det problem. Det omorganiserer en PDF, så en fremviser kan gengive åbningssiden fra et lille præfiks af filen og hente resten efter behov, hvilket er grunden til, at Adobe markedsfører funktionen som "Fast Web View."
Dette er overhovedet ikke et andet filformat. En lineariseret PDF er en almindelig PDF, som en kompatibel læser vil åbne uden speciel håndtering. Tricket ligger helt i, hvordan bytene er ordnet, og i to ekstra strukturer, som filen bærer på. ISO 32000-1 specificerer hele arrangementet i bilag F, og når du først har set layoutet, stopper adfærden med at ligne magi og begynder at ligne en bevidst byttehandel af filrækkefølge for first-paint-latenstid
Hvad linearisering egentlig omorganiserer
En normal PDF kan sprede sine objekter i næsten hvilken som helst rækkefølge. Krydsreferencetabellen i slutningen af filen er det, der får det til at fungere: en læser søger til slutningen, læser startxref-pointeren, indlæser xref, og derfra kan den lokalisere ethvert objekt via dets forskydning. Det design er fremragende til lokale filer, hvor det intet koster at søge til slutningen, og dårligt for en fil, der streames over et netværk, hvor slutningen netop er den del, der ankommer sidst. For at gengive side et har en konventionel læser brug for sideobjektet, dets indholdsstrøm, de skrifttyper, det refererer til, og eventuelle billeder, det tegner, og i en uordnet fil kan disse sidde hvor som helst, inklusive den sidste megabyte
Linearisering fastsætter rækkefølgen. De objekter, der er nødvendige for at vise den første side, samles i en sammenhængende blok nær begyndelsen, lige efter en lille header-sektion, så de ankommer tidligt i bytestrømmen. Alt andet, de resterende sider og de ressourcer, de deler, følger i en forudsigelig sekvens. En anden, komplet krydsreferencetabel findes stadig i slutningen til læsere, der ignorerer optimeringen, men en lineariseret fil placerer også en krydsreference for første side og de parametre, en streaming-læser har brug for, forrest. Læseren behøver ikke længere at nå halen, før den kan tegne noget
Førsteside-objektsættet og parameterordbogen for linearisering
Det allerførste objekt i en lineariseret fil, efter %PDF-headeren, er parameterordbogen for linearisering. Det er det, en streaming-læser kigger efter for at beslutte, om optimeringen er til stede, og hvordan den skal bruges. Ordbogen registrerer længden af hele filen, byteforskydningen, hvor den primære krydsreferencesektion begynder, objektnummeret for den første side samt placeringen og længden af hint-streamen, der følger. Med disse tal ved en læser alene fra de første kilobytes, hvor meget den skal hente for at vise side et, og hvor den skal lede efter indekset, der lader den springe til andre steder
Bilag F er streng om, hvad "første side" betyder her. Førsteside-sektionen skal indeholde selve sideobjektet, dets indholdsstrømme og de ressourcer, som disse strømme refererer til, så siden er selvforsynende, når det præfiks er downloadet. Delte ressourcer, en skrifttype brugt på hver side, et logo, der gentages i et sidehoved, håndteres specielt: de vises tidligt nok til at betjene den første side, men markeres som delte, så læseren ikke henter dem igen, når den senere gengiver side 30. Den skelnen mellem side-private og delte objekter er den del, de fleste hjemmelavede "optimizers" misforstår, og en misforståelse her producerer en fil, der hævder at være lineariseret, men stadig går i stå
Hint-streams: indekset, der gør sidespring billige
At vise side et hurtigt er kun halvdelen af værdien. Den anden halvdel er at springe til en vilkårlig side uden at downloade alt derimellem, og det er det, hint-streams leverer. En lineariseret fil indeholder en tabelforskydning (page offset hint table) og en delt objekttabel (shared object hint table), der er lagret som en strøm refereret fra parameterordbogen. Sideforskydningstabellen registrerer for hver side, hvor dens objekter begynder i filen, og hvor lange de er. Den delte objekttabel gør det samme for ressourcer brugt på tværs af flere sider
Givet disse tabeller parsar en læser, der ønsker side 40, ikke filen sekventielt. Den konsulterer hint-tabellen for at finde ud af det byteområde, side 40 optager, beder serveren om netop det område og gengiver siden, når de bytes ankommer, mens den trækker alle delte ressourcer, den ikke allerede har, via den samme mekanisme. Hint-streamen er i bund og grund et random-access-kort lagt over dokumentet, og det er grunden til, at en vel-lineariseret 500-siders fil føles responsiv over en langsom forbindelse, mens en uoptimeret fil af samme størrelse ikke gør det
Hvorfor serveren skal samarbejde
Linearisering antager, at transporten kan levere vilkårlige dele af filen, og den antagelse er værd at kontrollere, før du bebrejder formatet for dårlige resultater. Mekanismen er HTTP byte-serving: læseren udsender område-anmodninger (range requests), og serveren besvarer dem med 206 Partial Content-svar. Hvis serveren ikke reklamerer for Accept-Ranges: bytes, eller hvis en proxy eller CDN foran den kollapser range requests til fulde overførsler, har læseren ingen måde at hente side 40 isoleret og falder tilbage på at downloade hele filen. Strukturen inde i PDF'en er da helt korrekt og fuldstændig spildt
Dette er den fejl, der oftest fejldiagnosticeres som "linearisering virker ikke". Filen er fin; leveringsvejen er det ikke. Før du genopbygger et dokument, skal du med en betinget anmodning (conditional request) bekræfte, at værten rent faktisk returnerer delvist indhold for den URL, læseren rammer. Mange statiske værter gør dette som standard, og mange fejlkonfigurerede applikationsservere og cachelag gør det ikke
Inkrementelle opdateringer ødelægger stille lineariseringen
Her er den begrænsning, der overrasker folk, der genererer lineariserede filer korrekt og derefter undrer sig over, hvorfor optimeringen fordamper. Linearisering afhænger af et enkelt, omhyggeligt ordnet layout med dets indeks forrest. En inkrementel opdatering overtræder dette bevidst. Når et værktøj tilføjer en signatur, udfylder et formularfelt eller tilføjer en annotation via en inkrementel gemning, omskriver det ikke filen. Det tilføjer de ændrede objekter, en ny krydsreferencesektion og en ny trailer i slutningen, og efterlader de originale bytes urørte. Den tilføjelse er hele pointen med inkrementelle opdateringer: det er hurtigt, og det bevarer den tidligere revision til revision eller signaturvalidering
Bivirkningen er, at filen nu har sine nyeste krydsreferencedata i halen, efter den omhyggeligt placerede førsteside-blok, og parameterordbogen for linearisering i fronten beskriver et layout, der ikke længere matcher filen. En kompatibel læser opdager uoverensstemmelsen og behandler dokumentet som en normal, ikke-lineariseret PDF. Fast Web View er væk, selvom den originale lineariserede struktur stadig sidder der i den første halvdel af filen. Hvis du tilføjer adskillige opdateringer, stabler hver enkelt en anden revision på slutningen, og kløften mellem det forældede front-indeks og den virkelige tilstand udvides
Hvis dit workflow har brug for både redigeringer og Fast Web View, følger reglen direkte af strukturen: rediger inkrementelt, mens dokumentet er i forandring, og lineariser derefter en enkelt gang til sidst. En fuld omskrivning er det, der gendanner layoutet. I HotPDF-termer betyder det, at en igangværende redigering går gennem BeginIncrementalUpdate og SaveIncrementalUpdate, som tilføjer en delta, mens det afsluttende trin indlæser hele dokumentet og serialiserer det på ny med LoadFromFile efterfulgt af SaveLoadedDocument, som kasserer de akkumulerede gamle revisioner og udsender et rent layout. Det samme bytteforhold dukker op med objekt-streams: at aktivere UseObjectStreams sammen med UseXRefStream komprimerer krydsreferencen og pakker objekter tæt, hvilket hjælper på filstørrelsen, men som ethvert strukturelt valg skal anvendes under den endelige omskrivning snarere end påhæftes en tilføjet revision
// 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 udstiller ikke en "lineariser"-rutine med et enkelt kald, så det praktiske mønster er at produce en ren, fuldt omskrevet fil og køre en dedikeret optimizer over den. Kommandolinjeværktøjer håndterer omorganiseringen direkte. qpdf omskriver en fil til lineariseret form med et enkelt flag:
qpdf --linearize report-final.pdf report-web.pdf
Sådan kan du se, om en fil er lineariseret
Stol ikke på filnavnet eller det værktøj, der hævder at have produceret det; verificer bytene. Det mest direkte tjek er i toppen af filen: åbn den og led efter parameterordbogen for linearisering som det første objekt efter headeren, der bærer /Linearized-nøglen. En læser-vendt genvej er Acrobats dialogboks Dokumentegenskaber (Document Properties), som rapporterer "Fast Web View: Yes", men kun når strukturen reelt er til stede og opdateret
For scriptede tjek rapporterer qpdf både tilstedeværelsen og integriteten af strukturen, hvilket betyder noget, fordi en fil kan bære en lineariseringsordbog, der ikke længere afspejler dens layout, præcis den tilstand en inkrementel opdatering efterlader:
# 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
Valideringstrinnet er det, der tjener sig ind. Et tjek, der kun bekræfter, at ordbogen findes, vil med glæde godkende en fil, hvis indeks peger på forkerte offsets; et tjek, der afstemmer hint-tabellerne mod de faktiske objektpositioner, er det, der fortæller dig, om optimeringen vil holde under en rigtig læsers range requests
Linearisering er stadig værd at anvende på ethvert stort dokument, der serveres over nettet, især for mobile læsere på ujævne forbindelser, og det koster et par procent af filstørrelsen for front-loaded indekset. De to ting, du skal holde styr på, er, at strukturen inde i PDF'en og byte-serving uden for den begge skal være rigtige, og at enhver redigering bagefter fortryder optimeringen, indtil du omskriver filen. Behandl relinearisering som det sidste trin i pipelinen, efter enhver anden ændring er på plads. Krydsreference-, objekt-stream- og inkrementel-opdatering-adfærden beskrevet her er en del af den strukturelle model, som HotPDF Component til Delphi og C++Builder implementerer; for den bredere baggrund om fil-layout se hvordan en PDF er struktureret, og for inkrementel opdatering og workflow for store filer i kode se behandling af store PDF'er fra Delphi