Send den arabiske sætning يوضح ملف PDF هذا til almindelig TextOut, og den side, der kommer tilbage, er forkert på to måder på én gang. Ordene løber fra venstre mod højre i stedet for højre mod venstre, og bogstaverne sidder adskilt i deres isolerede former i stedet for at samles til forbundne ord. Ingenting fejler. Delphi'en kompilerer, filen åbnes, og en anmelder, der læser arabisk, fortæller dig, at outputtet er ubrugeligt. Løsningen er ét kald, ikke en udskiftning af bibliotek (library swap): HotPDF dirigerer højre-til-venstre-tekst gennem en særskilt metode, RtLTextOut, der håndterer den omordning (reordering), som almindelig TextOut ikke vil. Denne side er arbejdsreferencen for den metode: signaturen og dens parametre, charset-argumentet (tegnsæt), der vælger scriptet, bivirkningen på dokumentniveau, skrifttypeopsætningen, der skal komme først, og de fejl, der faktisk når support, hver med sin rettelse
Signatur og parametre
procedure RtLTextOut(X, Y: Single; angle: Extended;
Text: WideString); overload;
procedure RtLTextOut(X, Y: Single; angle: Extended;
Text: PWORD; TextLength: Integer); overload;
X og Y forankrer forløbet i sidens eget koordinatsystem, målt fra det nederste venstre hjørne med Y voksende opad, samme origo som ethvert TextOut-kald bruger; RtLTextOut ændrer glyfrækkefølgen, ikke hvor siden måler fra. angle roterer grundlinjen (baseline) nøjagtigt som den gør i TextOut, så 0 tegner en horisontal linje. Text er strengen i logisk rækkefølge, den rækkefølge du ville skrive den, og den anden overload tager de samme UTF-16 data som en rå PWORD-buffer med et eksplicit code-unit-antal, hvilket er den form, der skal bruges, når teksten ankommer fra en API snarere end en Delphi-streng. På ældre Delphi-versioner, der går forud for overload-opløsning for disse typer, eksponeres strengformen under navnet RtLTextOutStr med den identiske parameterliste
Arbejdsdelingen mellem de to output-kald er streng. TextOut tegner kodepunkter i den rækkefølge, du overfører dem, hvilket er korrekt for latinsk, kyrillisk og CJK og forkert for arabisk og hebraisk. RtLTextOut omordner hver linje til visuel højre-til-venstre-rækkefølge først, og tegner derefter, idet indlejrede latinske ord og cifre fortsat læses fra venstre til højre inde i linjen. HotPDF holder de to metoder bevidst adskilt i stedet for at gætte retningen ud fra tegnene, så valget af hvilken man kalder, er valget af hvilken scriptadfærd man får; brug RtLTextOut til højre-til-venstre-forløb, TextOut til alt andet, og før aldrig den ene gennem den anden. Hvorfor omordningen overhovedet eksisterer, hvad Unicodes tovejs-algoritme (Bidirectional Algorithm) og arabisk kontekstuel sammensætning (contextual joining) rent faktisk gør, og hvor HotPDF's formning (shaping) stopper, er emnet for ledsageartiklen om arabisk og RTL tekstformning med HotPDF; alt nedenfor er den praktiske opsætning

Charset-argumentet beslutter scriptet
Det, der fortæller RtLTextOut, om det lægger arabisk eller hebraisk ud, er ikke metoden, det er skrifttypen. SetFont tager et Windows-tegnsæt (charset) som dets fjerde argument, og den værdi bærer scriptreglerne ind i højre-til-venstre-kaldet: 178 vælger arabisk, 177 vælger hebraisk. Indstil tegnsættet, tegn derefter, og de to linjer nedenfor kommer ud i korrekt læserækkefølge uden yderligere konfiguration
// 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 זה');
Én rækkefølgedetalje er let at overse: SetFont skal komme først og skal gentages efter hver AddPage, fordi den aktuelle skrifttype, inklusiv tegnsæt, ikke overlever et sideskift. Glem gentagelsen, og den anden side falder tilbage til, hvilken skrifttype der end var aktiv, hvilket for arabisk normalt betyder tomme bokse
Det vender ikke tekst, du allerede har vendt
Den ene fejl, der opsluger mest fejlfindingstid her, er at fodre RtLTextOut med en streng, du allerede har vendt manuelt. Folk når frem til denne metode, efter et første forsøg med almindelig TextOut kom baglæns ud, og en almindelig nødløsning er at vende tegnene i koden før tegning. RtLTextOut vender internt på egen hånd, så en præ-vendt streng bliver vendt en anden gang og lander lige tilbage, hvor den startede. Videregiv teksten i logisk rækkefølge, den rækkefølge du ville skrive den og læse den højt, og lad kaldet foretage omordningen
Fælden er styggere end en simpel vending, fordi en dobbelt-vendt streng kan se korrekt ud for én rent-arabisk testfrase og derefter gå i stykker i det øjeblik, en linje bærer et latinsk ord eller et tal. Inde i en højre-til-venstre-linje formodes de indlejrede forløb at læse fra venstre til højre, og manuel vending ødelægger den indlejring (nesting), mens den rene arabiske case tilfældigvis overlever det. Så fejlen sejler gennem din første røgstest (smoke test) og dukker op senere på en rigtig faktura med et kontonummer i. Fjern enhver manuel vending i det øjeblik, du skifter til RtLTextOut
Direction-bivirkningen der er værd at kende
At kalde RtLTextOut ændrer mere end den linje, du tegner. Det vender også dokumentets læseretnings-præference til højre-til-venstre, det samme du ellers ville sætte selv gennem Direction-egenskaben (property). Den setter (setter) tilføjer vpDirection til dokumentets ViewerPreferences, hvilket fortæller en fremviser (viewer), hvordan man arrangerer to-op (two-up) opslag, og hvilken side et opslag (facing-page layout) starter fra. Når hele dokumentet er arabisk eller hebraisk, er dette præcis, hvad du vil have, og du får det gratis
Det er værd at kende til netop, fordi det er usynligt på en enkelt side. Hvis dokumentet overvejende er venstre-til-højre med én højre-til-venstre-blok, vil det første RtLTextOut-kald stadig tippe hele filens præference, og intet i din énsides-prøve (proof) vil vise det. Symptomet vises uger senere, når nogen udskriver en dupleks-brochure (duplex booklet), og opslagene kommer spejlvendte ud. Hvis det ikke er det, du vil have, så sæt Direction tilbage eksplicit efter højre-til-venstre-forløbet:
// RtLTextOut already set the document direction to RightToLeft;
// restore left-to-right if the document is predominantly LTR
Pdf.Direction := LeftToRight;
For et dokument, der virkelig læses fra højre til venstre, lad det være. Pointen er at vide, at kaldet har en dokumentdækkende effekt, så brochure-overraskelsen aldrig sker
Registrer den skrifttype, du sender (ship), ikke den, du håber er installeret
Intet af omordningen betyder noget, hvis skrifttypen ikke har nogen glyffer at tegne. Den klassiske fejl er en rapport, der renderes fejlfrit på udviklerens maskine, hvor Arial Unicode MS tilfældigvis er til stede, og kommer ud som rækker af tomme bokse på en kundes server, hvor Windows stille erstattede en skrifttype uden nogen arabisk dækning overhovedet. Kuren er at stoppe med at stole på installerede systemskrifttyper og registrere én, du sender med applikationen
// 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 هذا');
To grænser følger med registrering. En skrifttype indbragt gennem RegisterUnicodeTTF bliver indlejret (embedded), og HotPDF's indlejrede Unicode-håndtering har brug for dokumentet ved PDF 1.5 eller nyere; det bider kun, hvis noget downstream insisterer på PDF 1.4, men når det gør, er fejlen lydløs. Den anden er juridisk snarere end teknisk: TrueType-filer bærer tilladelsesbits til indlejring (embedding-permission bits), og et skrifttype-face, der ser fint ud på skærmen, kan være licenseret på en måde, der forbyder at sende den inde i kundedokumenter. Bekræft licensen, før du indlejrer, ikke efter en klage
Et komplet konsol-eksempel
Ved at sætte brikkerne sammen, er her et selvstændigt program (self-contained program), der skriver én side med en arabisk linje, en hebraisk linje og en blandet linje, der bærer et latinsk produktnavn. Hver blok indstiller sit tegnsæt og tegner derefter i logisk rækkefølge
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.
Kør det og åbn resultatet. De arabiske og hebraiske linjer læses fra højre til venstre, bogstaverne samles, hvor scriptet samler dem, og i den sidste linje sidder tokenet HotPDF fra venstre til højre inde i det arabiske forløb. Den indlejring er det korrekte tovejsresultat (bidirectional result), ikke en fejl, selvom førstegangs-anmeldere (reviewers) rutinemæssigt anmelder det som én; formningsartiklen linket ovenfor forklarer, hvorfor Unicode-reglerne kræver det, og hvordan man formulerer sine acceptkriterier, så rapporten aldrig bliver indgivet
Almindelige fejl og deres rettelser
Enhver fejl nedenfor har optrådt i en rigtig supporttråd, og hver sporer tilbage til en af sektionerne ovenfor
- Output læses baglæns eller blandes på blandede linjer — strengen blev vendt manuelt før kaldet, normalt en efterladt nødløsning fra et
TextOut-forsøg. Slet enhver manuel vending og videregiv logisk rækkefølge;RtLTextOutvender internt - Bogstaver udskrives afbrudt i isolerede former — teksten gik gennem almindelig
TextOut, ellerSetFontblev kaldt uden et højre-til-venstre tegnsæt. Tegn medRtLTextOutog giv 178 for arabisk eller 177 for hebraisk som det fjerdeSetFont-argument - Tomme bokse på kundens maskine — Windows erstattede en skrifttype uden nogen arabisk eller hebraisk dækning. Stop med at navngive installerede skrifttyper; registrer et face (skrifttype), du sender (ship), gennem
RegisterUnicodeTTFog anvendSetFontmed det navn - Anden side renderes i den forkerte skrifttype — den aktuelle skrifttype overlever ikke
AddPage. GentagSetFont-kaldet, inklusive tegnsæt, efter hvert sideskift - Dupleks-opslag udskrives spejlvendt på et overvejende LTR-dokument — det første
RtLTextOut-kald vendte dokumentetsDirection(retning) som en bivirkning. SætPdf.Direction := LeftToRightefter højre-til-venstre-forløbet - Indlejret Unicode-tekst forringes (degrades) stille downstream — noget i pipelinen gennemtvinger PDF 1.4, og HotPDF's indlejrede Unicode-håndtering behøver 1.5 eller nyere. Hæv dokumentversionen eller fjern downstream-begrænsningen
Før formatet udgives (ships), skal du verificere ud over blot at vurdere med øjet: kopier teksten tilbage ud af fremviseren, kør søgningen i dokumentet, åbn filen på en maskine uden dine udviklingsskrifttyper, og læg ét ægte dokument foran en indfødt læser. Den fulde verificeringscheckliste, dækningskortet pr. script og teststreng-korpusset (test-string corpus), der er værd at bygge, lever alle i ledsageartiklen om arabisk og RTL tekstformning med HotPDF
RtLTextOut-, SetFont- og RegisterUnicodeTTF-kaldene, der er vist her, er en del af HotPDF-komponenten til Delphi og C++Builder