Pošaljite arapsku rečenicu يوضح ملف PDF هذا u obični TextOut i stranica koja se vrati bit će pogrešna na dva načina odjednom. Riječi idu s lijeva na desno umjesto s desna na lijevo, a slova stoje odvojeno u svojim izoliranim oblicima umjesto da se spajaju u povezane riječi. Nema nikakvih pogrešaka. Delphi se kompajlira, datoteka se otvara, a recenzent koji čita arapski reći će vam da je izlaz neupotrebljiv. Rješenje je jedan poziv, a ne zamjena knjižnice: HotPDF usmjerava tekst s desna na lijevo kroz zasebnu metodu, RtLTextOut, koja upravlja preslagivanjem koje obični TextOut ne podržava. Četiri stvari kod te metode određuju je li izlaz upotrebljiv: što radi s nizom znakova, kako njezin argument charset odabire pismo, promjena na razini dokumenta koju uzrokuje kao nuspojavu i priprema fonta koja se mora izvršiti prva.
Zašto tekst s desna na lijevo treba vlastiti poziv
PDF tok sadržaja (content stream) ne pohranjuje tekst koji se može uređivati. On pohranjuje glifove na fiksnim pozicijama, što znači da ono što generira taj tok mora odlučiti kojim redoslijedom ti glifovi idu. Na zaslonu je operacijski sustav to učinio umjesto vas: ako ubacite arapski tekst u TEdit, tekstualni stog operacijskog sustava preslaguje ga i spaja prije nego što uopće vidite piksel. To je upravo razlog zašto niz znakova izgleda savršeno u vašem obrascu, a kvari se u PDF-u. Stolno računalo je obavilo taj posao tiho, a u trenutku kada sami pišete svoj tok sadržaja, taj se posao vraća na vas.
TextOut vas drži za riječ. Crta kodne točke redoslijedom kojim ih proslijedite, s lijeva na desno, što je ispravno za latinicu, ćirilicu i CJK znakove, ali pogrešno za arapski i hebrejski. RtLTextOut je poziv koji najprije preslaguje liniju u vizualni redoslijed s desna na lijevo, a zatim je crta. HotPDF namjerno drži ove dvije metode odvojenima umjesto da pogađa smjer na temelju znakova, tako da je odabir metode ujedno i odabir ponašanja pisma. Dublja mehanika dvosmjernog preslagivanja i arapskog kontekstualnog spajanja posebna je tema, pokrivena u članku o oblikovanju arapskog i RTL teksta pomoću HotPDF-a; ovdje je praktični fokus uži. Koristite RtLTextOut za blokove teksta s desna na lijevo, TextOut za sve ostalo i nikada nemojte usmjeravati jedno kroz drugo.

Argument charset određuje pismo
Ono što govori metodi RtLTextOut raspoređuje li arapski ili hebrejski nije sama metoda, već font. SetFont prima Windows charset (skup znakova) kao svoj četvrti argument, a ta vrijednost prenosi pravila pisma u poziv s desna na lijevo: 178 odabire arapski, 177 odabire hebrejski. Postavite charset, zatim crtajte i dva retka u nastavku prikazat će se u ispravnom redoslijedu čitanja bez ikakve dodatne konfiguracije.
// 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 detalja o tim koordinatama lako je previdjeti. Pozicija koju prosljeđujete i dalje je početak bloka u koordinatnom sustavu same stranice, mjeren od donjeg lijevog kuta s Y koji raste prema gore, što je isto ishodište koje koristi svaki TextOut; RtLTextOut mijenja redoslijed glifova, a ne točku mjerenja na stranici. I kao i kod svakog poziva za crtanje, SetFont mora biti izvršen prvi i mora se ponoviti nakon svakog poziva AddPage, jer trenutni font ne preživljava prijelom stranice. Ako zaboravite ponoviti poziv, druga stranica se vraća na font koji je bio aktivan, što za arapski obično znači prazne okvire.
Metoda ne okreće tekst koji ste već sami okrenuli
Najčešća pogreška koja troši najviše vremena na ispravljanje pogrešaka je prosljeđivanje metodi RtLTextOut niza znakova koji ste već sami ručno okrenuli. Programeri obično posegnu za ovom metodom nakon što je prvi pokušaj s običnim TextOut ispisao tekst naopako, pa je uobičajeno privremeno rješenje okretanje znakova u kodu prije crtanja. RtLTextOut interno sam obavlja okretanje, tako da se prethodno okrenuti niz znakova okreće drugi put i završava točno tamo gdje je i započeo. Proslijedite tekst u logičkom redoslijedu, onako kako biste ga utipkali i čitali naglas, i pustite da poziv sam obavi preslagivanje.
Ova je zamka neugodnija od običnog okretanja jer dvostruko okrenuti niz može izgledati ispravno za jednu testnu frazu koja sadrži samo arapski tekst, a zatim se pokvariti u trenutku kada redak sadrži latiničnu riječ ili broj. Unutar retka s desna na lijevo, ti umetnuti dijelovi trebali bi se čitati s lijeva na desno, a ručno okretanje uništava to gniježđenje dok čisto arapski slučaj to nekako preživi. Tako bug prođe vaš prvi brzi test i pojavi se kasnije na stvarnom računu koji sadrži broj računa. Uklonite svako ručno okretanje čim prijeđete na RtLTextOut.
Nuspojava Direction koju vrijedi znati
Pozivanje metode RtLTextOut mijenja više od samog retka koji crtate. Ono također prebacuje postavku smjera čitanja dokumenta na desno-prema-lijevo, što biste inače sami postavili putem svojstva Direction. Taj setter dodaje vpDirection u ViewerPreferences dokumenta, što pregledniku govori kako rasporediti dvostruke stranice i s koje strane počinje raspored sučelnih stranica. Kada je cijeli dokument na arapskom ili hebrejskom, to je upravo ono što želite i to dobivate automatski.
To je važno znati upravo zato što je nevidljivo na jednoj stranici. Ako je dokument većinom s lijeva na desno s jednim blokom s desna na lijevo, prvi poziv RtLTextOut i dalje će promijeniti postavku cijele datoteke, a ništa u vašem testu od jedne stranice to neće pokazati. Simptom se pojavljuje tjednima kasnije kada netko ispiše obostranu knjižicu i stranice ispadnu zrcaljene. Ako to nije ono što želite, izričito vratite Direction nakon bloka s desna na lijevo:
// RtLTextOut already set the document direction to RightToLeft;
// restore left-to-right if the document is predominantly LTR
Pdf.Direction := LeftToRight;
Za dokument koji se doista čita s desna na lijevo, ostavite ga kako jest. Poanta je znati da poziv ima učinak na razini cijelog dokumenta kako se iznenađenje s knjižicom nikada ne bi dogodilo.
Registrirajte font koji isporučujete, a ne onaj za koji se nadate da je instaliran
Nikakvo preslagivanje nije važno ako font nema glifove za crtanje. Klasičan neuspjeh je izvještaj koji se besprijekorno prikazuje na razvojnom računalu, gdje je Arial Unicode MS prisutan, a na klijentovom poslužitelju se prikazuje kao nizovi praznih okvira jer je Windows tiho zamijenio font onim koji uopće ne podržava arapski. Rješenje je da prestanete vjerovati instaliranim sistemskim fontovima i registrirate onaj koji isporučujete s aplikacijom.
// 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 هذا');
Uz registraciju dolaze i dva ograničenja. Font uvezen putem RegisterUnicodeTTF se ugrađuje, a HotPDF-ovo ugrađeno rukovanje Unicodeom zahtijeva dokument u verziji PDF 1.5 ili novijoj; to stvara probleme samo ako neki vanjski sustav inzistira na verziji PDF 1.4, ali kada se to dogodi, pogreška je tiha. Drugo ograničenje je pravne, a ne tehničke prirode: TrueType datoteke sadrže bitove dopuštenja za ugradnju, a font koji dobro izgleda na zaslonu može biti licenciran na način koji zabranjuje njegovo slanje unutar dokumenata korisnika. Potvrdite licencu prije nego što ga ugradite, a ne nakon pritužbe.
Potpuni konzolni primjer
Spajajući sve dijelove, evo samostalnog programa koji piše jednu stranicu s arapskim retkom, hebrejskim retkom i mješovitim retkom koji sadrži latinični naziv proizvoda. Svaki blok postavlja svoj charset, a zatim crta u logičkom redoslijedu.
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.
Provjera izlaza
Stranica koja izgleda ispravno nije isto što i stranica koja je ispravna, stoga je provjerite onako kako će to učiniti drugi sustavi. Kopirajte tekst natrag iz preglednika i usporedite kodne točke sa svojim izvornim nizom znakova; ispravan vizualni redoslijed s pomiješanim logičkim redoslijedom čest je način zakazivanja. Pokrenite pretragu unutar dokumenta u pregledniku za riječ koju možete vidjeti na stranici. Zatim otvorite datoteku na računalu koje nema vaše razvojne fontove, što je najvjerojatniji način da otkrijete tihu zamjenu fontova. Ništa od toga ne zamjenjuje izvornog govornika koji čita stvarni dokument, što otkriva probleme koje nijedan sintetički testni niz neće otkriti, stoga planirajte taj pregled prije nego što format krene u produkciju.
RtLTextOut obrađuje dvosmjerno preslagivanje i arapsko kontekstualno spajanje, što pokriva veliku većinu rada s izvještajima i dokumentima s desna na lijevo. Granice mogućnosti, pisma koja zahtijevaju više od preslagivanja i spajanja kao što su indijske obitelji pisama te neobavezne OpenType značajke koje prolaze kroz zamjenu pojedinačnih glifova, detaljno su opisani uz pokrivenost glifovima i detalje oblikovanja u pratećem članku o oblikovanju arapskog i RTL teksta pomoću HotPDF-a.
Pozivi RtLTextOut, SetFont i RegisterUnicodeTTF koji su ovdje prikazani dio su komponente HotPDF Component za Delphi i C++Builder.