C# / .NET PDF ライブラリ — PDF Oxide
PDF Oxide は .NET 向けの最速 PDF ライブラリです。テキスト抽出はページ平均 0.8 ms、PyMuPDF の 5 倍、pypdf の 15 倍高速、3,830 件の PDF でパス率 100%。抽出・作成・編集をひとつのパッケージで扱えます。NativeAOT 対応、トリミング安全で、using、async Task<T>、CancellationToken、LINQ フレンドリーなコレクションを備えたイディオマティックな API。ライセンスは MIT / Apache-2.0 です。
インストール
dotnet add package PdfOxide
ターゲットフレームワーク: net8.0 と net10.0。IsAotCompatible=true と IsTrimmable=true が有効化されています。
NuGet パッケージには Windows、macOS(Intel + Apple Silicon)、Linux(x64 + ARM64)向けのビルド済みネイティブライブラリが同梱されています。システム依存関係も Rust ツールチェインも不要です。
PDF を開く
using PdfOxide.Core;
using var doc = PdfDocument.Open("research-paper.pdf");
Console.WriteLine($"ページ数: {doc.PageCount}");
Console.WriteLine($"PDF バージョン: {doc.Version.Major}.{doc.Version.Minor}");
ストリームから:
using var stream = File.OpenRead("report.pdf");
using var doc = PdfDocument.Open(stream);
パスワード付き:
using var doc = PdfDocument.OpenWithPassword("secure.pdf", "user-password");
AES-256 (V=5, R=6) の PDF も完全にサポートしています。
Page API
v0.3.34 から PdfDocument は Pages プロパティ(IReadOnlyList<PdfPage>)と int インデクサを提供するため、foreach による反復や LINQ が使えます。
using PdfOxide.Core;
using var doc = PdfDocument.Open("paper.pdf");
foreach (var page in doc.Pages)
{
Console.WriteLine($"--- ページ {page.Index + 1} ---");
Console.WriteLine(page.ExtractText());
}
// インデックスで直接アクセス
PdfPage first = doc[0];
string md = await first.ToMarkdownAsync();
PdfPage には同期・非同期のフルサーフェスが揃っています: ExtractText() / ExtractTextAsync()、ToMarkdown()、ToHtml()、ToPlainText()、ExtractWords()、ExtractTextLines()、ExtractTables()、ExtractChars()、ExtractImages()、Search()。
テキスト抽出
単一ページ
using var doc = PdfDocument.Open("report.pdf");
string text = doc.ExtractText(0);
Console.WriteLine(text);
全ページ
string allText = doc.ExtractAllText();
ページを手動で走査
for (int i = 0; i < doc.PageCount; i++)
{
Console.WriteLine($"--- ページ {i + 1} ---");
Console.WriteLine(doc.ExtractText(i));
}
非同期抽出
すべての抽出メソッドには *Async 版があり、Task<T> を返し、任意の CancellationToken を受け取ります。
using PdfOxide.Core;
using var doc = PdfDocument.Open("large.pdf");
string text = await doc.ExtractTextAsync(0);
// キャンセル付き fan-out
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);
完全なパターンは 非同期ガイド を参照してください。
構造化抽出
var words = doc.ExtractWords(0);
foreach (var (text, x, y, w, h) in words)
{
Console.WriteLine($"\"{text}\" @ ({x:F1}, {y:F1})");
}
// 矩形領域で
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($"{rows}x{cols} のテーブル");
}
Markdown 変換
string markdown = doc.ToMarkdown(0);
string allMarkdown = doc.ToMarkdownAll();
HTML 変換
string html = doc.ToHtml(0);
string allHtml = doc.ToHtmlAll();
画像抽出
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} バイト)");
File.WriteAllBytes($"image_{Array.IndexOf(images.ToArray(), img)}.{img.Format}", img.Data);
}
インデックスカラー PDF は自動的に RGB に展開されます(RGB・グレースケール・CMYK を基底色空間とする 1/2/4/8 bpc)。
検索
var results = doc.SearchAll("四半期売上");
foreach (var (page, text, x, y, w, h) in results)
{
Console.WriteLine($"ページ {page}: \"{text}\" @ ({x}, {y})");
}
// 単一ページ・大文字小文字を区別
var pageResults = doc.SearchPage(0, "exact phrase", caseSensitive: true);
LINQ も自然に使えます。
var hitsByPage = doc.SearchAll("keyword")
.GroupBy(r => r.Page)
.OrderBy(g => g.Key);
foreach (var group in hitsByPage)
{
Console.WriteLine($"ページ {group.Key}: ヒット {group.Count()} 件");
}
PDF の作成
using PdfOxide.Core;
// Markdown から
using (var pdf = Pdf.FromMarkdown("# 請求書\n\n合計: **$42.00**"))
{
pdf.Save("invoice.pdf");
}
// HTML から
using (var pdf = Pdf.FromHtml("<h1>レポート</h1><p>作成日 2026-04-09</p>"))
{
pdf.Save("report.pdf");
}
// プレーンテキストから
using (var pdf = Pdf.FromText("プレーンテキスト文書。\n\n2 段落目。"))
{
pdf.Save("notes.pdf");
}
// 画像から
using (var pdf = Pdf.FromImage("scan.jpg"))
{
pdf.Save("scan.pdf");
}
編集 — メタデータとフォーム
using PdfOxide.Core;
using var editor = DocumentEditor.Open("form.pdf");
// メタデータの読み取り
Console.WriteLine($"タイトル: {editor.Title}");
Console.WriteLine($"ページ数: {editor.PageCount}");
// メタデータの更新
editor.Title = "四半期レポート";
editor.Author = "財務チーム";
editor.Subject = "2026 Q1 業績";
// フォームフィールドの埋め込みとフラット化
editor.SetFormFieldValue("employee.name", "Jane Doe");
editor.SetFormFieldValue("employee.email", "jane@example.com");
editor.FlattenForms();
editor.Save("edited.pdf");
// または: await editor.SaveAsync("edited.pdf");
編集せずにフォームフィールドを読むだけの場合:
using var doc = PdfDocument.Open("form.pdf");
foreach (var f in doc.GetFormFields())
{
Console.WriteLine($"{f.Name} ({f.FieldType}) = \"{f.Value}\"");
}
補足: 現在の .NET バインディングは、ドキュメントの開く/読み取り/変換/作成、画像抽出、フォームフィールドの読み取り・入力・フラット化、メタデータ編集に対応しています。ページ操作、注釈、レンダリング、署名は Rust コアと他のバインディングでは使用できますが、同等の .NET サーフェスは今後のリリースで追加予定です。
NativeAOT での発行
PDF Oxide の .NET バインディングは NativeAOT による発行に対応しています。
dotnet publish -c Release -r linux-x64 --self-contained -p:PublishAot=true
881 件の P/Invoke 宣言はすべて LibraryImport(ソース生成 P/Invoke)を使い、IsAotCompatible=true、IsTrimmable=true が設定されています。AOT コンパイルされたバイナリは使用部分だけをリンクし、ネイティブの Rust コアは同梱のプラットフォーム固有ライブラリにスタティックリンクされます。
プラグインと拡張
PdfOxide.Plugins パッケージ(PdfOxide と同時に配布)は、抽出したコンテンツを変換するプロセッサ(分類器、後処理、バリデータ)向けの拡張ポイントを提供します。拡張の作り方は プラグインガイド を参照してください。
エラー処理
すべてのメソッドは失敗時に型付き例外をスローします。
using PdfOxide.Core;
try
{
using var doc = PdfDocument.Open("document.pdf");
string text = doc.ExtractText(0);
}
catch (PdfOxideException ex)
{
Console.Error.WriteLine($"PDF Oxide エラー: {ex.Message}");
}
catch (FileNotFoundException)
{
Console.Error.WriteLine("ファイルが見つかりません");
}
次のステップ
- Python 入門 — Python から PDF Oxide を使う
- C# API リファレンス — API の完全ドキュメント
- 非同期ガイド —
Task<T>+CancellationTokenのパターン - 並行性ガイド —
ReaderWriterLockSlimによる共有パターン - テキスト抽出 — 抽出オプションの詳細
- NuGet パッケージ — リリースノートとダウンロード統計