HotPDF piše linearizirane PDF datoteke, postavitev, ki jo Acrobat imenuje Fast Web View, prek lastnosti LinearizeOutput na THotPDF. Nastavitev pred BeginDoc povzroči, da HotPDF preuredi dokončan graf objektov, tako da bralnik, ki pozna razpone bajtov, prikaže prvo stran po pridobitvi le vodilnega dela datoteke, namesto da bi moral prenesti celoten dokument. Mehanizem je ISO 32000-1 Priloga F
Razlog, zakaj je to pomembno, ni bleščeč. Navaden PDF postavi svojo tabelo navzkrižnih referenc na konec, zato mora brskalnik doseči zadnji bajt, preden ve, kje je karkoli. Podajte brskalniku 200-stransko skenirano poročilo in uporabnik strmi v vrtavko čez ves prenos, čeprav je hotel le prvo stran. Linearizacija to popravi tako, da plača strošek ob pisanju. Ta članek se osredotoča prav na to pisalno pot, razdelitev, zanko meritve in trde omejitve; konceptualno ozadje o tem, kaj vam Fast Web View prinese, pokriva zgodnejša razlaga linearizacije PDF in Fast Web View
Kaj linearizirana postavitev dejansko zagotavlja
Linearizirana datoteka je navaden PDF z izjemno specifičnim fizičnim vrstnim redom, vsako zagotovilo, ki ga ponuja, pa izvira iz tega vrstnega reda, ne iz kakega novega tipa objekta. HotPDF izda dele v zaporedju, ki ga predpisuje Priloga F: slovar parametrov linearizacije znotraj prvih 1024 bajtov, zgodnjo tabelo navzkrižnih referenc, objekte na ravni dokumenta, primarni tok namigov, prvo stran in njene zasebne objekte, nato preostale strani, nato skupne objekte, nato vse ostalo in nazadnje glavno tabelo navzkrižnih referenc
Razdelitev je izpeljana, ne izjavljena. HotPDF sprehodi graf referenc iz vsakega objekta strani in za vsak posreden objekt zabeleži, koliko strani ga doseže in katera stran ga je dosegla prva. Objekt, ki ga uporablja natanko ena stran, postane zasebni objekt te strani. Objekt, dosežen z več kot eno, postane skupen. Katalog, skupaj z vsem, kar navaja pod /ViewerPreferences, /OpenAction, /Threads in /AcroForm, plus slovar šifriranja, kadar je zaščita aktivna, tvorijo skupino na ravni dokumenta, ki mora priti pred vsem. Vozlišča drevesa strani se namerno zadržijo, da ne onesnažijo odseka prve strani
Slovar parametrov nosi številke, ki jih bralnik potrebuje, preden je prebral kar koli drugega: /L za skupno dolžino datoteke, /H za odmik in dolžino toka namigov, /O za številko objekta prve strani, /E za bajt, kjer se konča odsek prve strani, /N za število strani in /T za odmik vnosa glavne tabele navzkrižnih referenc. Vsaka od teh je odmik v bajtih v datoteko, ki v trenutku, ko jih morate zapisati, še ne obstaja
Zakaj se morajo odmiki v tabeli namigov konvergirati?
Ker številke v slovarju parametrov opisujejo datoteko, ki jih vsebuje, sprememba katere koli od njih pa spremeni datoteko. To je osrednja težava lineariziranega zapisovalnika, in zato HotPDF meri ponovno namesto da bi pisal enkrat. Razširite /T iz 6 mest na 7 in slovar parametrov naraste za bajt; glava naraste; vsak objekt se premakne; glavna tabela navzkrižnih referenc se premakne; /T zdaj potrebuje drugačno vrednost. Postavitev mora doseči fiksno točko, preden se zaveže en sam bajt pravega izhoda
HotPDF to obravnava z omejeno iteracijo. Najprej serializira vsak objekt v štejoč tok, ki beleži dolžino brez ohranjanja bajtov, tako da ima vsak objekt znano serializirano velikost. Nato izvede prehod postavitve, ki dodeli odmike skupini na ravni dokumenta, toku namigov, skupini prve strani, poznejšim skupinam strani, skupni skupini in preostanku ter poroča, kam bi pristala glavna tabela navzkrižnih referenc. Ta rezultat se vrne kot vhod za naslednji prehod. Zanka je omejena na osem poskusov, nekonvergenca pa sproži izjemo namesto da bi ustvarila datoteko z verjetnimi, a napačnimi odmiki
CandidateMainOffset := 0;
for Attempt := 0 to 7 do
begin
CalculateLayout(CandidateMainOffset, FirstXRefData,
HintOffset, EndFirstPage, NewMainOffset);
if NewMainOffset = CandidateMainOffset then
Break;
CandidateMainOffset := NewMainOffset;
end;
if NewMainOffset <> CandidateMainOffset then
raise Exception.Create('Linearization layout did not converge');
Dve podrobnosti preprečita, da bi zanka mlatila v prazno. Slovar parametrov je zapisan v fiksno rezo 384 bajtov, zapolnjeno s presledki, tako da njegova lastna rast nikoli ne more destabilizirati postavitve; če bi besedilo slovarja kdaj preseglo to rezervacijo, HotPDF sproži izjemo namesto tihega premikanja vsega. Po konvergenci HotPDF izvede še en potrjevalni prehod postavitve in ponovno preveri dolžino toka namigov, ker sam tok namigov kodira odmike, ki so bili znani šele, ko se je postavitev umirila. Nagrada za vse to merjenje je, da HotPDF nikoli ne shrani druge kopije dokumenta: ko so odmiki fiksni, se objekti serializirajo neposredno v ciljni tok, s trditvijo ob vsaki meji odseka, ki preveri, da zapisani bajti ustrezajo obljubljenemu odmiku
Vklop iz Delphija
API površina je ena logična vrednost, njena edina zahteva pa je, da jo nastavite pred začetkom generiranja. LinearizeOutput je privzeto False, prehod postavitve pa teče ob zapisu dokumenta, zato dodelitev po EndDoc ne doseže ničesar
var
PDF: THotPDF;
begin
PDF := THotPDF.Create(nil);
try
PDF.FileName := 'fast-view.pdf';
PDF.Version := pdf17;
PDF.LinearizeOutput := True; // must precede BeginDoc
PDF.BeginDoc;
PDF.Canvas.TextOut(72, 72, 'First page');
PDF.EndDoc;
finally
PDF.Free;
end;
end;
Ena razmestitvena past prekaša vse na strani kode. Linearizacija se izplača le, kadar prenosna plast podpira zahteve HTTP Range. Postrezite isto datoteko z opore, ki jo pretaka v celoti, ali s konfiguracije CDN, ki ignorira Range, in kupite si le počasnejšo pisalno pot in večjo datoteko brez koristi za uporabnika. Preverite strežnik, preden preverite kodo
Zakaj linearizacija prevlada nad UseXRefStream in UseObjectStreams?
Ker lineariziran zapisovalnik potrebuje, da ima vsak objekt svoj neposredno naslovljiv odmik v bajtih, obe teh funkciji pa mu to vzameta. HotPDF zato izda tradicionalne besedilne tabele navzkrižnih referenc in nezapakirane posredne objekte, kadar koli je LinearizeOutput omogočen, tudi če je klicatelj nastavil tudi UseXRefStream ali UseObjectStreams. To je namerna prevlada, ne konflikt, ki bi ga morali sami razreševati
Utemeljitev sledi iz tabel namigov. Tabela namigov opisuje, kje se odsek strani začne in kako dolg je, tako da bralnik lahko zahteva natanko ta razpon. Objekt, zapakiran v vsebnik /ObjStm, sploh nima neodvisnega odmika; obstaja le kot rezina znotraj drugega stisnjenega toka, ki ga je treba pridobiti in napihniti kot celoto. Če ste stavili na tokove objektov za velikost datoteke, vedite, da linearizacija in kompresija tukaj vlečeta v nasprotni smeri, kompromis pa preberite v spremljevalnem članku o tokovih objektov in postopnih posodobitvah v HotPDF. Ista napetost oblikuje hibridne referenčne datoteke, ki obstajajo natanko zato, da starejši bralniki še naprej delujejo poleg tabel na osnovi tokov, kot je opisano v članku o hibridnih tokovih navzkrižnih referenc v PDF-jih, ustvarjenih z Office
Obstaja tudi spodnja meja različice. Linearizacija zahteva PDF 1.2 ali novejšo. Če je izbrana različica starejša, jo HotPDF samodejno dvigne, razen če je nastavljen StrictVersionLock, v tem primeru pisanje sproži izjemo namesto tihega povišanja dokumenta, ki ste ga namerno pripeli
Zid pri 4 GiB in zakaj ga HotPDF zavrne, namesto da bi ga obrezal
Tabele namigov za linearizacijo shranjujejo odmike kot 32-bitne vrednosti, zato lineraizirana datoteka ne more nasloviti ničesar na ali preko 4 GiB, HotPDF pa tak izhod zavrne z izrecno izjemo namesto da bi zapisal datoteko z zavitimi odmiki. Omejitev ni izbira izvedbe HotPDF; je širina polj, ki jih opredeljuje Priloga F
Preverjanje je uveljavljeno na treh mestih, vsa tri pa so pomembna. HotPDF potrdi vsak objekt, ko je znana njegova serializirana dolžina, potrdi dolžino vsakega odseka strani med gradnjo vnosov namigov in potrdi končno dolžino datoteke, ko je izmerjena glavna tabela navzkrižnih referenc. Zgodnja odpoved je celotna bistvo: tabela namigov s tiho odrezanim odmikom ustvari datoteko, ki se pravilno odpre v bralniku, ki jo prenese v celoti, odpove pa le pri odjemalcu z razponi bajtov, ki mu je linearizacija sploh namenjena, kar je najslabši možen način odpovedi, ker ga vaš testni bralnik nikoli ne ponovi. Če ustvarjate izhod v velikosti več gigabajtov, linearizacija ni pravo orodje, smer, v katero je treba pogledati, pa je pristop pretakanja, opisan v opombah o Direct File API za delovne tokove velikih PDF-jev
Zaznavanje linearizacije na naloženi datoteki
THotPDF.IsLoadedLinearized poroča, ali je bil trenutno naložen dokument že zapisan v linearizirani obliki, in odgovarja iz posnetka, zajetega pred razčlenjevanjem, ne iz živega toka. HotPDF prebere prvih 1024 bajtov od pozicije nič izvornega toka, jih pregleda za prvo ključno besedo obj in nato za vnos /Linearized z vrednostjo 1, ter predpomni logični rezultat
var
PDF: THotPDF;
PageCount: Integer;
begin
PDF := THotPDF.Create(nil);
try
PageCount := PDF.LoadFromFile('incoming.pdf');
if (PageCount > 0) and (not PDF.IsLoadedLinearized) then
Writeln('Source is not Fast Web View ready');
finally
PDF.Free;
end;
end;
Dve omejitvi v tem opisu sta nosilni. Zaznavanje se ne more zanašati na položaj toka, ker ga je razčlenjevalnik do trenutka, ko koda aplikacije postavi vprašanje, že premaknil, in ne more ponovno brati na zahtevo, ker LoadFromFile ob koncu nalaganja sprosti notranji izvorni tok. Od tod zasnova zajema pred razčlenjevanjem in predpomnjenja. Pregled je tudi namerno dobeseden glede vrednosti: sprejeta je le /Linearized 1 ali številčno enakovredna oblika z ničelnim delom, saj datoteka, katere slovar parametrov pravi kaj drugega, ne daje obljube Priloge F
Delphi past z zapisi, ki jo je vredno prevzeti
Lokalni zapisi, ki vsebujejo dinamična polja, inicializirajo svoja upravljana polja in nič drugega, in če imate poleg polja navadno polje Count, ga morate počistiti sami. To je med razvojem ugriznilo delitev linearizacije, in gre za vrsto hrošča, ki stane dan natanko zato, ker ga ena platforma skrije
type
THPDFLinearIndexList = record
Values: THPDFIntegerArray; // managed field: cleared for you
Count: Integer; // plain field: whatever was on the stack
end;
// Required, not cosmetic:
Part4 := Default(THPDFLinearIndexList);
Part6 := Default(THPDFLinearIndexList);
Part8 := Default(THPDFLinearIndexList);
Part9 := Default(THPDFLinearIndexList);
Polje dinamičnega polja je s štetjem referenc, zato ga prevajalnik ničla. Count zraven njega je navadno celo število brez takega jamstva, neinicializiran Count pa pošlje prvi dodatek na poljuben indeks. Pod Win32 je mesto na skladu naključno imelo ničlo, dodatek je pristal na indeksu 0, vsak test pa je uspel. Pod Win64 je ista koda pisala mimo konca polja. Lekcija posplošuje daleč onkraj linearizacije: kadar zapis meša upravljana in neupravljana polja, dodelite Default(TRecord) in nehajte ugibati, katera polja pokriva prevajalnik, in nikoli ne jemljite zelenega Win32 zagona kot dokaz, da je inicializacija pravilna
Člane LinearizeOutput in IsLoadedLinearized, opisane tukaj, dostavlja standardna komponenta HotPDF Component za Delphi in C++Builder; stran izdelka nosi celoten referenčni pregled lastnosti, vključno s pravili interakcije s tokovi navzkrižnih referenc, tokovi objektov in zaklepanjem različice