Pošlite arabskú vetu يوضح ملف PDF هذا do obyčajného TextOut a výsledná stránka bude nesprávna hneď v dvoch smeroch. Slová budú plynúť zľava doprava namiesto sprava doľava a písmená zostanú oddelené vo svojich izolovaných tvaroch namiesto toho, aby sa spojili do súvislých slov. Nevygeneruje sa žiadna chyba. Delphi kód sa skompiluje, súbor sa otvorí a recenzent, ktorý číta arabčinu, vám povie, že výstup je nepoužiteľný. Nápravou je jedno volanie, nie výmena knižnice: HotPDF smeruje text sprava doľava cez samostatnú metódu RtLTextOut, ktorá spracováva zmenu poradia, ktorú obyčajný TextOut nevykoná. Štyri aspekty tejto metódy rozhodujú o tom, či je výstup použiteľný: čo robí s reťazcom, ako jej parameter znakovej sady vyberá písmo, zmena na úrovni dokumentu, ktorú spôbuje ako vedľajší efekt, a nastavenie písma, ktoré musí prebehnúť ako prvé.
Prečo text sprava doľava potrebuje vlastné volanie
Prúd obsahu PDF (content stream) neukladá upraviteľný text. Ukladá glyfy na pevných pozíciách, čo znamená, že čokoľvek generuje tento prúd, nesie zodpovednosť za rozhodnutie, v akom poradí tieto glyfy pôjdu. Na obrazovke to za vás urobil operačný systém: vložte arabčinu do TEdit a textový zásobník OS zmení poradie a spojí znaky skôr, ako uvidíte jediný pixel. To je presne dôvod, prečo reťazec vyzerá vo vašom formulári dokonale, ale v PDF sa rozpadne. Desktop vykonal prácu potichu a vo chvíli, keď píšete vlastný prúd obsahu, je táto úloha opäť na vašej strane.
TextOut vás berie doslovne. Vykresľuje kódové body v poradí, v akom ich odovzdáte, zľava doprava, čo je správne pre latinku, cyriliku a CJK (čínštinu, japončinu, kórejčinu) a nesprávne pre arabčinu a hebrejčinu. RtLTextOut je volanie, ktoré najprv preusporiada riadok do vizuálneho poradia sprava doľava a až potom ho vykreslí. HotPDF zámerne uchováva tieto dve metódy oddelené, namiesto toho, aby hádal smer zo znakov, takže výber toho, ktorú metódu zavolať, určuje správanie písma, ktoré získate. Podrobnejšia mechanika obojsmerného preusporiadania a arabského kontextového spájania je samostatnou témou, ktorej sa venuje článok o tvarovaní arabského a RTL textu v HotPDF; tu je praktický bod užší. Na úseky sprava doľava použite RtLTextOut, na všetko ostatné použite TextOut a nikdy nesmerujte jedno cez druhé.

Parameter charset určuje písmo
To, čo hovorí metóde RtLTextOut, či rozkladá arabčinu alebo hebrejčinu, nie je samotná metóda, ale písmo. SetFont berie znakovú sadu Windows (charset) ako svoj štvrtý parameter a táto hodnota prenáša pravidlá písma do volania sprava doľava: 178 vyberá arabčinu, 177 vyberá hebrejčinu. Nastavte znakovú sadu, potom vykreslite a dva riadky nižšie sa zobrazia v správnom poradí čítania bez akéhokoľvek ďalšieho nastavenia.
// Arabic: charset 178 tells RtLTextOut to apply Arabic rules
Pdf.CurrentPage.SetFont('Arial Unicode MS', [], 12, 178);
Pdf.CurrentPage.RtLTextOut(400, 700, 0, 'يوضح ملف PDF هذا');
// Hebrew: charset 177 switches the rules to Hebrew
Pdf.CurrentPage.SetFont('Arial Unicode MS', [], 12, 177);
Pdf.CurrentPage.RtLTextOut(400, 660, 0, 'קובץ PDF זה');
Dva detaily o týchto súradniciach je ľahké prehliadnuť. Pozícia, ktorú odovzdávate, je stále začiatok úseku v súradnicovom systéme samotnej stránky, meraný od ľavého dolného rohu s rastúcou osou Y smerom nahor, čo je rovnaký počiatok, aký používa každé volanie TextOut. RtLTextOut mení poradie glyfov, nie miesto, od ktorého stránka meria. A rovnako ako pri každom inom volaní vykresľovania, SetFont musí prísť ako prvý a musí sa opakovať po každom AddPage, pretože aktuálne písmo neprežije zlom stránky. Ak na opakovanie zabudnete, druhá stránka sa vráti k akémukoľvek aktívnemu písmu, čo pri arabčine zvyčajne znamená prázdne štvorčeky.
Nereverzuje text, ktorý ste už reverzovali manuálne
Jedinou chybou, ktorá tu pohltí najviac času na ladenie, je odovzdanie reťazca do RtLTextOut, ktorý ste už ručne otočili. Vývojári sa k tejto metóde často dostanú po tom, čo prvý pokus s obyčajným TextOut skončil obrátene, a bežným dočasným riešením je otočiť znaky v kóde pred vykreslením. RtLTextOut vykonáva reverzovanie interne sám, takže vopred otočený reťazec sa otočí druhýkrát a skončí presne tam, kde začal. Odovzdajte text v logickom poradí, teda v poradí, v akom by ste ho písali a čítali nahlas, a preusporiadanie nechajte na samotné volanie.
Táto pasca je zákernejšia než obyčajné otočenie, pretože dvakrát otočený reťazec môže vyzerať správne pre jednu testovaciu frázu kompletne v arabčine a potom sa rozpadne v momente, keď riadok obsahuje latinské slovo alebo číslo. V rámci riadku sprava doľava sa tieto vložené úseky majú čítať zľava doprava a manuálne otočenie toto vnorenie naruší, zatiaľ čo čisto arabský prípad ho náhodou prežije. Chyba tak prejde cez váš prvý rýchly test a objaví sa neskôr na skutočnej faktúre s číslom účtu. Odstráňte akékoľvek manuálne obracanie textu hneď, ako prejdete na RtLTextOut.
Vedľajší efekt Direction, o ktorom je dobré vedieť
Volanie RtLTextOut mení viac než len riadok, ktorý práve vykresľujete. Prepína tiež preferenciu smeru čítania dokumentu na sprava doľava, čo by ste inak nastavili sami prostredníctvom vlastnosti Direction. Tento setter pridáva vpDirection do ViewerPreferences dokumentu, čo hovorí prehliadaču, ako usporiadať dvojstránky a z ktorej strany začína rozloženie protiľahlých stránok. Keď je celý dokument v arabčine alebo hebrejčine, je to presne to, čo chcete, a získate to zadarmo.
Je dôležité o tom vedieť práve preto, že to na jednej stránke nie je viditeľné. Ak je dokument prevažne zľava doprava s jedným blokom sprava doľava, prvé volanie RtLTextOut stále nakloní preferenciu celého súboru a na vašom jednostránkovom náhľade sa nič neprejaví. Príznak sa objaví o niekoľko týždňov neskôr, keď niekto vytlačí obojstrannú brožúru a strany vyjdú zrkadlovo otočené. Ak to nie je to, čo chcete, po dokončení úseku sprava doľava explicitne nastavte Direction späť:
// RtLTextOut already set the document direction to RightToLeft;
// restore left-to-right if the document is predominantly LTR
Pdf.Direction := LeftToRight;
Pri dokumente, ktorý sa skutočne číta sprava doľava, to nechajte tak. Cieľom je vedieť, že volanie má vplyv na celý dokument, aby sa predišlo prekvapeniu s brožúrou.
Registrujte písmo, ktoré distribuujete, nie to, o ktorom dúfate, že je nainštalované
Žiadne preusporiadanie nepomôže, ak písmo nemá glyfy na vykreslenie. Klasickým zlyhaním je report, ktorý sa vykresľuje bezchybne na počítači vývojára, kde je náhodou prítomný font Arial Unicode MS, ale na serveri zákazníka sa zobrazí ako riadky prázdnych štvorčekov, pretože Windows ticho nahradil písmo iným, ktoré nemá žiadne pokrytie arabčiny. Riešením je prestať dôverovať nainštalovaným systémovým písmam a zaregistrovať také, ktoré dodávate spolu s aplikáciou.
// Ship a known Arabic font and register it before drawing
Pdf.RegisterUnicodeTTF('C:\Fonts\NotoSansArabic.ttf');
Pdf.CurrentPage.SetFont('NotoSansArabic', [], 12, 178);
Pdf.CurrentPage.RtLTextOut(400, 700, 0, 'يوضح ملف PDF هذا');
S registráciou prichádzajú dve obmedzenia. Písmo vložené cez RegisterUnicodeTTF sa integruje priamo do dokumentu a spracovanie vloženého Unicode v HotPDF vyžaduje verziu PDF 1.5 alebo novšiu; to predstavuje problém iba vtedy, ak softvér na spracovanie trvá na verzii PDF 1.4, ale v takom prípade je zlyhanie tiché. Druhé obmedzenie je skôr právneho než technického charakteru: súbory TrueType nesú príznaky oprávnení na vkladanie a písmo, ktoré vyzerá dobre na obrazovke, môže byť licencované spôsobom, ktorý zakazuje jeho šírenie v dokumentoch zákazníkov. Licenciu si overte pred vkladaním, nie až po sťažnosti.
Kompletný príklad pre konzolu
Spojením všetkých častí získate samostatný program, ktorý zapíše jednu stránku s arabským riadkom, hebrejským riadkom a zmiešaným riadkom obsahujúcim latinský názov produktu. Každý blok nastaví svoju znakovú sadu a potom kreslí v logickom poradí.
program RtLTextOutDemo;
{$APPTYPE CONSOLE}
uses
HPDFDoc; // HotPDF main unit
var
Pdf: THotPDF;
begin
Pdf := THotPDF.Create(nil);
try
Pdf.FileName := 'RtLTextOut.pdf';
Pdf.BeginDoc;
// A Latin heading goes through the ordinary TextOut path
Pdf.CurrentPage.SetFont('Arial', [fsBold], 16);
Pdf.CurrentPage.TextOut(40, 780, 0, 'Right-to-left text with HotPDF');
// Arabic: charset 178, logical order, RtLTextOut does the reordering
Pdf.CurrentPage.SetFont('Arial Unicode MS', [], 12, 178);
Pdf.CurrentPage.RtLTextOut(400, 720, 0,
'يوضح ملف PDF هذا كيفية التعامل مع النص العربي.');
// Hebrew: charset 177
Pdf.CurrentPage.SetFont('Arial Unicode MS', [], 12, 177);
Pdf.CurrentPage.RtLTextOut(400, 680, 0,
'קובץ PDF זה מדגים טקסט עברי הזורם מימין לשמאל.');
// Mixed line: the embedded Latin word still reads left to right
Pdf.CurrentPage.SetFont('Arial Unicode MS', [], 12, 178);
Pdf.CurrentPage.RtLTextOut(400, 640, 0,
'مرحبا بالعالم! تم إنشاؤه بواسطة HotPDF');
Pdf.EndDoc;
Writeln('Wrote RtLTextOut.pdf');
finally
Pdf.Free;
end;
end.
Spustite ho a otvorte výsledok. Arabské a hebrejské riadky sa čítajú sprava doľava, písmená sa spájajú tam, kde sa spájať majú, a v poslednom riadku sa token HotPDF nachádza zľava doprava v rámci arabského textu, čo je správny výsledok podľa špecifikácie, hoci prekvapí každého, kto vidí obojsmerné rozloženie prvýkrát. Tento posledný bod stojí za to zapísať do vašich akceptačných kritérií pred tým, než výstup skontroluje rodený hovorca, pretože vložený úsek čítaný „opačným“ smerom vzhľadom na okolitý text je najčastejšie nahlasovaný ako chyba, hoci ňou nie je.
Overenie výstupu
Stránka, ktorá vyzerá správne, nie je to isté ako stránka, ktorá je správne, preto ju skontrolujte tak, ako to urobí následný systém. Skopírujte text z prehliadača a porovnajte kódové body s pôvodným reťazcom; správne vizuálne poradie s rozhádzaným logickým poradím je reálnym chybovým stavom. Spustite vyhľadávanie v dokumente pre slovo, ktoré vidíte na stránke. Potom otvorte súbor na počítači, ktorý nemá vaše vývojové písma, čo najpravdepodobnejšie odhalí tichú náhradu. Nič z toho nenahradí čítanie skutočného dokumentu rodeným hovorcom, ktorý zachytí problémy, ktoré žiadny syntetický testovací reťazec neodhalí, preto si túto kontrolu naplánujte pred odoslaním formátu do produkcie.
RtLTextOut spracováva obojsmerné preusporiadanie a arabské kontextové spájanie, čo pokrýva drvivú väčšinu úloh spojených s reportami a dokumentmi sprava doľava. Tam, kde končí, sú písma, ktoré vyžadujú viac než len preusporiadanie a spájanie (napríklad indické rodiny písiem) a voliteľné funkcie OpenType, ktoré prechádzajú cez substitúciu jedného glyfu. Tie sú popísané spolu s detailmi pokrytia glyfov a tvarovania v sprievodnom článku o tvarovaní arabského a RTL textu v HotPDF.
Volania RtLTextOut, SetFont a RegisterUnicodeTTF uvedené v tomto článku sú súčasťou komponentu HotPDF Component pre Delphi a C++Builder.