PDFlibPas išsprendžia simbolius, kurių pasirinktas šriftas negali nupiešti, ieškodamas atsarginėje įdiegtų šriftų grandinėje, klasteris po klasterio, tuo pačiu išsaugodamas formavimą ir dvikrypčių sekų tvarką. Šią funkciją įjungiate su SetAutomaticFontFallback, grandinę praplečiate su AddFontFallback, o į failą įterpiami tik tie atsarginiai šriftai, kurie iš tikrųjų buvo panaudoti išvedimui
Problema, kurią tai sprendžia, kiekvieną dokumentų generavimo sistemą pasiveja pirmą kartą, kai kliento vardas atkeliauja rašmenimis, kurių šablono šriftas niekada nenumatė. Gedimas tylus, ir būtent tai jį daro brangų
Kodėl nepalaikomas tekstas dingsta, o ne meta klaidą?
Todėl, kad PDF neturi sąvokos „šriftas, kuris negali nupiešti simbolio". Paprastas šriftas per koduotę susieja baitų kodus su glifų vardais; sudėtinis šriftas per CMap susieja kodus su glifų indeksais. Paprašykite glifo, kurio šriftas neturi, ir gausite nulinį glifo indeksą, .notdef, kurį dauguma šriftų nupiešia kaip tuštumą arba tuščią stačiakampį. Failas struktūriškai galiojantis, teksto operatorius taisyklingai suformuotas, o puslapis atvaizduojamas. Tiesiog tuščia ten, kur turėtų būti vardas
ISO 32000-1 niekur nereikalauja, kad generatorius tai pastebėtų. Generatorius, kuris rašo tekstą nepatikrinęs padengimo, sukuria techniškai atitinkantį PDF, kuris tyliai prarado turinį, ir šis praradimas paaiškėja kliento ekrane tik po kelių savaičių. Būtent todėl atsarginio šrifto funkcija ir trūkstamų glifų ataskaita pateikiamos kartu: išspręsti tai, ką galima išspręsti, yra tik pusė darbo, o pranešti apie tai, ko išspręsti nepavyko, yra antroji pusė
Atsarginis variantas taikomas klasteriui, ne kodo taškui
Detalumo lygis yra tas dalykas, kuris atskiria veikiančią realizaciją nuo tikėtinos. Tekstas nėra nepriklausomų simbolių seka. Devanagarų skiemuo, Emoji su odos tono modifikatoriumi, pagrindinė raidė su jungiamaisiais ženklais: kiekvienas jų yra vienas klasteris, kurį turi atvaizduoti vienas šriftas, nes formavimo sprendimai jo viduje priklauso nuo lentelių tame konkrečiame šrifte
PDFlibPas išsprendžia klasterius, todėl klasteris, kurį padengia atsarginis šriftas, visas nupiešiamas tuo šriftu. Skaidymas viduryje klasterio, pusę piešiant pagrindiniu šriftu, o pusę atsarginiu, sukurtų techniškai esantį, bet vizualiai sugadintą rezultatą, kuris tikriausiai būtų blogesnis nei tuštuma, nuo kurios pradėjote. Sekos tvarka taip pat išsaugoma, todėl atsarginis variantas dešinės į kairę sekoje neperrikiuoja aplinkinio teksto; ta pati mechanika naudojama vertikaliame maketavime, aprašytame straipsnyje apie vertikalų rašymą japonų ir kinų kalboms
var
Lib: TPDFlib;
begin
Lib := TPDFlib.Create;
try
Lib.SetOrigin(1);
Lib.SetAutomaticFontFallback(1);
// Paieškos tvarka: laimi pirmas atitikmuo, todėl plačiausius šriftus dėkite paskiausiai
Lib.AddFontFallback('Microsoft YaHei'); // Supaprastinta kinų
Lib.AddFontFallback('Meiryo'); // Japonų
Lib.AddFontFallback('Segoe UI Symbol');
Lib.AddFontFallback('Segoe UI Emoji');
Lib.SetMissingGlyphPolicy(PDF_MISSING_GLYPH_REPORT);
Lib.AddTrueTypeFont('Arial', 1); // 1 = įterpti šriftą
Lib.SetTextSize(11);
Lib.DrawText(72, 720, 'Invoice for 北京示例科技有限公司');
Lib.DrawText(72, 700, 'Delivery status: on time');
Lib.SaveToFile('invoice.pdf');
finally
Lib.Free;
end;
end;
Grandinę tvarkykite sąmoningai. Sprendimas paima pirmą šriftą, padengiantį klasterį, todėl plataus spektro visa Unicode aprėpianti šriftas, padėtas pirmas, laimės beveik viską, o jūsų kruopščiai parinkti konkretiems raštams skirti šriftai niekada nebus panaudoti. Konkrečius šriftus dėkite pirmus, o universalų – paskutinį
Ataskaita ar nutraukimas: kurią klaidos formą renkatės?
SetMissingGlyphPolicy priima PDF_MISSING_GLYPH_REPORT, suderinamą numatytąją reikšmę, arba PDF_MISSING_GLYPH_ABORT. Taikant ataskaitos politiką, teksto operacija tęsiasi, neišsprendžiami kodo taškai praleidžiami kaip anksčiau, ir kiekvienas jų užregistruojamas. Taikant nutraukimo politiką, teksto operacija atmetama dar prieš įrašant bet kokį turinį, o LastErrorCode nustatomas į 521
Pasirinkite pagal tai, kam skirtas dokumentas. Vidinių ataskaitų paketas turėtų toliau atvaizduoti ir registruoti spragas, nes šiek tiek nepilna ataskaita šiandien yra geriau nei jokios ataskaitos. Teisiškai įpareigojanti sutartis, sąskaita faktūra ar bet kas su vardu ant jo turėtų būti nutraukiama, nes tyliai praleistas simbolis šalies pavadinime yra defektas, kurį norite aptikti savo pačių procese, o ne ginče. Nutraukimo politika suveikia dar prieš įrašymą, todėl pusiau suformuotas turinio srautas nelieka
var
Lib: TPDFlib;
Report: WideString;
begin
Lib := TPDFlib.Create;
try
Lib.SetMissingGlyphPolicy(PDF_MISSING_GLYPH_ABORT);
// ... sukurkite dokumentą ...
if Lib.DrawText(72, 660, CustomerName) <> 1 then
if Lib.LastErrorCode = PDFLIB_ERROR_MISSING_GLYPH then
begin
Report := Lib.GetMissingGlyphReportJSON;
// {"valid":false,"policy":1,"eventCount":1,"events":[
// {"sequence":1,"documentIndex":0,"page":1,"utf16Index":12,
// "codePoint":21271,"unicode":"U+5317","fontName":"Arial",
// "fontType":"TrueType","operation":"DrawText"}]}
EscalateToOperator(Report);
end;
finally
Lib.Free;
end;
end;
Ataskaita sąmoningai sukurta mašininiam skaitymui ir ribota. Kiekvienas įvykis nurodo puslapį, UTF-16 indeksą eilutės viduje, kodo tašką tiek skaitine, tiek U+XXXX forma, pasirinktą šriftą, jo tipą ir operaciją, kurioje kilo problema, todėl pagalbos užklausoje galima nurodyti konkretų simbolį, o ne aprašyti simptomą. Sekėjas išsaugo naujausius 256 įvykius, kurių pakanka dokumentui diagnozuoti, tačiau pakankamai mažai, kad patologinis vykdymas negalėtų diagnostikos paversti atminties problema
Matavimas ir piešimas turi sutapti
Pločio matavimas naudoja tuos pačius klasteriais grįstus atsarginio šrifto sprendimus kaip ir piešimas. Tai skamba akivaizdžiai ir yra dalykas, kurį daugelis savadarbių atsarginių sluoksnių padaro klaidingai: jie pataiso piešimo kelią, palieka matavimą pagrindiniame šrifte, ir kiekvienas teksto laukas, dešinysis lygiavimas ir lentelės stulpelis galiausiai apskaičiuojamas iš pločių, kurie neatitinka to, kas buvo nupiešta
Kadangi abu keliai dalijasi sprendimu, prieš piešimą pamatuota eilutė užima tą patį plotį, kuriuo buvo pamatuota, įskaitant atsarginio šrifto sekas. Būtent tai leidžia saugiai įjungti atsarginį variantą visur, o ne tik vietose, kurias patikrinote rankiniu būdu
Įterpiama tik tai, kas panaudota
Atsarginiai šriftai įterpiami tinginiu būdu: šriftas grandinėje, kuris niekada neišsprendė nė vieno klasterio, į išvestį nieko neprideda. Dokumentas su vienu kinišku simboliu ir 5000 lotyniškų neneša viso CJK šrifto; jis neša tai, ką poaibio generavimo procesas sukūrė tam vienam glifui, o toks elgesys aprašytas straipsnyje apie failo dydžio optimizavimą ir šriftų poaibio generavimą
Šis tingumas leidžia pigiai sukonfigūruoti plačią grandinę. Registruokite šriftus, kurių gali prireikti jūsų dokumentų rinkiniui visose aptarnaujamose lokalėse, ir kiekvienas atskiras PDF sumoka tik už tai, ką iš tikrųjų panaudojo. Dokumentams, kurių jūs nesukūrėte ir kuriuose trūkstami šriftai jau yra esamame faile, taisymo kelias kitoks ir aprašytas straipsnyje apie trūkstamų šriftų įterpimą į esamą PDF
Vieną diegimo įspėjimą verta pasakyti tiesiai: atsarginis variantas sprendžiamas pagal šriftus, įdiegtus mašinoje, kurioje veikia kodas. Serveris be įdiegtų CJK šriftų neturi į ką pereiti, ir ataskaita tai pasakys jau su pirmuoju dokumentu, o ne po pirmojo skundo. Pristatykite šriftus, nuo kurių priklausote, ir patikrinkite jų įterpimo licencijavimo sąlygas
PDFlibPas yra Delphi, C++Builder ir Lazarus PDF biblioteka su atitinkamomis DLL ir ActiveX sąsajomis, todėl atsarginio šrifto ir trūkstamų glifų API pasiekiami ir ne Pascal kalbos programoms. Pilna dokumentacija pateikta PDFlibPas Delphi PDF bibliotekos puslapyje