Manjkajoči glif v PDF ni napaka. Proizvajalec zahteva znak, ki ga izbrana pisava ne more preslikati, pisava vrne indeks glifa nič in datoteka, ki pride ven, je strukturno veljavna, se odpira povsod in pokaže prazen kvadrat tam, kjer bi moralo biti ime ali znesek. Nihče v generirajočem cevovodu tega ne izve. Prejemnik pa. HotPDF zapre to zanko z TrackUnresolvedGlyphs: vklopite ga in pot risanja besedila zapiše vsako kodno točko, katere iskanje glifa se razreši v indeks nič, sproži OnUnresolvedGlyph enkrat na unikatno najdbo s kodno točko, pisavo, na kateri je odpovedala, skripto, ki ji pripada, in predlogom pisav, ki bi jo pokrile
Zaznavanje je polovica odgovora. Druga polovica je SetFontFallbackChain, ki registrira urejen seznam pisav po skripti, tako da se običajni primeri razrešijo sami in samo prave vrzeli dosežejo vaš ročaj. Skupaj pretvorita razred napak, ki so ga prej poročale stranke, v pregled ob času gradnje
Zakaj manjkajoči glif ne sproži ničesar?
Ker ISO 32000 ne postavlja nobene obveznosti na proizvajalca, da preveri pokritost, in indeks glifa nič je legitimen glif. Je .notdef, katerega konturo izbere oblikovalec pisave: običajno prazen ali votel pravokotnik, včasih sploh nič. Pregledovalnik, ki ga nariše, se obnaša pravilno. Izvlečenje besedila lahko celo vrne prave znake, ker je preslikava /ToUnicode zapisana iz izvornega besedila in ne iz kontur, zato samodejni preizkus povratnega toka bo vesel prepeljal dokument, katerega vidno besedilo ima luknje
Praktična posledica je, da je treba pokritost preveriti v trenutku risanja, ko knjižnica še ve, katera kodna točka je bila zahtevana in kateri glif je pisava dejansko ponudila. Potem je informacija odšla
Zaznavalnik mora gledati stanje podnabora in ne konteksta naprave
Tukaj je prva implementacija šla narobe in razlog je vredna razumevanja, ker velja za vsak pregled pokritosti, privit na besedilni cevovod. HotPDF ima dve besedilni poti. Ena izda skozi registrirano pisavo TrueType Unicode s preslikavo znakov v pomnilniku, zgrajeno ob času registracije. Druga je podedovana pot GDI, ki ustvari svež kontekst naprave in ročaj pisave na tek znakov
Soditi pokritost iz poti GDI je brezupno. Njegova preslikava ni preslikava, ki konča v izdanem toku vsebine, in nista sinhronizirana, zato zaznavalnik, ki bere rezultate GDI, poroča celoten natisljivi razpon ASCII kot nerazrešen. Avtoritativni odgovor živi v registrirani pisavi: preslikava znakov, ki jo razčleni RegisterUnicodeTTF, povprašana skozi GetUnicodeGlyphForCodepoint. Zaznavalnik je zato ograjen na stanje pripravljenosti podnabora in ne na kateri koli pogoj GDI, in preprosto ne teče na dokumentih, ki nikoli niso registrirali pisave Unicode, kar je pravilno, ker so ti dokumenti omejeni na standardna kodiranja vseeno
Druga past sedi ob njemu. Ime družine GDI pisave in ime PostScript, izvlečeno iz binarne pisave ob registraciji, sta različna niza in ne na način, ki ga lahko normalizirate: družina, imenovana Arial Unicode MS, nosi ime PostScript ArialMT. Vsaka vrata, zapisana kot »ali je trenutno izbrana pisava tista, ki smo jo registrirali«, primerjana po imenu, so mrtva koda, ki nikoli ne sproži. Ograjite na stanje, nikoli na imena pisav
Ne testirajte zaznavalnika glifov z emodžiji
Očiten testni primer je nasmehajoči obraz in vas bo prepričal, da je zaznavalnik pokvarjen. Pogoste kodne točke emodžijev v astralnih ravninah se razrešijo skozi pot sinteze zasebne rabe, ki jih preslika v indeks glifa neposredno, zato nikoli ne dosežejo splošne veje pokritosti. Zaznavalnik se obnaša pravilno in test meri napačno pot
Uporabite namesto tega nedodeljeno kodno točko. U+0378 je trajno nedodeljen v Unicode, zato ga nobena pisava ne more legitimno preslikati, in vadi natanko vejo, ki jo želite preveriti. To razlikovanje med »funkcija je pokvarjena« in »test je izbral vhod, ki obide funkcijo« stale realne ure in nedodeljene kodne točke so najcenejši način izogibanja
type
TCoverageAudit = class
private
FFindings: TStringList;
public
procedure Handle(Sender: TObject;
const Info: THPDFUnresolvedGlyphInfo);
property Findings: TStringList read FFindings;
end;
procedure TCoverageAudit.Handle(Sender: TObject;
const Info: THPDFUnresolvedGlyphInfo);
begin
// Sproži enkrat na unikatno kodno točko, ne enkrat na pojavitev
FFindings.Add(Format('U+%.4X missing in %s (script %d), try: %s',
[Info.CodePoint, String(Info.FontName), Ord(Info.Script),
String(Info.SuggestedFonts)]));
end;
// Povezovanje v generirajoče opravilo
Pdf := THotPDF.Create(nil);
try
Pdf.TrackUnresolvedGlyphs := True;
Pdf.OnUnresolvedGlyph := Audit.Handle;
Pdf.RegisterUnicodeTTF('C:\Windows\Fonts\arial.ttf');
Pdf.BeginDoc;
Pdf.CurrentPage.SetFont('Arial', [], 11);
Pdf.CurrentPage.TextOut(50, 720, 0, CustomerName);
Pdf.EndDoc;
if Audit.Findings.Count > 0 then
// Spodletite opravilo namesto pošiljanja strani s kvadrati nanjo
raise Exception.Create(Audit.Findings.Text);
finally
Pdf.Free;
end;
Verige zasilnih rešitev so na skripto in ne na pisavo
Razlog, zakaj je zasilna rešitev obsegana po skripti in ne po izvorni pisavi, je, da se vrzeli pokritosti zbirajo po pisavnem sistemu. Latinska besedilna pisava manjka Devanagari, tajščino, Han in emodžije vse naenkrat in zamenjava za vsakega je druga pisava. Deklariranje ene verige na skripto torej opisuje pravo namestitev: ena latinska pisava za telo besedila, ena pisava CJK, ena pisava emodžijev, ena vse-zajemajoča
// THPDFFontScript pokriva hfsCommon, hfsLatin, hfsGreek, hfsCyrillic,
// hfsHebrew, hfsArabic, hfsIndic, hfsSoutheastAsian, hfsCJK, hfsKana,
// hfsHangul, hfsEmoji in hfsOther
Pdf.SetFontFallbackChain(hfsCJK,
['Microsoft YaHei', 'SimSun', 'Yu Gothic']);
Pdf.SetFontFallbackChain(hfsArabic, ['Segoe UI', 'Arial']);
Pdf.SetFontFallbackChain(hfsEmoji, ['Segoe UI Emoji']);
Pdf.SetFontFallbackChain(hfsOther, ['Arial Unicode MS']);
Zasilna rešitev in zaznavanje sta komplementarna in ne alternativna. Verige obravnava pokritost, ki ste jo predvideli; zaznavalnik poroča pokritost, ki je niste, kar na sistemu, ki obdeluje poljubne podatke strank, je zanimiva polovica. Upoštevajte, da zamenjava pisave spremeni metrike, zato se lahko odstavek, ki pade nazaj, preoblikuje; če je razporeditev pomembna, je zapiranje in vedenje podnaborov nadomestne pisave vredno branja v članku o zaprtju podnabora pisave, skripte, ki potrebujejo preurejanje ali spajanje, pa obravnava stopnja oblikovanja, opisana v oblikovanju besedila kompleksnih skript
Kako vgrajiti vedenje naknadno brez tveganja obstoječe poti
Ista izdaja je dodala podedovano zasilno rešitev tabele kern za razmik parov in način, kako je bila obsegana, je vzorec vreden kopiranja. Namesto dodajanja nove točke odločanja logiki kerninga visi zasilna rešitev na veji zgodnjega izstopa, ki je že obstajala za pisave brez tabele GPOS. Moderna pisava z GPOS je nikoli ne doseže, zato je njeno vedenje nespremenjeno po zasnovi in ne po testiranju. Poti, ki ne registrirajo pisave Unicode, proizvedejo dva ničelna odmika, zato so tudi one nespremenjene
To je splošna oblika nizko tveganega naknadnega vgrajevanja v zreli knjižnici upodabljanja: najdite vejo, ki trenutno ne proizvede ničesar, in dajte novo vedenje noter. Pretvori »verjamemo, da to ni povrnilo ničesar« v »to ne more povrniti ničesar«, kar je veliko boljša stvar za povedati o besedilnem motorju, skozi katerega gredo tuji računi
Naredite vrata, ne dnevnik
Najdbe pokritosti so samo koristne, če na njih kaj odpove. V storitvi generiranja dokumentov je produktivna ureditev obdržati sledenje vklopljeno v nočnem regresijskem opravilu proti korpusu pravih imen strank, naslovov in opisov produktov, in spodleteti opravilo na vsaki najdbi. Ker dogodek sproži enkrat na unikatno kodno točko in ne enkrat na pojavitev, izhod ostane dovolj majhen za branje, tudi ko manjka cela skripta
V produkciji je isti ročaj bolje uporabljen kot telemetrija: zapišite kodno točko in pisavo, ostanite služeč dokument in pustite agregatu povedati, katero skripto dodati naslednjo v nabor pisav namestitve. Vedenje upodabljanja za vgrajene in nadomestne pisave je pokrito naprej v upodabljanju glifov vgrajenih pisav, polni seznam lastnosti, vključno z TrackUnresolvedGlyphs, pa je dokumentiran na strani produkta HotPDF Delphi PDF component