Nusiųskite arabišką sakinį يوضح ملف PDF هذا įprastam TextOut ir gautas puslapis bus klaidingas dviem būdais iškart. Žodžiai bus rašomi iš kairės į dešinę, o ne iš dešinės į kairę, o raidės bus atskirtos savo izoliuotomis formomis, užuot susijungusios į vientisus žodžius. Jokių klaidų neatsiranda. Delphi sukompiliuojamas, failas atidaromas, tačiau arabiškai skaitantis recenzentas pasakys, kad rezultatas yra nenaudotinas. Sprendimas yra viena funkcija, o ne bibliotekos keitimas: HotPDF nukreipia tekstą iš dešinės į kairę per atskirą metodą RtLTextOut, kuris atlieka pertvarkymą, kurio įprastas TextOut neatlieka. Keturi dalykai apie šį metodą lemia, ar rezultatas yra tinkamas naudoti: ką jis daro su eilute, kaip jo charset argumentas parenka raštą, dokumento lygio pakeitimas, kurį jis atlieka kaip šalutinį poveikį, ir darbas su šriftais, kurį reikia atlikti pirmiausia.
Kodėl tekstui iš dešinės į kairę reikia atskiro metodo
PDF turinio srautas nesaugo redaguojamo teksto. Jame saugomi glifai fiksuotose pozicijose, o tai reiškia, kad bet koks srauto generavimo įrankis turi pats nuspręsti, kokia tvarka tie glifai išdėstomi. Ekrane operacinė sistema tai padaro už jus: įkelkite arabų kalbos tekstą į TEdit ir OS teksto stekas jį pertvarko bei sujungia dar prieš jums pamatant bent vieną pikselį. Būtent todėl eilutė atrodo nepriekaištingai jūsų formoje, bet sugadinama PDF faile. Darbalaukis šį darbą atliko tyliai, o kai tik pradedate rašyti savo turinio srautą, šis darbas vėl tenka jums.
TextOut tiesiogiai vykdo jūsų nurodymus. Jis piešia kodus ta tvarka, kuria juos perduodate, iš kairės į dešinę, kas tinka lotynų raštui, kirilicai bei CJK, bet netinka arabų ir hebrajų kalboms. RtLTextOut yra funkcija, kuri pirmiausia pertvarko eilutę į vizualią tvarką iš dešinės į kairę, o tada piešia. HotPDF sąmoningai laiko šiuos du metodus atskirus, užuot bandęs atspėti kryptį vien tik iš pačių simbolių savybių, todėl pasirinkimas, kurį metodą iškviesti, lemia gaunamą rašto elgseną. Gilesnė dvikryptio pertvarkymo ir arabų kalbos kontekstinio sujungimo mechanika yra atskira tema, aprašyta straipsnyje apie arabų ir RTL teksto formavimą su HotPDF; čia praktinis aspektas yra siauresnis. Naudokite RtLTextOut tekstui iš dešinės į kairę, o TextOut – viskam kitam, ir niekada nenukreipkite vieno per kitą.

Charset argumentas nustato raštą
Kas nurodo RtLTextOut, ar išdėstomas arabiškas, ar hebrajiškas tekstas, yra ne pats metodas, o šriftas. SetFont kaip ketvirtąjį argumentą priima Windows charset reikšmę, ir ši reikšmė perduoda rašto taisykles į iš dešinės į kairę iškvietimą: 178 pasirenka arabų kalbą, 177 – hebrajų. Nustatykite charset reikšmę, tada nupieškite, ir dvi žemiau pateiktos eilutės bus atvaizduotos teisinga skaitymo tvarka be jokių papildomų nustatymų.
// 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 זה');
Lengva nepastebėti dviejų detalių apie šias koordinates. Pozicija, kurią perduodate, vis tiek yra teksto pradžia paties puslapio koordinačių sistemoje, matuojama nuo apatinio kairiojo kampo, kur Y didėja į viršų – tai ta pati pradžia, kurią naudoja kiekviena TextOut funkcija; RtLTextOut pakeičia glifų tvarką, o ne tai, nuo kur puslapis matuoja. Be to, kaip ir bet kuriam piešimo iškvietimui, SetFont turi būti atliekamas pirmiausia ir turi būti kartojamas po kiekvieno AddPage, nes esamas šriftas neišlieka po puslapio lūžio. Jei pamiršite tai pakartoti, antrame puslapyje bus grįžtama prie bet kokio buvusio aktyvaus šrifto, o tai arabų kalbos atveju dažniausiai reiškia tuščius langelius.
Metodas neapverčia teksto, kurį jau apvertėte patys
Didžiausia klaida, reikalaujanti daugiausia derinimo laiko, yra perduoti į RtLTextOut eilutę, kurią jau apvertėte rankiniu būdu. Kūrėjai prieina prie šio metodo po to, kai pirmasis bandymas su paprastu TextOut buvo atvaizduotas atvirkščiai, ir dažnas laikinas sprendimas yra apversti simbolius kode prieš piešimą. Kadangi RtLTextOut pati atlieka apvertimą viduje, iš anksto apversta eilutė bus apversta antrą kartą ir grįš į pradinę neteisingą padėtį. Perduokite tekstą logine tvarka – ta tvarka, kuria jį vestumėte klaviatūra ir skaitytumėte garsiai, ir leiskite metodui pačiam atlikti pertvarkymą.
Šie spąstai yra pavojingesni nei paprastas apvertimas, nes dvigubai apversta eilutė gali atrodyti teisingai vienoje bandomojoje frazėje, kurioje yra tik arabų kalba, tačiau sugriūti tą akimirką, kai eilutėje atsiranda lotyniškas žodis ar skaičius. Eilutės, rašomos iš dešinės į kairę, viduje tokie įterpti segmentai turėtų būti skaitomi iš kairės į dešinę, o rankinis apvertimas sugadina šį lizdinį išdėstymą, nors grynai arabiškas atvejis jį ir atlaiko. Taigi, ši klaida praeina pirmąjį paviršutinį testavimą ir išryškėja vėliau realioje sąskaitoje-faktūroje, kurioje yra sąskaitos numeris. Pašalinkite bet kokį rankinį apvertimą, kai tik pradedate naudoti RtLTextOut.
Verta žinoti apie Direction šalutinį poveikį
RtLTextOut iškvietimas pakeičia daugiau nei tik piešiamą eilutę. Jis taip pat pakeičia dokumento skaitymo krypties parinktį į iš dešinės į kairę – tą patį, ką kitu atveju nustatytumėte patys per Direction savybę. Šis nustatymas prideda vpDirection prie dokumento ViewerPreferences, kas nurodo peržiūros programai, kaip išdėstyti dviejų puslapių atvartus ir nuo kurios pusės prasideda puslapio maketas. Kai visas dokumentas yra arabiškas arba hebrajiškas, tai yra būtent tai, ko norite, ir gaunate tai automatiškai.
Apie tai verta žinoti būtent todėl, kad tai nematoma viename puslapyje. Jei dokumentas daugiausia skaitomas iš kairės į dešinę su vienu bloku iš dešinės į kairę, pirmasis RtLTextOut iškvietimas vis tiek pakeis viso failo parinktį, ir niekas jūsų vieno puslapio bandyme to neparodys. Simptomas išryškėja po kelių savaičių, kai kas nors atspausdina dvipusį lankstinuką ir atvartai pasirodo veidrodiniu principu. Jei to nenorite, po iš dešinės į kairę parašytos dalies aiškiai nustatykite Direction atgal:
// 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 šį nustatymą ramybėje. Svarbu žinoti, kad iškvietimas daro įtaką visam dokumentui, kad išvengtumėte netikėtumų su lankstinukais.
Registruokite šriftą, kurį pateikiate kartu su programa, o ne tikėkitės, kad jis yra įdiegtas
Joks teksto pertvarkymas nepadės, jei šriftas neturi piešimui reikalingų glifų. Klasikinė klaida – ataskaita, kuri nepriekaištingai veikia kūrėjo kompiuteryje, kuriame yra Arial Unicode MS šriftas, o kliento serveryje ji atvaizduojama kaip tuščių langelių eilutės, nes Windows tyliai pakeitė šriftą kitu, visiškai neturinčiu arabų kalbos palaikymo. Sprendimas yra nebepasitikėti įdiegtais sistemos šriftais ir užregistruoti šriftą, kurį platinate 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 هذا');
Registracija apima du apribojimus. Šriftas, įkeltas per RegisterUnicodeTTF, yra įterpiamas, o HotPDF įterptojo Unicode apdorojimui reikalinga PDF 1.5 ar vėlesnė dokumento versija; tai trukdo tik tada, kai kas nors vėlesnėse stadijose reikalauja PDF 1.4 versijos, tačiau tokiu atveju klaida įvyksta tyliai. Kitas apribojimas yra labiau teisinis nei techninis: TrueType failai turi įterpimo leidimo bitus, o šriftas, kuris puikiai atrodo ekrane, gali būti licencijuotas taip, kad jį draudžiama platinti klientų dokumentuose. Patikrinkite licenciją prieš įterpdami šriftą, o ne gavę skundą.
Visas konsolės pavyzdys
Sujungus visas dalis, pateikiama savarankiška programa, kuri įrašo vieną puslapį su arabiška eilute, hebrajiška eilute ir mišria eilute, kurioje yra lotyniškas produkto pavadinimas. Kiekvienas blokas nustato savo charset reikšmę, o tada piešia logine 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ą. Arabiškos ir hebrajiškas eilutės skaitomos iš dešinės į kairę, raidės sujungiamos ten, kur jas sujungia pats raštas, o paskutinėje eilutėje elementas HotPDF stovi iš kairės į dešinę arabiško teksto viduje – tai yra specifikaciją atitinkantis teisingas rezultatas, nors ir stebina kiekvieną, pirmą kartą matantį dvikryptį maketą. Šį paskutinį punktą verta įtraukti į priėmimo kriterijus prieš gimtosios kalbos skaitytojui peržiūrint rezultatą, nes įterptas segmentas, skaitomas „neteisinga“ kryptimi aplinkinio teksto atžvilgiu, yra dalykas, kuris dažniausiai pranešamas kaip klaida, nors tai nėra klaida.
Rezultato tikrinimas
Puslapis, kuris atrodo teisingai, nebūtinai yra teisingas, todėl patikrinkite jį taip, kaip tai darys kitos sistemos. Nukopijuokite tekstą iš peržiūros programos ir palyginkite jo kodus su šaltinio eilute; teisinga vizuali tvarka su sugadinta logine tvarka yra reali nesėkmės forma. Paleiskite peržiūros programos paiešką dokumente ieškodami žodžio, kurį matote puslapyje. Tada atidarykite failą kompiuteryje, kuriame nėra jūsų kūrimo šriftų, kas greičiausiai atskleis tylų šrifto pakeitimą. Niekas iš to nepakeičia gimtosios kalbos vartotojo, skaitančio tikrą dokumentą – tai leidžia pastebėti problemas, kurių neparodys jokia sintetinė testavimo eilutė, todėl suplanuokite šią peržiūrą prieš platinant formatą.
RtLTextOut atlieka dvikryptį pertvarkymą ir arabų kalbos kontekstinį sujungimą, kas apima didžiąją dalį iš dešinės į kairę rašomų ataskaitų bei dokumentų kūrimo darbų. Ten, kur šio metodo galimybės baigiasi, pavyzdžiui, raštams, kuriems reikia daugiau nei pertvarkymo ir sujungimo (kaip indų šeimos raštams), bei pasirenkamoms OpenType funkcijoms, veikiančioms per vieno glifo pakeitimą, viskas yra aprašyta kartu su glifų aprėpties bei formavimo detalėmis susijusiame straipsnyje apie arabų ir RTL teksto formavimą su HotPDF.
Čia parodyti RtLTextOut, SetFont ir RegisterUnicodeTTF iškvietimai yra HotPDF komponento, skirto Delphi ir C++Builder, dalis.