Műszaki cikk

PDFlibPas automatikus betűtartalék CJK és emoji szöveghez

A PDFlibPas feloldja azokat a karaktereket, amelyeket a kiválasztott betűtípus nem tud kirajzolni, egy telepített betűkészletekből álló tartaléklánc végigkeresésével, klaszterenként, miközben megőrzi a shapinget és a kétirányú futássorrendet. A SetAutomaticFontFallback függvénnyel engedélyezed, a AddFontFallback függvénnyel bővíted a láncot, és csak azok a tartalék betűtípusok kerülnek beágyazásra a fájlba, amelyeket ténylegesen felhasználtak a kimenethez

A probléma, amelyet megold, olyan, amellyel minden dokumentumgenerátor szembesül első alkalommal, amikor egy ügyfélnév olyan írásrendszerben érkezik, amelyre a sablon betűtípusa soha nem számított. A hiba csendes, és ez teszi költségessé

Miért tűnik el a nem támogatott szöveg hiba jelzése helyett?

Mert a PDF-nek nincs fogalma egy olyan betűtípusról, amely nem tud kirajzolni egy karaktert. Egy egyszerű betűtípus byte-kódokat glyph-nevekre képez le egy kódoláson keresztül; egy összetett betűtípus kódokat egy CMap-en keresztül glyph-indexekre képez le. Kérj egy glyph-et, amelyet a betűkészlet nem tartalmaz, és a nulla glyph-indexet kapod, a .notdef-et, amelyet a legtöbb betűkészlet semmiként vagy üres dobozként rajzol ki. A fájl strukturálisan érvényes, a szövegoperátor jól formázott, és az oldal renderelődik. Egyszerűen üres ott, ahol a névnek kellene lennie

Az ISO 32000-1-ben semmi sem követeli meg, hogy egy előállító ezt észrevegye. Egy generátor, amely lefedettség-ellenőrzés nélkül ír szöveget, egy technikailag megfelelő PDF-et állít elő, amely csendben elvesztett tartalmat, és a veszteség hetekkel később bukkan fel egy ügyfél képernyőjén. Ezért szállítják együtt a tartalék funkciót és a hiányzóglyph-jelentést: annak feloldása, ami feloldható, csak a fele a munkának, és annak jelentése, ami nem oldható fel, a másik fele

A tartalék klaszterenként történik, nem kódponttonként

A granularitás az a részlet, amely elválasztja a működő implementációt a hihetőtől. A szöveg nem független karakterek sorozata. Egy devanagari szótag, egy bőrszín-módosítóval ellátott emoji, egy kombináló jelekkel rendelkező alapbetű: mindegyik egy klaszter, amelyet egyetlen betűtípusnak kell renderelnie, mert a benne lévő shaping-döntések az adott betűkészlet tábláitól függenek

A PDFlibPas klasztereket old fel, így egy olyan klasztert, amelyet egy tartalék betűkészlet lefed, teljes egészében az a betűkészlet rajzol ki. A klaszter közepén való szétvágás, ahol a fele az elsődleges betűtípusból, a fele egy tartalékból származna, technikailag jelenlévő, de láthatóan hibás eredményt produkálna, ami vitathatóan rosszabb, mint az üresség, amivel kezdtél. A futássorrend is megőrződik, így egy jobbról balra futáson belüli tartalék nem rendezi át a körülötte lévő szöveget; ugyanez a gépezet áll a japán és kínai függőleges írás című cikkben leírt függőleges elrendezés mögött is

var
  Lib: TPDFlib;
begin
  Lib := TPDFlib.Create;
  try
    Lib.SetOrigin(1);
    Lib.SetAutomaticFontFallback(1);

    // Keresési sorrend: az első találat nyer, így a legszélesebb betűkészleteket tedd utoljára
    Lib.AddFontFallback('Microsoft YaHei');   // egyszerűsített kínai
    Lib.AddFontFallback('Meiryo');            // japán
    Lib.AddFontFallback('Segoe UI Symbol');
    Lib.AddFontFallback('Segoe UI Emoji');

    Lib.SetMissingGlyphPolicy(PDF_MISSING_GLYPH_REPORT);

    Lib.AddTrueTypeFont('Arial', 1);          // 1 = a betűkészlet beágyazása
    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;

Rendezd el a láncot tudatosan. A feloldás az első olyan betűkészletet veszi, amely lefedi a klasztert, így egy elsőként elhelyezett, széles pan-Unicode betűtípus szinte mindent megnyer, és a gondosan kiválasztott, írásrendszer-specifikus betűkészleteidet soha nem fogják konzultálni. Tedd elsőre a specifikus betűkészleteket, és utolsóra a mindent-elkapót

Jelentés vagy megszakítás: melyik hibát szeretnéd?

A SetMissingGlyphPolicy elfogadja a PDF_MISSING_GLYPH_REPORT, a kompatibilis alapértelmezett, vagy a PDF_MISSING_GLYPH_ABORT értéket. A report szabályzat alatt a szövegművelet folytatódik, a fel nem oldható kódpontok a korábbihoz hasonlóan kimaradnak, és mindegyik rögzítésre kerül. Az abort szabályzat alatt a szövegművelet elutasításra kerül, mielőtt bármilyen tartalom megíródna, és a LastErrorCode 521-re áll be

Válassz aszerint, mire szolgál a dokumentum. Egy köteg belső jelentésnek folytatnia kell a renderelést, és naplóznia kell a hiányosságokat, mert egy ma kissé hiányos jelentés jobb, mint egyáltalán semmilyen. Egy jogilag kötelező érvényű szerződésnek, egy számlának, vagy bármi olyannak, amin egy név szerepel, meg kell szakadnia, mert egy fél nevében csendben kimaradt karakter olyan hiba, amelyet a saját folyamatodban szeretnél felfedezni, nem egy jogvitában. Az abort szabályzat írás előtt hibázik, így nem marad hátra félig kialakult tartalmi folyam

var
  Lib: TPDFlib;
  Report: WideString;
begin
  Lib := TPDFlib.Create;
  try
    Lib.SetMissingGlyphPolicy(PDF_MISSING_GLYPH_ABORT);
    // ... a dokumentum felépítése ...

    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;

A jelentés szándékosan géppel olvasható és korlátozott. Minden esemény hordozza az oldalt, a UTF-16 indexet a stringen belül, a kódpontot numerikus és U+XXXX formában is, a kiválasztott betűtípust, annak típusát és a műveletet, amely a problémát okozta, így egy support jegy meg tudja nevezni a pontos karaktert ahelyett, hogy egy tünetet írna le. A tracker a legutóbbi 256 eseményt tartja meg, ami elég egy dokumentum diagnosztizálásához, és elég kicsi ahhoz, hogy egy kóros futás ne tudja memóriaproblémává alakítani a diagnosztikát

A mérésnek és a rajzolásnak egyeznie kell

A szélességmérés ugyanazokat a klaszter-tudatos tartalékdöntéseket használja, mint a rajzolás. Ez triviálisnak hangzik, és ez az, amit a legtöbb házilag fejlesztett tartalékréteg elront: befoltozzák a rajzolási útvonalat, a mérést az elsődleges betűtípuson hagyják, és minden szövegdoboz, jobbra igazítás és táblázatoszlop olyan szélességekből lesz kiszámítva, amelyek nem egyeznek azzal, ami renderelődött

Mivel mindkét útvonal ugyanazt a feloldást osztja meg, egy rajzolás előtt mért string azt a szélességet foglalja el, amelynél mérték, beleértve a tartalék futásokat is. Ez teszi biztonságossá a tartalék globális bekapcsolását ahelyett, hogy csak azokon a helyeken engednéd meg, amelyeket kézzel auditáltál

Csak az kerül beágyazásra, amit használtál

A tartalék betűtípusok lusta módon kerülnek beágyazásra: egy olyan betűkészlet a láncban, amely soha nem oldott fel egyetlen klasztert sem, semmivel sem járul hozzá a kimenethez. Egy dokumentum, amely egy kínai karaktert és 5000 latin karaktert tartalmaz, nem hordoz egy teljes CJK betűkészletet; azt hordozza, amit a subsetting lépés annak az egy glyph-nek előállított, ami a fájlméret-optimalizálás és betűkészlet-subsetting című cikkben leírt viselkedés

Ez a lustaság teszi olcsóvá egy széles lánc konfigurálását. Regisztráld azokat a betűkészleteket, amelyekre a dokumentumkészleted szüksége lehet minden kiszolgált locale-ban, és minden egyes PDF csak azért fizet, amit ténylegesen felhasznált. Az általad nem generált dokumentumoknál, ahol a hiányzó betűkészletek már egy meglévő fájlon belül vannak, a javítási útvonal más, és a hiányzó betűkészletek beágyazása egy meglévő PDF-be című cikkben van tárgyalva

Egy telepítési fenntartást érdemes egyértelműen kimondani: a tartalék a kódot futtató gépre telepített betűkészletekkel szemben oldódik fel. Egy CJK betűtípusok nélküli szerveren nincs mire visszaesni, és a jelentés az első dokumentumnál megmondja ezt, nem az első panasz után. Szállítsd azokat a betűtípusokat, amelyektől függsz, és erősítsd meg a beágyazásukhoz szükséges licencelést

A PDFlibPas egy Delphi, C++Builder és Lazarus PDF-könyvtár, illeszkedő DLL és ActiveX interfészekkel, így a tartalék és hiányzóglyph API-k nem Pascal hívók számára is elérhetők. A teljes dokumentáció a PDFlibPas Delphi PDF-könyvtár oldalán található