Ko PDF ne vdelava pisave, komponenta HotPDF izriše ta tekst z nameščeno pisavo Windows, ki jo izbere HPDFMapBaseFontToSystem: dekodira ime /BaseFont, odstrani stilski del, poskusi več črkovanj, dokler GDI ne potrdi, da je družina nameščena, izmeri manjkajoče širine standardnih 14 iz metriko-združljivih pisav in pretvori eno-bajtne kode v Unicode, preden riše. Vsak od teh korakov obstaja, ker je naivna verzija odpovedala na resničnih datotekah. Izrisovalnik strani RenderLoadedPageToBitmap dobro opravi z vdelanimi programi; to je zgodba o pisavah, ki jih v datoteki sploh ni
Zakaj GDI tiho izriše napačno pisavo za nevdelano pisavo?
GDI nikoli ne poroča o manjkajoči pisavi: podajte CreateFontIndirect ime pisave, ki ga ne pozna, in tiho izbere nadomestek, pogosto drug serif brez krepke teže. Zgodnji izrisovalnik je PDF ime posredoval skoraj dobesedno, zato TimesNewRoman,Bold, TimesNewRomanPS-BoldMT in SegoeUI-Semibold niso ujemale ničesar in izšle v tem, kar je GDI izbral. Imena so lahko še slabša. ISO 32000-1 §7.3.5 dovoli, da ime zapiše kateri koli bajt kot #xx, proizvajalci CJK pa po navadi črkujejo imena pisav kot ubežni UTF-8 ali zapuščinske bajte kodne strani; pred v2.766.69 so sami ubežni zapisi postali ime pisave. HPDFMapBaseFontToSystem zdaj najprej dekodira ubežne zapise, kot znake vrne veljavno zaporedje bajtov UTF-8 in vse ostale visoke bajte bere v sistemski kodni strani
Odrez stila je kraj, kjer hevristika ugrizne. Vejica vedno konča družino (Arial,Bold da Arial), vezaj pa samo, kadar je beseda za njim stil: Bold, Italic, Oblique, Regular, Roman, Medium, Light, Black, Heavy, Semi, Demi, Thin, Extra, Ultra ali Condensed. To pravilo obdrži MS-Mincho cela, medtem ko Calibri-Light spremeni v Calibri. HotPDF nato poskusi črkovanja družine, ki jim sledijo črkovanja družine brez pripone PSMT, MT ali PS. Od v2.768.18 ta črkovanja pokrivajo vsako izbiro presledkov na mestih, kjer se lahko začne beseda: pred veliko začetnico, ki sledi majhni črki (MyriadPro postane Myriad Pro), pri zadnji veliki začetnici teka, ki mu sledi majhna črka (UIGothic), in za vodilnim MS (MSPGothic), od povsem razmaknjene oblike do imena, kakršno je zapisano; čez štiri taka mesta sta poskušani samo povsem razmaknjeno in zlepljeno ime. Presledkov ni mogoče uporabiti slepo, ker Windows nekatera beseda drži skupaj: SimSun je nameščen točno pod tem črkovanjem, MicrosoftYaHei, MicrosoftJhengHei in MSPGothic pa pripadajo Microsoft YaHei, Microsoft JhengHei in MS PGothic. Pred v2.768.18 je maper postavil presledek pred vsako notranjo veliko začetnico, zato je iskal MicrosoftYaHei kot Microsoft Ya Hei in ga nikoli ne našel. Kandidat šteje kot nameščen, kadar CreateFontIndirect, sleden s GetTextFace, vrne zahtevano ime, ali, od v2.768.18, kadar ga tabela name izbrane pisave našteje kot družino, polno ali tipografsko ime družine v katerem koli jeziku; odgovor se predpomni na ime, zato dokumenti s številnimi ne-nameščenimi pisavami ne preizprašujejo Windows za vsakim imenom na vsaki strani več
Ker je preslikovalna funkcija javna v enoti HPDFRenderFontMetrics, lahko predpoletno poročilo pokaže, s katero nameščeno družino se bo izrisala vsaka ne-vdelana pisava, z uporabo naštevanja pisav, ki ga THotPDF že izpostavlja za naložene dokumente:
uses
HPDFDoc, HPDFRenderFontMetrics;
procedure ListSystemFontMappings(Pdf: THotPDF; Log: TStrings);
var
Page, I: Integer;
Info: THPDFLoadedFontInfo;
begin
for Page := 0 to Pdf.LoadedPageCount - 1 do
for I := 0 to Pdf.GetLoadedFontCount(Page) - 1 do
if Pdf.GetLoadedFontInfo(Page, I, Info) and not Info.IsEmbedded then
Log.Add(Format('page %d /%s %s -> %s',
[Page + 1, string(Info.ResourceName), string(Info.FontName),
HPDFMapBaseFontToSystem(Info.FontName)]));
end;
Kako HotPDF izmeri standardne pisave 14, ki nimajo /Widths?
HotPDF izmeri manjkajoče zasuke na nameščeni pisavi z enakimi metriko, ker ISO 32000-1 §9.6.2.2 dovoli standardnim 14 pisavam izpustiti /Widths, knjižnica pa nima priloženih tabel AFM. Arial nosi metriko Helvetica, Times New Roman nosi Times in Courier New nosi Courier, zato HPDFMeasureBaseFontWidths ustvari ujemajočo pisavo pri lfHeight = -1000 in pokliče GetCharWidth32W; pri tej višini je rezultat že v enotah 1/1000 em, ki jih uporabljajo širine PDF. Izrisovalnik najprej pretvori vsako kodo v Unicode skozi /Encoding, /BaseEncoding in /Differences, s privzetkom StandardEncoding. Izvoz SVG in izvlečenje teksta sta naletela še na eno past: standardna pisava Type 1 brez vsakršnega /Encoding je izdelala dekodirnik brez podatkov o kodiranju, izvoz SVG je nikoli ni registriral in vsaka izmerjena širina je ostala neuporabljena. Podati nakazani StandardEncoding je to popravilo, pod pogojem, da je označena kot vnaprej določeno kodiranje; poslana po poti imena CMap pa dekodira vsako kodo kot 0 in vsaka širina ji sledi
Krepko, ležeče in napaka za ena v zastavicah opisovalnika pisave
Vnos /Flags opisovalnika pisave šteje svoje bite od 1, ne od 0, zato je ForceBold bit 19 ($40000), Italic pa bit 7 ($40), po ISO 32000-1 tabeli 123. Stara koda je testirala $20000, kar je bit 18, SmallCap. Napaka je preživela od v2.345.0 do v2.766.53, ker je /FontDescriptor skoraj vedno posredna referenca, graditelj pisav pa je bral samo neposredne objekte, zato se celotna veja zastavic ni nikoli zagnala, ista slepota pa je spregledala /Widths 12 0 R in razpostavila tekst pri rezervnem zasuku 500 enot. Ko je v2.766.53 začel razreševati posredne reference skozi izrisovalnik, je bilo treba bit popraviti v isti spremembi, sicer bi vsaka pisava malih velikih črk nenadoma izšla krepko:
const
// ISO 32000-1 tabela 123 šteje bitne položaje od 1
FD_ITALIC = $00040; // bit 7
FD_SMALLCAP = $20000; // bit 18, ni teža
FD_FORCEBOLD = $40000; // bit 19
procedure ApplyDescriptorFlags(Flags: Integer; var LF: TLogFont);
begin
if (Flags and FD_FORCEBOLD) <> 0 then
LF.lfWeight := FW_BOLD;
if (Flags and FD_ITALIC) <> 0 then
LF.lfItalic := 1;
end;
Zakaj pisave CJK s CMap UCS2 dobijo napačne širine?
Tekst CJK z vnaprej določenim CMap UCS2 izriše prave glife, a napačno razmaknjenost, kadar izrisovalnik ravna s kodo kot s CID, ker je /W indeksiran po CID, ne po znakovni kodi. Pri STSong-Light in UniGB-UCS2-H koda slučajno enaka vrednosti Unicode, zato GDI izriše prave znake in hrošč se skrije v zasukih: male črke prispejo kot kode 97 in več, padejo izven vnosa /W, kot je [1 95 500], in vse dobijo privzeto širino /DW 1000. Od v2.766.56 izrisovalnik HotPDF bere kode skozi območja kodnega prostora CMap (ISO 32000-1 §9.7.6.2) in jih preslika v CID, preden išče širine. Uporabljajo se samo vgrajene tabele UCS2 in UTF16 ter vdelani tokovi CMap; identitetno približanje za nekaj, kot je GBK-EUC-H, bi izgledalo le kot podprto, medtem ko daje napačen izhod, zato se izrisovalnik ne igra
Zakaj se znaki z diakritikami spremenijo v vprašaje na kitajskem Windows?
Eno-bajtne kode nikoli ne smejo doseči ANSI (»A«) funkcij GDI, ker GetGlyphOutlineA in GetGlyphIndicesA interpretirata bajte v sistemski kodni strani, TextOutA pa uporablja izbrani nabor znakov pisave. Na kitajskem sistemu je Arial bajt $A9 (znak avtorskih pravic v Windows-1252) postal vodilni bajt GBK in se izrisal kot »?«, past, v katero je naravnost stopila pot ne-navedenih orisov, dodana v v2.766.83. v2.767.3 vpraša uresničeno pisavo po njenem naboru znakov s GetTextCharset, to pretvori v kodno stran skozi TranslateCharsetInfo, požene bajt skozi MultiByteToWideChar in pokliče funkcije W; simbolne pisave namesto tega uporabljajo U+F000 plus kodo. Kodiranja, ki se ne strinjajo z Windows-1252 — /Differences, StandardEncoding, MacRomanEncoding — se preslikajo v Unicode, preden jih vidi katera koli sistemska pisava
Kje so meje risanja s sistemskimi pisavami?
Izris s sistemskimi pisavami je približek, komponenta HotPDF pa je iskrena glede tega, kjer se ustavi. Pred v2.768.18 je preizkus namestitve primerjal samo ime, ki ga vrne GetTextFace, na lokaliziranem Windows pa ta funkcija poroča ime družine v sistemskem jeziku, zato je bil Microsoft YaHei na kitajskem Windows ali Yu Mincho na japonskem Windows ocenjen kot manjkajoč in izrisan z nadomestkom GDI; od v2.768.18 se pisava, ki pride nazaj pod drugim imenom, išče tudi v tabeli name pisave, take pisave pa se najdejo. Metrična združljivost je zagotovljena samo za družine Helvetica, Times in Courier; Symbol se preslika v Symbol in ZapfDingbats v Wingdings, kar je zasilna rešitev, ne ujemanje. Predpoletni pregled zgoraj vidi tudi samo pisave v slovarju /Resources vsake strani, ne tistih, navedenih iz znotraj form XObjects. Ko kode še vedno ni mogoče izrisati, to poroča sledenje nerazrešenih glif ob času risanja, kar je boljši signal kot gledanje sličic z očmi
Trajen popravek sedi na strani avtorstva. HotPDF sam zapisuje z FontEmbedding privzeto nastavljenim na True, nadomešča vdelano Arial, tudi ko koda pokliče SetFont s Helvetica, vdelani tekst pa gre skozi izrisovalnik glif vdelanih pisav, namesto skozi katero koli ugibanje zgoraj. Poceni varovalka za dohajajoče datoteke je opozoriti pred izrisom, kadar preslikana družina ni na seznamu zasonskih pisav:
// VCL: Screen.Fonts našteva nameščena imena družin (enota Forms)
function MissingSystemFamily(const BaseFont: AnsiString): Boolean;
begin
Result := Screen.Fonts.IndexOf(HPDFMapBaseFontToSystem(BaseFont)) < 0;
end;
Za celo komponento, vključno z izrisovanjem strani, izvlečenjem teksta in podnaborjenjem pisav na strani pisanja, glejte stran izdelka HotPDF Delphi PDF component