Předejte arabskou frázi يوضح ملف PDF funkci TextOut a otevřete výsledek. Písmena běží nesprávným směrem a každé z nich stojí ve své izolované podobě s viditelnou mezerou před dalším, jako by někdo psal anglicky pozpátku a mezi každým znakem stiskl mezerník. Nebyla vyvolána žádná výjimka. Nevypsalo se žádné varování. Výstup je jednoduše špatně a je špatně, protože dvě oddělené transformace, na kterých arabština závisí, nikdy neproběhly. Znalost toho, jaké tyto dvě transformace jsou a které volání je provádí, je většinou tím, o čem výstup PDF pro komplexní písma (complex-script) ve skutečnosti je
HotPDF je nativní VCL PDF komponenta pro Delphi a C++Builder a vykonává práci směrem zprava doleva (right-to-left) za vás prostřednictvím odlišného volání. Také se ale zastaví na několika specifických místech, o kterých byste měli vědět předtím, než dané locale slíbíte. Tento článek proto mapuje koncepty a poctivé hranice; praktické nastavení pro samotné volání najdete v referenčním článku o RtLTextOut
Proč se i správný řetězec vytiskne chybně
Unicode uchovává text v logickém pořadí, v jakém jej píšete a čtete nahlas. Vykreslovač (renderer) musí naopak umístit piktogramy (glyphs) ve vizuálním pořadí. Pro písma psaná zleva doprava se tato pořadí shodují a nikdo nad tím nepřemýšlí. U arabštiny a hebrejštiny se neshodují, a když se v jednom řádku smíchají směry (např. arabská věta nesoucí latinkový token "PDF" nebo cena zapsaná číslicemi), algoritmus Unicode Bidirectional Algorithm (UAX #9) přesně rozhoduje o tom, jak se fragmenty psané zleva doprava zanoří do řádku zprava doleva. To je první transformace, takzvané přeřazení (reordering), a její vynechání je důvodem, proč se řádek převrátí
Druhým bodem je kontextuální formování (contextual shaping). Arabské písmeno se kreslí odlišně v závislosti na tom, kde se ve slově nachází: počáteční, střední, koncová nebo samostatně stojící podoba. Samotný bod kódu (codepoint) zůstává v celém textu stejný, mění se pouze tvar písmene (glyph). Datová pipeline, která každý kód předá rovnou na jeho výchozí glyph, vyprodukuje přesně onen nespojitý výstup izolovaných forem popsaný v úvodním odstavci. Hebrejština tento krok přeskakuje, protože její písmena se nespojují, ale stále potřebuje přeřazení (reordering). Arabština potřebuje obojí, a to je ten důvod, proč byste měli testovat arabštinu, a ne hebrejštinu
Na desktopu nic z toho není váš problém. Když VCL formulář vykreslí arabštinu do prvku TEdit, textový zásobník operačního systému ji tiše přeřadí a zformuje. A to je přesně ten důvod, proč řetězec, který vypadá na obrazovce perfektně, vyjde v naivním PDF rozbitý. Záznam obsahu (content stream) v PDF neukládá editovatelný text. Ukládá pozičně umístěné glyphy, takže ten, kdo záznam obsahu generuje, dědí práci formování textu (shaping), kterou dříve zvládal operační systém. RtLTextOut je volání, které si tuto práci bere zpět
Co za vás zformuje RtLTextOut
HotPDF udržuje cestu pro latinku a cestu pro složitá písma (complex-script) jako dvě odlišné metody. TextOut vytiskne, co mu předáte, přesně v pořadí, v jakém mu to předáte. RtLTextOut provede nejprve obě transformace – obousměrné (bidirectional) přeřazení přes celý řádek a kontextuální analýzu pro spojující se písma – a poté text vytiskne. Která pravidla písma se uplatní, je určeno pomocí znakové sady písma (charset) místo samotného volání, takže směr je explicitní volbou při každém volání (call site) a ne pouhým odhadem znaků. Nastavení parametr po parametru, hodnoty znakových sad, kroky pro registraci fontů a kompletní zkompilovatelný příklad jsou obsaženy v referenčním článku o RtLTextOut. Zde se zaměříme na to, co dané transformace znamenají, kde končí a jak ověřit, že zafungovaly
Jedno pravidlo použití má zásadní význam i na této úrovni: vstupní text musí být v logickém pořadí. To proto, že RtLTextOut provádí obrácení textu sám. Pokud byste vložili řetězec, který jste již ručně otočili, vyjde dvojnásobně převrácený. Referenční článek prochází tuto past a způsoby její nápravy. Důvod, proč o této pasti padla zmínka zde, je skutečnost, proč tak snadno projde testováním. Dvojnásobně převrácený čistě arabský řetězec může vypadat naprosto správně a rozpadne se, až když je na řádku latinkové slovo nebo číslo. Tyto vložené znaky se pak totiž nezanořují tak, jak diktuje standard UAX #9. Problém v tomto případě není ve vykreslování, ale v podstrčení algoritmu textu, který už byl z poloviny zpracován
Stejné chování s kombinovaným směrem plete recenzenty častěji než kód. Uvnitř řádku psaného zprava doleva se číslice a vložená latinská slova stále čtou zleva doprava. Někdo, kdo nepracoval s obousměrným rozložením, se podívá na vygenerovanou fakturu, uvidí číslo účtu zobrazené „špatným“ směrem vzhledem k arabštině kolem něj a nahlásí to jako chybu. Jde přitom o výsledek přesně podle specifikací (spec-correct). Krátká poznámka do kritérií přijetí, sepsaná před první kontrolou rodilým mluvčím, ušetří tento oboustranný problém
Kdy přeřazování a spojování stačí a kdy ne
U arabského a hebrejského běžného textu (running text) – sestavy, faktury, smlouvy, dopisy – jsou přeřazování a kontextové spojování celou prací, kterou musí program odvést, a funkce RtLTextOut ji zvládne sama. Hranice se objeví ve chvíli, kdy typografie vyžaduje něco víc než jen spojování (joining). Odpovědí knihovny HotPDF na straně arabštiny je možnost zapnutí tvarovače (shaper) na straně producenta. Pokud nastavíte parametr AutoShapeArabic := True, komponenta přepíše běh textu logického pořadí (logical-order run) do tvarů Unicode Presentation Forms, a to před průchodem obousměrného procesu. K zjišťování tvarů napojení tak dochází podle logických sousedů a spojování ligatur (ligature folds) je zapsáno rovnou do kódových bodů (codepoints), jež s sebou PDF nese, namísto toho, aby to zbylo k vyřešení až na prohlížeči. Přepínač je výchozím nastavením vypnut a v případě jeho vypnutí je datový výstup bytově stabilní. K jeho zapnutí se uchýlíte podle rozhodnutí (document pipeline), ne v podobě obecného nastavení aplikace. Stejný model opt-in možností platí pro další spojovaná zprava-doleva-psaná písma, jež HotPDF zvládá formovat. Syrština (Syriac), N'Ko, adlamské písmo (Adlam) a haniacké rohingské písmo (Hanifi Rohingya) mají každý svůj vlastní přepínač na automatické tvarování (auto-shape), které slouží jako ekvivalent arabského přepínače
Volitelné vlastnosti (features) OpenType představují opět jiný mechanismus. Volitelné ligatury a další funkce pro nahrazování po jednom kusu (single-substitution features) používají parametr GetSingleSubstituteGlyph(GID, 'liga'). Tyto funkce se vyřeší střídáním prvků po jednom kusu, nejprve vstupní ID piktogramu (glyph ID), poté značka vlastnosti, jež vrací nedotčený původní tvar znaku v případě, kdy vlastnost nelze použít. Tímto je pokryt váš konečný i známý list ligatur a udrží si sám svou povahu (maintain yourself). Toto však ale není plný systém s knihovnou nahrazování (GSUB engine). Rozdíl přitom leží tam, kde končí velkolepé plány lokalizace u chybných textů: program, který perfektně formuje arabštinu prokázal přeřazování (reordering) a spojování (joining) a jinak nic
Pokrytí písem
Arabština cvičí obě transformace, což vysvětluje její oblibu u testování znaků a toho proč se jeví tím nejsilnějším důkazem toho, že systém pro tvorbu (pipeline) vůbec funguje. Hebrejština na druhou stranu vyžaduje pro sebe přesměrování bez nutnosti vzájemného napojování písmen, protože se zkrátka píší o samotě (letters stand alone). Když to tedy hebrejské rozložení načrtne (renders correctly), a to arabské vyběhne nepřipojené, máte vyřešený systém bidi, leč ne tu samotnou kontextuální polovinu. Perština a urdština přebírají pravidla pro psaní znaků z arabštiny a mají s ní totožné procesy a projevy – u urdštiny je ale v zálibě použití fontu typu Nastaliq s dalekosáhlými ohledy na její čitelnost k posouzení samotným domorodým čtenářem
Thajština na sobě na rozdíl leží od okraje plně izolována zleva. Na ni neplatí vůbec nic jako obousměrnost, bez vzájemného lepení znaků a nevyžaduje tedy ke zpracování ani nic takového jak kontextuální bádání; Thajská písmena se proto provádějí cestou skrze TextOut jako u latinky. S thajštinou přišla jen jiná problematika v podobě složenin znamének s vrstvenými (stacked marks) vokály s ukazatelem znělosti shora, a zdola konsonantu, kde jejich spolehlivost pozic svisí z fontů v nich zahrnuté samotné pomocné kombinace bez úprav ve vyhledávací vrstvě (shaping-engine help). K tomuto slouží ale právě vyhrazené znakové systémy
U Dévanágarí a příbuzných rodin písma je to po pravdě zastávka na hraně. Znaky samohlásek obíhají podle klusterů (consonant clusters), tvoříc s těmito pak shluk ve spojkách pro kontextové podmíněné sestavování (chains of context-dependent substitutions). Běžná práce je plně nad přeřazováním (reordering) či tvořením znaků. Budete-li proto potřebovat implementaci do dalších indikátorských formátů z vašeho plánu cesty (roadmap), vyzkoušejte prosím funkčnost těchto parametrů bez nutnosti se zavazovat, že pokud uspěla sázka u testování řetězců arabštiny, nejedná se tu naštěstí ještě o záruky s indikátory Dévanágarí. Texty CJK s vietnamskými znaménky bez obousměrné analýzy běží do rutiny odlehlé cesty. Stálo by za to rozdělit kód ve vykazování sestav do dvou (reporting code) zvláštní, kde jedny řídí zprávy textů pro řády RTL, do druhých vkládejte zbylou polovinu s viditelnou volbou pro volání, ne abyste to skryli jako zvyklost přes ignorovaný příznak (flag someone forgets to set)
O pokrytí glyphů je rozhodnuto ještě před spuštěním formování
Formování (shaping) vybírá glyphy z písma (fontu). Pokud je písmo neobsahuje, není z čeho vybírat, což je důvodem toho klasického selhání nasazení – dokonalé na počítači vývojáře, zatímco na serveru zákazníka prázdné čtverečky poté, co došlo k tichému nahrazení písma. Je to totiž problém s pokrytím (coverage), nikoliv problém formování (shaping). Praktické řešení formou registrace fontu, který s aplikací dodáte místo toho abyste se spoléhali na cokoliv, co už má cílový stroj nainstalované, popisuje krok za krokem referenční článek. Jde hlavně o pochopení konceptu v tom smyslu, že se nejdříve stanoví nutnost určení jeho vymezení před kladením možných otázek jeho uspořádání. Účelností zde bývá zajištění provádění toho pomocí samotného programu, čímž se docílí spíše lepších řešení a snazší průhlednosti (programmatically instead of by eyeballing output)
// After RegisterUnicodeTTF, audit coverage for the
// codepoints your data actually uses
GID := Pdf.GetUnicodeGlyphForCodepoint($0628); // U+0628 ARABIC LETTER BEH
LogGlyphAudit($0628, GID);
Registrace sama sebou uplatňuje dvě vymezení omezení. Udržení základní vrstvy obsažené hodnoty se snesením podmínek Unicode pod PDF 1.5, spolu s hodnotou pro povolení vloženého písma k zabudování u instalace (font's embedding-permission bits) – ty jsou do kroků provázány s obsahem referenčního článku v RtLTextOut. Smysl do tohoto ale patří vložit pravidlo zvyklostí zkoušky, protože se to u GetUnicodeGlyphForCodepoint chová jako systém brzkého ohrožení (early-warning system). Jistotou si proveďte proces ve zpracovávaných rozpětích kódových znaků na začátku načtení a logujte je co přinese jako glyf vrácením se ID (log what glyph IDs come back). Chybění na místě by vás s tím poté upomenulo při započetí rolovací vlny ve zprávy uvítacích výstupů z protokolu a nikoli jako fakt, kdy už obdržel prázdné nesmysly po obdržení koncový příjemce daného textu v dokladu (startup log during rollout)
Směr čtení patří dokumentu, nikoliv glyphům
Sice budete mít na své straně všechny písmena (glyphs) v pořádku, stále to neznamená dokonalé vyřešení situace. U parametru popisu PDF zobrazení ve standardizacích pro ISO 32000-1 §12.2 s určením takzvaného nastavení prohlížeče (viewer preference) známého takto od /Direction, sdílí toto popis pro celkové čtení podle strany obou stran, bez promlouvání na konkrétní písmena (glyphs). Tak vlastně sděluje uspořádání textových dvousloupových výstupů na stranách s prohledávacím zařízením do jakých prvků se to má zbarvit či klonit, aby to nevyznělo divně. Ale tohle nepůjde ověřit z výstupu k testování ze stran v uceleném jediném celku a zrovna to se zrovna většinou pomíjí (forgotten)
// Declare right-to-left reading order at the document level
Pdf.Direction := RightToLeft; // adds vpDirection to ViewerPreferences
Dosazení do Direction plní tu roli. Přepisováním pod správcem atributů za dodání přidává vpDirection pod ViewerPreferences, tudíž vkládá tento jeden rýč s preferencí směrem pro spuštění souborů textu (file). Pakliže na tenhle zápis výstupu probíhá pod programem na obou případech funkce pod RtLTextOut obdrží toto, vy ho pro tuto věc máte pod zdarma záštitou u spuštění – poněvadž má zavolání dopady zvracení pod stejné cesty chování s referenčním článkem vysvětlujícím to, na jaké tyto u dokumentů lze k potřebám změn (mixed document needs that undone). Nastalá zvyklost, do kterých toho lze nastavovat a z kterých dochází na zkoumání pravého doleva posunutí psaného textu zprostředkovávající s tím vytvořeno od začátku do konce obvyklého pochodu (shaping upstream). Pro takové vyznění zanechte zrovna jeden papír, nechte tam tohle vynechat u provedení jako takového s náhledem, což se ukáže nakonec tak jak to má za potřebí po okopírování z toho papíru (look identical either way), do kdy neudělá nikdo brožuru u obou obracených stránek s tiskem s vadnou hodnotou po zrcadlení z promeškaných chyb nastalých dávno přes upomenutím do předešlého provedení
Ověření zformovaného výstupu
Testujte a ověřujte do začátku na konec v kuse, přestože i strana na monitoru vyjde korektně, může se pro proces na nižším patře jevit nepoužitelně k uplatnění u koncových řádových provedení (useless to everything downstream). U toho lze k detekcím použít 3 body: zkopírováním srovnejte hodnotu v kódovém řetězci po obdržení s kódováním oproti Acrobatovi do počátku původních hodnot vstupního originálu. Použijte zkoušku vložených možností ve standardním obsaženém integrovaném hledání z prohlížeče k viděným (in-document search) vlastnostem ze zařazené hodnoty slova k určení viděnému faktu nalezitelného na papíře textu dokumentu, nakonec z toho uvidíte zda nedošlo u výstupu bez vloženého nainstalovaného vývojářského s balíku chyb do fontu nechtěně neposunutím ke změně na neplánovaný znak z chyby u nahrazení s prázdnými bloky na znakem písma. Žádné prověřování neudělá lepší zázemí spíše bez nutnosti rodilého testování rodilým k viditelnostem nad výkazem oprav chyb pominutých mimo strojových umělých přetvořeních ze zapomenutí z korpusu (synthetic corpus will). Rozvrh na to ale vložte ve svém ujednání a kalendáři ještě dříve po doručení
Vezměte v rámci úkolu do testování zkoumané určené hodnoty úmyslem a nenahrazujte slovy starou obnosnou slátaninou poslannou s loňskými pozdravy k testování (sent last year). Pro přípustný počátek (workable minimum) v daném regionu a v zemi (locale): udělejte k němu čistý vymyšlený větný úryvek v místní hantýrce s použitím jednoho obsaženého latinkou vtesaným do toho k obeznámené značky nebo čísla do vymezené sekce se zabudováním ceny z čísel u textu pro měnovou formu pro úhrady. A do toho dejte znak s obsaženými modifikacemi navrch a dole i shora jako čárky s jinými u obou stran a uvidíte z nich co vše k tomu s diakritikami, nechtějte z takové zvyklosti upuštění a z reálných zákaznických profilů neuvidíte prolomení u přednastavení pod hlavičkou s uchráněním nedotčené pravdy. V každém z těchto výstupů přitom se pro toto může objevit tak s podanými zprávami (regression set grow) nápravy z nových chyb u případu u podpory po dalších změnách chování ze získání jiných pro zkoušku ze kterých chování už jinde na začátku ještě z toho nedošlo
Registrace písem, podskupin (subsetting) a běžného aplikačního rozhraní (API) k tvoření dokumentů, textů jsou zmíněna v článku o výstupech, písmech (fonts) a obrazech se systémem a podporou u komponent knihovny od nástroje z portfolia pro HotPDF. V momentě u potřeb kdy musí dodržovat tyto dokumentační pravidla s danými normami kvůli provázanosti po přistupitelnosti a použitelnosti (accessibility profiles) k tomu pomůže vkládání a označení daných tagovacích řečí podle stanovených pravidel ve strukturách u dokumentací o tvorbě se systémem norem viz validace pro protokoly s ohledem ve zprávě v PDF/A, PDF/UA a další k nápravám u těchto standardních validací (validation article) po uplatňování řešení z obou nad rámce práce po dokončení uspořádání textových úprav (shaping work here)
Popisované API pro směr zprava doleva (right-to-left) a Unicode fonty je dodáváno spolu s komponentou HotPDF (HotPDF Component) pro Delphi a C++Builder; produktová stránka obsahuje odkaz na plnohodnotnou referenční dokumentaci k výstupu textu