Tehnički članak

Otkrivanje nedostajućih PDF glifova u trenutku crtanja

Nedostajući glif u PDF-u nije pogreška. Proizvođač traži znak koji odabrani font ne može preslikati, font vraća indeks glifa nula, i datoteka koja izađe strukturno je valjana, otvara se svugdje i prikazuje prazan okvir tamo gdje treba biti ime ili iznos. Nitko u cjevovodu generiranja ne saznaje. Primatelj da. HotPDF zatvara tu petlju s TrackUnresolvedGlyphs: uključite ga i put crtanja teksta zabilježi svaku točku koda čije se traženje glifa rješava u indeks nula, aktivirajući OnUnresolvedGlyph jednom po jedinstvenom nalazu s točkom koda, fontom na kojem je pala, pismom kojem pripada i prijedlogom fontova koji bi je pokrili

Otkrivanje je pola odgovora. Druga polovica je SetFontFallbackChain, koja registrira uređeni popis fontova po pismu, tako da se uobičajeni slučajevi riješe sami i da do vašeg rukovatelja dopru samo stvarni jazovi. Zajedno pretvaraju klasu defekata koju su nekad javljali kupci u provjeru u vremenu izgradnje

Zašto nedostajući glif ne baca ništa?

Zato što ISO 32000 ne postavlja obvezu na proizvođača da provjeri pokrivenost, i indeks glifa nula je legitimni glif. To je .notdef, čiji oblik odabire dizajner fonta: obično prazan ili šuplji pravokutnik, ponekad ništa. Preglednik koji ga crta ponaša se ispravno. Izdvajanje teksta može čak vratiti ispravne znakove, jer se preslikavanje /ToUnicode piše iz izvornog teksta, a ne iz oblika, pa automatizirana provjera povratnog putanja rado će propustiti dokument čiji vidljivi tekst ima rupe

Dijagram zašto nedostajući PDF glif ostaje tih dok glif nula crta prazan okvir a ToUnicode izdvajanje prolazi provjere povratne putanje
Glif nula legitimni je .notdef odgovor, a /ToUnicode piše se iz izvornog teksta, pa se o jazu u cjevovodu ništa ne doznaje

Praktična posljedica jest da pokrivenost treba provjeriti u trenutku crtanja, kada knjižnica još zna koja je točka koda tražena i koji je glif font stvarno ponudio. Poslije je informacija nestala

Otkrivač mora promatrati stanje podskupa, ne kontekst uređaja

Ovdje je prva implementacija pogriješila, i razlog vrijedi razumjeti jer se primjenjuje na svaku provjeru pokrivenosti pričvršćenu na tekstualni cjevovod. HotPDF ima dva tekstualna puta. Jedan emitira kroz registrirani Unicode TrueType font s mapom znakova u memoriji izgrađenom u trenutku registracije. Drugi je naslijeđeni GDI put koji stvara svjež kontekst uređaja i handle fonta po nizu znakova

Procjenjivati pokrivenost iz GDI puta beznadno je. Njegovo preslikavanje nije preslikavanje koje završi u emitiranom toku sadržaja, i njih dvoje nisu usklađeni, pa otkrivač koji čita GDI rezultate javlja cijeli ispisiv ASCII raspon kao neriješen. Autoritativni odgovor živi u registriranom fontu: mapa znakova koju RegisterUnicodeTTF raščlanjuje, ispitivana kroz GetUnicodeGlyphForCodepoint. Otkrivač je dakle ograničen na stanje spremnosti podskupa, a ne na bilo koji GDI uvjet, i jednostavno ne radi na dokumentima koji nikad nisu registrirali Unicode font, što je ispravno jer su ti dokumenti ionako ograničeni na standardna kodiranja

Druga zamka sjedi uz nju. GDI ime obitelji fonta i PostScript ime izdvojeno iz binarne datoteke fonta u trenutku registracije različiti su nizovi, i to na način koji ne možete normalizirati: obitelj nazvana Arial Unicode MS nosi PostScript ime ArialMT. Svaka grana napisana kao "je li trenutno odabrani font onaj koji smo registrirali", uspoređivana imenom, mrtav je kôd koji se nikad ne aktivira. Ograničavajte na stanje, nikad na imena fontova

Tok otkrivanja neriješenih glifova u HotPDF-u prikazuje granu stanja podskupa, traženje GetUnicodeGlyphForCodepoint i povezivanje događaja OnUnresolvedGlyph
Pokrivenost se procjenjuje iz registra Unicode mape fonta umjesto iz GDI-ja, a svaka jedinstvena točka koda aktivira jedan događaj s prijedlogom fonta

Ne testirajte otkrivač glifova emojijem

Očiti testni slučaj jest nasmijano lice, i uvjerit će vas da je otkrivač pokvaren. Uobičajene točke koda emojija u astralnim ravninama rješavaju se kroz put privatne sinteze koji ih preslikava u indeks glifa izravno, pa nikad ne dosežu opću granu pokrivenosti. Otkrivač se ponaša ispravno, a test mjeri pogrešan put

Koristite dodijeljenu točku koda umjesto toga. U+0378 trajno je nedodijeljen u Unicodeu, pa ga nijedan font legitimno ne može preslikati, i vježba točno granu koju želite provjeriti. Ta razlika između "značajka je pokvarena" i "test je odabrao unos koji zaobilazi značajku" košta stvarnih sati, a nedodijeljene točke koda najjeftiniji su način da to izbjegnete

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
  // Aktivira se jednom po jedinstvenoj točki koda, ne jednom po pojavi
  FFindings.Add(Format('U+%.4X missing in %s (script %d), try: %s',
    [Info.CodePoint, String(Info.FontName), Ord(Info.Script),
     String(Info.SuggestedFonts)]));
end;

// Povezivanje u posao generiranja
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
    // Oborite posao umjesto isporuke stranice s okvirima
    raise Exception.Create(Audit.Findings.Text);
finally
  Pdf.Free;
end;

Lanci povratka su po pismu, ne po fontu

Razlog zbog kojeg je povratak opsegnut pismom, a ne izvornim fontom, jest to da se jazovi pokrivenosti skupljaju po sustavu pisanja. Font latiničnog teksta nedostaje devanagari, tajski, han i emoji, sve odjednom, i zamjena za svaki je drugi font. Jedan lanac po pismu dakle opisuje stvarno raspoređivanje: jedan latinički font za tijelo teksta, jedan CJK font, jedan emoji font, jedan za sve ostalo

Dijagram zamjenskih fontova po pismu koji preslikava pisma hfsCJK, hfsArabic, hfsEmoji i hfsOther na uređene lance zamjenskih fontova u HotPDF-u
Svako pismo dobiva svoj uređeni lanac, pa latinički font tijela koji nedostaje han, arapski ili emoji pada dalje na font koji ih pokriva
// THPDFFontScript pokriva hfsCommon, hfsLatin, hfsGreek, hfsCyrillic,
// hfsHebrew, hfsArabic, hfsIndic, hfsSoutheastAsian, hfsCJK, hfsKana,
// hfsHangul, hfsEmoji i 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']);

Povratak i otkrivanje komplementarni su umjesto alternativa. Lanci rukuju pokrivenošću koju ste predvidjeli; otkrivač javlja pokrivenost koju niste, a na sustavu koji obrađuje proizvoljne podatke kupaca to je zanimljiva polovica. Imajte na umu da zamjena fonta mijenja metrike, pa odlomak koji padne na povratak može se ponovno prelamati; ako raspored važi, ponašanje zatvaranja i podskupova zamijenjenog fonta vrijedi pročitati u članku o zatvaranju podskupa fontova, a pisma koja trebaju preuređenje ili povezivanje rukuje faza oblikovanja opisana u oblikovanju teksta složenih pisama

Kako dograditi ponašanje bez rizika za postojeći put

Isto izdanje dodalo je naslijeđeni povratak tablice kern za razmak parova, i način na koji je bio opsegnut obrazac je vrijedan preslikavanja. Umjesto dodavanja nove točke odluke u logiku kerninga, povratak visi na grani ranog izlaska koja je već postojala za fontove bez tablice GPOS. Moderni font s GPOS-om nikad do nje ne dođe, pa mu se ponašanje ne mijenja po konstrukciji umjesto po testiranju. Putovi koji ne registriraju Unicode font proizvode dva nultog pomaka, pa su i oni nepromijenjeni

To je opći oblik niskorizične dogradnje u zreloj knjižnici prikazivanja: pronađite granu koja trenutno ne proizvodi ništa i smjestite novo ponašanje tamo. To pretvara "vjerujemo da ovo ništa nije pokvarilo" u "ovo ništa nije moglo pokvariti", što je mnogo bolja stvar reći o tekstualnom motoru kroz koji prolaze tuđi računi

Učinite od toga granu, ne dnevnik

Nalazi pokrivenosti korisni su samo ako na njima nešto padne. U servisu za generiranje dokumenata plodan aranžman jest držati praćenje uključenim u noćnom poslu regresije nad korpusom stvarnih imena kupaca, adresa i opisa proizvoda, i oboriti posao na svaki nalaz. Budući da se događaj aktivira jednom po jedinstvenoj točki koda umjesto jednom po pojavi, izlaz ostaje dovoljno mali za čitanje čak i kada cijelo pismo nedostaje

U produkciji isti je rukovatelj bolje koristiti kao telemetriju: zabilježite točku koda i font, nastavite isporučivati dokument, i pustite zbir da vam kaže koje pismo dodati sljedeće u skup fontova raspoređivanja. Ponašanje prikazivanja ugrađenih i zamijenjenih fontova dalje je pokriveno u prikazivanju glifova ugrađenih fontova, a potpuni popis svojstava uključujući TrackUnresolvedGlyphs dokumentiran je na stranici proizvoda HotPDF Delphi PDF component