Eine Annotation ist kein Seiteninhalt. Wenn Sie TextOut aufrufen oder ein Rechteck zeichnen, werden die Markierungen Teil des Content-Streams der Seite, eingebrannt in die Bytes, die ein Renderer malt. Eine Annotation ist ein separates Dictionary, das über das /Annots-Array an der Seite hängt, mit eigenem Rechteck, eigenem Erscheinungsbild und eigenem Lebenszyklus. Ein Reader kann sie öffnen, verschieben, ausblenden oder entfernen, ohne eine einzige Glyphe der darunterliegenden Seite anzutasten. Diese Trennung ist der ganze Grund, warum Annotationen existieren, und sie ist zugleich die Quelle der beiden Dinge, die zuerst überraschen: wo eine Annotation landet und wie sie aussieht, sobald ein bestimmter Viewer sie in die Hände bekommt
HotPDF stellt die Annotations-Subtypen aus ISO 32000 über eine Familie von AddXxxAnnotation-Aufrufen am Seitenobjekt bereit. Sie haben alle dieselbe Gestalt: ein Rechteck, das die Annotation im PDF-Benutzerraum auf der Seite fixiert, eine Nutzlast (Text, ein Stempelname, ein Punktepaar) und eine Farbe. Stimmt das Rechteck, ist der Großteil der Arbeit getan. Der Rest besteht darin zu wissen, welche Subtypen ihr eigenes Erscheinungsbild mitbringen und welche sich beim Zeichnen auf den Viewer verlassen

Das Rechteck ist die Annotation, nicht der Text
Jeder Annotationsaufruf nimmt ein TRect entgegen, und dieses Rechteck bedeutet etwas anderes als die Koordinaten, die Sie an TextOut übergeben. Für eine Textnotiz ist es der klickbare Hotspot, der kleine Bereich, in dem das Notiz-Icon sitzt und in dem ein Klick den Kommentar aufklappt. Für ein Quadrat oder ein Freitextfeld ist es die sichtbare Ausdehnung der Markierung. Für einen Stempel ist es die Box, in die die Stempelgrafik skaliert wird. Die Zahlen sind PDF-Benutzerraum-Punkte, gemessen von der linken unteren Ecke der Seite mit nach oben wachsendem Y, dieselbe Konvention, die der Rest von HotPDF verwendet
Eine Textnotiz ist der leichteste Subtyp. Sie geben ihr den Textkörper, ein Rechteck für das Icon, ein Flag, ob sie standardmäßig geöffnet ist, einen Icon-Namen und eine Farbe
Pdf.CurrentPage.AddTextAnnotation(
'Reviewer: confirm the totals on this line before sign-off.',
Rect(120, 700, 140, 720), // Icon-Hotspot, ca. 20 pt Quadrat
False, // geschlossen, bis der Leser darauf klickt
taComment, // Sprechblasen-Icon
clBlue);
Das Rechteck ist hier bewusst klein, etwa zwanzig Punkte Seitenlänge, weil eine Textnotiz nur ein Icon ist, bis jemand darauf klickt. Machen Sie das Rechteck groß, bekommen Sie keine große Notiz; Sie bekommen ein überdimensioniertes Klickziel mit dem Icon in einer Ecke. Das Flag Open steuert, ob das Popup beim Laden des Dokuments angezeigt wird. Setzen Sie eine Handvoll Notizen auf True, stapeln sie sich übereinander und über dem Inhalt, also reservieren Sie das für die eine Notiz, die der Leser tatsächlich sofort sehen soll
Der Icon-Name stammt aus THPDFTextAnnotationType, das auf die Standard-Notiz-Icons abbildet: taComment, taKey, taNote, taHelp, taParagraph, taNewParagraph und taInsert. Das Icon ist das Einzige, was der Typ ändert. Er verändert nicht das Verhalten, und es lohnt sich zu wissen, dass nicht jeder Viewer alle sieben zeichnet; die sicheren über alte und neue Reader hinweg sind taComment, taNote und taHelp
Freitext schreibt auf die Seite, bleibt aber eine Annotation
Eine Freitext-Annotation sieht wie Inhalt aus, weil der Text ohne Klick sichtbar ist und wie eine Bildunterschrift in seinem Rechteck sitzt. Sie ist trotzdem eine Annotation, mit aller Trennbarkeit, die das mit sich bringt, und genau das wollen Sie für einen Review-Stempel oder ein Entwurfsetikett, das jemand später entfernen können soll. Die Signatur tauscht Icon und Open-Flag gegen einen Ausrichtungswert
Pdf.CurrentPage.AddFreeTextAnnotation(
'DRAFT - not for distribution',
Rect(200, 210, 400, 235), // die Box, in die der Text gesetzt wird
ftCenter, // ftLeftJust / ftCenter / ftRightJust
clRed);
Hier zählt das Rechteck mehr als bei einer Textnotiz, weil der Text darin umbricht und ausgerichtet wird. Machen Sie die Box zu niedrig, wird der Text am unteren Rand abgeschnitten; zu schmal, und er bricht an Stellen um, die Sie nicht beabsichtigt haben. Die Ausrichtung stammt aus THPDFFreeTextAnnotationJust und hat nur die drei Werte. Weil Freitext eine Markup-Annotation ist, kann ein Leser, der die Datei in einem Editor öffnet, sie als Einheit auswählen, verschieben oder löschen, und das ist der Unterschied, der entscheidet, ob Sie zu Freitext greifen oder die Wörter einfach mit TextOut zeichnen. Muss das Etikett dauerhaft sein, zeichnen Sie es. Ist es redaktionell und soll wieder entfernt werden, machen Sie es zur Annotation
Geometrische und Linienmarkierungen, um auf Dinge zu zeigen
Quadrate, Kreise und Linien sind die Markierungen, mit denen Sie auf einen Bereich zeigen, statt ihn in Worten zu beschreiben. AddCircleSquareAnnotation deckt die beiden Kastenformen über einen THPDFCSAnnotationType von csCircle oder csSquare ab, wobei das Rechteck die Grenzen der Form angibt
// Ein Kasten um eine Abbildung, die Aufmerksamkeit braucht
Pdf.CurrentPage.AddCircleSquareAnnotation(
'Check this region against the source data',
Rect(50, 300, 120, 360),
csSquare,
clGreen);
// Eine Linie, definiert durch zwei Punkte statt ein Rechteck
var
StartPt, EndPt: THPDFCurrPoint;
begin
StartPt.X := 130; StartPt.Y := 360;
EndPt.X := 250; EndPt.Y := 320;
Pdf.CurrentPage.AddLineAnnotation(
'Points from the note to the figure',
StartPt, EndPt,
clBlue);
end;
Beachten Sie, dass die Linienannotation das Rechteckmuster durchbricht: Sie nimmt zwei THPDFCurrPoint-Records entgegen, einen Anfang und ein Ende, weil eine Linie durch ihre Endpunkte definiert ist, nicht durch einen Begrenzungsrahmen. Die Farbe legt den Strich fest. Wenn Sie Pfeilspitzen wollen, hat HotPDF Überladungen von AddLineAnnotation, die Linienendstile akzeptieren, aber die schlichte Form mit drei Argumenten zeichnet eine nackte Linie, was bei einem Callout meist gewünscht ist
Text-Markup-Subtypen arbeiten auf einem Bereich, den Sie bereits gesetzt haben. AddHighlightAnnotation nimmt ein Rechteck, optionale Inhalte und eine Farbe entgegen, die standardmäßig Gelb ist, und tönt den Bereich so, wie es ein Textmarker täte. Sie soll über echtem Text liegen, also sollte das Rechteck den Grenzen der gezeichneten Wörter entsprechen, was bedeutet, dass Sie es in der Regel aus denselben Koordinaten berechnen, die Sie an TextOut übergeben haben, statt zu raten
Stempel sind beim Rendern auf den Viewer angewiesen
Eine Stempelannotation ist diejenige, die am ehesten von einem Reader zum nächsten anders aussieht, und der Grund ist es wert, verstanden zu werden. AddStampAnnotation benennt einen Standardstempel über THPDFStampAnnotationType, mit Werten wie satApproved, satConfidential, satFinal, satDraft und satForComment
Pdf.CurrentPage.AddStampAnnotation(
'Approved for release on review',
Rect(50, 400, 200, 440),
satApproved,
clGreen);
Der Stempelname ist eine Anfrage. PDF definiert die Menge der Standard-Stempelnamen, aber nicht die Grafik dahinter, sodass jeder Viewer seine eigene Darstellung von „APPROVED“ oder „CONFIDENTIAL“ mitbringt, und einige rendern für Namen, die sie nicht kennen, gar nichts. Das Rechteck steuert die Box, in die die Grafik skaliert wird, und die Farbe ist ein Hinweis, den der Viewer beachten kann oder auch nicht. Wenn ein Stempel überall identisch aussehen muss, ist der verlässliche Weg gar kein Standardstempel: Zeichnen Sie die Markierung selbst mit TextOut und den Zeichenaufrufen, oder platzieren Sie sie als Freitext-Annotation, deren Erscheinungsbild Sie kontrollieren. Greifen Sie zum Standardstempel, wenn Sie den vertrauten Look des Viewers wollen und die Abweichungen tolerieren können
Dateianhänge folgen derselben Gestalt aus Rechteck plus Nutzlast. AddFileAttachmentAnnotation nimmt die Beschreibung, den Pfad der einzubettenden Datei, ein Rechteck für das Büroklammer-Icon und eine Farbe entgegen. Die Datei reist im PDF mit, und das Icon ist der Griff, mit dem ein Leser sie extrahiert
Worin sich Annotationen von AcroForm-Feldern unterscheiden
Die Verwechslung, die am meisten Zeit kostet, ist, eine Annotation wie ein Formularfeld zu behandeln. Beide hängen über /Annots an der Seite, und ein Formularfeld ist tatsächlich ein spezieller Annotations-Subtyp (ein Widget), weshalb sie verwandt wirken. Sie sind nicht austauschbar. Ein Formularfeld hält einen Wert, hat einen Namen, nimmt an der Tab-Reihenfolge teil und kann übermittelt, zurückgesetzt oder per Skript gesteuert werden; die erstellen Sie mit den Aufrufen AddTextField, AddCheckBox und AddPushButton, nicht mit den Annotationsaufrufen auf dieser Seite. Eine Markup-Annotation hält einen Kommentar oder eine Form, hat keinen Wert zum Übermitteln und ist das falsche Werkzeug, sobald Sie Eingaben sammeln müssen
Der praktische Test ist einfach. Soll ein Benutzer tippen, auswählen oder klicken und das Dokument sich das merken, wollen Sie ein AcroForm-Feld. Hinterlassen Sie eine Notiz, markieren Sie einen Bereich oder stempeln Sie einen Status, der mit der Datei reist, aber keine Daten ist, wollen Sie eine Annotation. Wer sie verwechselt, erzeugt Dokumente, die richtig aussehen und falsch funktionieren: ein „Feld“, das niemand ausfüllen kann, oder einen Kommentar, der verschwindet, wenn ein Formular zurückgesetzt wird. Die interaktive Seite, mit Feldtypen, Validierung und Submit-Aktionen, ist ein eigenes Thema, das in der Anleitung zu AcroForm-Feldern und -Aktionen behandelt wird
Eine Seite zusammensetzen
Die Bausteine fügen sich so zusammen wie der Rest von HotPDF. Setzen Sie die Dokumenteigenschaften, rufen Sie BeginDoc auf, zeichnen Sie mit den Text- und Grafikaufrufen den benötigten Seiteninhalt, fügen Sie darüber Annotationen hinzu und schließen Sie mit EndDoc ab. Annotationen hängen an CurrentPage, sodass sie nach einem AddPage auf der neuen Seite landen, und eine Notiz, die Sie für Seite eins vorgesehen hatten, erscheint stillschweigend auf Seite zwei, wenn Sie sie nach dem Umbruch hinzufügen
Pdf := THotPDF.Create(nil);
try
Pdf.FileName := 'annotated.pdf';
Pdf.Compression := cmFlateDecode;
Pdf.FontEmbedding := True;
Pdf.BeginDoc;
Pdf.CurrentPage.SetFont('Arial', [], 11);
Pdf.CurrentPage.TextOut(50, 740, 0, 'Quarterly figures, draft for review');
Pdf.CurrentPage.AddTextAnnotation(
'Confirm the totals before sign-off.',
Rect(50, 720, 70, 740), False, taComment, clBlue);
Pdf.CurrentPage.AddFreeTextAnnotation(
'DRAFT', Rect(450, 720, 540, 745), ftCenter, clRed);
Pdf.CurrentPage.AddStampAnnotation(
'For comment', Rect(50, 660, 180, 695), satForComment, clGreen);
Pdf.EndDoc;
finally
Pdf.Free;
end;
Ein letzter Reflex, den es sich aufzubauen lohnt, wenn die Ausgabe falsch aussieht: Öffnen Sie die Datei in mehr als einem Viewer, bevor Sie entscheiden, dass der Code kaputt ist. Stempel und die selteneren Notiz-Icons sind die üblichen Verdächtigen, und weil die Annotation eine Anfrage an den Reader ist und keine gemalten Pixel, ist ein Unterschied zwischen Acrobat und einem leichtgewichtigen Viewer oft die Spezifikation, die wie vorgesehen arbeitet, und kein Fehler in Ihrem Aufruf
Die hier gezeigten Annotationsaufrufe sind Teil der HotPDF Delphi Component für Delphi und C++Builder