Pošlite arabskú vetu يوضح ملف PDF هذا obyčajnej metóde TextOut a strana, ktorá sa vráti, bude nesprávna hneď dvojako. Slová idú zľava doprava namiesto sprava doľava a písmená stoja oddelene vo svojich izolovaných tvaroch namiesto toho, aby sa spájali do súvislých slov. Nič nevyhodí chybu. Delphi sa preloží, súbor sa otvorí a recenzent, ktorý číta po arabsky, vám povie, že výstup je nepoužiteľný. Riešením je jedno volanie, nie výmena knižnice: HotPDF smeruje text sprava doľava cez samostatnú metódu RtLTextOut, ktorá zvláda preusporiadanie, aké obyčajný TextOut nerobí. Táto stránka je funkčnou referenciou k tejto metóde: signatúra a jej parametre, argument znakovej sady, ktorý volí písmo, vedľajší účinok na úrovni dokumentu, nastavenie písma, ktoré musí prísť ako prvé, a zlyhania, ktoré sa naozaj dostanú na podporu, každé aj s opravou
Signatúra a parametre
procedure RtLTextOut(X, Y: Single; angle: Extended;
Text: WideString); overload;
procedure RtLTextOut(X, Y: Single; angle: Extended;
Text: PWORD; TextLength: Integer); overload;
X a Y ukotvujú beh textu v súradnicovej sústave samotnej strany, meranej od ľavého dolného rohu s Y rastúcim nahor, teda z rovnakého počiatku, aký používa každé volanie TextOut; RtLTextOut mení poradie glyfov, nie to, odkiaľ strana meria. angle otáča účiaru presne tak ako v TextOut, takže 0 kreslí vodorovný riadok. Text je reťazec v logickom poradí, teda v poradí, v akom by ste ho napísali, a druhá preťažená verzia berie tie isté dáta UTF-16 ako surový buffer PWORD s explicitným počtom kódových jednotiek, čo je tvar na použitie vtedy, keď text prichádza z API namiesto z reťazca v Delphi. Na starších verziách Delphi, ktoré predchádzajú riešeniu preťaženia pre tieto typy, je reťazcová verzia dostupná pod názvom RtLTextOutStr s identickým zoznamom parametrov
Rozdelenie práce medzi obe výstupné volania je prísne. TextOut kreslí kódové body v poradí, v akom ich odovzdáte, čo je správne pre latinku, cyriliku a CJK a nesprávne pre arabčinu a hebrejčinu. RtLTextOut najprv preusporiada každý riadok do vizuálneho poradia sprava doľava a až potom kreslí, pričom vložené latinské slová a číslice v rámci riadka čítajú zľava doprava. HotPDF drží tieto dve metódy zámerne oddelene namiesto hádania smeru zo znakov, takže voľba, ktorú z nich zavoláte, je voľbou správania pre dané písmo; pre behy sprava doľava použite RtLTextOut, pre všetko ostatné TextOut, a nikdy jedno neposielajte cez druhé. Prečo preusporiadanie vôbec existuje, čo presne robí obojsmerný algoritmus Unicode a kontextové spájanie arabčiny a kde končí shaping v HotPDF, je predmetom sprievodného článku o shapingu arabského a RTL textu pomocou HotPDF; všetko nižšie je praktické nastavenie

O písme rozhoduje argument znakovej sady
To, čo metóde RtLTextOut povie, či sadzí arabčinu alebo hebrejčinu, nie je samotná metóda, ale písmo. SetFont berie ako štvrtý argument znakovú sadu Windows a táto hodnota vnáša pravidlá písma do volania sprava doľava: 178 volí arabčinu, 177 volí hebrejčinu. Nastavte znakovú sadu, potom kreslite a oba riadky nižšie vyjdú v správnom poradí čítania bez ďalšej konfigurácie
// Arabčina: znaková sada 178 povie RtLTextOut, aby použil arabské pravidlá
Pdf.CurrentPage.SetFont('Arial Unicode MS', [], 12, 178);
Pdf.CurrentPage.RtLTextOut(400, 700, 0, 'يوضح ملف PDF هذا');
// Hebrejčina: znaková sada 177 prepne pravidlá na hebrejské
Pdf.CurrentPage.SetFont('Arial Unicode MS', [], 12, 177);
Pdf.CurrentPage.RtLTextOut(400, 660, 0, 'קובץ PDF זה');
Jeden detail poradia sa dá ľahko prehliadnuť: SetFont musí prísť ako prvé a musí sa zopakovať po každom AddPage, pretože aktuálne písmo vrátane znakovej sady zalomenie strany neprežije. Zabudnite na opakovanie a druhá strana spadne späť na akékoľvek písmo, ktoré bolo aktívne, čo pri arabčine zvyčajne znamená prázdne štvorčeky
Text, ktorý ste už obrátili, znovu neobracia
Jedinou chybou, ktorá tu spotrebuje najviac času na ladenie, je podávať metóde RtLTextOut reťazec, ktorý ste už ručne otočili. Ľudia sa k tejto metóde dostanú po tom, čo prvý pokus s obyčajným TextOut vyšiel pozpiatku, a bežnou provizórnou náplasťou je obrátiť znaky v kóde ešte pred kreslením. RtLTextOut obracia vnútri sám, takže vopred obrátený reťazec sa obráti druhýkrát a pristane presne tam, kde začal. Odovzdajte text v logickom poradí, teda v tom, v akom by ste ho napísali a nahlas prečítali, a preusporiadanie nechajte na volanie
Táto pasca je zákernejšia než obyčajné otočenie, pretože dvojito obrátený reťazec môže pri jednej celoarabskej testovacej fráze vyzerať správne a rozsypať sa v okamihu, keď riadok nesie latinské slovo alebo číslo. Vnútri riadka sprava doľava majú tieto vložené behy čítať zľava doprava a ručné obracanie toto vnorenie zničí, hoci čisto arabský prípad ho zhodou okolností prežije. Chyba tak prekĺzne vaším prvým rýchlym testom a vyplává neskôr na skutočnej faktúre s číslom účtu. Odstráňte každé ručné obracanie v okamihu, keď prejdete na RtLTextOut
Vedľajší účinok na Direction, ktorý treba poznať
Volanie RtLTextOut zmení viac než len riadok, ktorý práve kreslíte. Preklopí aj preferenciu smeru čítania celého dokumentu na sprava doľava, teda to isté, čo by ste inak nastavili sami cez vlastnosť Direction. Tento setter pridá vpDirection do ViewerPreferences dokumentu, čo prehliadaču povie, ako usporiadať dvojstrany a z ktorej strany sa rozloženie s protiľahlými stranami začína. Keď je celý dokument arabský alebo hebrejský, je to presne to, čo chcete, a dostanete to zadarmo
Oplatí sa o tom vedieť práve preto, že na jednej strane je to neviditeľné. Ak je dokument prevažne zľava doprava s jedným blokom sprava doľava, prvé volanie RtLTextOut aj tak preklopí preferenciu celého súboru a vo vašom jednostranovom náhľade to nič neukáže. Príznak sa objaví o týždne neskôr, keď niekto vytlačí obojstrannú brožúru a dvojstrany vyjdú zrkadlovo. Ak to nechcete, nastavte Direction po behu sprava doľava naspäť explicitne:
// RtLTextOut už nastavil smer dokumentu na RightToLeft;
// obnovte zľava doprava, ak je dokument prevažne LTR
Pdf.Direction := LeftToRight;
Pri dokumente, ktorý naozaj číta sprava doľava, to nechajte tak. Ide o to vedieť, že volanie má účinok na celý dokument, aby prekvapenie s brožúrou nikdy nenastalo
Zaregistrujte písmo, ktoré dodávate, nie to, o ktorom dúfate, že je nainštalované
Žiadne preusporiadanie nepomôže, ak písmo nemá čo kresliť. Klasickým zlyhaním je report, ktorý sa bezchybne vykreslí na vývojárskom stroji, kde Arial Unicode MS zhodou okolností je, a na zákazníkovom serveri vyjde ako rady prázdnych štvorčekov, pretože Windows ticho nahradil písmo takým, ktoré arabčinu vôbec nepokrýva. Liekom je prestať dôverovať nainštalovaným systémovým písmam a zaregistrovať si to, ktoré dodávate s aplikáciou
// Dodajte známe arabské písmo a pred kreslením ho zaregistrujte
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 hranice. Písmo vnesené cez RegisterUnicodeTTF sa vloží do dokumentu a práca s vloženým Unicode v HotPDF vyžaduje dokument vo verzii PDF 1.5 alebo novšej; to zabolí len vtedy, keď niečo ďalej v spracovaní trvá na PDF 1.4, no keď sa to stane, zlyhanie je tiché. Druhá hranica je skôr právna než technická: súbory TrueType nesú bity s povolením na vkladanie a rez, ktorý na obrazovke vyzerá v poriadku, môže mať licenciu, ktorá jeho dodávanie vnútri zákazníckych dokumentov zakazuje. Licenciu si overte pred vložením, nie až po sťažnosti
Kompletný konzolový príklad
Keď skladáme diely dohromady, tu je samostatný program, ktorý zapíše jednu stranu s arabským riadkom, hebrejským riadkom a zmiešaným riadkom nesúcim latinský názov produktu. Každý blok si nastaví svoju znakovú sadu a potom kreslí v logickom poradí
program RtLTextOutDemo;
{$APPTYPE CONSOLE}
uses
HPDFDoc; // hlavná jednotka HotPDF
var
Pdf: THotPDF;
begin
Pdf := THotPDF.Create(nil);
try
Pdf.FileName := 'RtLTextOut.pdf';
Pdf.BeginDoc;
// Latinský nadpis ide obyčajnou cestou cez TextOut
Pdf.CurrentPage.SetFont('Arial', [fsBold], 16);
Pdf.CurrentPage.TextOut(40, 780, 0, 'Right-to-left text with HotPDF');
// Arabčina: znaková sada 178, logické poradie, preusporiadanie rieši RtLTextOut
Pdf.CurrentPage.SetFont('Arial Unicode MS', [], 12, 178);
Pdf.CurrentPage.RtLTextOut(400, 720, 0,
'يوضح ملف PDF هذا كيفية التعامل مع النص العربي.');
// Hebrejčina: znaková sada 177
Pdf.CurrentPage.SetFont('Arial Unicode MS', [], 12, 177);
Pdf.CurrentPage.RtLTextOut(400, 680, 0,
'קובץ PDF זה מדגים טקסט עברי הזורם מימין לשמאל.');
// Zmiešaný riadok: vložené latinské slovo stále číta zľava doprava
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ý riadok čítajú sprava doľava, písmená sa spájajú tam, kde ich písmo spája, a v poslednom riadku sedí token HotPDF zľava doprava vnútri arabského behu. Toto vnorenie je správnym obojsmerným výsledkom, nie chybou, hoci recenzenti ho pri prvom stretnutí bežne nahlasujú ako chybu; článok o shapingu odkazovaný vyššie vysvetľuje, prečo to pravidlá Unicode vyžadujú a ako sformulovať vaše akceptačné kritériá, aby sa také hlásenie nikdy nepodalo
Bežné chyby a ich opravy
Každé zlyhanie nižšie sa objavilo v skutočnom vlákne podpory a každé sa dá vystopovať k niektorej z častí vyššie
- Výstup číta pozpiatku alebo sa na zmiešaných riadkoch rozsype — reťazec bol pred volaním obrátený ručne, zvyčajne ide o pozostatok náhradného riešenia z pokusu s
TextOut. Zmažte každé ručné obracanie a odovzdajte logické poradie;RtLTextOutobracia vnútri - Písmená sa tlačia oddelene v izolovaných tvaroch — text prešiel obyčajným
TextOut, alebo boloSetFontzavolané bez znakovej sady pre smer sprava doľava. Kreslite cezRtLTextOuta ako štvrtý argumentSetFontodovzdajte 178 pre arabčinu alebo 177 pre hebrejčinu - Prázdne štvorčeky na zákazníkovom stroji — Windows nahradil písmo takým, ktoré arabčinu ani hebrejčinu nepokrýva. Prestaňte pomenúvať nainštalované písma; zaregistrujte rez, ktorý dodávate, cez
RegisterUnicodeTTFa nastavte ho cezSetFontpod týmto názvom - Druhá strana sa vykreslí v nesprávnom písme — aktuálne písmo neprežije
AddPage. Zopakujte volanieSetFontvrátane znakovej sady po každom zalomení strany - Obojstranné dvojstrany sa v prevažne LTR dokumente tlačia zrkadlovo — prvé volanie
RtLTextOutako vedľajší účinok preklopiloDirectiondokumentu. Po behu sprava doľava nastavtePdf.Direction := LeftToRight - Vložený Unicode text ticho degraduje ďalej v spracovaní — niečo v pipeline vynucuje PDF 1.4 a práca s vloženým Unicode v HotPDF vyžaduje 1.5 alebo novšiu. Zdvihnite verziu dokumentu alebo odstráňte to obmedzenie
Než formát pošlete do sveta, overte ho nad rámec obhliadky očami: skopírujte text z prehliadača von, spustite vyhľadávanie v dokumente, otvorte súbor na stroji bez vašich vývojárskych písiem a jeden skutočný dokument položte pred rodeného čitateľa. Kompletný overovací zoznam, mapa pokrytia pre jednotlivé písma aj korpus testovacích reťazcov, ktorý sa oplatí vybudovať, sídlia v sprievodnom článku o shapingu arabského a RTL textu pomocou HotPDF
Volania RtLTextOut, SetFont a RegisterUnicodeTTF zobrazené tu sú súčasťou komponentu HotPDF Delphi Component pre Delphi a C++Builder