Stuur de Arabische zin يوضح ملف PDF هذا naar een gewone TextOut en de pagina die u terugkrijgt is op twee manieren tegelijk fout. De woorden lopen van links naar rechts in plaats van rechts naar links, en de letters staan los van elkaar in hun geïsoleerde vorm in plaats van zich te verbinden tot aaneengesloten woorden. Er treden geen foutmeldingen op. De Delphi-code compileert, het bestand opent, en een reviewer die Arabisch leest vertelt u dat de uitvoer onbruikbaar is. De oplossing is één enkele aanroep, geen bibliotheekwissel: HotPDF stuurt rechts-naar-links tekst via een aparte methode, RtLTextOut, die de herordening afhandelt die gewone TextOut niet doet. Vier aspecten van die methode bepalen of de uitvoer bruikbaar is: wat de methode met de string doet, hoe het charset-argument het schrift selecteert, het neveneffect op documentniveau, en de lettertypeconfiguratie die vooraf moet gaan.
Waarom rechts-naar-links een eigen aanroep nodig heeft
Een PDF-contentstream slaat geen bewerkbare tekst op. Het slaat glyphs op vaste posities op, wat betekent dat de tool die de stream genereert de taak heeft om te bepalen in welke volgorde die glyphs moeten worden geplaatst. Op het scherm deed het besturingssysteem dat voor u: plaats Arabisch in een TEdit en de tekst-stack van het besturingssysteem herordent en verbindt de letters nog voordat u een pixel ziet. Dat is precies de reden waarom de string er perfect uitziet in uw formulier en misgaat in de PDF. Het besturingssysteem deed het werk geruisloos, en op het moment dat u uw eigen contentstream schrijft, ligt de taak weer bij u.
TextOut gelooft u op uw woord. Het tekent de codepunten in de volgorde waarin u ze doorgeeft, van links naar rechts. Dit is correct voor Latijns, Cyrillisch en CJK, maar fout voor Arabisch en Hebreeuws. RtLTextOut is de aanroep die de regel eerst in visuele rechts-naar-links volgorde zet en vervolgens tekent. HotPDF houdt de twee methoden bewust gescheiden in plaats van de richting te raden aan de hand van de tekens. De keuze van welke methode u aanroept bepaalt dus het gedrag van het schrift dat u krijgt. De diepere mechanica van bidirectionele herordening en Arabische contextuele verbinding zijn een onderwerp op zich, dat wordt behandeld in het artikel over Arabische en RTL-tekstvorming met HotPDF; hier is het praktische punt specifieker. Gebruik RtLTextOut voor rechts-naar-links blokken, gebruik TextOut voor al het andere, en stuur de een nooit door de ander.

Het charset-argument bepaalt het schrift
Wat aan RtLTextOut vertelt of het Arabisch of Hebreeuws moet lay-outen is niet de methode, maar het lettertype. SetFont accepteert een Windows-charset als vierde argument, en die waarde geeft de schriftregels door aan de rechts-naar-links aanroep: 178 selecteert Arabisch, 177 selecteert Hebreeuws. Stel de charset in, teken vervolgens, en de twee regels hieronder worden zonder verdere configuratie in de juiste leesvolgorde weergegeven.
// 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 זה');
Twee details over die coördinaten zijn gemakkelijk over het hoofd te zien. De positie die u doorgeeft is nog steeds het startpunt van de tekst in het eigen coördinatensysteem van de pagina, gemeten vanaf de linksonderhoek waarbij Y naar boven toe groeit. Dit is dezelfde oorsprong die elke TextOut gebruikt; RtLTextOut verandert de glyphvolgorde, niet het meetpunt van de pagina. En zoals bij elke tekenaanroep moet SetFont als eerste komen en na elke AddPage worden herhaald, omdat het huidige lettertype een pagina-einde niet overleeft. Als u de herhaling vergeet, valt de tweede pagina terug op het lettertype dat actief was, wat voor Arabisch meestal lege vakjes betekent.
Het keert geen tekst om die u al hebt omgedraaid
De fout die hier de meeste debuggingtijd opslokt, is het doorgeven van een handmatig omgedraaide string aan RtLTextOut. Ontwikkelaars komen bij deze methode terecht nadat een eerste poging met de gewone TextOut achterstevoren werd weergegeven, en een veelgebruikte tussenoplossing is om de tekens in de code om te keren alvorens te tekenen. RtLTextOut keert de tekst intern zelf om, dus een vooraf omgedraaide string wordt een tweede keer omgekeerd en komt precies zo uit als hoe deze begon. Geef de tekst door in logische volgorde, de volgorde waarin u deze zou typen en naar behoefte zou voorlezen, en laat de aanroep de herordening afhandelen.
Deze valkuil is complexer dan een eenvoudige omdraaiing, omdat een dubbel omgekeerde string er correct uit kan zien voor een volledig Arabische testzin, maar direct faalt zodra een regel een Latijns woord of een getal bevat. Binnen een rechts-naar-links regel moeten die ingebedde delen namelijk van links naar rechts worden gelezen. Handmatige omdraaiing verpest die nesteling, terwijl het puur Arabische geval er toevallig wel correct uit blijft zien. Hierdoor glipt de bug door uw eerste rooktest en duikt deze pas later op bij een echte factuur met een rekeningnummer erin. Verwijder elke handmatige omdraaiing zodra u overstapt op RtLTextOut.
Het neveneffect van Direction dat belangrijk is om te weten
Het aanroepen van RtLTextOut verandert meer dan alleen de regel die u tekent. Het past ook de leesrichtingvoorkeur van het document aan naar rechts-naar-links, wat u anders handmatig via de eigenschap Direction zou instellen. Die setter voegt vpDirection toe aan de ViewerPreferences van het document, wat een PDF-viewer vertelt hoe hij spreads van twee pagina's moet rangschikken en aan welke kant een lay-out met tegenover elkaar liggende pagina's begint. Wanneer het hele document in het Arabisch of Hebreeuws is, is dit precies wat u wilt en krijgt u dit gratis.
Dit is belangrijk om te weten, juist omdat het onzichtbaar is op een enkele pagina. Als het document voornamelijk van links naar rechts is met één rechts-naar-links blok, zal de eerste aanroep van RtLTextOut toch de voorkeur van het hele bestand omzetten, en niets in uw proefdruk van één pagina zal dat laten zien. Het symptoom verschijnt weken later wanneer iemand een dubbelzijdige brochure afdrukt en de spreads gespiegeld uitvallen. Als dat niet is wat u wilt, stel dan Direction expliciet terug na de rechts-naar-links aanroep:
// RtLTextOut already set the document direction to RightToLeft;
// restore left-to-right if the document is predominantly LTR
Pdf.Direction := LeftToRight;
Laat dit voor een document dat echt van rechts naar links leest ongewijzigd. Het gaat erom dat u weet dat de aanroep een effect heeft op het hele document, zodat de brochure-verrassing achterwege blijft.
Registreer het lettertype dat u meelevert, niet degene die u hoopt dat geïnstalleerd is
Niets van de herordening maakt uit als het lettertype geen glyphs heeft om te tekenen. De klassieke fout is een rapport dat vlekkeloos wordt weergegeven op de machine van de ontwikkelelaar, waar Arial Unicode MS toevallig aanwezig is, en als rijen lege vakjes verschijnt op de server van een klant waar Windows stilletjes een lettertype heeft gesubstitueerd dat helemaal geen Arabische dekking heeft. De oplossing is om te stoppen met het vertrouwen op geïnstalleerde systeemlettertypen en er een te registreren die u met de applicatie meelevert.
// 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 هذا');
Er zijn twee beperkingen bij registratie. Een lettertype dat via RegisterUnicodeTTF wordt geladen, wordt ingebed, en de ingebedde Unicode-afhandeling van HotPDF vereist dat het document PDF 1.5 of nieuwer is. Dit is alleen een probleem als er downstream strikt PDF 1.4 wordt geëist, maar in dat geval is de fout stil. Het andere punt is juridisch in plaats van technisch: TrueType-bestanden bevatten bits voor inbeddingsrechten, en een lettertype dat er op het scherm goed uitziet, kan een licentie hebben die het verspreiden in documenten van klanten verbiedt. Controleer de licentie voordat u inbedt, niet pas na een klacht.
Een compleet console-voorbeeld
Om alle stukken samen te voegen, is hier een op zichzelf staand programma dat één pagina schrijft met een Arabische regel, een Hebreeuwse regel en een gemengde regel met een Latijnse productnaam. Elk blok stelt zijn charset in en tekent vervolgens in logische volgorde.
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.
Voer het uit en open het resultaat. De Arabische en Hebreeuwse regels lezen van rechts naar links, de letters verbinden zich waar het schrift dat vereist, en in de laatste regel staat de token HotPDF van links naar rechts binnen de Arabische tekst. Dit is het specificatie-correcte resultaat, ook al verrast het iedereen die voor het eerst een bidirectionele lay-out ziet. Het is verstandig om dat laatste punt op te nemen in uw acceptatiecriteria voordat een moedertaalspreker de uitvoer beoordeelt, omdat een ingebed tekstdeel dat de "verkeerde" kant op leest ten opzichte van het omringende schrift het meest als bug wordt gemeld terwijl het dat niet is.
De uitvoer verifiëren
Een pagina die er goed uitziet is niet hetzelfde als een pagina die correct is, dus controleer deze zoals een downstream-systeem dat zou doen. Kopieer de tekst uit de viewer en vergelijk de codepunten met uw bronstring; een correcte visuele volgorde met een verminkte logische volgorde is een reëel faalscenario. Voer een zoekopdracht uit in de viewer naar een woord dat u op de pagina kunt zien. Open het bestand vervolgens op een machine die niet over uw ontwikkelingslettertypen beschikt, aangezien die de grootste kans heeft om een stille lettertypevervanging bloot te leggen. Niets daarvan vervangt echter een moedertaalspreker die een echt document leest, wat problemen aan het licht brengt die geen enkele synthetische teststring zal vangen. Plan die controle dus in voordat het formaat definitief wordt opgeleverd.
RtLTextOut handelt bidirectionele herordening en Arabische contextuele verbinding af, wat het overgrote deel van het rechts-naar-links rapportage- en documentwerk dekt. Waar het ophoudt (bij schriften die meer nodig hebben dan herordening en verbinding, zoals de Indic-families, en de optionele OpenType-functies die via vervanging van afzonderlijke glyphs verlopen) is in kaart gebracht samen met de details over glyph-dekking en -vorming in het begeleidende artikel over Arabische en RTL-tekstvorming met HotPDF.
De hier getoonde aanroepen van RtLTextOut, SetFont en RegisterUnicodeTTF maken deel uit van de HotPDF-component voor Delphi en C++Builder.