Trije rastrirniki lahko preberejo isti PDF in se ne strinjajo o tem, kaj piše. Vgrajeni pogon v PDFlibPas je tisti, ki se pošlje brez dodatnih datotek in vse upodobi kompetentno, zato si zasluži privzeto mesto. Cairo prinaša drugačen cevovod za prosojnost in mehčanje robov (anti-aliasing) ter je običajno tisti, po katerem ljudje posežejo, ko so mehke maske ali mešalni načini drugje napačni. PDFium vsebuje Chrome-ovo kodo za upodabljanje, zato je stran, ki je videti pravilna v brskalniku, običajno pravilna tudi pod PDFiumom, za ceno precej velikega DLL-ja in bitnosti, ki jo zahteva. Nobeden od treh ni absolutno pravilen. Pravilnost je odvisna od dokumenta, edini pošten način, da ugotovite, kateri pogon najbolje obravnava določen korpus, pa je, da ta korpus zaženete skozi vsakega od njih.
To je razlog, da obravnavamo pogon kot izbiro med delovanjem in ne ob gradnji. PDFlibPas, knjižnica za PDF za Delphi in C++Builder podjetja losLab, postavlja vse tri za enotno površino za upodabljanje, tako da odločitev stane eno celo število namesto koda. Preostanek se zmanjša na varno izbiro med njimi, potrditev, katere pogone dejansko vsebuje nameščena binarna datoteka, in preprečevanje, da bi stanje upodabljanja tiho zastrupilo naslednje opravilo.
Trije rastrirniki za eno klicno površino
Knjižnica označuje svoje pogone s številkami. Pogon 1 je vgrajeni upodabljalnik, privzeti, z možnostmi glajenja GDI+ v sistemu Windows. Pogon 2 je Cairo, pogon 3 pa PDFium, oba izbrana med delovanjem prek SelectRenderer. Zunanja pogona se naložita iz datotek DLL, katerih poti navedete s SetCairoFileName in SetPDFiumFileName pred njuno izbiro. Ne glede na to, kateri pogon je aktiven, delo poteka prek istih klicev: RenderPageToFile, RenderPageToStream, RenderDocumentToFile. Preklop med pogoni premakne le eno številko, preostali del vaše kode za upodabljanje pa tega sploh ne opazi.
Ciljni model seže daleč čez bitne slike. Razred upodabljalnika cilja tudi na metadatoteke (WMF, EMF, EMF+), EPS, neposredne kontekste naprav (device contexts), tiskalnike in HTML5, pri čemer se Cairo in PDFium prikažeta kot dodatni cilji le, če sta bila vključena ob prevajanju. Rastrski izhod je področje, kjer se trije pogoni najbolj vidno razlikujejo, zato primeri tukaj uporabljajo to možnost.
Nikoli ne predpostavljajte, da pogon obstaja: preverite ob zagonu
Cairo in PDFium sta funkciji pogojnega prevajanja, kar pomeni, da je binarna datoteka lahko zgrajena povsem brez njiju. Ko se to zgodi, zahteva po pogonu 2 ali 3 ne sproži ničesar. SelectRenderer preprosto vrne vrednost, ki se razlikuje od zahtevanega ID-ja, koda, ki ignorira povratno vrednost, pa nadaljuje z upodabljanjem s tistim pogonom, ki je bil že aktiven. Obramba je zagon preverjanja ob štartu, ki prosi vsak pogon za identifikacijo in zabeleži odgovor:
function ProbeEngines(PDF: TPDFlib): string;
begin
Result := 'built-in'; // engine 1 is always present
if (PDF.SetCairoFileName('cairo.dll') = 1) and (PDF.SelectRenderer(2) = 2) then
Result := Result + ', cairo';
if (PDF.SetPDFiumFileName('pdfium.dll') = 1) and (PDF.SelectRenderer(3) = 3) then
Result := Result + ', pdfium';
PDF.SelectRenderer(1); // restore the default before real work
end;
Zaženite to preverjanje enkrat ob zagonu in zapišite njegov rezultat v dnevnik poleg vsakega opravila upodabljanja. Najpogostejše vprašanje, ko stranka poroča o razliki v upodabljanju, je, katere pogone njihova namestitev dejansko vsebuje, enovrstični odgovor v dnevniku pa to reši brez seje na daljavo. Koristen stranski učinek: če SetPDFiumFileName vrne 0, že veste, da je težava v DLL-ju (napačna pot, napačna bitnost, manjkajoča odvisnost) in ne v binarni datoteki, prevedeni brez podpore za PDFium, saj klic poti ni razrešil ničesar, še preden se je SelectRenderer sploh izvedel.
Deset izhodnih formatov za enim celim številom Options
Parameter Options pri klicih upodabljanja izbere izhodno kodiranje: 0 je BMP, 1 JPEG, 2 WMF, 3 EMF, 4 EPS, 5 PNG, 6 GIF, 7 TIFF, 8 EMF+ in 9 HTML5. PNG (5) is the sensible default for previews and archival page images. JPEG (1), paired with SetJPEGQuality, is the better pick for photographic scans where file size matters more than crisp edges.
Eden od formatov skriva zahtevo glede ciljnega toka. Pot BMP najprej zapiše podatke o sliki, nato pa se vrne na odmik 0x26, da popravi polja ločljivosti v glavi. Če to usmerite v tok, ki omogoča le premikanje naprej (forward-only stream), stiskalni ovoj ali omrežno vtičnico, klic spodleti na način, ki je videti kot napaka pogona, vendar ni. Ko se ne-seekable cilju ni mogoče izogniti, namesto tega upodobite PNG ali pa BMP prenesite prek pomnilniškega toka in ga kopirate naprej, ko je zaključen.
DPI, ki ga posredujete, ni DPI, ki ga dobite
Vsak klic upodabljanja sprejme argument DPI, vendar je ločljivost, ki jo dejansko dobite, ta vrednost, pomnožena z globalnim merilom upodabljanja (render scale). SetRenderScale se začne pri 1.0, in ko ga spremenite, se novi faktor tiho uporabi pri vsakem kasnejšem upodabljanju na tej instanci:
PDF.SetRenderScale(2.0); // every later render is doubled
PDF.RenderPageToFile(150, 1, 5, 'p1.png'); // effectively 300 DPI
PDF.SetRenderScale(1.0); // reset, or your thumbnails arrive huge
Enaka lepljivost velja za SetRenderCropType in nastavitev kakovosti JPEG. V storitvi, ki ustvarja sličice, predoglede in slike v ločljivosti za tiskanje iz ene skupne instance, te preostale nastavitve tiste, ki dejansko stojijo za občasnimi težavami tipa "sličice so nenadoma velike 40 MB". Dva čista izhoda: ponastavite ustrezno stanje na začetku vsake operacije ali pa namenite ločeno instanco za vsak izhodni profil, da nič ne uhaja med njimi.
Fino nastavljanje privzetega pogona pred izbiro drugega
Presenetljiv delež zahtev po "drugem pogonu" se izkaže za težave z nastavitvami v preobleki. Vgrajeni upodabljalnik izpostavi svoje glajenje prek SetGDIPlusOptions in širše družine SetRenderOptions, metoda SetGDIPlusFileName pa vam omogoča, da ga usmerite v določen čas izvajanja GDI+, ko namestitveno okolje pošilja nenavadnega. Nazobčane črte pri nizkem DPI, zamegljeno besedilo v sličicah, pasovi čez gradiente: vse to se odziva na te gumbe, njihovo spreminjanje pa v namestitvenem programu ne stane nič. Nasprotno pa dodajanje Caira ali PDFiuma pomeni pošiljanje več datotek DLL, sledenje drugi ali tretji bitni različici in obveznost njihovega posodabljanja.
Tako ima pritožba glede kakovosti naraven vrstni red postopkov. Najprej jo poustvarite pri strankinem natančnem DPI in merilu, saj v polovici primerov razlika izpine, ko se ta dva ujemata. Nato poskusite z možnostmi glajenja vgrajenega pogona. Šele nato postavite stran vzporedno med pogoni, pri čemer so vse ostale spremenljivke konstantne: upodobite jo v PNG prek pogonov 1, 2 in 3 pri enakem DPI in priložite vse tri. Običajno se dva od treh strinjata, ta večina pa vam pove, ali je posebnež dokument, ki se interpretira drugače, ali pa so napačna vaša lastna pričakovanja. Tri konkretne slike rešijo spor glede "napačnega upodabljanja" veliko hitreje kot odstavek pridevnikov.
Veriga izjem, ki pojasnjuje samo sebe
Ko sta preverjanje in disciplina stanja vzpostavljena, je sama veriga izjem kratka. Zaznavanje napake temelji na LastRenderError, ki vsebuje besedilo sporočila pogona za zadnje upodabljanje in je prazno, ko je upodabljanje uspelo:
procedure RenderPageWithFallback(PDF: TPDFlib; Page: Integer; const OutFile: string);
begin
PDF.SelectRenderer(1); // built-in first
PDF.RenderPageToFile(200, Page, 5, OutFile); // 5 = PNG
if PDF.LastRenderError = '' then Exit;
LogEngineFailure('built-in', Page, PDF.LastRenderError);
if PDF.SelectRenderer(3) = 3 then // PDFium as the heavy fallback
begin
PDF.RenderPageToFile(200, Page, 5, OutFile);
if PDF.LastRenderError = '' then Exit;
LogEngineFailure('pdfium', Page, PDF.LastRenderError);
end;
raise Exception.CreateFmt('Page %d failed on all available engines', [Page]);
end;
Dve oblikovalske točki imata tukaj svojo težo. Veriga beleži, zakaj je prišlo do preklopa, saj je vrstica v dnevniku, ki pravi "ta stran je preklopila na PDFium od izdaje 3.7", regresijski signal, ki ga želite spremljati v monitoringu in ne izgubiti. Vrstni red preklopa je politika, ki jo je vredno izbrati glede na delovno obremenitev. Vgrajeni pogon se namesti brez dodatnih DLL-jev, zaradi česar je primeren za prvi poskus v večini namestitev, medtem ko so dokumenti z veliko skupinami prosojnosti ali nenavadnim senčenjem običajno razlog, da ekipa sploh vključi alternativni pogon. Noben pogon ni na splošno najhitrejši, kar je bistvo izbire na klic: primerjajte delovanje vsakega na vzorcu vaših resničnih dokumentov pri vašem resničnem DPI in to meritev ponovite vsakič, ko se spremenijo DLL-ji ali mešanica dokumentov. Korpus vsakič zmaga v razpravi.
Preko posameznih strani: paketi TIFF in konteksti naprav v živo
Dva sorodna klica dopolnjujeta orodjarno. RenderAsMultipageTIFFToFile upodobi izraz obsega strani neposredno v večstransko datoteko TIFF, kar je naravna oblika za arhivske predaje sistemom za upravljanje dokumentov, ki so starejši od PDF-ja. RenderPageToDC riše neposredno na kontekst naprave Windows za kontrole predogleda, pri čemer ga krmili lastna trojica nastavitev (SetRenderDCOffset, SetRenderDCErasePage in vrsta obrezovanja), ki potrebujejo enako disciplino ponastavitve kot faktor merila. Predogled na zaslonu in upodabljanje tiskalne poti vsebujeta dovolj lastnih pasti, da si zaslužita namenski članek, povezan spodaj.
Navada, ki jo je vredno ohraniti: ker SelectRenderer vpliva na vsak kasnejši klic na instanci, lahko eno trmasto stran poskusite znova na drugem pogonu, medtem ko preostanek dokumenta ostane na privzetem. Za risanje predogledov, izbiro tiskalnika in obravnavo DevMode nadaljujte s člankom Predogled tiskanja in kontekst naprave. Ko upodabljanje hrani visoko-zmogljiv cevovod velikih datotek, se pristop z ročaji v priročniku za neposreden dostop naravno ujema z upodabljanjem strani prek DARenderPageToFile. Pakiranje pogonov, podprti formati in preizkusne različice so podrobno opisani na produktni strani PDFlibPas.