Odovzdajte arabskú frázu يوضح ملف PDF metóde TextOut a otvorte výsledok. Písmená idú opačným smerom a každé z nich sedí vo svojej izolovanej forme s viditeľnou medzerou pred ďalším, akoby niekto písal angličtinu odzadu a stláčal medzerník medzi každým znakom. Nevyvolala sa žiadna výnimka. Nevytlačilo sa žiadne varovanie. Výstup je jednoducho nesprávny, a je nesprávny preto, lebo neprebehli dve samostatné transformácie, od ktorých arabčina závisí. Vedieť, čo sú tieto dve transformácie a ktoré volanie ich vykonáva, je väčšina toho, na čo sa výstup PDF s komplexným skriptom napokon zvedie
HotPDF je natívny VCL PDF komponent pre Delphi a C++Builder a prácu s písaním sprava doľava za vás vykoná prostredníctvom samostatného volania. Zároveň sa na niekoľkých konkrétnych miestach zastaví, o ktorých je dobré vedieť skôr, než sa zaviažete k danej lokalite, takže tento text mapuje koncepty a poctivé hranice; praktické nastavenie samotného volania nájdete v referenčnom článku o RtLTextOut
Prečo sa aj správny reťazec vytlačí nesprávne
Unicode uchováva text v logickom poradí, teda v poradí, v akom ho píšete a čítate nahlas. Vykresľovač musí umiestniť glyfy vo vizuálnom poradí. Pri skriptoch zľava doprava sa tieto poradia zhodujú a nikto nad tým nerozmýšľa. Pri arabčine a hebrejčine sa nezhodujú, a keď jeden riadok mieša smery, povedzme arabská veta nesúca latinský token "PDF" alebo cena zapísaná číslicami, algoritmus Unicode Bidirectional Algorithm (UAX #9) presne určí, ako sa fragmenty zľava doprava vnárajú do riadku sprava doľava. To je prvá transformácia, preusporiadanie, a jej vynechanie je to, čo riadok obráti
Druhá je kontextové tvarovanie. Arabské písmeno sa kreslí inak podľa toho, kde v slove sa nachádza: na začiatku, uprostred, na konci, alebo samostatne. Kódový bod zostáva počas celého procesu rovnaký; mení sa iba glyf. Pipeline, ktorý odovzdá každý kódový bod priamo jeho predvolenému glyfu, produkuje presne ten odpojený výstup v izolovanej forme z úvodného odseku. Hebrejčina tento krok preskakuje, keďže jej písmená sa nespájajú, no stále potrebuje preusporiadanie. Arabčina potrebuje oboje, a preto je to práve arabčina, nie hebrejčina, s ktorou testujete
Na desktope nič z toho nie je váš problém. Keď VCL formulár vykreslí arabčinu do TEdit, textový zásobník operačného systému ju potichu preusporiada a tvaruje, čo je presne dôvod, prečo reťazec, ktorý na obrazovke vyzerá dokonale, vyjde v naivnom PDF poškodený. Content stream neuchováva editovateľný text. Uchováva umiestnené glyfy, takže ten, kto stream generuje, preberá úlohu tvarovania, ktorú predtým riešil operačný systém. RtLTextOut je volanie, ktoré túto úlohu preberá späť
Čo za vás RtLTextOut tvaruje
HotPDF udržuje latinskú cestu a cestu pre komplexný skript ako dve rôzne metódy. TextOut vytlačí to, čo mu odovzdáte, v poradí, v akom mu to odovzdáte. RtLTextOut najprv vykoná obe transformácie — obojsmerné preusporiadanie cez celý riadok, kontextovú analýzu pre spájajúce sa skripty — a potom tlačí. To, ktoré pravidlá skriptu platia, sa prenáša cez charset fontu, nie cez samotné volanie, takže smer je explicitná voľba pri každom volaní namiesto odhadu zo znakov. Nastavenie parameter po parametri, hodnoty charsetu, kroky registrácie fontu a kompletný kompilovateľný príklad, to všetko nájdete v referenčnom článku o RtLTextOut; tento text zostáva pri tom, čo transformácie znamenajú, kde sa zastavujú, a ako dokázať, že fungovali
Jedno pravidlo použitia je dôležité už na tejto úrovni: vstup musí byť v logickom poradí, pretože RtLTextOut samo vykonáva obrátenie, a reťazec, ktorý ste už ručne obrátili, vyjde dvojito obrátený — referenčný článok prechádza touto pascou a jej opravou. Prečo si táto pasca zaslúži zmienku práve tu, je otázka, prečo prežije testovanie. Dvojito obrátený čisto arabský reťazec môže vyzerať úplne správne a rozpadne sa až vtedy, keď riadok nesie latinské slovo alebo číslo, pretože tieto vložené úseky sa už nevnárajú spôsobom, aký predpisuje UAX #9. Chyba nie je vo vykresľovaní; je v tom, že algoritmu odovzdávate text, ktorý je už napoly spracovaný
To isté správanie so zmiešaným smerom pomýli recenzentov viac než kód. Vnútri riadku sprava doľava sa číslice a vložené latinské slová stále čítajú zľava doprava. Niekto, kto nepracoval s obojsmerným rozložením, sa pozrie na vykreslenú faktúru, uvidí, že číslo účtu sa číta "nesprávnym" smerom vzhľadom na arabčinu okolo neho, a nahlási to ako chybu. Je to výsledok správny podľa špecifikácie. Krátka poznámka vo vašich akceptačných kritériách, napísaná pred prvým prechodom rodeného hovoriaceho, ušetrí tento zbytočný kolobeh
Kedy stačí preusporiadanie a spájanie, a kedy nie
Pre bežný text v arabčine a hebrejčine — správy, faktúry, zmluvy, listy — je preusporiadanie plus kontextové spájanie celá úloha, a RtLTextOut ju zvládne sám. Hranica sa objaví, keď typografia žiada viac než spájanie. Odpoveďou HotPDF na arabskej strane je voliteľný tvarovač na strane producenta: nastavte AutoShapeArabic := True a komponent prepíše úsek v logickom poradí na Unicode Presentation Forms ešte pred obojsmerným priechodom, takže spájacie formy sa počítajú voči logickým susedom a ligatúrne zlúčenia sú zapečené do kódových bodov, ktoré PDF skutočne nesie, namiesto toho, aby ich musel riešiť prehliadač. Prepínač je predvolene vypnutý a výstup je pri vypnutom stave bajtovo stabilný, takže jeho zapnutie je zámerné rozhodnutie pre každý dokumentový pipeline, nie globálny upgrade. Rovnaký voliteľný model sa vzťahuje aj na ďalšie spájajúce sa skripty sprava doľava, ktoré HotPDF tvaruje: sýrčina, N'Ko, Adlam a Hanifi Rohingya majú každý svoj vlastný príznak automatického tvarovania, ktorý zrkadlí ten arabský
Voliteľné OpenType funkcie sú opäť iný mechanizmus. Voliteľné ligatúry a podobné funkcie s jednou substitúciou prechádzajú cez GetSingleSubstituteGlyph(GID, 'liga'), ktorá rieši jednu substitúciu naraz — najprv ID vstupného glyfu, potom značku funkcie — a vráti vstupný glyf nezmenený, keď sa funkcia neuplatňuje. To stačí na riadenie známeho, konečného zoznamu ligatúr, ktorý si spravujete sami. Nie je to plnohodnotný GSUB engine, a práve v tomto rozdiele sa ambiciózne lokalizačné plány pokazia: pipeline na tvarovanie, ktorý bezchybne zvláda arabčinu, preukázal preusporiadanie a spájanie, nič viac
Pokrytie naprieč skriptami
Arabčina precvičuje obe transformácie, preto je to reťazec na testovanie a preto je prechod arabčinou najsilnejším jednotlivým dôkazom, že pipeline funguje. Hebrejčina potrebuje preusporiadanie, ale nie spájanie, keďže jej písmená stoja samostatne; ak sa hebrejčina vykreslí správne, no arabčina vyjde odpojená, obojsmerná polovica je v poriadku a kontextová polovica nikdy nebežala. Perzština a urdčina jazdia na arabskom skripte a dedia jeho správanie, hoci preferencia urdčiny pre štýl Nastaliq je rozhodnutie o fonte s dôsledkami na čitateľnosť, ktoré by mal posúdiť rodený čitateľ
Thajčina stojí úplne na druhej strane čiary. Číta sa zľava doprava, takže nepotrebuje žiadnu obojsmernú prácu, a jej písmená sa nespájajú, takže nepotrebuje žiadnu kontextovú analýzu; thajské reťazce prechádzajú bežnou cestou TextOut ako latinka. Čo thajčina má, sú vrstvené znaky — samohlásky a tónové značky nad a pod základnou spoluhláskou — a to, či sedia správne, závisí od toho, či je font postavený tak, aby sa jeho kombinujúce značky vrstvili bez pomoci tvarovacieho enginu. Väčšina špecializovaných thajských fontov to zvláda. Testujte presne s tým fontom, ktorý budete vkladať, nie s podobným náhradníkom
Dévanágarí a zvyšok indickej rodiny skriptov sú poctivá tvrdá hranica. Ich znaky samohlások sa preusporiadavajú okolo zhlukov spoluhlások a ich ligatúry (konjunkty) vznikajú reťazcami substitúcií závislých od kontextu, čo je plné územie GSUB, ďaleko za preusporiadaním a spájaním. Ak je indická lokalita na roadmape, spustite skutočný pilotný projekt na reálnych zákazníckych reťazcoch skôr, než ju prisľúbite — to, že funguje arabčina, nie je dôkaz, že bude fungovať dévanágarí. Reťazce CJK, vietnamčina s jej vrstvenými diakritikami a zmiešaný európsky text idú všetky bežnou cestou bez obojsmernej analýzy, a oplatí sa v kóde reportov udržiavať tieto dve cesty fyzicky oddelené, jednu rutinu pre RTL úseky a jednu pre všetko ostatné, aby bola lokalizačná logika viditeľná priamo pri volaní namiesto skrytá za príznakom, na ktorého nastavenie niekto zabudne
Pokrytie glyfmi sa rozhoduje ešte pred spustením tvarovania
Tvarovanie vyberá glyfy z fontu. Ak ich font neobsahuje, niet čo vyberať, čo je dôvod, prečo klasické zlyhanie pri nasadení — bezchybné na počítači vývojára, prázdne rámčeky na serveri zákazníka po tichej náhrade fontu — je problém pokrytia, nie problém tvarovania. Praktickým liekom, registráciou fontu, ktorý dodávate, namiesto spoliehania sa na to, čo má počítač nainštalované, prevedie krok za krokom referenčný článok. Koncepčný bod je, že pokrytie treba stanoviť skôr, než má akákoľvek otázka tvarovania vôbec zmysel, a že ho možno stanoviť programovo namiesto vizuálnej kontroly výstupu
// Po RegisterUnicodeTTF preverte pokrytie pre
// kódové body, ktoré vaše dáta skutočne používajú
GID := Pdf.GetUnicodeGlyphForCodepoint($0628); // U+0628 ARABIC LETTER BEH
LogGlyphAudit($0628, GID);
Samotná registrácia so sebou nesie dve obmedzenia — spodnú hranicu PDF 1.5 pre vkladané spracovanie Unicode a bity povolenia vkladania daného fontu — obe sú pokryté spolu s krokmi nastavenia v referenčnom článku o RtLTextOut. Čo patrí sem, je návyk auditovania: GetUnicodeGlyphForCodepoint je váš systém včasného varovania. Pri štarte služby prejdite rozsahy kódových bodov, ktoré vaše dáta skutočne používajú, a zaznamenajte, aké ID glyfov sa vrátia. Medzera v pokrytí sa potom prejaví ako riadok v štartovacom logu počas nasadenia, namiesto chýbajúcich znakov vo faktúre, ktorá už dorazila k zákazníkovi
Poradie čítania patrí dokumentu, nie glyfom
Aj keď máte každý glyf správne, jedna vec ostáva nedokončená. ISO 32000-1 §12.2 definuje preferenciu prehliadača s názvom /Direction, ktorá určuje celkové poradie čítania dokumentu. Netýka sa žiadnych glyfov. To, čo robí, je povedať prehliadaču, ako usporiadať dvojstranové rozloženia, z ktorej strany má začínať rozloženie protiľahlých strán, a ktorým smerom sa má nakláňať používateľské rozhranie na čítanie. Nič z toho sa neprejaví na jednej strane, čo je presne dôvod, prečo sa na to zabúda
// Deklarujte poradie čítania sprava doľava na úrovni dokumentu
Pdf.Direction := RightToLeft; // pridá vpDirection do ViewerPreferences
Nastavenie Direction je celá úloha: setter vlastnosti pridá vpDirection do ViewerPreferences dokumentu, takže jeden riadok prenesie preferenciu do súboru. Ak text ide von cez RtLTextOut, dostanete toto zadarmo, pretože volanie ako vedľajší efekt obráti smer dokumentu — referenčný článok pokrýva, kedy zmiešaný dokument potrebuje toto vrátiť späť. Prípad, keď to musíte nastaviť sami, je dokument sprava doľava vyprodukovaný akýmkoľvek iným spôsobom, napríklad zo vstupu, ktorý ste vopred tvarovali vyššie v reťazci a vykreslili bežnou cestou. Vynechajte to a jednostránkový dôkaz, na ktorý sa pozeráte, vyzerá identicky tak či onak; potom niekto vytlačí obojstrannú brožúru, rozloženia vyjdú zrkadlovo, a príčinou je chýbajúci jednoriadkový príkaz spred niekoľkých týždňov
Overovanie tvarovaného výstupu
Overujte od začiatku do konca, pretože strana môže vyzerať správne a napriek tomu byť nepoužiteľná pre všetko, čo nasleduje. Tri kontroly odhalia väčšinu problémov. Skopírujte text späť z Acrobatu a porovnajte kódové body s vaším zdrojovým reťazcom. Spustite vyhľadávanie v dokumente prehliadača pre slovo, ktoré vidíte na strane. A otvorte výstup na počítači, ktorý nemá vaše vývojárske fonty, ten, ktorý s najväčšou pravdepodobnosťou odhalí náhradu. Nič z toho nenahradí rodeného čitateľa, ktorý sa pozrie na jeden skutočný dokument, čo odhalí veci, ktoré žiadny syntetický korpus neodhalí. Naplánujte túto recenziu skôr, než sa formát odošle
Vyberajte testovacie reťazce zámerne namiesto recyklovania toho, čo prekladateľ poslal minulý rok. Funkčné minimum na lokalitu: veta v čistom skripte, veta s vloženými latinskými značkami, riadok nesúci číslice a menu, a mená s diakritikou alebo kombinujúcimi značkami. Skutočné mená zákazníkov porušujú predpoklady, ktoré výplňový text necháva nedotknuté, takže nechajte regresnú sadu rásť o jeden reťazec vždy, keď podporný prípad odhalí vzor, ktorý ste ešte nevideli
Registrácia fontu, subsetting a bežné API na kreslenie textu sú pokryté v článku o výstupe reportov, fontoch a obrázkoch s HotPDF. Keď tie isté dokumenty musia zároveň spĺňať profily prístupnosti, pravidlá jazykového značenia a štruktúry v článku o validácii PDF/A a PDF/UA stavajú na tejto práci s tvarovaním
API pre písanie sprava doľava a pre Unicode fonty opísané vyššie sú súčasťou HotPDF Delphi Component pre Delphi a C++Builder; produktová stránka odkazuje na kompletnú referenciu výstupu textu