Introductie van de RtLTextOut-functie in HotPDF voor rechts-naar-links tekstuitvoer in gegenereerde PDF-documenten.
Dit artikel is bedoeld voor ontwikkelaars die met pdf-programmeren werken. Productnamen, API-namen, bestandsnamen en codefragmenten zijn bewust ongewijzigd gehouden, zodat de voorbeelden direct met de oorspronkelijke documentatie en broncode te vergelijken zijn.
Overzicht
De pagina beschrijft het probleemgebied, de relevante implementatiekeuzes en de controles die belangrijk zijn voordat de oplossing in een echte toepassing wordt gebruikt.
Codevoorbeeld
Het onderstaande codefragment is ongewijzigd uit de Engelse bron overgenomen om identifiers, API-aanroepen en syntaxis exact te behouden.
|
1 2 3 4 5 |
// PWORD version for direct Unicode character array access procedure RtLTextOut(X, Y: Single; angle: Extended; Text: PWORD; TextLength: Integer); // WideString version for convenient string handling procedure RtLTextOut(X, Y: Single; angle: Extended; Text: WideString); |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
// Core segment processing logic I := 0; while I < TextLength do begin // Determine if current character starts an RTL or LTR segment IsRTLChar := ((ReversedText[I] >= $0600) and (ReversedText[I] <= $06FF)) or // Arabic ((ReversedText[I] >= $0590) and (ReversedText[I] <= $05FF)); // Hebrew CurrentSegmentIsRTL := IsRTLChar; SegmentStart := I; // Find the end of current segment (same character type) while (I < TextLength) do begin IsRTLChar := ((ReversedText[I] >= $0600) and (ReversedText[I] <= $06FF)) or ((ReversedText[I] >= $0590) and (ReversedText[I] <= $05FF)); if IsRTLChar <> CurrentSegmentIsRTL then Break; Inc(I); end; SegmentEnd := I - 1; // Process the segment if CurrentSegmentIsRTL then begin // RTL segment: keep original order for J := SegmentStart to SegmentEnd do OutputText[J] := ReversedText[J]; end else begin // LTR segment: reverse the segment internally for J := SegmentStart to SegmentEnd do OutputText[J] := ReversedText[SegmentEnd - (J - SegmentStart)]; end; end; |
|
1 2 3 4 5 |
// Store original direction and set to RightToLeft OriginalDirection := FParent.FDirection; FParent.FDirection := RightToLeft; FParent.FViewerPreference := FParent.FViewerPreference + [vpDirection]; FParent.FVPChanged := true; |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
program RtLTextOut; {$I ..\..\..\Lib\HotPDF.inc} {$APPTYPE CONSOLE} uses {$IFDEF XE2+} System.SysUtils, Vcl.Graphics, {$ELSE} SysUtils, Graphics, {$ENDIF} HPDFDoc; var HotPDF: THotPDF; begin try HotPDF := THotPDF.Create(nil); try HotPDF.FileName := 'RtLTextOut.pdf'; HotPDF.Title := 'RtLTextOut Function Test - Right-to-Left Text Output'; HotPDF.BeginDoc; // Title HotPDF.CurrentPage.SetFont('Arial', [fsBold], 18, 0, False); HotPDF.CurrentPage.TextOut(40, 50, 0, 'RtLTextOut Function Demonstration'); // Arabic text demonstration HotPDF.CurrentPage.SetFont('Arial Unicode MS', [], 12, 178, False); HotPDF.CurrentPage.TextOut(40, 160, 0, 'RtLTextOut:'); HotPDF.CurrentPage.RtLTextOut(40, 180, 0, 'يوضح ملف PDF هذا كيفية التعامل بشكل صحيح مع النص العربي من اليمين إلى اليسار.'); // Hebrew text demonstration HotPDF.CurrentPage.SetFont('Arial Unicode MS', [], 12, 177, False); HotPDF.CurrentPage.RtLTextOut(40, 370, 0, 'קובץ PDF זה מדגים כיצד לטפל כראוי בטקסט עברי הזורם מימין לשמאל.'); // Mixed text demonstration HotPDF.CurrentPage.RtLTextOut(40, 550, 0, 'مرحبا بالعالم! اكتب في مستندات PDF التي تم إنشاؤها بواسطة مكون HotPDF'); HotPDF.EndDoc; Writeln('RtLTextOut.pdf created successfully!'); finally HotPDF.Free; end; except on E: Exception do Writeln('Error: ', E.Message); end; end. |
|
1 2 3 4 5 6 7 8 9 10 |
// Initialize arrays SetLength(ReversedText, TextLength); SetLength(OutputText, TextLength); // Copy original text first for I := 0 to TextLength - 1 do begin ReversedText[I] := TempText^; Inc(TempText); end; |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
if CurrentFontObj.IsVertical then begin DeltaH := TextHeight('Zj'); DeltaW := TextWidth('W'); HorizontalLine := Y; ChBuff := @ChCode; for I := 0 to TextLength - 1 do begin ChCode := OutputText[I]; if (ChCode = $30FC) then ChCode := $7C; InternUnicodeTextOut(X + (DeltaW / 2), HorizontalLine - DeltaH, 0, ChBuff, 1); HorizontalLine := HorizontalLine + DeltaH; end; end else InternUnicodeTextOut(X, Y, angle, @OutputText[0], TextLength); |
|
1 2 3 4 5 6 7 |
// Use WideString for Unicode text var ArabicText: WideString; begin ArabicText := 'النص العربي'; HotPDF.CurrentPage.RtLTextOut(X, Y, 0, ArabicText); end; |
|
1 2 3 4 5 |
// Correct approach HotPDF.CurrentPage.SetFont('Arial Unicode MS', [], 12, 178, False); var Text: WideString := 'النص العربي'; HotPDF.CurrentPage.RtLTextOut(X, Y, 0, Text); |
Praktische aandachtspunten
- Controleer invoerbestanden en foutpaden expliciet voordat u de routine in productie gebruikt.
- Houd paginalay-out, lettertypen en coördinaten reproduceerbaar, vooral bij server-side verwerking.
- Test het resultaat in meer dan één PDF-viewer wanneer rendering, annotaties of interactieve elementen belangrijk zijn.
- Laat componentlevensduur en bestandshandles altijd via try/finally-achtige patronen opruimen.