Skip to content

C# / .NET PDF-Bibliothek — PDF Oxide

PDF Oxide ist die schnellste PDF-Bibliothek für .NET: 0,8 ms Textextraktion im Durchschnitt, 5× schneller als PyMuPDF, 15× schneller als pypdf, 100 % Trefferquote auf 3.830 PDFs. Ein Paket für Extraktion, Erstellung und Bearbeitung — NativeAOT-ready, trim-safe, mit idiomatischem using, async Task<T>, CancellationToken und LINQ-freundlichen Collections. Lizenz: MIT / Apache-2.0.

Installation

dotnet add package PdfOxide

Ziel-Frameworks: net8.0 und net10.0. IsAotCompatible=true und IsTrimmable=true sind aktiviert.

Das NuGet-Paket enthält vorgebaute native Bibliotheken für Windows, macOS (Intel + Apple Silicon) sowie Linux (x64 + ARM64). Keine Systemabhängigkeiten, keine Rust-Toolchain erforderlich.

PDF öffnen

using PdfOxide.Core;

using var doc = PdfDocument.Open("research-paper.pdf");
Console.WriteLine($"Seiten: {doc.PageCount}");
Console.WriteLine($"PDF-Version: {doc.Version.Major}.{doc.Version.Minor}");

Aus einem Stream:

using var stream = File.OpenRead("report.pdf");
using var doc = PdfDocument.Open(stream);

Mit Passwort:

using var doc = PdfDocument.OpenWithPassword("secure.pdf", "user-password");

AES-256-PDFs (V=5, R=6) werden vollständig unterstützt.

Page-API

Seit v0.3.34 stellt PdfDocument eine Pages-Eigenschaft (ein IReadOnlyList<PdfPage>) sowie einen int-Indexer bereit, sodass Sie per foreach iterieren und LINQ verwenden können.

using PdfOxide.Core;

using var doc = PdfDocument.Open("paper.pdf");

foreach (var page in doc.Pages)
{
    Console.WriteLine($"--- Seite {page.Index + 1} ---");
    Console.WriteLine(page.ExtractText());
}

// Oder direkt per Index
PdfPage first = doc[0];
string md = await first.ToMarkdownAsync();

Jede PdfPage bietet eine vollständige synchrone und asynchrone Oberfläche: ExtractText() / ExtractTextAsync(), ToMarkdown(), ToHtml(), ToPlainText(), ExtractWords(), ExtractTextLines(), ExtractTables(), ExtractChars(), ExtractImages(), Search().

Textextraktion

Einzelne Seite

using var doc = PdfDocument.Open("report.pdf");

string text = doc.ExtractText(0);
Console.WriteLine(text);

Alle Seiten

string allText = doc.ExtractAllText();

Seiten manuell durchlaufen

for (int i = 0; i < doc.PageCount; i++)
{
    Console.WriteLine($"--- Seite {i + 1} ---");
    Console.WriteLine(doc.ExtractText(i));
}

Asynchrone Extraktion

Zu jeder Extraktionsmethode gibt es ein *Async-Pendant, das Task<T> zurückgibt und optional einen CancellationToken entgegennimmt.

using PdfOxide.Core;

using var doc = PdfDocument.Open("large.pdf");

string text = await doc.ExtractTextAsync(0);

// Fan-out mit Abbruch
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30));
var tasks = Enumerable.Range(0, doc.PageCount)
    .Select(i => doc.ExtractTextAsync(i, cts.Token));
string[] pages = await Task.WhenAll(tasks);

Vollständige Muster finden Sie im Async-Leitfaden.

Strukturierte Extraktion

var words = doc.ExtractWords(0);
foreach (var (text, x, y, w, h) in words)
{
    Console.WriteLine($"\"{text}\" bei ({x:F1}, {y:F1})");
}

// Nach Region
string regionText = doc.ExtractTextInRect(0, x: 50, y: 700, width: 200, height: 50);

var tables = doc.ExtractTables(0);
foreach (var (rows, cols) in tables)
{
    Console.WriteLine($"Tabelle {rows}x{cols}");
}

Markdown-Konvertierung

string markdown = doc.ToMarkdown(0);
string allMarkdown = doc.ToMarkdownAll();

HTML-Konvertierung

string html = doc.ToHtml(0);
string allHtml = doc.ToHtmlAll();

Bildextraktion

using PdfOxide.Core;

using var doc = PdfDocument.Open("brochure.pdf");
var images = doc.ExtractImages(0);

foreach (var img in images)
{
    Console.WriteLine($"{img.Width}x{img.Height} {img.Format} ({img.Colorspace}, {img.BitsPerComponent} bpc, {img.Data.Length} Bytes)");
    File.WriteAllBytes($"image_{Array.IndexOf(images.ToArray(), img)}.{img.Format}", img.Data);
}

PDFs mit indizierten Farben werden automatisch nach RGB expandiert (1/2/4/8 bpc mit RGB, Graustufen oder CMYK als Basisfarbraum).

Suche

var results = doc.SearchAll("Quartalsumsatz");
foreach (var (page, text, x, y, w, h) in results)
{
    Console.WriteLine($"Seite {page}: \"{text}\" bei ({x}, {y})");
}

// Eine einzelne Seite mit Groß-/Kleinschreibung
var pageResults = doc.SearchPage(0, "exakter Ausdruck", caseSensitive: true);

LINQ lässt sich nahtlos einsetzen:

var hitsByPage = doc.SearchAll("keyword")
    .GroupBy(r => r.Page)
    .OrderBy(g => g.Key);

foreach (var group in hitsByPage)
{
    Console.WriteLine($"Seite {group.Key}: {group.Count()} Treffer");
}

PDF-Erstellung

using PdfOxide.Core;

// Aus Markdown
using (var pdf = Pdf.FromMarkdown("# Rechnung\n\nSumme: **$42,00**"))
{
    pdf.Save("invoice.pdf");
}

// Aus HTML
using (var pdf = Pdf.FromHtml("<h1>Bericht</h1><p>Erstellt am 2026-04-09</p>"))
{
    pdf.Save("report.pdf");
}

// Aus reinem Text
using (var pdf = Pdf.FromText("Reines Textdokument.\n\nZweiter Absatz."))
{
    pdf.Save("notes.pdf");
}

// Aus einem Bild
using (var pdf = Pdf.FromImage("scan.jpg"))
{
    pdf.Save("scan.pdf");
}

Bearbeiten — Metadaten und Formulare

using PdfOxide.Core;

using var editor = DocumentEditor.Open("form.pdf");

// Metadaten lesen
Console.WriteLine($"Titel: {editor.Title}");
Console.WriteLine($"Seiten: {editor.PageCount}");

// Metadaten aktualisieren
editor.Title = "Quartalsbericht";
editor.Author = "Finanzabteilung";
editor.Subject = "Ergebnisse Q1 2026";

// Formularfelder füllen und flach zeichnen
editor.SetFormFieldValue("employee.name", "Jane Doe");
editor.SetFormFieldValue("employee.email", "jane@example.com");
editor.FlattenForms();

editor.Save("edited.pdf");
// oder: await editor.SaveAsync("edited.pdf");

Formularfelder nur lesen, ohne zu bearbeiten:

using var doc = PdfDocument.Open("form.pdf");
foreach (var f in doc.GetFormFields())
{
    Console.WriteLine($"{f.Name} ({f.FieldType}) = \"{f.Value}\"");
}

Hinweis: Die .NET-Bindung unterstützt derzeit das Öffnen, Lesen, Konvertieren und Erstellen von Dokumenten, Bildextraktion, Lesen, Füllen und Flachzeichnen von Formularfeldern sowie die Bearbeitung von Metadaten. Seitenoperationen, Anmerkungen, Rendering und Signaturen sind im Rust-Kern und in anderen Bindings verfügbar; ein entsprechendes .NET-API folgt in einer zukünftigen Version.

NativeAOT-Publishing

Die .NET-Bindung von PDF Oxide ist für NativeAOT-Publishing vorbereitet:

dotnet publish -c Release -r linux-x64 --self-contained -p:PublishAot=true

Alle 881 P/Invoke-Deklarationen nutzen LibraryImport (source-generated P/Invoke), IsAotCompatible=true und IsTrimmable=true. Ihr AOT-kompiliertes Binary bindet nur die tatsächlich verwendeten Teile ein; der native Rust-Kern wird über die mitgelieferte plattformspezifische Bibliothek statisch gelinkt.

Plugins und Erweiterungen

Das Paket PdfOxide.Plugins (ausgeliefert neben PdfOxide) stellt Erweiterungspunkte für Prozessoren bereit, die extrahierte Inhalte transformieren — Klassifikatoren, Nachbearbeiter, Validatoren. Für die Erstellung von Erweiterungen siehe den Plugin-Leitfaden.

Fehlerbehandlung

Alle Methoden werfen im Fehlerfall typisierte Exceptions:

using PdfOxide.Core;

try
{
    using var doc = PdfDocument.Open("document.pdf");
    string text = doc.ExtractText(0);
}
catch (PdfOxideException ex)
{
    Console.Error.WriteLine($"Fehler in PDF Oxide: {ex.Message}");
}
catch (FileNotFoundException)
{
    Console.Error.WriteLine("Datei nicht gefunden");
}

Nächste Schritte