Tehnički članak

RtLTextOut u HotPDF-u: PDF tekst zdesna nalevo u Delphi-ju

Pošaljite arapsku rečenicu يوضح ملف PDF هذا običnoj funkciji TextOut i dobićete stranicu koja je pogrešna na dva načina: reči teku sleva nadesno umesto zdesna nalevo, a slova ostaju u izolovanim oblicima umesto da se spoje u reči. Nema greške pri izvršavanju; Delphi prevodi kod, datoteka se otvara, ali čitalac arapskog kaže da je rezultat neupotrebljiv. Rešenje je jedan poziv, a ne promena biblioteke: HotPDF usmerava tekst zdesna nalevo kroz posebnu metodu RtLTextOut, koja obavlja promenu redosleda koju obični TextOut ne radi. Ovo je praktična referenca za potpis metode, parametre, argument charset koji bira pismo, efekat na ceo dokument, obavezno podešavanje fonta i greške koje zaista stižu do podrške

Potpis i parametri

procedure RtLTextOut(X, Y: Single; angle: Extended;
  Text: WideString); overload;
procedure RtLTextOut(X, Y: Single; angle: Extended;
  Text: PWORD; TextLength: Integer); overload;

X i Y vezuju tekst za koordinatni sistem stranice, meren od donjeg levog ugla sa rastom Y nagore, isto kao kod svakog poziva TextOut; RtLTextOut menja redosled glifova, a ne koordinatni sistem. angle rotira osnovnu liniju kao u TextOut, pa 0 ispisuje vodoravno. Text je string u logičkom redosledu, onako kako biste ga uneli. Drugo preopterećenje prima iste UTF-16 podatke kao sirovi bafer PWORD sa eksplicitnim brojem kodnih jedinica, što odgovara tekstu dobijenom iz API-ja. Na starijim verzijama Delphija bez odgovarajućeg razrešavanja preopterećenja, string varijanta se zove RtLTextOutStr i ima isti spisak parametara

Podela odgovornosti je stroga. TextOut iscrtava kodne tačke redosledom kojim ih prosledite, što je ispravno za latinicu, ćirilicu i CJK, ali nije za arapski i hebrejski. RtLTextOut prvo preuređuje svaki red u vizuelni redosled zdesna nalevo, a zatim ga iscrtava, zadržavajući ugrađene latinične reči i cifre sleva nadesno. HotPDF namerno drži metode odvojene umesto da pogađa smer iz znakova: koristite RtLTextOut za RTL segmente, TextOut za ostalo i ne prosleđujte jedan rezultat drugom. Razloge za preuređivanje, Unicode Bidirectional Algorithm, arapsko kontekstualno spajanje i granice HotPDF oblikovanja obrađuje prateći tekst o arapskom i RTL oblikovanju teksta u HotPDF-u

Argument charset odlučuje o pismu

Pismo ne bira sama metoda, već font. Četvrti argument funkcije SetFont jeste Windows charset i prenosi pravila pisma u poziv zdesna nalevo: 178 bira arapski, a 177 hebrejski. Podesite charset, zatim crtajte, i sledeća dva reda izlaze u ispravnom redosledu čitanja bez 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 זה');

Jedan detalj redosleda lako se propušta: SetFont mora doći prvi i mora se ponoviti posle svakog AddPage, jer trenutni font, uključujući charset, ne preživljava prelaz na novu stranicu. Ako ga ne ponovite, druga stranica koristi prethodno aktivan ili podrazumevani font, što kod arapskog obično znači prazne kvadrate

Ne obrće tekst koji ste već ručno obrnuli

Najviše vremena se izgubi kada se funkciji RtLTextOut prosledi string koji je već ručno obrnut. Programeri često stižu do ove metode nakon što je obični TextOut prikazao tekst unazad, pa su privremeno obrnuli znakove u kodu. RtLTextOut sam menja redosled, zato se unapred obrnuti string obrće drugi put i vraća na početni pogrešan rezultat. Prosledite tekst u logičkom redosledu, onako kako ga unosite i čitate naglas, i prepustite metodi preuređivanje

Zamka je gora od običnog obrtanja jer dvostruko obrnuta rečenica može izgledati ispravno u testu koji sadrži samo arapski, a zatim se raspasti čim se pojave latinična reč ili broj. Ti ugrađeni segmenti unutar RTL reda treba da ostanu sleva nadesno; ručno obrtanje uništava to ugnježđavanje, dok čisto arapski primer slučajno prolazi. Zato uklonite svako ručno obrtanje čim pređete na RtLTextOut

Sporedni efekat Direction koji treba poznavati

Poziv RtLTextOut menja više od nacrtanog reda. On postavlja i preferirani smer čitanja dokumenta na zdesna nalevo, isto što biste ručno uradili svojstvom Direction. Taj setter dodaje vpDirection u ViewerPreferences, čime čitaču govori kako da rasporedi dvostrane prikaze i sa koje strane počinje raspored naspramnih stranica. Za ceo arapski ili hebrejski dokument to je upravo željeno ponašanje

Važno je zato što se efekat ne vidi na jednoj stranici. Ako je dokument uglavnom sleva nadesno i sadrži samo jedan RTL blok, prvi RtLTextOut ipak menja preferencu cele datoteke. Probna stranica neće pokazati problem; on se može pojaviti tek pri dvostranoj štampi kada se rasponi preslikaju. Ako to nije željeno, posle RTL segmenta izričito vratite Direction:

// 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 zaista čita zdesna nalevo ostavite vrednost kako jeste. Bitno je znati da poziv ima efekat na ceo dokument kako kasnije ne biste dobili iznenađenje pri rasporedu stranica

Registrujte font koji isporučujete

Preuređivanje ne pomaže ako font nema potrebne glifove. Klasičan kvar je izveštaj koji savršeno radi na računaru programera, gde je instaliran Arial Unicode MS, ali na korisničkom serveru prikazuje prazne kvadrate jer je Windows zamenio font drugim bez arapske pokrivenosti. Rešenje je da se ne oslanjate na sistemske fontove, već da registrujete font koji isporučujete uz aplikaciju

// 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 ima dve granice. Font dodat preko RegisterUnicodeTTF ugrađuje se u PDF, a HotPDF obrada ugrađenog Unicode fonta zahteva PDF 1.5 ili noviji; problem je tih ako nizvodni sistem insistira na PDF 1.4. Druga granica je pravna: TrueType datoteke nose bitove dozvole za ugrađivanje, pa font koji se normalno prikazuje može imati licencu koja zabranjuje ugradnju u korisničke dokumente. Proverite licencu pre distribucije

Potpun konzolni primer

Sledeći samostalni program spaja sve delove: ispisuje jednu stranicu sa arapskim redom, hebrejskim redom i mešovitim redom koji sadrži latinični naziv proizvoda. Svaki blok prvo postavlja svoj charset, a zatim crta tekst u logičkom redosledu

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.

Otvorite rezultat. Arapski i hebrejski redovi čitaju se zdesna nalevo, slova se spajaju tamo gde pismo to zahteva, a u poslednjem redu token HotPDF ostaje sleva nadesno unutar arapskog segmenta. To ugnježđavanje je ispravan dvosmerni rezultat, a ne greška; tekst o oblikovanju povezan iznad objašnjava zašto ga Unicode pravila zahtevaju i kako da napišete kriterijume prihvatanja

Uobičajene greške i rešenja

Svaki problem naveden u nastavku pojavio se u stvarnoj komunikaciji sa podrškom i svaki vodi do jedne od prethodnih sekcija

Pre isporuke proverite više od vizuelnog utiska: kopirajte tekst iz čitača, pokrenite pretragu unutar dokumenta, otvorite datoteku na računaru bez razvojnih fontova i pokažite stvarni dokument izvornom govorniku. Potpun spisak provera, mapa pokrivenosti po pismu i korpus testnih stringova nalaze se u pratećem tekstu o arapskom i RTL oblikovanju teksta u HotPDF-u

Pozivi RtLTextOut, SetFont i RegisterUnicodeTTF prikazani ovde deo su HotPDF Component za Delphi i C++Builder