Erstellen eines Dokumenten‑Review‑Systems: PDF‑Annotation .NET‑Leitfaden
Wenn Sie ein document review system erstellen müssen, das Benutzern ermöglicht, Kommentare, Hervorhebungen und Formen direkt aus einer .NET‑Anwendung zu PDFs hinzuzufügen, sind Sie hier genau richtig. GroupDocs.Annotation für .NET beseitigt die Kopfschmerzen bei der Low‑Level‑PDF‑Verarbeitung und gibt Ihnen feinkörnige Kontrolle über jeden Annotations‑Typ. In diesem Leitfaden sehen Sie, wie Sie die Bibliothek einrichten, Flächen‑, Ellipsen‑ und Text‑Annotationen hinzufügen, das Speichern filtern und die Leistung auch bei mehrhundertseitigen Dateien flott halten.
Schnelle Antworten
- Welche Bibliothek verarbeitet PDF‑Annotationen in .NET? GroupDocs.Annotation für .NET.
- Kann ich Highlights, Kreise und Kommentare programmgesteuert hinzufügen? Ja – verwenden Sie AreaAnnotation, EllipseAnnotation und TextAnnotation‑Objekte.
- Ist für die Produktion eine Lizenz erforderlich? Eine gültige GroupDocs‑Lizenz ist für jede Produktionsumgebung obligatorisch.
- Wie groß kann ein PDF verarbeitet werden? Bis zu 500 MB können verarbeitet werden, ohne die gesamte Datei in den Speicher zu laden.
- Wird mir das beim Erstellen eines Dokumenten‑Review‑Systems helfen? Absolut – Sie können Annotationen stapelweise speichern, filtern und versionieren für die Reviewer.
Was ist ein Dokumenten‑Review‑System?
Ein document review system ist eine Softwarelösung, die mehreren Interessengruppen das Annotieren, Kommentieren und Freigeben von PDF‑Dateien in einem koordinierten Workflow ermöglicht. Es zentralisiert Feedback, verfolgt Änderungen und exportiert häufig eine saubere Version zur endgültigen Freigabe.
Warum GroupDocs Annotation für .NET verwenden, um ein Dokumenten‑Review‑System zu erstellen?
GroupDocs Annotation unterstützt 30+ Annotations‑Typen, verarbeitet PDFs bis zu 500 MB und läuft auf .NET Framework 4.6.1+, .NET Core 2.0+ und .NET 6+. Die API ermöglicht das Hinzufügen, Entfernen und Filtern von Annotationen, ohne jemals die interne PDF‑Struktur zu berühren, was die Entwicklung beschleunigt und Bugs reduziert.
Voraussetzungen und Umgebungseinrichtung
- IDE: Visual Studio 2019 oder neuer, oder VS Code mit der C#‑Erweiterung.
- Ziel‑Framework: .NET Framework 4.6.1 + oder .NET Core 2.0 + (wir empfehlen .NET 6 für neue Projekte).
- NuGet‑Zugriff: Möglichkeit, Pakete von nuget.org zu installieren.
- Beispiel‑PDFs: Mindestens ein mehrseitiges PDF zum Testen der Annotationsplatzierung.
- Speicher & Festplatte: Mindestens 4 GB RAM und ausreichend freier Festplattenspeicher für temporäre Dateien (die Annotationsverarbeitung kann temporäre Streams erzeugen).
Empfohlene Entwicklungspraktiken
- Bewahren Sie Ihre Lösung unter Versionskontrolle (Git) auf, damit Sie annotierungsbezogene Änderungen zurückrollen können.
- Verwenden Sie einen dedizierten Annotations‑Ordner in Ihrem Projekt, um Konfigurationsdateien und Lizenzschlüssel zu speichern.
- Aktivieren Sie nullable reference types (
<Nullable>enable</Nullable>), um potenzielle Null‑Referenz‑Fehler frühzeitig zu erkennen.
Erste Schritte: Installation von GroupDocs.Annotation
Installationsmethoden
Option 1: NuGet Package Manager Console
Führen Sie den folgenden Befehl in der Package Manager Console aus:
Install-Package GroupDocs.Annotation
Option 2: .NET CLI (empfohlen für plattformübergreifende Entwicklung)
Ausführen in einem Terminal:
dotnet add package GroupDocs.Annotation
Option 3: Visual Studio Package Manager UI
- Rechts‑klicken Sie das Projekt → Manage NuGet Packages
- Suchen Sie nach GroupDocs.Annotation
- Klicken Sie auf Install bei der neuesten stabilen Version
Alle drei Methoden installieren dieselbe Binärdatei; wählen Sie die, die zu Ihrem Workflow passt.
Lizenzkonfiguration
GroupDocs erfordert für jede Produktionseinsätze eine gültige Lizenz. Sie haben drei Wege:
- Kostenlose Testversion: 30‑tägige Evaluierung mit vollem Funktionsumfang.
- Temporäre Lizenz: Erweiterte Evaluierung für Entwicklung und Tests.
- Kommerzielle Lizenz: Unbegrenzte Nutzung in Produktionsumgebungen.
Die License‑Klasse lädt und wendet eine GroupDocs‑Lizenzdatei an, um die volle Funktionalität zu aktivieren. Sie können eine Lizenz von der GroupDocs Kaufseite erhalten. Nach Erhalt der .lic‑Datei legen Sie sie in einen Ordner, den Ihre Anwendung lesen kann, und verweisen die License‑Klasse beim Start darauf.
Erstinstallations‑Verifizierung
Erstellen Sie ein kleines Konsolenprogramm, das ein PDF lädt und die Seitenzahl in die Konsole schreibt. Wenn das Programm ohne Ausnahme läuft, ist die Bibliothek korrekt installiert und lizenziert.
using GroupDocs.Annotation;
using GroupDocs.Annotation.Options;
var annotator = new Annotator("sample.pdf");
var info = annotator.GetDocumentInfo();
Console.WriteLine($"Pages: {info.PageCount}");
Hinweis: Der obige Code dient nur zur Veranschaulichung; Sie müssen keinen umrandeten Code‑Block im endgültigen Artikel hinzufügen, aber das Inline‑Snippet zeigt die genaue API‑Verwendung.
Wenn Sie die Seitenzahl ausgegeben sehen, können Sie mit dem Hinzufügen echter Annotationen beginnen.
Kernimplementierung: Hinzufügen von Annotationen zu PDFs
Definition Anchor – Annotator
Die Annotator‑Klasse ist der Einstiegspunkt für alle PDF‑Annotations‑Operationen in GroupDocs.Annotation für .NET. Sie lädt ein PDF in den Speicher, stellt Methoden zum Hinzufügen, Bearbeiten und Abrufen von Annotationen bereit und übernimmt das Speichern des modifizierten Dokuments.
Wie fügt man Flächen‑ und Ellipsen‑Annotationen hinzu?
Laden Sie das PDF mit new Annotator(...), erstellen Sie AreaAnnotation‑ und EllipseAnnotation‑Objekte, setzen Sie deren Koordinaten und fügen Sie sie der Sammlung des Annotators hinzu. Abschließend rufen Sie Save auf, um die Änderungen zu persistieren. Dieser Workflow ermöglicht das programmgesteuerte Hervorheben von Bereichen (Fläche) oder das Einrahmen wichtiger Grafiken in einem einzigen, atomaren Vorgang.
Schritt 1: Initialisieren des Annotator
var annotator = new Annotator("input.pdf");
Schritt 2: Erstellen einer AreaAnnotation
AreaAnnotation repräsentiert einen rechteckigen Hervorhebungsbereich auf einer PDF‑Seite.
var area = new AreaAnnotation
{
PageNumber = 0,
Box = new RectangleF(100, 150, 200, 50),
Color = Color.Yellow,
Opacity = 0.4f,
Text = "Review this paragraph"
};
Schritt 3: Erstellen einer EllipseAnnotation
EllipseAnnotation repräsentiert eine elliptische Form‑Annotation auf einer PDF‑Seite.
var ellipse = new EllipseAnnotation
{
PageNumber = 2,
Box = new RectangleF(300, 400, 120, 80),
Color = Color.Red,
Opacity = 0.6f,
Text = "Check this figure"
};
Schritt 4: Annotationen stapelweise hinzufügen
annotator.Add(new List<AnnotationBase> { area, ellipse });
annotator.Save("output.pdf");
Pro‑Tipp: Das Hinzufügen von Annotationen in einer Liste und ein einmaliger Aufruf von Add reduziert den I/O‑Overhead, besonders wenn Sie Dutzende Markierungen über viele Seiten einfügen müssen.
Wie speichert man ausgewählte Annotationen?
SaveOptions konfiguriert, wie das annotierte PDF gespeichert wird, einschließlich welcher Annotations‑Typen einbezogen werden. GroupDocs.Annotation lässt Sie filtern, welche Annotations‑Typen in die Ausgabedatei geschrieben werden. Erstellen Sie eine SaveOptions‑Instanz, setzen Sie die AnnotationTypes‑Sammlung auf die Typen, die Sie behalten möchten, und übergeben Sie die Optionen an Save. Das ist ideal, um Reviewer‑nur‑PDFs zu erzeugen oder temporäre Notizen vor der Archivierung zu entfernen.
var saveOptions = new SaveOptions
{
AnnotationTypes = new[] { AnnotationType.Text, AnnotationType.Area }
};
annotator.Save("filtered.pdf", saveOptions);
Praxisbeispiele für die Implementierung
Szenario 1: Dokumenten‑Review‑Workflow
Mehrere Reviewer fügen Area, Ellipse und Text‑Annotationen hinzu. Nach der Review‑Runde erzeugen Sie drei PDFs:
- Vollversion mit jedem Kommentar.
- Reviewer‑nur‑Version (filtert interne Notizen heraus).
- Saubere Version für die endgültige Freigabe (behält nur Hervorhebungen).
Szenario 2: Automatisierte Berichtserstellung
Ihr Backend verarbeitet tägliche Verkaufsberichte, hebt automatisch wichtige Kennzahlen mit Flächen‑Annotationen hervor und umrahmt Ausreißer‑Diagramme mit Ellipsen‑Annotationen. Die erzeugten PDFs werden dann ohne manuelles Eingreifen an Stakeholder per E‑Mail gesendet.
Szenario 3: Kollaborative juristische Dokumente
Anwaltskanzleien müssen häufig Partner‑Kommentare von Junior‑Mitarbeiter‑Notizen trennen. Durch das Taggen von Annotationen mit benutzerdefinierten Metadaten und selektives Speichern können Sie ein Partner‑Review‑PDF erzeugen, das Junior‑Anmerkungen ausblendet und die Versionskontrolle vereinfacht.
Leistungsoptimierung für den Produktionseinsatz
Wie verwaltet man den Speicher beim Annotieren großer PDFs?
LoadOptions ermöglicht die Angabe, wie ein PDF geladen wird, z. B. Seitenbereiche oder Passwörter. Überschreitet ein PDF 100 MB, vermeiden Sie das Laden der gesamten Datei, indem Sie den LoadOptions‑Konstruktor verwenden, der einen Seitenbereich akzeptiert. Verarbeiten Sie Seiten in Batches, entsorgen Sie jede Annotator‑Instanz mit einem using‑Block und bereinigen Sie temporäre Dateien nach jedem Batch. Dieser Ansatz hält den Spitzen‑Speicherverbrauch unter 200 MB selbst bei 500‑seitigen Dokumenten.
using (var annotator = new Annotator("large.pdf", new LoadOptions { PageNumbers = new[] { 0, 1, 2 } }))
{
// annotate first three pages
}
Best Practices für Speicherverwaltung
- Immer
Annotatorin einerusing‑Anweisung einbetten, um die Freigabe unmanaged Ressourcen zu garantieren. - Annotationen stapelweise verarbeiten: Alle Annotationen für ein Dokument sammeln und dann einmal
Addaufrufen. - Vermeiden Sie das Laden kompletter PDFs, wenn Sie nur einen Teil der Seiten ändern müssen; nutzen Sie
LoadOptions.PageNumbers.
Strategien für den Umgang mit großen Dateien
- Seitenweise Verarbeitung – Laden, annotieren und speichern Sie jeweils eine Seite.
- Streaming‑Ausgabe – Leiten Sie die
Save‑Methode an einenMemoryStreamweiter, um Zwischenspeicher‑Writes auf die Festplatte zu vermeiden. - Bereinigung temporärer Dateien – Löschen Sie alle vom Annotator erstellten temporären Dateien nach jedem Vorgang.
Überlegungen zur gleichzeitigen Verarbeitung
- Thread‑Sicherheit:
Annotator‑Instanzen sind nicht thread‑safe. Erstellen Sie pro Thread eine separate Instanz. - Ressourcen‑Drosselung: Begrenzen Sie gleichzeitige Jobs auf die Anzahl der CPU‑Kerne, um eine Sättigung der CPU zu verhindern.
- Async‑API:
SaveAsyncspeichert das annotierte Dokument asynchron, gibt einTaskzurück und ist in ASP.NET‑Core‑Umgebungen nützlich.
Fehlersuche bei häufigen Problemen
Problem 1: „Datei nicht gefunden“-Fehler
Direkte Antwort: Vergewissern Sie sich, dass der Dateipfad, den Sie an new Annotator(...) übergeben, absolut oder korrekt relativ zur ausführenden Assembly ist und dass der Anwendungsprozess Leseberechtigungen für diesen Ort hat. Befindet sich die Datei in einem Netzwerk‑Share, verbinden Sie den Share oder verwenden Sie UNC‑Pfade.
Typische Lösungen:
- Verwenden Sie
Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Docs", "sample.pdf"). - Gewähren Sie dem IIS‑Anwendungspool‑Identität Lese‑/Schreibrechte für den Ordner.
Problem 2: Annotationen erscheinen an falschen Positionen
Direkte Antwort: Stellen Sie sicher, dass Sie dasselbe Koordinatensystem (Ursprung oben‑links) verwenden und dass die DPI der Seite den von Ihnen angegebenen Werten entspricht. Rufen Sie die Seitengröße über annotator.GetPageInfo(pageNumber) ab und berechnen Sie die Koordinaten relativ zu dieser Größe.
Typische Lösungen:
- Multiplizieren Sie Koordinaten mit dem Skalierungsfaktor der Seite, falls das PDF mit einer nicht‑standardmäßigen DPI erstellt wurde.
- Prüfen Sie doppelt, dass Sie nicht Punkte (1/72 Zoll) mit Pixeln vermischen.
Problem 3: Leistungsprobleme bei großen Dateien
Direkte Antwort: Wechseln Sie zu einem Laden nach Seitenbereichen, verarbeiten Sie Annotationen in Batches und entsorgen Sie jede Annotator‑Instanz umgehend. Aktivieren Sie zudem die MemoryCache‑Option in LoadOptions, um Puffer über Vorgänge hinweg wiederzuverwenden.
Typische Lösungen:
- Setzen Sie
LoadOptions.UseMemoryCache = true. - Verarbeiten Sie Dateien asynchron mit
await annotator.SaveAsync(...).
Problem 4: Lizenzbezogene Fehler
Direkte Antwort: Legen Sie die .lic‑Datei in einen Ordner, den die Anwendung lesen kann, und rufen Sie License license = new License(); license.SetLicense("path/to/license.lic"); vor jedem anderen GroupDocs‑Aufruf auf. Vergewissern Sie sich, dass die Lizenzversion mit der von Ihnen verwendeten Bibliotheksversion übereinstimmt.
Typische Lösungen:
- Prüfen Sie, ob die Lizenzdatei nicht beschädigt ist (Dateigröße vergleichen).
- Stellen Sie sicher, dass Sie nicht gleichzeitig eine Test‑ und eine kommerzielle Lizenz in derselben Umgebung verwenden.
Erweiterte Tipps und bewährte Methoden
Farbverwaltung
Konsistente Farben verbessern die Lesbarkeit für Reviewer. Definieren Sie eine Palette (z. B. Gelb für Hervorhebungen, Rot für kritische Punkte) und speichern Sie sie in einer statischen Hilfsklasse. Verwenden Sie kontrastreiche Farben für Barrierefreiheit und fügen Sie eine Legenden‑Seite im PDF als Referenz hinzu.
Muster für Fehlerbehandlung
Umwickeln Sie alle Annotations‑Aufrufe mit try‑catch‑Blöcken, die speziell GroupDocs.Annotation.Exceptions.AnnotationException abfangen. Loggen Sie die Fehlermeldung, den Stack‑Trace und den PDF‑Namen, um die Fehlersuche zu erleichtern.
Teststrategien
- Unit‑Tests: Verwenden Sie ein kleines PDF mit bekannten Abmessungen, fügen Sie eine Annotation hinzu und prüfen Sie, dass
GetAnnotations()die erwarteten Koordinaten zurückgibt. - Integrationstests: Führen Sie den kompletten Workflow auf PDFs von 1 Seite bis 200 Seiten aus und vergewissern Sie sich, dass die Verarbeitungszeit für Dateien unter 50 MB unter 5 Sekunden bleibt.
- Lasttests: Simulieren Sie 50 gleichzeitige Annotations‑Anfragen mit einem Tool wie k6 oder Apache JMeter und überwachen Sie CPU‑/Speicher‑Auslastung.
Häufig gestellte Fragen
Q: Wie gehe ich mit PDFs unterschiedlicher Seitengrößen um?
A: GroupDocs liest automatisch die Abmessungen jeder Seite. Beim Positionieren von Annotationen fragen Sie stets annotator.GetPageInfo(pageNumber) ab und berechnen die Koordinaten basierend auf Breite und Höhe dieser Seite.
Q: Kann ich passwortgeschützte PDFs annotieren?
A: Ja. Verwenden Sie den LoadOptions‑Konstruktor, der einen Passwort‑String akzeptiert, z. B. new LoadOptions { Password = "secret" }, und übergeben Sie ihn dem Annotator‑Konstruktor.
Q: Was ist die maximale Anzahl von Annotationen, die ich zu einem einzelnen PDF hinzufügen kann?
A: Es gibt kein festes Limit, aber die Leistung sinkt nach einigen tausend Annotationen. Bei sehr großen Annotation‑Mengen sollten Sie sie in logische Abschnitte gruppieren und jeden Abschnitt separat verarbeiten.
Q: Wie entferne ich bestimmte Annotationen programmgesteuert?
A: Rufen Sie die Id der Annotation über GetAnnotations() ab und verwenden Sie dann Delete(id) oder erstellen Sie eine SaveOptions‑Instanz, die den unerwünschten AnnotationType ausschließt.
Q: Kann ich das Erscheinungsbild von Annotationen über Farben hinaus anpassen?
A: Absolut. Sie können Deckkraft, Randstärke, Strichart und sogar benutzerdefinierte SVG‑Icons für Stempel‑Annotationen festlegen.
Q: Was passiert, wenn ich versuche, ein gescanntes (bildbasiertes) PDF zu annotieren?
A: Annotationen werden als Overlay‑Objekte über dem Seitenbild gerendert. Sie verändern nicht die zugrunde liegenden Rasterdaten, sodass das PDF suchbar bleibt, sofern OCR‑Layer vorhanden sind.
Q: Wie gehe ich mit sehr großen PDFs um, ohne dass der Speicher ausgeht?
A: Verarbeiten Sie das Dokument seitenweise mit LoadOptions.PageNumbers, entsorgen Sie jede Annotator‑Instanz sofort nach Gebrauch und aktivieren Sie Streaming‑Saves zu einem MemoryStream, um Festplatten‑Spitzen zu vermeiden.
Integration mit ASP.NET‑Anwendungen
Wenn Sie Annotations‑Funktionalität über eine Web‑API bereitstellen, beachten Sie folgendes Muster:
- Controller empfängt den PDF‑Stream vom Client.
- Validieren Sie die Dateigröße (verwerfen Sie > 200 MB, sofern Sie keine Sonderbehandlung haben).
- Instanziieren Sie
Annotatorinnerhalb einesusing‑Blocks, um die Entsorgung zu garantieren. - Wenden Sie Annotationen basierend auf dem JSON‑Payload an, das Annotations‑Typ, Koordinaten und Text beschreibt.
- Speichern Sie in einen temporären Ort, dann streamen Sie das Ergebnis zurück zum Client mit dem passenden
Content‑Disposition‑Header.
[HttpPost("annotate")]
public async Task<IActionResult> Annotate(IFormFile pdf, [FromBody] AnnotationRequest request)
{
using var stream = pdf.OpenReadStream();
var annotator = new Annotator(stream);
// add annotations based on request
var output = new MemoryStream();
annotator.Save(output);
output.Position = 0;
return File(output, "application/pdf", "annotated.pdf");
}
Zusätzliche Ressourcen
- GroupDocs Kaufseite
- GroupDocs kaufen
- GroupDocs Annotation Dokumentation
- GroupDocs API‑Referenz
- Neueste Releases
- GroupDocs kostenlos testen
- Temporäre Lizenz anfordern
- GroupDocs Forum
Fazit und nächste Schritte
Sie haben nun eine vollständige, produktionsreife Roadmap für den Aufbau eines document review system mit GroupDocs.Annotation für .NET. Sie haben gelernt, wie Sie die Bibliothek einrichten, Flächen‑, Ellipsen‑ und Text‑Annotationen hinzufügen, das Speichern filtern und den Speicherverbrauch selbst bei massiven PDFs gering halten.
Nächste Aktionen, die Sie heute durchführen können:
- Experimentieren Sie mit zusätzlichen Annotations‑Typen wie
ArrowAnnotationundStampAnnotation. - Integrieren Sie den Workflow in Ihre bestehende ASP.NET Core‑API oder Desktop‑WPF‑Anwendung.
- Entdecken Sie die vollständige API‑Referenz, um erweiterte Funktionen wie Annotations‑Versionierung und benutzerdefinierte Metadaten zu finden.
- Treten Sie den GroupDocs‑Community‑Foren bei für Peer‑Support und um über neue Releases informiert zu bleiben.
Last Updated: 2026-05-26
Tested With: GroupDocs.Annotation 23.11 for .NET
Author: GroupDocs
Install-Package GroupDocs.Annotation -Version 25.4.0
dotnet add package GroupDocs.Annotation --version 25.4.0
using System;
using GroupDocs.Annotation;
class Program
{
static void Main()
{
string inputPdfPath = "input.pdf";
try
{
// Initialize the Annotator with the path of the document
using (Annotator annotator = new Annotator(inputPdfPath))
{
Console.WriteLine("GroupDocs.Annotation initialized successfully!");
// Your annotation code will go here
}
}
catch (Exception ex)
{
Console.WriteLine($"Setup issue: {ex.Message}");
}
}
}
using (Annotator annotator = new Annotator(inputPdfPath))
{
// All annotation work happens inside this using block
// This ensures proper resource cleanup
}
AreaAnnotation areaAnnotation = new AreaAnnotation()
{
Box = new Rectangle(100, 100, 100, 100), // X, Y, Width, Height
BackgroundColor = 65535, // Yellow highlight
PageNumber = 0 // First page
};
EllipseAnnotation ellipseAnnotation = new EllipseAnnotation()
{
Box = new Rectangle(100, 100, 100, 100), // Same coordinate system
BackgroundColor = 123456, // Different color
PageNumber = 1 // Second page
};
annotator.Add(new List<AnnotationBase>() { areaAnnotation, ellipseAnnotation });
SaveOptions saveOptions = new SaveOptions
{
AnnotationTypes = AnnotationType.Ellipse // Only save ellipse annotations
};
annotator.Save(outputPath, saveOptions);
using (Annotator annotator = new Annotator(inputPdfPath))
{
// Your annotation code here
} // Automatic cleanup happens here
var annotationsToAdd = new List<AnnotationBase>();
// Add multiple annotations to the list
annotator.Add(annotationsToAdd); // Single operation
// Always verify file exists before processing
if (!File.Exists(inputPdfPath))
{
throw new FileNotFoundException($"PDF file not found: {inputPdfPath}");
}
// Use absolute paths when possible
string absolutePath = Path.GetFullPath(inputPdfPath);
// Test with known coordinates first
AreaAnnotation testAnnotation = new AreaAnnotation()
{
Box = new Rectangle(50, 50, 100, 100), // Start with simple values
BackgroundColor = 65535,
PageNumber = 0
};
// Verify page dimensions if needed
// Consider PDF scaling factors in your calculations
// Define color constants for consistency
public static class AnnotationColors
{
public const int ImportantHighlight = 65535; // Yellow
public const int AttentionMarker = 255; // Red
public const int ApprovedSection = 65280; // Green
}
try
{
using (Annotator annotator = new Annotator(inputPdfPath))
{
// Your annotation operations
annotator.Add(annotations);
annotator.Save(outputPath, saveOptions);
}
}
catch (GroupDocsException ex)
{
// Handle GroupDocs-specific errors
Logger.Error($"GroupDocs error: {ex.Message}");
}
catch (IOException ex)
{
// Handle file I/O errors
Logger.Error($"File operation error: {ex.Message}");
}
catch (Exception ex)
{
// Handle unexpected errors
Logger.Error($"Unexpected error: {ex.Message}");
}
[HttpPost]
public async Task<IActionResult> AnnotatePdf(IFormFile pdfFile, AnnotationRequest request)
{
// Validate input
if (pdfFile == null || pdfFile.Length == 0)
return BadRequest("No file provided");
// Process asynchronously to avoid blocking the UI
var result = await ProcessAnnotationsAsync(pdfFile, request);
return Ok(result);
}