Išsiuntus arabišką sakinį يوضح ملف PDF هذا į paprastą TextOut, grąžinamas puslapis yra klaidingas iš karto dviem aspektais. Žodžiai eina iš kairės į dešinę, o ne iš dešinės į kairę, o raidės stovi atskirai savo izoliuotomis formomis, o ne susijungia į sujungtus žodžius. Jokių klaidų neparodoma. Delphi kodas sėkmingai sukompiliuojamas, failas atidaromas, o recenzentas, skaitantis arabiškai, pasakys, kad rezultatas yra netinkamas naudoti. Ištaisymas yra vienas iškvietimas, o ne bibliotekos keitimas: HotPDF nukreipia iš dešinės į kairę skaitomą tekstą per atskirą metodą, RtLTextOut, kuris apdoroja pertvarkymą, kurio nepadarys paprastas TextOut. Šis puslapis yra to metodo darbinė nuoroda: parašas ir jo parametrai, charset (koduotės) argumentas, pasirenkantis raštą, dokumento lygio šalutinis poveikis, šriftų sąranka, kuri turi būti atlikta pirmiausia, ir nesklandumai, kurie iš tikrųjų pasiekia palaikymo komandą, kiekvienas kartu su ištaisymo būdu
Parašas ir parametrai
procedure RtLTextOut(X, Y: Single; angle: Extended;
Text: WideString); overload;
procedure RtLTextOut(X, Y: Single; angle: Extended;
Text: PWORD; TextLength: Integer); overload;
X ir Y pritvirtina eigą pačios puslapio koordinačių sistemoje, matuojant nuo apatinio kairiojo kampo, kai Y didėja į viršų, naudojant tą patį atskaitos tašką, kurį naudoja kiekvienas TextOut iškvietimas; RtLTextOut keičia glifų tvarką, bet ne tai, nuo kur puslapis matuoja. angle pasuka bazinę liniją lygiai taip pat, kaip tai daro TextOut, todėl 0 nubrėžia horizontalią liniją. Text yra eilutė logiška tvarka, ta tvarka, kuria ją įvestumėte, o antrasis perkrovimas (overload) priima tuos pačius UTF-16 duomenis kaip ir neapdorotas PWORD buferis su aiškiu kodo vienetų skaičiumi, o tai yra forma, kurią reikia naudoti, kai tekstas gaunamas iš API, o ne iš Delphi eilutės. Senesnėse Delphi versijose, sukurtose prieš perkrovos skiriamąją gebą (overload resolution) šiems tipams, eilutės forma pasiekiama pavadinimu RtLTextOutStr su identišku parametrų sąrašu
Darbo pasidalijimas tarp šių dviejų išvesties iškvietimų yra griežtas. TextOut piešia kodo taškus tokia tvarka, kokia juos perduodate, kas yra teisinga lotynų, kirilicos ir CJK (kinų, japonų, korėjiečių) rašmenims, bet neteisinga arabų ir hebrajų rašmenims. RtLTextOut pirmiausia pertvarko kiekvieną eilutę į vizualią tvarką iš dešinės į kairę, o tada piešia, išlaikant įterptus lotyniškus žodžius ir skaitmenis, kurie skaitomi iš kairės į dešinę eilutės viduje. HotPDF tyčia laiko abu metodus atskirai, užuot spėjusi kryptį iš simbolių, todėl pasirinkimas, kurį metodą iškviesti, lemia, kokį rašto elgesį gausite; naudokite RtLTextOut tekstams iš dešinės į kairę, TextOut – visam kitam, ir niekada nenukreipkite vieno per kitą. Kodėl iš viso egzistuoja pertvarkymas, ką iš tikrųjų daro Unikodo dvikryptis (Bidirectional) algoritmas ir arabų kontekstinis sujungimas, ir kur baigiasi HotPDF formavimas, aptariama papildomame straipsnyje Arabų ir RTL teksto formavimas naudojant HotPDF; viskas žemiau yra praktinė sąranka

Charset (koduotės) argumentas nusprendžia raštą
Tai, kas nurodo RtLTextOut, ar jis išdėsto arabų, ar hebrajų kalbą, yra ne metodas, o šriftas. SetFont kaip ketvirtą argumentą priima Windows koduotę (charset), ir ta reikšmė perkelia rašto taisykles į iškvietimą iš dešinės į kairę: 178 pasirenka arabų kalbą, 177 pasirenka hebrajų kalbą. Nustatykite koduotę, tada pieškite, ir dvi žemiau esančios eilutės bus išvestos teisinga skaitymo tvarka be jokios papildomos konfigūracijos
// 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 זה');
Vieną sekos detalę lengva praleisti: SetFont turi būti pirmas ir turi būti kartojamas po kiekvieno AddPage, nes dabartinis šriftas, įskaitant koduotę, neišlieka perėjus į kitą puslapį. Pamirškite pakartojimą ir antrasis puslapis grįš prie bet kurio prieš tai aktyvaus šrifto, o arabų kalbai tai dažniausiai reiškia tuščius langelius
Jis neapverčia teksto, kurį jau apvertėte
Viena klaida, kuri čia atima daugiausiai derinimo laiko, yra RtLTextOut eilutės, kurią jau apvertėte rankiniu būdu, pateikimas. Žmonės atranda šį metodą po pirmojo bandymo, kai paprastas TextOut grąžino atvirkščią rezultatą, ir įprastas laikinas sprendimas yra apversti simbolius kode prieš piešiant. RtLTextOut pats atlieka apvertimą viduje, todėl iš anksto apversta eilutė apverčiama antrą kartą ir atsiduria ten pat, kur prasidėjo. Perduokite tekstą logiška tvarka, ta tvarka, kuria jį įvestumėte ir skaitytumėte garsiai, ir leiskite iškvietimui atlikti pertvarkymą
Šie spąstai yra pavojingesni nei paprastas apvertimas, nes dvigubai apversta eilutė gali atrodyti teisinga vienai tik arabiškai bandomajai frazei, o vėliau sugęsti vos tik eilutėje atsiranda lotyniškas žodis ar skaičius. Eilutės iš dešinės į kairę viduje šios įterptos eigos turi būti skaitomos iš kairės į dešinę, o apvertimas rankiniu būdu griauna šį įterpimą, nors grynai arabišku atveju jis išlieka nepakitęs. Taigi klaida sėkmingai praeina jūsų pirmąjį bazinį testą ir vėliau iškyla tikroje sąskaitoje faktūroje, kurioje yra sąskaitos numeris. Pašalinkite kiekvieną apvertimą rankiniu būdu tuo momentu, kai pereinate prie RtLTextOut
Šalutinis Direction (krypties) poveikis, kurį verta žinoti
RtLTextOut iškvietimas keičia daugiau nei tik eilutę, kurią piešiate. Jis taip pat apverčia dokumento skaitymo krypties nuostatą iš dešinės į kairę – tai yra tas pats, ką kitu atveju nustatytumėte patys naudodami savybę Direction. Šis nustatymas prideda vpDirection į dokumento ViewerPreferences, o tai nurodo peržiūros programai, kaip išdėstyti dviejų puslapių išklotines ir iš kurios pusės prasideda priešingų puslapių išdėstymas. Kai visas dokumentas yra arabiškas ar hebrajiškas, tai yra būtent tai, ko norite, ir gaunate tai nemokamai
Apie tai verta žinoti būtent todėl, kad tai nematoma viename puslapyje. Jei dokumentas daugiausia yra skaitomas iš kairės į dešinę su vienu bloku iš dešinės į kairę, pirmasis RtLTextOut iškvietimas vis tiek pakeis viso failo nuostatą, ir niekas jūsų vieno puslapio bandomajame variante to neparodys. Simptomas atsiranda po kelių savaičių, kai kas nors atspausdina dvipusę brošiūrą, ir atvartai išeina veidrodiniai. Jei tai nėra tai, ko norite, aiškiai nustatykite atgalinę Direction reikšmę po eigos iš dešinės į kairę:
// RtLTextOut already set the document direction to RightToLeft;
// restore left-to-right if the document is predominantly LTR
Pdf.Direction := LeftToRight;
Dokumentui, kuris iš tikrųjų skaitomas iš dešinės į kairę, palikite tai taip, kaip yra. Esmė – žinoti, kad iškvietimas turi poveikį visam dokumentui, kad niekada nenutiktų brošiūros staigmenos
Užregistruokite kartu pristatomą šriftą, o ne tą, kurio tikitės esant įdiegto
Joks pertvarkymas neturi reikšmės, jei šriftas neturi glifų, kuriuos galėtų nupiešti. Klasikinė nesėkmė yra ataskaita, kuri nepriekaištingai atvaizduojama kūrėjo kompiuteryje, kuriame atsitiktinai yra Arial Unicode MS, ir pasirodo kaip tuščių langelių eilės kliento serveryje, kur Windows tyliai pakeitė šriftą tokiu, kuris visiškai neapima arabų kalbos. Sprendimas yra nustoti pasitikėti įdiegtais sistemos šriftais ir užregistruoti tą, kurį pristatote kartu su programa
// 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 هذا');
Kartu su registracija atsiranda dvi ribos. Šriftas, įtrauktas per RegisterUnicodeTTF, yra įterpiamas, o HotPDF įterpto Unikodo apdorojimui reikia PDF 1.5 ar naujesnės versijos dokumento; tai tampa problema tik tuo atveju, jei kažkas vėliau procese reikalauja PDF 1.4, bet kai tai nutinka, klaida įvyksta tyliai. Kita riba yra labiau teisinė nei techninė: TrueType failai turi įterpimo leidimo bitus, ir šriftas, kuris puikiai atrodo ekrane, gali turėti licenciją, kuri draudžia jį pristatyti klientų dokumentuose. Prieš įterpdami patvirtinkite licenciją, o ne po gauto skundo
Išsamus konsolės pavyzdys
Sujungus visas dalis, čia pateikiama savarankiška programa, kuri įrašo vieną puslapį su arabiška eilute, hebrajiška eilute ir mišria eilute, turinčia lotynišką produkto pavadinimą. Kiekvienas blokas nustato savo koduotę, tada piešia logiška tvarka
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.
Paleiskite ją ir atidarykite rezultatą. Arabų ir hebrajų eilutės skaitomos iš dešinės į kairę, raidės susijungia ten, kur jas sujungia raštas, o paskutinėje eilutėje žymeklis HotPDF stovi iš kairės į dešinę arabiškos eigos viduje. Šis įterpimas yra teisingas dvikryptis rezultatas, o ne klaida, nors pirmą kartą vertinantys žmonės reguliariai tai fiksuoja kaip klaidą; aukščiau susietame formavimo straipsnyje paaiškinama, kodėl Unikodo taisyklės to reikalauja ir kaip suformuluoti savo priėmimo kriterijus, kad tokia ataskaita niekada nebūtų pateikta
Dažniausiai pasitaikančios klaidos ir jų ištaisymas
Kiekvienas žemiau pateiktas nesklandumas pasirodė realioje palaikymo gijoje, ir kiekvienas jų veda atgal į vieną iš aukščiau esančių skyrių
- Išvestis skaitoma atvirkščiai arba susimaišo mišriose eilutėse — eilutė buvo apversta rankiniu būdu prieš iškvietimą, dažniausiai tai likęs laikinas sprendimas iš
TextOutbandymo. Ištrinkite kiekvieną apvertimą rankiniu būdu ir perduokite logišką tvarką;RtLTextOutapverčia viduje - Raidės atspausdinamos atsijungusios izoliuotomis formomis — tekstas perėjo per paprastą
TextOut, arbaSetFontbuvo iškviestas be koduotės iš dešinės į kairę. Pieškite naudodamiRtLTextOutir perduokite 178 arabų kalbai arba 177 hebrajų kalbai kaip ketvirtąjįSetFontargumentą - Tušti langeliai kliento kompiuteryje — Windows pakeitė šriftą į tokį, kuris visiškai neapima arabų ar hebrajų kalbų. Nustokite nurodyti įdiegtus šriftus; užregistruokite pristatomą šriftą naudodami
RegisterUnicodeTTFir nustatykite jį perSetFontnaudodami tą pavadinimą - Antras puslapis atvaizduojamas netinkamu šriftu — dabartinis šriftas neišlieka po
AddPage. PakartokiteSetFontiškvietimą, įskaitant koduotę, po kiekvieno puslapio lūžio - Dvipusiai atvartai spausdinami veidrodiniu būdu dokumente, kuris daugiausia skaitomas iš kairės į dešinę — pirmasis
RtLTextOutiškvietimas pakeitė dokumentoDirection(kryptį) kaip šalutinį poveikį. NustatykitePdf.Direction := LeftToRightpo eigos iš dešinės į kairę - Įterptas Unikodo tekstas tyliai prastėja vėliau procese — kažkas sraute verčia naudoti PDF 1.4, o HotPDF įterpto Unikodo apdorojimui reikia 1.5 ar naujesnės versijos. Padidinkite dokumento versiją arba pašalinkite vėlesnio proceso apribojimą
Prieš išleidžiant formatą, patikrinkite daugiau nei tik vizualiai: nukopijuokite tekstą atgal iš peržiūros programos, paleiskite paiešką dokumente, atidarykite failą kompiuteryje, kuriame nėra jūsų kūrimo šriftų, ir pateikite vieną tikrą dokumentą skaitytojui, kuriam ši kalba yra gimtoji. Visas tikrinimo kontrolinis sąrašas, aprėpties žemėlapis kiekvienam raštui ir bandomųjų eilučių korpusas, kurį verta sukurti, yra papildomame straipsnyje Arabų ir RTL teksto formavimas naudojant HotPDF
Čia parodyti RtLTextOut, SetFont ir RegisterUnicodeTTF iškvietimai yra HotPDF Component, skirto Delphi ir C++Builder, dalis