Teknisk artikkel

PDF-linearisering og Fast Web View: Hvordan det fungerer

Legg en 80 MB skannet rapport bak en lenke, åpne den i en nettleser, og se hva som skjer: visningsprogrammet sitter på en blank rute til en stor andel av disse bytene har ankommet, deretter maler den side én alt på en gang. Hopp til side 40, og på en dårlig bygget fil kan hele nedlastingen starte på nytt. Det frustrerende er at leseren egentlig bare ville ha den første siden. Linearisering er det strukturelle svaret på det problemet. Det omarrangerer en PDF slik at et visningsprogram kan gjengi åpningssiden fra et lite prefiks av filen og hente resten ved behov, noe som er grunnen til at Adobe markedsfører funksjonen som "Fast Web View."

Ingenting av dette er et annerledes filformat. En linearisert PDF er en vanlig PDF som en kompatibel leser vil åpne uten spesiell håndtering. Trikset ligger utelukkende i hvordan bytene er ordnet og i to ekstra strukturer filen bærer. ISO 32000-1 spesifiserer hele ordningen i Vedlegg F, og når du først har sett oppsettet, slutter atferden å se ut som magi og begynner å se ut som et bevisst bytte av filrekkefølge for førstegangstegning-latens

Hva linearisering faktisk omarrangerer

En normal PDF kan spre objektene sine i nesten hvilken som helst rekkefølge. Kryssreferansetabellen på slutten av filen er det som får det til å fungere: en leser søker til slutten, leser startxref-pekeren, laster inn xref, og derfra kan den finne hvert objekt etter dets forskyvning. Dette designet er utmerket for lokale filer, der det koster ingenting å søke til slutten, og dårlig for en fil som strømmes inn over et nettverk, der slutten er nøyaktig den delen som ankommer sist. For å gjengi side én trenger en konvensjonell leser sideobjektet, dets innholdsstrøm, skrifttypene det refererer til, og eventuelle bilder det tegner, og i en uordnet fil kan disse sitte hvor som helst, inkludert i den siste megabyten

Linearisering fikser rekkefølgen. Objektene som trengs for å vise den første siden samles i en sammenhengende blokk nær fronten, rett etter en liten hodeseksjon, slik at de ankommer tidlig i bytestrømmen. Alt annet, de gjenværende sidene og ressursene de deler, følger i en forutsigbar sekvens. En andre, komplett kryssreferansetabell lever fortsatt på slutten for lesere som ignorerer optimaliseringen, men en linearisert fil plasserer også en kryssreferanse for første side og parametrene en strømmende leser trenger helt foran. Leseren trenger ikke lenger å nå halen før den kan tegne noe

Førsteside-objektsettet og ordboken for lineariseringsparametere

Det aller første objektet i en linearisert fil, etter %PDF-hodet, er ordboken for lineariseringsparametere. Det er det en strømmende leser ser etter for å avgjøre om optimaliseringen er til stede og hvordan den skal brukes. Ordboken registrerer lengden på hele filen, byteforskyvningen der den viktigste kryssreferanseseksjonen begynner, objektnummeret til den første siden, og plasseringen og lengden på hintstrømmen som følger. Med disse tallene vet en leser, bare fra de første kilobytene, hvor mye den må hente for å vise side én, og hvor den skal lete etter indeksen som lar den hoppe et annet sted

Vedlegg F er strengt på hva "første side" betyr her. Førstesideseksjonen må inneholde selve sideobjektet, dets innholdsstrømmer, og ressursene disse strømmene refererer til, slik at siden er selvtilstrekkelig når det prefikset er lastet ned. Delte ressurser, en skrifttype brukt på hver side, en logo som gjentas i et topptekst, håndteres spesielt: de dukker opp tidlig nok til å betjene den første siden, men flagges som delte slik at leseren ikke henter dem på nytt når den senere gjengir side 30. Det skillet mellom sideprivate og delte objekter er det de fleste hjemmesnekrede "optimalisatorer" gjør feil, og å gjøre det feil er det som produserer en fil som hevder å være linearisert, men som likevel stopper opp

Hintstrømmer: indeksen som gjør sidehopp billige

Å vise side én raskt er bare halve verdien. Den andre halvdelen er å hoppe til en vilkårlig side uten å laste ned alt i mellom, og det er hva hintstrømmene gir. En linearisert fil bærer en hint-tabell for sideforskyvninger og en hint-tabell for delte objekter, lagret som en strøm det refereres til fra parameterordboken. Sideforskyvningstabellen registrerer, for hver side, hvor objektene dens begynner i filen og hvor lange de er. Den delte objekttabellen gjør det samme for ressurser som brukes på tvers av flere sider

Gitt disse tabellene, vil ikke en leser som vil ha side 40, tolke filen sekvensielt. Den konsulterer hint-tabellen for å lære hvilket byteområde side 40 opptar, ber serveren om nøyaktig det området, og gjengir siden når disse bytene ankommer, og trekker inn eventuelle delte ressurser den ikke allerede har, gjennom samme mekanisme. Hintstrømmen er, i praksis, et kart for vilkårlig tilgang lagt over dokumentet, og det er grunnen til at en godt linearisert fil på 500 sider føles responsiv over en treg forbindelse, mens en uoptimalisert en av samme størrelse ikke gjør det

Hvorfor serveren må samarbeide

Linearisering forutsetter at transporten kan levere vilkårlige skiver av filen, og den antakelsen er verdt å sjekke før du gir formatet skylden for dårlige resultater. Mekanismen er HTTP byte-servering: leseren utsteder områdeforespørsler (range requests), og serveren svarer på dem med 206 Partial Content-svar. Hvis serveren ikke annonserer Accept-Ranges: bytes, eller hvis en proxy eller CDN foran den slår sammen områdeforespørsler til fulle overføringer, har leseren ingen måte å hente side 40 isolert, og faller tilbake til å laste ned hele filen. Strukturen inne i PDF-en er da perfekt riktig og fullstendig bortkastet

Dette er feilen som oftest feildiagnostiseres som at "linearisering ikke fungerer." Filen er grei; leveringsveien er det ikke. Før du bygger om et dokument, bekreft med en betinget forespørsel at verten faktisk returnerer delvis innhold for URL-en leseren treffer. Mange statiske verter gjør dette som standard, og mange feilkonfigurerte applikasjonsservere og hurtigbufferlag gjør det ikke

Inkrementelle oppdateringer ødelegger i det stille linearisering

Her er begrensningen som overrasker folk som genererer lineariserte filer riktig og deretter lurer på hvorfor optimaliseringen fordamper. Linearisering er avhengig av ett enkelt, nøye ordnet oppsett med indeksen foran. En inkrementell oppdatering bryter dette ved design. Når et verktøy legger til en signatur, fyller ut et skjemafelt eller legger til en annotasjon gjennom en inkrementell lagring, skriver det ikke om filen. Den legger til de endrede objektene, en ny kryssreferanseseksjon og en ny trailer på slutten, og lar de originale bytene være urørt. Det tillegget er hele poenget med inkrementelle oppdateringer: det er raskt, og det bevarer den tidligere revisjonen for revisjon eller signaturvalidering

Bivirkningen er at filen nå har sine nyeste kryssreferansedata i halen, etter den nøye plasserte førsteside-blokken, og ordboken for lineariseringsparametere foran beskriver et oppsett som ikke lenger samsvarer med filen. En kompatibel leser oppdager avviket og behandler dokumentet som en normal, ikke-linearisert PDF. Fast Web View er borte, selv om den opprinnelige lineariserte strukturen fortsatt sitter der i første halvdel av filen. Hvis du legger til flere oppdateringer, stabler hver av dem nok en revisjon på slutten, og gapet mellom den utdaterte frontindeksen og den virkelige tilstanden utvides

Hvis arbeidsflyten din krever både redigeringer og Fast Web View, følger regelen direkte av strukturen: rediger inkrementelt mens dokumentet er i bevegelse, og re-lineariser deretter én gang på slutten. En full omskriving er det som gjenoppretter oppsettet. I HotPDF-termer betyr det at en pågående redigering går gjennom BeginIncrementalUpdate og SaveIncrementalUpdate, som legger til et delta, mens det avsluttende trinnet laster inn hele dokumentet og serialiserer det på nytt med LoadFromFile etterfulgt av SaveLoadedDocument, som fjerner de akkumulerte gamle revisjonene og avgir ett rent oppsett. Den samme avveiningen dukker opp med objektstrømmer: å aktivere UseObjectStreams sammen med UseXRefStream komprimerer kryssreferansen og pakker objekter tett, noe som hjelper filstørrelsen, men, som ethvert strukturelt valg, må dette brukes under den siste omskrivingen fremfor å boltes fast på en tilføyd revisjon

var
  Pdf: THotPDF;
begin
  Pdf := THotPDF.Create(nil);
  try
    Pdf.LoadFromFile('draft_with_updates.pdf');

    // These choices require a full rewrite to take effect
    Pdf.UseObjectStreams := True;
    Pdf.UseXRefStream := True;
    
    // SaveLoadedDocument flattens the updates and writes a clean structure
    Pdf.SaveLoadedDocument('final_clean.pdf');
  finally
    Pdf.Free;
  end;
end;

HotPDF eksponerer ikke en "lineariserings"-rutine i ett kall, så det praktiske mønsteret er å produsere en ren, fullstendig omskrevet fil og kjøre en dedikert optimalisator over den. Kommandolinjeverktøy håndterer omorganiseringen direkte. qpdf skriver om en fil til linearisert form med et enkelt flagg:

qpdf --linearize final_clean.pdf ready_for_web.pdf

Hvordan du kan se om en fil er linearisert

Stol ikke på filnavnet eller verktøyet som hevder å ha produsert den; verifiser bytene. Den mest direkte sjekken er hodet til filen: åpne den og se etter ordboken for lineariseringsparametere som det første objektet etter hodet, som bærer /Linearized-nøkkelen. En leservendt snarvei er Acrobats dialogboks for dokumentegenskaper, som rapporterer "Fast Web View: Ja" bare når strukturen er genuint til stede og aktuell

For skriptede sjekker rapporterer qpdf både tilstedeværelsen og integriteten til strukturen, noe som er viktig fordi en fil kan bære en lineariseringsordbok som ikke lenger gjenspeiler dens layout, nøyaktig den tilstanden en inkrementell oppdatering etterlater seg:

$ qpdf --check ready_for_web.pdf
checking ready_for_web.pdf
PDF Version: 1.7
File is linearized

Valideringstrinnet er det som tjener til livets opphold. En gjennomgang som bare bekrefter at ordboken eksisterer, vil gladelig velsigne en fil hvis indeks peker på feil forskyvninger; en sjekk som avstemmer hint-tabellene mot de faktiske objektposisjonene er det som forteller deg at optimaliseringen vil holde stand under en ekte lesers områdeforespørsler

Linearisering er fremdeles verdt å bruke på ethvert stort dokument som serveres over nettet, spesielt for mobillesere på ujevne tilkoblinger, og det koster et par prosent av filstørrelsen for den forhåndslastede indeksen. De to tingene å holde styr på, er at strukturen inne i PDF-en og byte-serveringen utenfor begge må være riktige, og at enhver redigering i etterkant opphever optimaliseringen til du skriver filen på nytt. Behandle re-linearisering som det siste trinnet i rørledningen, etter at hver annen endring er på plass. Kryssreferanse-, objektstrøm- og inkrementell-oppdatering-oppførselen beskrevet her er en del av den strukturelle modellen HotPDF Component for Delphi og C++Builder implementerer; for den bredere bakgrunnen for fillayout se hvordan en PDF er strukturert, og for arbeidsflyten med inkrementelle oppdateringer og store filer i kode se prosessering av store PDF-er fra Delphi