PDFlibPas ratkaisee merkit, joita valittu fontti ei osaa piirtää, etsimällä asennettujen fonttien varausketjusta klusteri kerrallaan, säilyttäen samalla muotoilun ja kaksisuuntaisen ajojärjestyksen. Otat sen käyttöön SetAutomaticFontFallback-metodilla, laajennat ketjua AddFontFallback-metodilla, ja vain tulosteessa todella käytetyt varafontit upotetaan tiedostoon
Ongelma, jonka se ratkaisee, on sellainen, jonka jokainen asiakirjageneraattori kohtaa ensimmäistä kertaa, kun asiakkaan nimi saapuu kirjoitusjärjestelmässä, jota mallin fontti ei koskaan osannut ennakoida. Virhe on hiljainen, mikä tekee siitä kalliin
Miksi tukematon teksti katoaa sen sijaan, että se nostaisi virheen?
Koska PDF:llä ei ole käsitettä fontista, joka ei osaa piirtää merkkiä. Yksinkertainen fontti kuvaa tavukoodit glyfien nimiin koodauksen kautta; yhdistelmäfontti kuvaa koodit CMapin kautta glyfi-indekseiksi. Pyydä glyfiä, jota fontti ei sisällä, ja saat glyfi-indeksin nolla, .notdef, jonka useimmat fontit piirtävät tyhjänä tai tyhjänä laatikkona. Tiedosto on rakenteellisesti kelvollinen, tekstioperaattori on hyvin muodostettu, ja sivu renderöityy. Se on vain tyhjä siinä kohdassa, missä nimen pitäisi olla
Mikään ISO 32000-1:ssä ei vaadi tuottajaa huomaamaan tätä. Generaattori, joka kirjoittaa tekstiä tarkistamatta kattavuutta, tuottaa teknisesti standardinmukaisen PDF:n, joka on hiljaisesti menettänyt sisältöä, ja menetys nousee esiin asiakkaan näytöllä viikkoja myöhemmin. Tästä syystä varausominaisuus ja puuttuvien merkkien raportti toimitetaan yhdessä: sen ratkaiseminen, mikä voidaan ratkaista, on vain puolet työstä, ja sen raportoiminen, mitä ei voitu ratkaista, on toinen puoli
Varaus tapahtuu klusterikohtaisesti, ei koodipistekohtaisesti
Rakeisuus on se yksityiskohta, joka erottaa toimivan toteutuksen uskottavasta. Teksti ei ole itsenäisten merkkien sarja. Devanagari-tavu, ihonvärimuuntimella varustettu emoji, peruskirjain yhdistävine merkkeineen: kukin on yksi klusteri, joka täytyy renderöidä yhdellä fontilla, koska sen sisäiset muotoilupäätökset riippuvat kyseisen fontin tauluista
PDFlibPas ratkaisee klustereita, joten klusteri, jonka varafontti kattaa, piirretään kokonaan tuolla fontilla. Klusterin puolittaminen ja puolen piirtäminen ensisijaisesta fontista ja puolen varafontista tuottaisi teknisesti läsnä olevan mutta silmin nähden rikkinäisen tuloksen, mikä on väitetysti pahempi kuin alkuperäinen tyhjä kohta. Ajojärjestys säilyy myös, joten varaus oikealta-vasemmalle-ajon sisällä ei järjestä ympäröivää tekstiä uudelleen; sama mekanismi on pohjana artikkelissa pystysuora kirjoitus japanille ja kiinalle kuvatulle pystyasettelulle
var
Lib: TPDFlib;
begin
Lib := TPDFlib.Create;
try
Lib.SetOrigin(1);
Lib.SetAutomaticFontFallback(1);
// Hakujärjestys: ensimmäinen osuma voittaa, joten laita laajimmat fontit viimeiseksi
Lib.AddFontFallback('Microsoft YaHei'); // Yksinkertaistettu kiina
Lib.AddFontFallback('Meiryo'); // Japani
Lib.AddFontFallback('Segoe UI Symbol');
Lib.AddFontFallback('Segoe UI Emoji');
Lib.SetMissingGlyphPolicy(PDF_MISSING_GLYPH_REPORT);
Lib.AddTrueTypeFont('Arial', 1); // 1 = upota fontti
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;
Järjestä ketju tarkoituksella. Ratkaisu ottaa ensimmäisen fontin, joka kattaa klusterin, joten ensimmäiseksi asetettu laaja pan-Unicode-fontti voittaa lähes kaiken, eikä huolellisesti valittuja kirjoitusjärjestelmäkohtaisia fontteja koskaan konsultoida. Laita täsmälliset fontit ensin ja kaiken kattava viimeiseksi
Raportoi vai keskeytä: kumman virheen haluat?
SetMissingGlyphPolicy ottaa arvon PDF_MISSING_GLYPH_REPORT, yhteensopiva oletus, tai PDF_MISSING_GLYPH_ABORT. Raportointikäytännössä tekstioperaatio jatkuu, ratkaisemattomat koodipisteet pudotetaan kuten ennenkin, ja jokainen kirjataan. Keskeytyskäytännössä tekstioperaatio hylätään ennen kuin mitään sisältöä kirjoitetaan, ja LastErrorCode asetetaan arvoon 521
Valitse sen mukaan, mihin asiakirja on tarkoitettu. Sisäisten raporttien erän tulisi jatkaa renderöintiä ja kirjata aukot lokiin, koska hieman puutteellinen raportti tänään on parempi kuin ei raporttia lainkaan. Oikeudellisesti sitovan sopimuksen, laskun tai minkä tahansa nimeä sisältävän asiakirjan pitäisi keskeytyä, koska hiljaisesti pudonnut merkki osapuolen nimessä on virhe, jonka haluat löytää omasta prosessistasi eikä riita-asiassa. Keskeytyskäytäntö epäonnistuu ennen kirjoitusta, joten yhtään puolivalmista sisältövirtaa ei jää jäljelle
var
Lib: TPDFlib;
Report: WideString;
begin
Lib := TPDFlib.Create;
try
Lib.SetMissingGlyphPolicy(PDF_MISSING_GLYPH_ABORT);
// ... rakenna asiakirja ...
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;
Raportti on tarkoituksella koneluettava ja rajattu. Jokainen tapahtuma kantaa sivun, merkkijonon sisäisen UTF-16-indeksin, koodipisteen sekä numeerisessa että U+XXXX-muodossa, valitun fontin, sen tyypin ja operaation, joka törmäsi ongelmaan, joten tukipyyntö voi nimetä täsmällisen merkin sen sijaan, että se kuvailisi oiretta. Seuranta säilyttää 256 viimeisintä tapahtumaa, mikä riittää asiakirjan diagnosointiin ja on riittävän pieni, jottei patologinen ajo voi muuttaa diagnostiikkaa muistiongelmaksi
Mittauksen ja piirron on täsmättävä
Leveyden mittaus käyttää samoja klusteritietoisia varauspäätöksiä kuin piirto. Tämä kuulostaa itsestäänselvältä ja on juuri se asia, jonka useimmat itse tehdyt varauskerrokset tekevät väärin: ne paikkaavat piirtopolun, jättävät mittauksen ensisijaiseen fonttiin, ja jokainen tekstilaatikko, oikeatasaus ja taulukkosarake päätyy laskettavaksi leveyksistä, jotka eivät täsmää renderöidyn tuloksen kanssa
Koska molemmat polut jakavat ratkaisun, ennen piirtoa mitattu merkkijono käyttää sen leveyden, jolle se mitattiin, varausajot mukaan lukien. Tämä on se, mikä tekee varauksesta turvallisen ottaa käyttöön globaalisti sen sijaan, että se otettaisiin käyttöön vain paikoissa, jotka olet tarkastanut käsin
Vain se, mitä käytit, upotetaan
Varafontit upotetaan laiskasti: ketjun fontti, joka ei koskaan ratkaissut klusteria, ei tuo mitään tulosteeseen. Asiakirja, joka sisältää yhden kiinalaisen merkin ja 5 000 latinalaista merkkiä, ei kanna täyttä CJK-fonttia; se kantaa sen, mitä osajoukkoistuksen vaihe tuotti tuolle yhdelle glyfille, mikä on käyttäytyminen, joka on kuvattu artikkelissa tiedostokoon optimointi ja fonttien osajoukkoistus
Tämä laiskuus tekee laajan ketjun edulliseksi määrittää. Rekisteröi fontit, joita asiakirjajoukkosi saattaa tarvita jokaisessa palvelemassasi lokaalissa, ja jokainen yksittäinen PDF maksaa vain siitä, mitä se todella käytti. Asiakirjoille, joita et itse tuottanut ja joissa puuttuvat fontit ovat jo olemassa olevan tiedoston sisällä, korjauspolku on erilainen ja se käsitellään artikkelissa puuttuvien fonttien upottaminen olemassa olevaan PDF-tiedostoon
Yksi käyttöönottovaroitus kannattaa sanoa suoraan: varaus ratkaisee koodia ajavalle koneelle asennettuja fontteja vasten. Palvelimella, jolla ei ole CJK-fontteja asennettuna, ei ole mitään, mihin varautua, ja raportti kertoo sen sinulle ensimmäisessä asiakirjassa eikä vasta ensimmäisen valituksen jälkeen. Toimita mukana fontit, joista olet riippuvainen, ja vahvista niiden upotuslisensointi
PDFlibPas on Delphi-, C++Builder- ja Lazarus-PDF-kirjasto, jossa on vastaavat DLL- ja ActiveX-rajapinnat, joten varaus- ja puuttuvien merkkien API:t ovat käytettävissä myös muille kuin Pascal-kutsujille. Täydellinen dokumentaatio löytyy sivulta PDFlibPas Delphi PDF library page