Annotationen
Fügen Sie dem Viewer Annotationsunterstützung hinzu
Annotationen in Doconut funktionieren in zwei Richtungen: Benutzer zeichnen sie im Browser‑Widget und der Server speichert sie pro Seite, oder Ihr Code erstellt sie programmgesteuert und lädt sie in eine offene Sitzung. In beiden Fällen werden sie auf den Seiten gerendert und können in PDF/PNG‑Exporte eingebettet werden.
Die Annotationsunterstützung ist durch die Lizenzfunktion Annotation geschützt (automatisch gewährt bei einer aktiven temporären Lizenz).
Aktivieren der Annotations‑Benutzeroberfläche
Annotation ist ein Viewer‑Modul, keine eigenständige Symbolleiste. Die komplette Seite muss die Viewer‑Ressourcen, die Viewer‑Symbolleiste, das Viewer‑Mount und das initialisierte objViewer enthalten; das Annotation‑Ribbon wird dann eingebunden und an dieselbe Instanz angehängt.
Geben Sie die Annotations‑Bundles zusammen mit den Viewer‑Bundles aus – sie sind lizenzgesteuert, sodass die Tags nur erscheinen, wenn die Funktion verfügbar ist:
@Html.Raw(Viewer.ReferenceCss(new CssConfig
{
IncludeViewerCss = true,
IncludeAnnotationCss = true // jquery-ui.min.css + annotationBar.css
}))
@Html.Raw(Viewer.ReferenceScripts(new ScriptConfig
{
IncludeJQuery = true,
IncludeViewerScripts = true,
IncludeAnnotationScripts = true, // jquery-ui, raphael.js, annotation.js
IncludeAnnotationBar = true // the embedded annotation ribbon
}))Behalten Sie die komplette Viewer‑Zusammensetzung im Markup bei:
<nav id="toolbar" aria-label="Document viewer controls">
<!-- Viewer controls, including the button that opens Annotation -->
</nav>
<div id="annBarMount"></div>
<div id="divDocViewer"><div id="div_ctlDoc"></div></div>Das Annotation‑Bundle erzeugt das Ribbon‑DOM innerhalb von annBarMount; Sie müssen dessen Schaltflächen oder Dialog‑Markup nicht kopieren. Initialisieren Sie zuerst docViewer und erstellen Sie das Ribbon nur, wenn der Server bestätigt, dass Annotation lizenziert ist:
<script>
let annBar = null;
let currentToken = '';
const objViewer = $('#div_ctlDoc').docViewer({
BasePath: 'doconut',
ResPath: 'doconut-res/images',
onAnnLoaded: () => annBar?.handleAnnLoaded(),
onAnnSaved: () => annBar?.handleAnnSaved(),
onAnnSaveError: () => annBar?.handleAnnSaveError(),
onAnnClosed: () => annBar?.handleAnnClosed(),
onError: (message) => console.error('Viewer error:', message)
});
@if (Viewer.IsAnnotationEnabled)
{
<text>
annBar = $('#annBarMount').doconutAnnotationBar({
docId: 'ctlDoc',
getRequestParams: () => ({ token: currentToken }),
onStatus: (message) => console.log(message),
onToast: (message, type) => console.log(type, message),
onLayout: () => requestAnimationFrame(() => objViewer.Refit())
});
annBar.attach(objViewer);
</text>
}
</script>Das Speichern über das Ribbon sendet Daten über die Middleware (AnnSave), die sie pro Seite in der Dokumentensitzung speichert. Das Laden (AnnLoad) erfolgt automatisch, wenn eine Seite mit Annotationen gerendert wird. Die vier onAnn*‑Callbacks halten das Ribbon mit dem Viewer‑Lebenszyklus synchron.
Öffnen und schließen Sie es über jede host‑eigene Viewer‑Symbolleiste:
annBar.open();
annBar.close();Die öffentliche Ribbon‑API ist:
| Methode | Zweck |
|---|---|
attach(objViewer) | Verbindet das Ribbon mit dem initialisierten Viewer; einmalig erforderlich |
open() / close() | Beginnt bzw. beendet die Annotationsbearbeitung |
reset() | Setzt das Ribbon in den geschlossenen, nicht bearbeitenden Zustand zurück |
isOpen() / annotating() | Liest den Ribbon‑Status / den Annotationsbearbeitungsstatus des Viewers |
reopenEditable() | Lädt die Annotationen der aktuellen Seite als bearbeitbare Objekte neu |
updateActionState() | Aktualisiert die Verfügbarkeit von Speicher‑/Lösch‑Steuerelementen nach Host‑Änderungen |
headerSlot() | Gibt den optionalen Header‑Erweiterungsplatz für host‑eigene Steuerelemente zurück |
onStatus, onToast, onLayout, onEditStart und onEditEnd sind optionale Host‑Callbacks. Das endpoints‑Objekt kann zusätzlich exportPdf, exportPng, imageUpload und imageList bereitstellen; Steuerelemente ohne konfigurierten Endpunkt bleiben verborgen. Für die kombinierte Viewer‑, Such‑ und Annotations‑Startsequenz siehe Schnellstart.
Das Annotation‑Bundle fügt die Browser‑Autorentools hinzu, aber die Daten gehören weiterhin zur serverseitigen Dokumentensitzung, die durch das Token identifiziert wird. Das erneute Öffnen der Quelle erstellt eine neue Sitzung; speichern Sie das XML oder den codierten Annotationsumschlag in Ihrer Anwendung, wenn Annotationen über die Sitzungsdauer hinaus erhalten bleiben müssen.
Anmerkungen in C# erstellen
Erhalte einen Manager, der an die offene Sitzung gebunden ist, füge Anmerkungen hinzu und lade sie (mit using Doconut.Annotations; für die Typen und using System.Drawing; für Rectangle/Color):
app.MapPost("/api/annotations/load-sample", (string token, Viewer viewer) =>
{
// Gebunden an die Seitenabmessungen der offenen Sitzung
var manager = viewer.GetAnnotationManager(token);
var pageCount = viewer.GetPageCount(token);
// Ein Stempel pro Seite
for (int page = 1; page <= pageCount; page++)
{
manager.Add(new StampAnnotation(page, new Rectangle(30, 20, 240, 90),
$"PAGE {page}", 28, 4, Color.Maroon)
{
Opacity = 60,
Rotate = -8
});
}
manager.Add(new NoteAnnotation(1, new Rectangle(420, 150, 220, 120),
"Loaded from C# code.", Color.FromArgb(255, 255, 255, 170), 14));
// Laden in die Sitzung — das Widget holt sie über AnnLoad und das
// Renderer brennt sie in Bild/PDF-Exporte ein.
viewer.LoadAnnotationData(token, manager);
return Results.Ok();
});Anmerkungstypen
Alle Typen befinden sich in Doconut.Annotations und erben von BaseAnnotation (Seitenzahl + begrenzendes Rectangle):
| Typ | Hinweise |
|---|---|
StampAnnotation | Textstempel mit Schriftgröße, Rahmen, Farbe; unterstützt Opacity, Rotate |
NoteAnnotation | Haftnotiz mit Text, Hintergrundfarbe, Schriftgröße, TitleColor |
RectangleAnnotation | Rahmen- + Füllfarben, Title/ShowTitle |
CircleAnnotation | Rahmen- + Füllung, ShowBorder |
EllipseAnnotation | Rahmen- + Füllung, ShowBorder |
TriangleAnnotation | Rahmenfarbe, BackColor, ShowBorder |
LineAnnotation | Gerade Linie mit Breite und Farbe |
ArrowAnnotation | Linie mit Pfeilspitze; einstellbare Direction (Typ ArrowDirection, Himmelsrichtungen, Standard E) |
FreehandAnnotation | Freihandstrich aus codierten FreehandData-Punkten |
ImageAnnotation | Bild von einer URL. Eine relative URL wird beim Hinzufügen der Anmerkung relativ zum Anforderungs‑Host aufgelöst (nur das Bild wird zur Brennzeit abgerufen) — sie muss vom Server aus erreichbar sein (z. B. eine Datei unter wwwroot, die von UseStaticFiles bereitgestellt wird) |
Die AnnotationManager-API
| Mitglied | Zweck |
|---|---|
Add(BaseAnnotation) | Anmerkung in die Warteschlange stellen |
GetAnnotations() / GetAnnotations(int page) | Anzeigen, was der Manager enthält |
ClearAnnotations() / ClearAnnotations(int page) | Alle entfernen / pro Seite |
GetAnnotationData() / GetAnnotationData(int page) | Kodierte Anmerkungsdaten‑String — ein Base64‑Datenpaket (wie das Widget es verwendet) |
GetAnnotationXml() | XML‑Form |
Viewer spiegelt die Lade‑/Lese‑Operationen gegenüber einer Sitzung wider: LoadAnnotationData(token, manager) oder LoadAnnotationData(token, encodedData) (das Base64‑Datenpaket von GetAnnotationData()), LoadAnnotationXML(token, xml), GetAnnotationXML(token).
Export mit eingebrannten Anmerkungen
// PDF aller Seiten mit darauf gerenderten Anmerkungen
app.MapGet("/api/annotations/export-pdf", async (string token, Viewer viewer) =>
{
byte[] pdf = await viewer.ExportAnnotationsToPdfAsync(token, zoom: 100);
return Results.File(pdf, "application/pdf", "export.pdf");
});
// Oder ein ZIP mit PNGs pro Seite
app.MapGet("/api/annotations/export-png-zip", async (string token, Viewer viewer) =>
{
byte[] zip = await viewer.ExportAnnotationsToPngZipAsync(token, zoom: 100);
return Results.File(zip, "application/zip", "annotations-png.zip");
});Exporte verwenden denselben Brenner wie die Bildschirmausgabe, sodass das, was die Benutzer sehen, im Dateiinhalt enthalten ist.
Persistenz‑Workflow
- Dokument öffnen und dessen Token erhalten.
- Vorher gespeichtes XML oder kodierte Daten in diesen Token laden.
- Das Widget die Sitzungsanmerkungen lesen und bearbeiten lassen.
- XML mit
GetAnnotationXML(token)abrufen, wenn Ihre Anwendung die Persistenz entscheidet. - PDF/PNG exportieren, wenn ein flaches Ergebnis benötigt wird.
- Dokumentensitzung schließen.
Verwenden Sie das undurchsichtige Viewer‑Token nicht als dauerhaften Anmerkungs‑Identifier. Verknüpfen Sie persistente Anmerkungsdaten mit Ihren eigenen Dokument‑ und Versions‑Identifikatoren.
Sicherheit und Rendering-Hinweise
- Annotationsanfragen verwenden dieselbe Sitzungs-/Token-Sicherheit wie Seitenanfragen.
- Eine relative
ImageAnnotation-URL wird vom Anforderungs‑Host aufgelöst und muss zum Zeitpunkt des Renderns für den Server erreichbar bleiben. - Validieren und kontrollieren Sie jede vom Benutzer bereitgestellte Bild‑URL, um Server‑seitige Request‑Fälschungen zu vermeiden.
- Exporte verwenden dieselbe Lizenz‑/benutzerdefinierte Wasserzeichen‑Entscheidung wie die Bildschirmpage‑Renderung.
- Große Freihand‑Payloads und hochauflösende Exporte erhöhen den Speicherverbrauch; testen Sie realistische Dokumente und Zoom‑Werte.
Fehlersuche
| Symptom | Prüfung |
|---|---|
| Annotationsleiste fehlt | Annotation‑Fähigkeit und die vier Annotations‑CSS/Script‑Flags |
| Speicher‑Callback meldet einen Fehler | Token‑/Sitzungsablauf und Middleware BasePath |
| C#‑Annotationen werden nicht angezeigt | Seitennummerierung ist einsbasiert und Daten wurden in das aktive Token geladen |
| Bildannotation wird auf dem Bildschirm angezeigt, aber nicht beim Export | Der Server kann die Bild‑URL während des Renderns erreichen |
| Wieder geöffnetes Dokument hat keine Annotationen | XML/Daten außerhalb der Viewer‑Sitzung persistieren und dann in das neue Token laden |
War diese Seite hilfreich?