Anmerkungen

Fügen Sie dem Viewer Anmerkungsunterstützung hinzu

Anmerkungen 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 eingebrannt werden.

Die Anmerkungsunterstützung ist durch die Lizenzfunktion Annotation (automatisch gewährt bei einer aktiven temporären Lizenz) eingeschränkt.

Aktivieren Sie die Anmerkungs‑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 montiert und an dieselbe Instanz angehängt.

Geben Sie die Annotations‑Bündel zusammen mit den Viewer‑Bündeln aus – sie sind lizenzgesteuert, sodass die Tags nur erscheinen, wenn die Funktion verfügbar ist:

html
@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 sichtbar:

html
<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‑Bündel 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:

html
<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 Anmerkungen gerendert wird. Die vier onAnn*‑Callbacks halten das Ribbon mit dem Viewer‑Lebenszyklus synchronisiert.

Öffnen und schließen Sie es über jede host‑eigene Viewer‑Symbolleiste:

javascript
annBar.open();
annBar.close();

Die öffentliche Ribbon‑API ist:

MethodeZweck
attach(objViewer)Verbinden Sie das Ribbon mit dem initialisierten Viewer; einmal erforderlich
open() / close()Beginnen bzw. beenden Sie die Anmerkungsbearbeitung
reset()Setzt das Ribbon in den geschlossenen, nicht bearbeitenden Zustand zurück
isOpen() / annotating()Liest den Ribbon‑Status / den Anmerkungsbearbeitungsstatus des Viewers
reopenEditable()Lädt die Anmerkungen der aktuellen Seite erneut als editierbare Objekte
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 Startsequenz des kombinierten Viewers, der Suche und der Annotation siehe Schnellstart.

Das Annotation‑Bündel 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 Anmerkungsumschlag in Ihrer Anwendung, wenn Anmerkungen über die Sitzungsdauer hinaus erhalten bleiben müssen.

Anmerkungen in C# erstellen

Erhalten Sie einen Manager, der an die offene Sitzung gebunden ist, fügen Sie Anmerkungen hinzu und laden Sie sie (mit using Doconut.Annotations; für die Typen und using System.Drawing; für Rectangle/Color):

csharp
app.MapPost("/api/annotations/load-sample", (string token, Viewer viewer) =>
{
    // Bound to the open session's page dimensions
    var manager = viewer.GetAnnotationManager(token);
    var pageCount = viewer.GetPageCount(token);

    // One stamp per page
    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));

    // Load into the session — the widget fetches them via AnnLoad and the
    // renderer burns them into image/PDF exports.
    viewer.LoadAnnotationData(token, manager);
    return Results.Ok();
});

Anmerkungstypen

Alle Typen befinden sich in Doconut.Annotations und erben von BaseAnnotation (Seitennummer + begrenzendes Rectangle):

TypHinweise
StampAnnotationTextstempel mit Schriftgröße, Rand, Farbe; unterstützt Opacity, Rotate
NoteAnnotationHaftnotiz mit Text, Hintergrundfarbe, Schriftgröße, TitleColor
RectangleAnnotationRand‑ + Füllfarben, Title/ShowTitle
CircleAnnotationRand + Füllung, ShowBorder
EllipseAnnotationRand + Füllung, ShowBorder
TriangleAnnotationRandfarbe, BackColor, ShowBorder
LineAnnotationGerade Linie mit Breite und Farbe
ArrowAnnotationLinie mit Pfeilspitze; einstellbare Direction (Typ ArrowDirection, Himmelsrichtungen, Standard E)
FreehandAnnotationFreihandstrich aus codierten FreehandData‑Punkten
ImageAnnotationBild von einer URL. Eine relative URL wird beim Hinzufügen der Anmerkung gegen den Anforderungs‑Host aufgelöst (nur das Bild wird beim Einbrennen abgerufen) – sie muss vom Server aus erreichbar sein (z. B. eine Datei unter wwwroot, die von UseStaticFiles bereitgestellt wird).

Die AnnotationManager‑API

MitgliedZweck
Add(BaseAnnotation)Fügt eine Anmerkung zur Warteschlange hinzu
GetAnnotations() / GetAnnotations(int page)Untersucht, was der Manager enthält
ClearAnnotations() / ClearAnnotations(int page)Entfernt alle / pro Seite
GetAnnotationData() / GetAnnotationData(int page)Kodierter Anmerkungsdaten‑String — ein Base64‑Übertragungsumschlag (was das Widget verwendet)
GetAnnotationXml()XML‑Form

Viewer spiegelt die Lade‑/Lesevorgänge gegen eine Sitzung wider: LoadAnnotationData(token, manager) oder LoadAnnotationData(token, encodedData) (der Base64‑Übertragungsumschlag von GetAnnotationData()), LoadAnnotationXML(token, xml), GetAnnotationXML(token).

Export mit eingebrannten Anmerkungen

Exporte verwenden denselben Brenner wie die Bildschirmausgabe, sodass das, was Benutzer sehen, im Dateiinhalt enthalten ist.

csharp
// PDF of all pages with annotations rendered onto them
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");
});

// Or a ZIP of per-page PNGs
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");
});

Persistenzablauf

  1. Öffnen Sie das Dokument und erhalten Sie dessen Token.
  2. Laden Sie zuvor gespeichertes XML oder kodierte Daten in dieses Token.
  3. Lassen Sie das Widget die Sitzungs‑Anmerkungen lesen und bearbeiten.
  4. Rufen Sie XML mit GetAnnotationXML(token) ab, wenn Ihre Anwendung entscheidet, zu persistieren.
  5. Exportieren Sie PDF/PNG, wenn ein flaches Ergebnis benötigt wird.
  6. Schließen Sie die Dokumentsitzung.

Verwenden Sie das undurchsichtige Viewer‑Token nicht als dauerhaften Anmerkungsbezeichner. Verknüpfen Sie persistente Anmerkungsdaten mit Ihren eigenen Dokument‑ und Versionskennungen.

Sicherheits‑ und Rendering‑Hinweise

  • Anmerkungsanfragen verwenden dieselbe Sitzungs‑/Token‑Sicherheit wie Seitenanfragen.
  • Eine relative ImageAnnotation‑URL wird vom Anforderungs‑Host aufgelöst und muss zum Zeitpunkt des Einbrennens für den Server erreichbar bleiben.
  • Validieren und kontrollieren Sie jede vom Benutzer bereitgestellte Bild‑URL, um Server‑seitige Anforderungsfälschungen zu vermeiden.
  • Exporte wenden dieselbe Lizenz/benutzerdefinierte Wasserzeichen‑Entscheidung wie die Bildschirmausgabe von Seiten an.
  • Große Freihand‑Payloads und hochauflösende Exporte erhöhen den Speicherverbrauch; testen Sie realistische Dokumente und Zoom‑Werte.

Fehlerbehebung

SymptomPrüfung
Annotation‑Ribbon fehltAnnotation‑Funktion und die vier Annotations‑CSS/Script‑Flags
Speicher‑Callback meldet einen FehlerToken‑/Sitzungsablauf und Middleware BasePath
C#‑Anmerkungen erscheinen nichtSeitennummerierung beginnt bei 1 und Daten wurden in das aktive Token geladen
Bild‑Anmerkung erscheint auf dem Bildschirm, aber nicht im ExportDer Server kann die Bild‑URL beim Einbrennen erreichen
Wieder geöffnetes Dokument hat keine AnmerkungenPersistieren Sie XML/Daten außerhalb der Viewer‑Sitzung und laden Sie sie dann in das neue Token

War diese Seite hilfreich?