Technischer Artikel

Delphi-PDF-Berichte mit HotPDF: TextOut, Schriften und Bilder

Dieser deutsche Artikel behandelt Delphi-PDF-Berichte mit HotPDF: TextOut, Schriften und Bilder für Teams, die mit Delphi, C++Builder, Lazarus/FPC und losLab-Komponenten arbeiten

Textplatzierung und der Ursprung in der unteren linken Ecke

Der Kernaufruf für Seitenobjekte lautet . X und Y positionieren den Text in Punkten aus der unteren linken Ecke, und Angle rotiert den Text in Grad – so werden diagonale Stempel wie DRAFT und COPY ohne zusätzliche Mechanismen gezeichnet. Die Vorgehensweise, um mit VCL trainierte Intuition weiterzunutzen, besteht darin, Y als Seitenhöhe minus dem Abstand vom oberen Rand zu berechnen:

var
  Pdf: THotPDF;
begin
  Pdf := THotPDF.Create(nil);
  try
    Pdf.FileName := 'invoice-0001.pdf';
    Pdf.BeginDoc;
    Pdf.CurrentPage.SetFont('Arial', [fsBold], 16);
    Pdf.CurrentPage.TextOut(50, 792 - 50, 0, 'INVOICE');       // 50pt from top of Letter
    Pdf.CurrentPage.SetFont('Arial', [], 10);
    Pdf.CurrentPage.TextOut(50, 792 - 70, 0, 'Date: 2026-06-11');
    Pdf.CurrentPage.TextOut(300, 400, 45, 'COPY');              // rotated stamp
    Pdf.AddPage;                                                // CurrentPage now points here
    Pdf.CurrentPage.SetFont('Arial', [], 10);                   // font state does not carry over
    Pdf.CurrentPage.TextOut(50, 742, 0, 'Page 2 detail rows');
    Pdf.EndDoc;
  finally
    Pdf.Free;
  end;
end;

Der zentrale Aufruf des Seitenobjekts ist (X, Y, Angle, Text). X und Y positionieren den Text in Punkten von der linken unteren Ecke aus, und Angle rotiert ihn in Grad; so entstehen diagonale DRAFT- und COPY-Stempel ohne weitere Mechanik. Das Idiom, das VCL-geprägte Intuition nutzbar hält, berechnet Y als Seitenhöhe minus Abstand von oben:

Schriftarten müssen auf dem Server vorhanden sein, nicht nur auf Ihrem Desktop

Ein Schriftartenfehler ist ein Bereitstellungsfehler. Die Entwicklerumgebung hat Unternehmensschriftarten installiert; das Windows-Dienstkonto auf dem Produktionshost nicht, sodass die Ausgabe stillschweigend ersetzt wird. Ein defensiver Modus besteht darin, Schriftarten aus Dateien zu laden, die vom Installationsprogramm gesteuert werden, anstatt dem Schriftartenverzeichnis des Betriebssystems zu vertrauen, was genau das ist, was der Unicode-Registrierungsaufruf von HotPDF tut:

Pdf.RegisterUnicodeTTF('C:\ProgramData\MyApp\Fonts\NotoSans.ttf');
Pdf.CurrentPage.SetFont('NotoSans', [], 12);
Pdf.CurrentPage.TextOut(50, 700, 0, WideString('Łódź — Ünïcode test ✓'));

Schriftfehler sind Deployment-Fehler. Auf dem Entwicklungsrechner ist die Corporate Font installiert; das Windows-Dienstkonto auf dem Produktionshost hat sie nicht, und die Ausgabe ersetzt sie stillschweigend. Das defensive Muster ist, Schriften aus Dateien zu laden, die Ihr Installer kontrolliert, statt dem OS-Schriftenverzeichnis zu vertrauen, und genau das erledigt HotPDFs Unicode-Registrierungsaufruf:

In den seltenen Fällen, in denen „keine Schriftdatei den erforderlichen Inhalt darstellen kann“, wie z. B. bei MICR-Markierungen oder proprietären Symbolen, unterstützt HotPDF Type-3-Schriften über und , wobei jedes Glyph ein von Ihnen definierter kleiner Inhaltsstrom ist. Dies ist ein Nischenwerkzeug, aber besser, als Symbole als Hunderte winziger Bilder auszuliefern

Bilder: Die mittleren Parameter sind Breite und Höhe, nicht eine andere Ecke

HotPDF trennt die Bildregistrierung von der Platzierung. empfängt oder auf einmal, PNG-Grafiken werden zuerst in Bitmaps decodiert und geben einen Index zurück; kann diesen Index nach Bedarf mehrmals platzieren. Was zweimal gelesen werden muss, ist die Signatur:

var
  Png: TPngImage;
  Logo: TBitmap;
  LogoIdx: Integer;
begin
  Png := TPngImage.Create;
  Logo := TBitmap.Create;
  try
    Png.LoadFromFile('brand-logo.png');
    Logo.Assign(Png);                       // decode PNG to a bitmap
    LogoIdx := Pdf.AddImage(Logo, icFlate); // lossless for flat-color art
  finally
    Logo.Free;
    Png.Free;
  end;
  // (Index, X, Y, Width, Height, Angle) — not (X1, Y1, X2, Y2)
  Pdf.CurrentPage.ShowImage(LogoIdx, 50, 700, 120, 40, 0);
end;

HotPDF trennt Bildregistrierung und Platzierung. AddImage nimmt ein TBitmap oder TJPEGImage einmal auf — PNG-Grafiken vorher in ein Bitmap dekodieren — und gibt einen Index zurück; ShowImage platziert diesen Index beliebig oft. Die Signatur ist der Teil, den man zweimal lesen sollte:

Die beiden Zahlen nach der Position sind Breite und Höhe, nicht die gegenüberliegende Ecke, und das letzte Argument ist ein Rotationswinkel. Code, der von X1/Y1/X2/Y2 ausgeht, zieht Logos über den Großteil der Seite, ein Fehler, der in der Ausgabe offensichtlich und im Quelltext rätselhaft wirkt. Verwandt damit: KeepImageAspectRatio steht standardmäßig auf True, daher erzeugt eine unpassende Box Letterboxing statt Verzerrung; setzen Sie es nur dann auf False, wenn Strecken wirklich beabsichtigt ist

Die Trennung von Registrierung und Platzierung ist auch für Performance und Dateigröße wichtig: bettet die Bitmap-Daten einmal ein, und jedes ShowImage mit demselben Index nutzt dieses eine eingebettete Objekt wieder. Ein 500-seitiger Kontoauszugslauf, der für dasselbe Logo pro Seite AddImage aufruft, bettet das Logo 500-mal ein; derselbe Lauf mit einmaliger Registrierung und wiederverwendetem Index bettet es einmal ein. Cachen Sie die Indizes in einem kleinen Dictionary nach Asset-Pfad, und das Problem tritt nicht auf

Verwenden Sie Pfadprimitive, um regelmäßige Linien, Rahmen und Schattierungen zu zeichnen

Tabellelinien und Summenfelder benötigen überhaupt keine Bilder; Vektorprimitive sind bei jeder Skalierung schärfer, und die Dateigrößenkosten sind nahezu null. Das Modell besteht darin, zuerst den Pfad zu erstellen und dann den Zeichenvorgang auszuführen:

// Horizontal rule under the table header
Pdf.CurrentPage.SetLineWidth(0.75);
Pdf.CurrentPage.MoveTo(50, 660);
Pdf.CurrentPage.LineTo(545, 660);
Pdf.CurrentPage.Stroke;

// Shaded totals box: X, Y, width, height
Pdf.CurrentPage.SetRGBFillColor(RGB(235, 235, 235));
Pdf.CurrentPage.Rectangle(395, 120, 150, 40);
Pdf.CurrentPage.Fill;

Tabellenlinien und Summenkästen brauchen überhaupt keine Bilder; Vektorprimitive liefern bei jedem Zoom schärfere Ausgabe und kosten nahezu nichts in der Dateigröße. Das Modell ist Pfadkonstruktion gefolgt von einem Paint-Operator:

Verarbeiten Sie die Paginierung mit echten Daten statt mit Beispieldaten

Numerische Spalten offenbaren eine weitere Gewohnheit, die frühzeitig etabliert werden sollte: Berechnen Sie die X-Position, indem Sie die gerenderte Breite jedes Werts vom rechten Rand der Spalte abziehen, um Geldbeträge rechtsbündig auszurichten, anstatt Zeichenfolgen mit Leerzeichen aufzufüllen. Die Auffüllung mit Leerzeichen funktioniert nur bei Monospace-Schriftarten, während Finanzberichte fast nie Monospace-Schriftarten verwenden. Numerische Werte sollten zuerst mit Delphi-eigenen Routinen, die die jeweilige Lokalisierung berücksichtigen (z. B. ), formatiert und dann gemessen werden. Auf diese Weise ist das Tausendertrennzeichen, das die Kunden-Lokalisierung erwartet, genau das Zeichen, dessen Breite Sie messen

Numerische Spalten zeigen eine weitere Gewohnheit, die früh aufgebaut werden sollte: Richten Sie Beträge an ihrer rechten Kante aus, indem Sie die X-Position aus der rechten Spaltengrenze und der gerenderten Breite jedes Werts berechnen, statt Zeichenketten mit Leerzeichen aufzufüllen. Leerzeichen funktionieren nur in Monospace-Schriften, und Finanzberichte werden nie in Monospace-Schriften gesetzt. Formatieren Sie Werte mit Delphis locale-bewussten Routinen wie FormatFloat, bevor Sie messen, damit genau das Tausendertrennzeichen, das die Locale des Kunden erwartet, auch in seiner Breite gemessen wurde

FAQ

Warum wird mein Text am unteren Rand der Seite gerendert?

Der PDF-Ursprung liegt in der unteren linken Ecke, und Y wächst nach oben. Konvertieren Sie die Position relativ zum oberen Rand mit , oder entwerfen Sie Layout-Code von Anfang an um den Ursprung unten links

Warum ist die Schriftart auf der ersten Seite korrekt und auf der zweiten Seite falsch?

AddPageCurrentPageSetFontAddPageTextOut

Wie hält man die Dateigröße beim Einbetten vieler Fotos angemessen?

Übergeben Sie an für fotografische Inhalte und stellen Sie auf nahezu 85 ein; überlassen Sie das verlustfreie Logos und Strichzeichnungen mit flachen Farben. Jedes unterschiedliche Bild wird nur einmal mit registriert, und dann wird der Index wiederverwendet

Produktreferenz

Jeder Aufruf in diesem Artikel ist in der HotPDF-Komponente für Delphi und C++Builder enthalten. Er dokumentiert neben Formular-, Verschlüsselungs- und Signaturfunktionen auch vollständige Text-, Schriftarten-, Bild- und Zeichen-APIs