このページには自動翻訳されたテキストを含めることができます。
C# および VB.NET で PDF ドキュメントを作成する方法
この記事では、Docotic.Pdf ライブラリを使用して .NET で PDF ドキュメントを作成するさまざまな方法について説明します。これは、外部依存関係なしで PDF ドキュメントの作成、編集、変換、処理を行う、高性能な純粋 C# .NET ライブラリです。

以下のセクションでは、Docotic.Pdf を使用して PDF を作成する主なアプローチを紹介します。
- 低レベル制御を提供し、テキスト、グラフィックス、PDF の内部構造を扱える Core API を使用する方法。このオプションは、カスタムレイアウト、グラフィックス中心のドキュメント、高度な機能に最適です。
- 段落、表、ヘッダー、フッター、自動ページ分割をサポートする 高レベルの Layout API を使用する方法。この API は、位置を手動で計算せずに構造化されたドキュメントを作成したい場合に最適です。
- SVG やその他の Web 形式をサポートする HTML を PDF に変換する方法。このアプローチは、既に HTML ドキュメントを生成しており、それらの HTML および CSS ファイルの PDF 版が必要な場合に特に有用です。
- 画像から PDF を作成する方法。この方法は、スキャン文書、画像ベースのレポート、領収書、ラスター画像から始まるあらゆるワークフローに適しています。
- PDF の 結合または分割を行う方法。これは、レポートのまとめ、ユーザーアップロードの処理、関連ドキュメントの結合、大きな PDF の再構成に適しています。
- テンプレートから PDF を作成する方法。このアプローチは、領収書、税務書類、雇用契約書、その他の反復的なドキュメント種別など、バッチ生成されるドキュメントで一貫した書式が必要な場合に有効です。
ガイドで扱う追加トピック:
Core API を使用した PDF の作成
Core API は、Docotic.Pdf における PDF 作成の基盤です。Core API の Canvas API を通じて、PDF の canvas 上でテキスト、画像、ベクターグラフィックスの配置を完全かつ低レベルに制御できます。この描画 API は Core API のサブセットであり、canvas を使用してページや他のオブジェクトにコンテンツを追加するためのメソッドとプロパティを提供します。レンダリングに加えて、Core API は注釈、フォームフィールド、レイヤー、ブックマーク、その他の PDF 機能もサポートします。
以下は、テキストの描画、画像の配置、ページ canvas 上でのベクターグラフィックスの描画という 3 つの基本操作を使ってシンプルな PDF を作成する C# コードです。
using var pdf = new PdfDocument();
var canvas = pdf.Pages[0].Canvas;
canvas.Font = pdf.CreateFont(PdfBuiltInFont.HelveticaBold);
canvas.FontSize = 14;
canvas.DrawString(40, 100, "Core API demo: text, images, and vector graphics");
var image = pdf.CreateImage("image.png");
canvas.DrawImage(image, 40, 180, 120, 120, 0);
canvas.Pen.Color = new PdfRgbColor(30, 60, 160);
canvas.Pen.Width = 2;
canvas.Brush.Color = new PdfRgbColor(200, 230, 255);
canvas.DrawRectangle(new PdfRectangle(200, 200, 150, 80), PdfDrawMode.FillAndStroke);
pdf.Save("core-api-demo.pdf");
この概要では、Core API ができることのごく一部しか紹介していません。Core API を使用した PDF の構築に関する詳細な記事については、高度なトピック を参照してください。この記事では、テキスト測定、色空間の扱い、クリッピングの適用、パターンによる領域の塗りつぶし、透過処理、その他の機能を扱います。
Layout API を使用した PDF の生成
Layout API は、複雑で情報量の多い PDF を生成するための、最も簡単で効率的な高レベルのドキュメント構築エンジンです。
この API を使用すると、ページ、コンテナ、テキストスパン、画像、表、リンク、ヘッダー、フッターなどの構造要素から PDF を組み立てます。座標を計算したりページ分割を手動で管理したりする代わりに、ドキュメントの構造を記述し、残りはレイアウトエンジンに任せます。
以下の例では、手動配置ではなく宣言的レイアウトに基づいて Layout API を使って PDF を作成する方法を示します。
PdfDocumentBuilder.Create()
.Info(info => info.Title = "Docotic.Pdf Layout API demo")
.Generate("layout-api-demo.pdf", doc => doc.Pages(pages =>
{
pages.Content().Padding(100).Text(text =>
{
text.Span("The Layout API lets you compose PDFs from structural elements ");
text.Line("without manually calculating coordinates or handling pagination.")
.Style(s => s.Strong);
});
}));
詳細ガイドを確認して、.NET で PDF を生成する アプリケーションで Layout API を使う方法を学んでください。
HTML を PDF に変換して Web コンテンツを扱う
Docotic.Pdf は、無料の HtmlToPdf アドオンと組み合わせることで、最新かつ高品質な Chrome ベースの HTML から PDF へのエンジンを提供します。SVG や WebP 画像などの最新の HTML やその他の Web コンテンツを、アドオンが提供する API を使って高品質な PDF ドキュメントに変換できます。
HTML to PDF API は、完全な HTML ページや HTML フラグメントから PDF を作成できます。URL、未加工の HTML 文字列、ローカル HTML ファイルからコンテンツを変換できます。後者 2 つのオプションにより、HTML テンプレートから PDF を簡単に生成できます。
HTML テンプレートから PDF を生成する例を示します。
public static async Task HelloHtmlTemplate()
{
static string GetUserName()
{
// 実際のロジックに置き換えてください: フォーム入力、API 呼び出し、設定など。
return "World";
}
string html = $@"
<h1>Hello, {GetUserName()}!</h1>
<p>This PDF was generated from an HTML template.</p>";
using var converter = await HtmlConverter.CreateAsync();
using var pdf = await converter.CreatePdfFromStringAsync(html);
pdf.Save("hello-html-template.pdf");
}
詳細と追加例については、HTML から PDF への概要 を参照してください。
画像から PDF を作成する
Docotic.Pdf は、画像を PDF に変換する柔軟で開発者に優しい方法を提供します。ライブラリは Core API を通じて JPEG、BMP、GIF、PNG、TIFF、JPEG 2000 形式の画像をサポートします。

PDF 形式でサポートされている場合、Docotic.Pdf は画像バイト列をそのまま埋め込み、元の圧縮を維持するためにピクセルのデコードや再エンコードを回避します。可能な場合は色空間も保持します。
さらに、SVG と WebP 形式は HTML to PDF API を通じてサポートされます。ラベルと並べて画像を配置する 必要がある場合や、説明文を併置したい場合は、Layout API を使うと最小限の手間で要素を配置・整列できます。
複数の画像を 1 つの PDF にまとめる方法
Docotic.Pdf を使うと、画像のセットを 1 つの PDF に簡単に変換し、各ページに 1 枚ずつ配置できます。
以下の例では、ファイルから画像を読み込み、それぞれを独自のページに描画します。各画像はページに収まるようにスケーリングされ、中央に配置されるため、すっきり一貫したレイアウトになります。
public static void ImagesOnToPdf(string[] imagePaths, string outputPath)
{
using var pdf = new PdfDocument();
foreach (string path in imagePaths)
{
var image = pdf.CreateImage(path);
var page = pdf.AddPage();
var pageWidth = page.Width;
var pageHeight = page.Height;
var scale = Math.Min(pageWidth / image.Width, pageHeight / image.Height);
var drawWidth = image.Width * scale;
var drawHeight = image.Height * scale;
var x = (pageWidth - drawWidth) / 2;
var y = (pageHeight - drawHeight) / 2;
page.Canvas.DrawImage(image, x, y, drawWidth, drawHeight, 0);
}
pdf.RemovePage(0);
pdf.Save(outputPath);
}
複数ページ TIFF と GIF 画像の扱い
Docotic.Pdf は複数ページの TIFF と GIF ファイルを完全にサポートします。PDF に画像を追加する際、いずれかの画像が複数ページを含む可能性がある場合は、CreateImage の代わりに OpenImage メソッドを使用してください。
以下のコードは TIFF を PDF に変換する方法を示しており、単一ページ画像と複数ページ画像の両方で動作します。
public static void OddFramesToPdf(string[] imagePaths, string outputPath)
{
using var pdf = new PdfDocument();
foreach (string path in imagePaths)
{
var imageFrames = pdf.OpenImage(path);
for (int i = 0; i < imageFrames.Count; i++)
{
if (i % 2 != 0)
continue;
var image = pdf.CreateImage(imageFrames[i]);
var page = pdf.AddPage();
page.Width = image.Width;
page.Height = image.Height;
page.Canvas.DrawImage(image, 0, 0, image.Width, image.Height, 0);
}
}
pdf.RemovePage(0);
pdf.Save(outputPath);
}
同じアプローチを使って GIF を PDF に変換できます。単一フレームしか含まない形式に対しては、これは必要以上に複雑ですが、他の画像形式にも適用できます。
PDF の結合と分割
完全な機能を備えた .NET ライブラリとして、Docotic.Pdf は既存ドキュメントのページを結合、抽出、再構成して新しい PDF を作成できます。
PDF を結合する場合、ライブラリは別ドキュメントのページを追加するだけでなく、レイヤー、ブックマーク、ページラベル、共有 JavaScript、destination(リンク先)、埋め込みファイルも追加します。詳細や、結合した PDF のサイズを削減するための指針については、PDF の結合 に関する記事を参照してください。
デジタル署名済みの PDF は、既存の署名を無効にせずに結合することはできません。署名を保持するには、ドキュメントを追加する代わりに PDF ポートフォリオを作成 してください。別の方法として、最初に PDF を結合し、その後で結合済みドキュメントに 新しいデジタル署名を適用する 方法もあります。
Docotic.Pdf では、ページを新しいドキュメントへコピーおよび抽出することもできます。コピーされたページに関連するすべてのコンテンツは保持され、注釈、フォームコントロール、構造化コンテンツ、レイヤー、その他の関連データも含まれます。実践的な例については、.NET で PDF を分割する 記事を参照してください。そこでは、ページの抽出や削除の方法も説明しています。
PDF テンプレートを扱う
PDF テンプレートは、新しいドキュメントを作成するためのベース構造として機能する、あらかじめ設計された PDF ファイルです。異なるデータを与えながら一貫したレイアウトの PDF を生成する必要がある場合に役立ちます。視覚デザインとデータ自体を分離したい場合にも、PDF テンプレートは良い選択です。
テンプレートは、フォームベースの PDF でも、フォームのない静的 PDF でもかまいません。どちらの種類も同じ目的を果たします。さらに、フォームベースのテンプレートには対話要素が含まれ、平坦化されていない場合はユーザーから情報を収集できます。
フォームベースのテンプレートから PDF を作成する
フォームベースのテンプレートには通常、対話型 PDF フォームの標準で広くサポートされている種類である AcroForms が含まれます。このようなテンプレートから PDF を生成するには、通常次のことが必要です。
- 各プレースホルダーフィールドを埋める
- 以後の編集を防ぐためにフィールドを平坦化する
- 結果を新しい PDF として保存する
以下は、名前でプレースホルダーテキストフィールドを検索し、値を設定してフィールドを平坦化し、結果を保存してテンプレートから PDF を作成する C# コードです。
var nameOnCertificate = "Eva Marin";
using var pdf = new PdfDocument("certificate-template.pdf");
if (pdf.TryGetControl("name", out var field))
{
if (field is PdfTextBox nameField)
{
nameField.Text = nameOnCertificate;
nameField.Flatten();
}
}
pdf.Save($"certificate-{nameOnCertificate}.pdf");
テンプレートに多数のプレースホルダーが含まれている場合は、各フィールドを個別に埋める代わりに FDF データをインポートできます。PdfDocument.FlattenControls を使って、すべてのフィールドを一度に平坦化することもできます。
フォームのない静的テンプレートから PDF を作成する
テンプレートにフォームフィールドが含まれていない場合は、名前やその他のデータをページ canvas 上に直接描画します。静的 PDF テンプレートには、通常、テキスト、画像、空白領域などの固定された視覚的プレースホルダーが含まれます。テンプレートから PDF を作成するには、これらの空白領域を埋め、プレースホルダーテキストや画像をプログラムで置き換える必要があります。
空白領域
Canvas API を使って、空白領域にテキストや画像を配置します。名前や写真を追加する程度の小さな変更だけが必要な単純なケースでは、この方法が有効です。領域の座標とサイズを把握しておく必要があり、テキストを適切に配置するには、まず測定してから整列する必要がある場合があります。
可変長テキストや複数行テキストの扱いはより難しいですが、それでも実現可能です。DrawText、DrawString、およびテキスト測定用のメソッドを組み合わせることで、必要に応じて行を折り返し、配置できます。テンプレートにこのような領域がいくつもある場合は、Layout API を使って PDF を生成するなどの別アプローチを検討してください。
プレースホルダーテキスト
Docotic.Pdf には テキストの検索と置換 を行うメソッドもあります。ただし、テンプレート機構としてテキスト検索を使うのは、通常、空のプレースホルダー領域を扱うより簡単ではありません。新しいコンテンツを挿入する前に、正確なテキスト断片を特定し、きれいに削除する必要があります。
プレースホルダー画像
静的テンプレートには、ユーザーのアバターや製品写真のためのプレースホルダー画像が含まれる場合があります。プレースホルダー画像を見つけるには、各ページに描画された画像のコレクションを列挙します。描画された各画像について、表示サイズと位置を取得できます。プレースホルダーを置き換えるには、PdfImage.ReplaceWith を使用します。
using var pdf = new PdfDocument("invoice-template.pdf");
var paintedImages = pdf.Pages[0].GetPaintedImages();
var placeholder = paintedImages.First();
placeholder.Image.ReplaceWith("company-logo.jpg");
pdf.Save($"invoice.pdf");
別の方法として、プレースホルダー画像が占める領域に新しい画像を描画することもできますが、通常これは正当な理由なく結果の PDF のサイズを増やします。
置き換えやすいプレースホルダーの設計
静的テンプレートでは、テキストと画像の両方に対して、予測可能で明確に定義された領域を持つレイアウトにするのが有効です。可変長コンテンツを含む領域の周囲には十分な余白を確保し、後から挿入する予定のアスペクト比に合う中立的なプレースホルダー画像を使用してください。
置き換える予定のプレースホルダーテキストをテンプレートで使う場合は、生のテキストの代わりにテキストボックスを使うとワークフローを簡略化できます。読み取り専用で枠線のないテキストボックスをテンプレートに追加し、その中にプレースホルダーテキストを配置します。最終 PDF を生成する際は、テンプレートを開き、名前でテキストボックスを見つけて、box.Text = "new text"; で新しい値を直接設定します。その後、さらに編集されないようにテキストボックスを平坦化します。
対話要素の追加
対話機能は、静的な PDF を、注釈やマークアップで強化された動的でナビゲートしやすいドキュメントに変えます。アクションと JavaScript により、PDF 内で直接自動化を実現できます。
注釈
注釈は、ページに付加されたオブジェクトで、コメント、ハイライト、ファイル添付、その他の対話ウィジェットを表します。ページ内容に表示され、レビューのワークフローや共同作業をサポートします。
次の C# 例は、Docotic.Pdf を使って PDF ページにテキスト注釈、いわゆる付箋を追加する方法を示しています。
using var pdf = new PdfDocument("example.pdf");
var page = pdf.Pages[0];
var textAnnot = page.AddTextAnnotation(new PdfPoint(50, 100), "Reviewer comment");
textAnnot.Contents = "Please check the figures on this page.";
pdf.Save("text-annotation.pdf");
次の例では、ドキュメントの重要な部分に注意を向けさせるために、テキストやその他のコンテンツをハイライトする方法を示します。
using var pdf = new PdfDocument("example.pdf");
var page = pdf.Pages[0];
var color = new PdfRgbColor(255, 255, 120);
var annotationText = "Please confirm this part.";
var bounds = new PdfRectangle(50, 250, 120, 40);
page.AddHighlightAnnotation(annotationText, bounds, color);
pdf.Save("highlight-annotation.pdf");
リンク
PDF 標準では、いくつかの種類の PDF リンクが定義されています。最も重要で広く使われているのは、内部リンクとハイパーリンクです。
内部リンクは GoTo アクションとも呼ばれ、同じ PDF 内のページや名前付き destination へのジャンプを可能にします。相互参照や内部ナビゲーションに役立ちます。
以下は、最初のページからインデックスが 5 のページへのリンクを作成する C# コードです。
using var pdf = new PdfDocument();
var page = pdf.Pages[0];
int targetPageIndex = 5;
for (int i = 0; i < targetPageIndex; i++)
pdf.AddPage();
var rect = new PdfRectangle(50, 50, 100, 40);
page.Canvas.DrawRectangle(rect);
page.AddLinkToPage(rect, targetPageIndex);
pdf.Pages[targetPageIndex].Canvas.DrawString(50, 50, "Glad to have you here.");
pdf.Save("link-to-page.pdf");
Layout API には、絶対位置指定を必要としない 別の方法 で内部リンクを作成する手段もあります。
外部リンクは URI アクションとも呼ばれ、Web URL を開きます。PdfPage.AddHyperlink メソッドを使って PDF ページにハイパーリンクを追加できます。それ以外の点では、アプローチは内部リンクと同じです。
ブックマーク
ブックマークはアウトラインとも呼ばれ、読者が特定のセクションやページにすばやく移動できる特別なショートカットまたはリンクです。読者がブックマークをクリックすると、ビューアーアプリケーションは指定されたドキュメントの部分へ移動します。
アウトラインはビューアーのブックマークパネルに表示され、本の目次に似た階層型のナビゲーションツリーを提供しますが、対話的です。PDF のアウトラインには、メインのブックマークとネストされたブックマークを含めることができるため、大きなドキュメントを構成しやすくなります。
次の例は、C# と Docotic.Pdf を使って PDF にブックマークを作成する方法を示しています。コードは 3 つのトップレベルブックマークを作成します。2 番目のブックマークには 1 つのネストされたブックマークが含まれます。
using var pdf = new PdfDocument();
for (int i = 0; i < 5; i++)
{
var page = i == 0 ? pdf.Pages[0] : pdf.AddPage();
var canvas = page.Canvas;
canvas.FontSize = 14;
canvas.DrawString(50, 50, $"Page {i + 1}");
}
var root = pdf.OutlineRoot;
root.AddChild("Getting Started", 1);
var child = root.AddChild("Things You Can Do", 2);
child.AddChild("Making Quick Improvements", 3);
root.AddChild("Keeping Everything Running Smoothly", 4);
pdf.PageMode = PdfPageMode.UseOutlines;
pdf.Save("bookmarks.pdf");
ブックマークは、物理的な本のページに印刷されたり PDF に表示されたりする目次とは異なります。見出しを測定し、ページ番号付きでエントリを書き込むことで、プログラムで目次を作成できます。
Layout API を使って目次を作成する 別のアプローチ については、サンプルリポジトリ内の関連コードを参照してください。
PDF スクリプティング
JavaScript アクションは、最も強力な対話機能の一つです。PDF JavaScript は JavaScript のサブセットであり、ドキュメントおよびビューアーの API を公開します。フォーム検証、計算、UI ダイアログ、小規模な自動化タスクに使用されます。
スクリプトは注釈、ブックマーク、フォームコントロール、オープンアクションに関連付けることができます。Docotic.Pdf では、PDF 内に JavaScript コードを埋め込めます。このコードはフォーム入力の検証、値の計算、フィールドの表示/非表示、ビューアー操作の実行などを行えます。
共有 JavaScript のコレクションには、ドキュメントレベルに保存されたスクリプトが含まれます。これらのスクリプトは複数のアクションから再利用できます。つまり、共有スクリプトはユーティリティ関数や共有ロジックに有用です。重複を減らし、保守を簡単にします。
以下のコードは、PDF ビューアーにアラートメッセージを表示する共有スクリプトを定義し、それをボタンのクリックアクションに割り当てて起動する方法を示します。
using var pdf = new PdfDocument();
pdf.SharedScripts.Add(
pdf.CreateJavaScriptAction("function messageBox(message) { app.alert(message,3); }")
);
var button = pdf.Pages[0].AddButton(50, 50, 100, 40);
button.Text = "Click me";
button.OnMouseUp = pdf.CreateJavaScriptAction("messageBox('Hello, dear!');");
pdf.Save("shared-javascript.pdf");
例のスクリプトは単純ですが、任意の複雑さの JavaScript アクション を構築できます。Adobe JavaScript API リファレンスには、利用できる多くのメソッドが記載されています。Adobe 以外のビューアーは通常、API のサブセットしかサポートしない点に注意してください。
オープンアクション
オープンアクションは、ドキュメントが開かれたときに PDF ビューアーが実行するアクションです。一般的な用途には、特定ページで開く、JavaScript 初期化ルーチンを実行する、ビューアー設定を行う、などがあります。オープンアクションの種類に制限はありません。
次の例では、GoTo オープンアクションを作成する方法を示します。コードは 2 ページ目にテキストを追加し、PDF が開かれたときにビューアーを自動的にそのページへ移動させるオープンアクションを設定します。
using var pdf = new PdfDocument();
var canvas = pdf.AddPage().Canvas;
canvas.FontSize = 14;
var message =
"If you see this immediately after opening the file, " +
"your PDF viewer supports open actions.";
var options = new PdfTextDrawingOptions(new PdfRectangle(100, 100, 100, 150));
canvas.DrawText(message, options);
pdf.OnOpenDocument = pdf.CreateGoToPageAction(1, 0);
pdf.Save("open-action.pdf");
すべてのビューアーが JavaScript のオープンアクションを実行するわけではない点に注意してください。無視するものや、最初にユーザーに確認を求めるものがあります。オープンアクションを完全にブロックするビューアーもあります。
PDF にオープンアクションが含まれているかどうかを確認するには、それを PdfDocument に読み込み、OnOpenDocument プロパティを調べます。このプロパティが null であれば、そのドキュメントにはオープンアクションは定義されていません。
暗号化とデジタル署名の適用
暗号化とデジタル署名は、作成する PDF を保護するという相補的な 2 つの側面を扱います。暗号化は、誰がドキュメントを開けるか、また何ができるかを制御し、署名はファイルを誰が作成または承認したかを証明し、変更されていないことを確認します。
パスワード保護では、作成時にアクセスルールを設定できます。閲覧を制限するためのオープンパスワードと、印刷、コピー、編集、フォーム入力などの権限を定義するオーナーパスワードを設定できます。証明書ベースの暗号化は、より強力で受信者固有の保護を提供し、共有パスワードに依存せずに機密 PDF を複数人へ配布する場合に有効です。詳細は、パスワードと証明書による PDF の暗号化 記事を参照してください。
デジタル署名は、作成時に真正性と完全性を追加します。Docotic.Pdf は、ファイル、Windows ストア、ハードウェアトークン、HSM、クラウドキーサービスの証明書を使って PDF に署名 できます。タイムスタンプや長期検証データを含めることで、ドキュメント作成後も長期間にわたり署名を検証可能にできます。PKCS#11 やクラウド KMS を含む外部署名ワークフローもサポートされています。
PDF メタデータの設定
PDF メタデータは、タイトル、著者、件名、キーワード、作成日時など、ドキュメントに埋め込まれた説明情報です。ファイルを開かなくても、ソフトウェア、検索エンジン、文書管理システムが内容を理解するのに役立ちます。
PDF ドキュメントは、2 つの共存するシステムでメタデータを保持できます。
- XMP メタデータ
- ドキュメント情報辞書 (
Info辞書)

XMP は、説明メタデータを埋め込むための、より豊富で構造化され標準化された形式です。Info 辞書はシンプルで広くサポートされていますが制約があり、PDF 2.0 標準 (ISO 32000‑2) では XMP メタデータが推奨されるため非推奨です。Docotic.Pdf は両方のシステムを読み書きでき、同期を保つためのヘルパーメソッドも提供します。
Docotic.Pdf は、PDF ファイルを保存する前に一部のメタデータを自動更新します。たとえば、ライブラリは既定で Producer と Creator の値を設定します。保存オプション を使うと、この挙動を変更し、明示的に設定したメタデータ値を保持できます。
XMP メタデータ
PdfDocument.Metadata プロパティを使って、PDF 内の XMP メタデータにアクセスし、変更します。このプロパティを通じて、XMP Core、Dublin Core、PDF スキーマなどの既知のスキーマを扱うほか、独自のカスタムメタデータも管理できます。
using var pdf = new PdfDocument();
var xmp = pdf.Metadata;
xmp.Pdf.Creator = new XmpString("Second-line authoring terminal");
xmp.Pdf.Title = new XmpString("Quarterly Report");
var creators = new XmpArray(XmpArrayType.Ordered);
creators.Values.Add(new XmpString("Second-line authoring terminal"));
creators.Values.Add(new XmpString("Assistive authoring terminal"));
xmp.DublinCore.Creators = creators;
var descriptions = new XmpArray(XmpArrayType.Alternative);
descriptions.Values.Add(new XmpLanguageAlternative("x-default", "Quarterly Report"));
descriptions.Values.Add(new XmpLanguageAlternative("fr", "Rapport trimestriel"));
descriptions.Values.Add(new XmpLanguageAlternative("de", "Quartalsbericht"));
xmp.DublinCore.Descriptions = descriptions;
var author1 = new XmpString("First Author");
author1.Qualifiers.Add("role", "main author");
var author2 = new XmpString("Second Author");
author2.Qualifiers.Add("role", "co-author");
var authors = new XmpArray(XmpArrayType.Unordered);
authors.Values.Add(author1);
authors.Values.Add(author2);
xmp.Custom.Properties.Add("authors", authors);
pdf.Save("with-xmp-metadata.pdf");
XMP は配列、構造体、型付き値をサポートしているため、豊富なメタデータに適しています。上のコードでは、カスタム XMP スキーマにアプリケーション固有のプロパティを保存する方法も示しています。
ドキュメント情報辞書
Info 辞書は主にテキスト文字列値を保存します。コンパクトで広くサポートされていますが、制限があります。古いツールとの互換性が必要な場合に Info 辞書を使用し、それ以外では XMP を優先してください。
メタデータの同期
不整合による混乱を避けるため、両方のメタデータシステムを同期しておくことが推奨されます。これは読者や自動化ツールにとって有益です。
PdfDocument.SyncMetadata を使うと、対応するフィールドが一致するように XMP と Info の値を整合できます。このメソッドは、XMP から不足している Info プロパティを補い、同様に Info から不足している XMP フィールドを埋めます。XMP が正本である場合は preferXmp: true を、Info 辞書を優先する場合は false を設定します。
pdf.SyncMetadata(preferXmp: true);
メソッドが どのプロパティを同期するか についての詳細は、SyncMetadata ドキュメントの Remarks セクションを参照してください。
ページラベルとビューアー設定の構成
新しく作成した PDF では、明示的なページ番号付け、細かく調整されたビューアー設定、ドキュメント内容をより効果的に表示するためのページレイアウトが有効です。これらの設定は、読者が最初にファイルをどのように見るか、どのように移動するかに影響します。
ページラベル
ページラベルは、PDF ビューアーに各ページで表示するラベルを伝えるメタデータです。表示上の番号が物理ページインデックスと異なる必要がある場合に使用します。たとえば、PDF の前付けで i, ii, iii を使い、本編で 1, 2, 3 を使いたい場合です。
以下の C# コードは、最初の 3 ページに小文字のローマ数字を、残りに 1 から始まるアラビア数字を付ける方法を示します。
using var pdf = new PdfDocument();
for (int i = 0; i < 8; i++)
pdf.AddPage();
pdf.PageLabels.AddRange(0, 2, PdfPageNumberingStyle.LowercaseRoman);
pdf.PageLabels.AddRange(3, PdfPageNumberingStyle.DecimalArabic);
pdf.Save("with-page-labels.pdf");
PDF ビューアーの設定
PDF ビューアーの設定は、ビューアーがドキュメントをどう表示するかの推奨を埋め込んだものです。たとえば、ツールバーを非表示にする、ウィンドウを中央に配置する、ページに合わせてウィンドウを調整する、などを指定できます。ビューアー設定はページレイアウトと オープンアクション 設定を補完します。
Docotic.Pdf を使って PDF の表示設定を変更する方法は次のとおりです。
using var pdf = new PdfDocument();
pdf.ViewerPreferences.DisplayTitle = false;
pdf.ViewerPreferences.FitWindow = true;
pdf.ViewerPreferences.HideToolBar = true;
pdf.ViewerPreferences.HideMenuBar = true;
pdf.ViewerPreferences.HideWindowUI = true;
pdf.ViewerPreferences.CenterWindow = true;
pdf.Save("with-viewer-prefs.pdf");
Adobe Acrobat やその他のビューアーは、その構成によってはこれらの設定を無視する場合があります。
ページレイアウトとページモード
ページレイアウトは、ドキュメントを開いたときのページの並び方を決定します。1 ページずつ、1 列の連続表示、2 ページ見開きなどがあります。ページモードは、オープン時にどの UI パネルを表示するかを制御します。ブックマーク/アウトライン、添付ファイル、サムネイル、またはなしです。
以下は、作成した PDF を左ページ先頭の 2 ページ見開きで表示し、サムネイルパネルを開いた状態にする指定方法です。
using var pdf = new PdfDocument();
for (int i = 0; i < 7; i++)
{
var page = i > 0 ? pdf.AddPage() : pdf.Pages[0];
page.Canvas.FontSize = 36;
page.Canvas.DrawString(100, 100, $"Page {i + 1}");
}
pdf.PageLayout = PdfPageLayout.TwoPageLeft;
pdf.PageMode = PdfPageMode.UseThumbs;
pdf.Save("with-layout-and-mode.pdf");
PDF の保存
Docotic.Pdf は、作成または編集した同じドキュメントから、異なる PDF ファイルやストリームを生成できます。これらの出力は、PDF 形式の異なるバージョンに準拠し、バイト長が異なり、生成に必要なメモリ量も異なります。
ライブラリが PDF のバイト列を生成する方法は保存オプションに依存します。保存オプションを明示的に指定しない場合、PdfDocument オブジェクトの Save、SignAndSave、TimestampAndSave メソッドは既定設定を使用します。これらの既定値は慎重に選ばれており、ほとんどのシナリオで有効ですが、調整が必要な場合もあります。
利用可能なオプションと既定値の詳細については、PdfSaveOptions クラス のドキュメントを参照してください。以下のセクションでは、より重要なオプションのいくつかを取り上げ、実用上の推奨事項を示します。
PDF バージョン
Docotic.Pdf は、生成するファイルの圧縮率を向上させるために、既定で object stream を使用します。その結果、ライブラリは既定で PDF 1.5 のファイルとストリームを作成します。
PDF 1.5 を表示するには、Adobe Reader 6(2003 年公開)以降が必要です。古いツール、古いビューアー、または旧バージョンの PDF のみを受け入れる組み込みデバイスをサポートする必要がある場合を除き、通常は問題になりません。
以下は、より古い PDF ファイルバージョンで保存する方法です。
using var pdf = new PdfDocument();
var options = new PdfSaveOptions
{
Version = PdfVersion.Pdf14,
UseObjectStreams = false,
};
pdf.Save("version-1.4.pdf", options);
PDF 1.4 で保存するには、object stream も無効にする必要があります。ドキュメントに後のバージョンで導入された機能が含まれている場合、ライブラリはそれより古いバージョンを使用しません。
ファイルサイズの削減
true に設定すると、Docotic.Pdf がより小さいファイル(バイト単位)を生成する保存オプションがいくつかあります。RemoveUnusedObjects、OptimizeIndirectObjects、WriteWithoutFormatting、UseObjectStreams です。
以下は、参照されていないオブジェクトや余分な空白を含まず、データを object stream に密に詰めて PDF を生成する方法です。
using var pdf = new PdfDocument();
var options = new PdfSaveOptions
{
UseObjectStreams = true,
RemoveUnusedObjects = true,
OptimizeIndirectObjects = true,
WriteWithoutFormatting = true,
};
pdf.Save("optimized.pdf", options);
これらのオプションは、PDF を完全に再書き込みする場合に最も効果的です。増分保存中は、新しく追加されたリビジョンにのみ適用され、ファイルの以前の部分をクリーンアップまたは最適化することはできません。
増分更新
Docotic.Pdf は PDF を増分更新できます。WriteIncrementally が true の場合、ライブラリは既存ファイルを書き直さず、変更を末尾に追加します。以前の相互参照データとオブジェクトデータはそのまま保持されます。追加されたデータは増分更新と呼ばれ、現在の更新とすべての以前の更新が新しいリビジョンを構成します。
新しく作成したドキュメントには、追加先となる以前のリビジョンがないため、増分更新はできません。ライブラリは新しいドキュメントではこのオプションを無視し、非増分モードで書き込みます。
増分更新が必要な場合
すでに署名が含まれているドキュメントに 新しいデジタル署名を追加 する場合は、増分保存が必要です。以前に署名されたファイルに新しい注釈やフォームデータを加える場合も同様です。これらの場合にファイル全体を書き直すと、既存の署名が無効になります。
同時に、最初のデジタル署名を適用する前には、非増分(完全)保存を実行するのが最善です。そうすることで、署名対象のベースラインがクリーンで完全に再書き込みされたファイルになります。以前のリビジョンに構造上の問題があるドキュメントに署名すると、予期しない署名検証の問題につながる可能性があります。
監査可能なリビジョン履歴を保持する必要があるワークフローや、追記専用のドキュメント保存を強制するワークフローでも、増分追加が必要です。
増分更新の利点
増分更新により、同じファイルに複数の署名を付与でき、既存の署名を無効にせずに、フォームフィールドの入力など一部の署名後変更も可能になります。
このアプローチは、変更されたデータだけを書き込むため、小さな変更では保存速度も向上します。さらに、監査やその他のコンプライアンス主導のワークフローに不可欠な、ドキュメントのリビジョン履歴も保持します。
避けるべき問題と落とし穴
増分更新は、変更されたオブジェクトのみを追加するため、ファイル全体に対するグローバル圧縮や、古いオブジェクトの削除はできません。その結果、通常は完全再書き込みよりもサイズが大きく、最適化も不十分なファイルになります。
不要なオブジェクトが存在しない場合でも、以前のすべてのリビジョンがファイル内に埋め込まれ、容量を占有し続けるため、ファイルサイズはリビジョンごとに増加します。
以前のリビジョンに含まれる機微情報や誤った情報は引き続き復元可能であり、既存の PDF 形式の問題や以前のリビジョンの構造的欠陥も、新しいデータを追加するだけでは修正されません。
最後に、一部のビューアーや処理ツールは複数リビジョンの PDF をうまく扱えません。増分更新を前提にする前に、ドキュメントの利用側が複数リビジョンのファイルを処理できることを確認してください。
PDF 出力のテスト
自動 PDF テストは、生成された PDF をリポジトリやアーティファクトストレージに保存されたベースライン PDF と比較することで、コンテンツやレイアウトの回帰からリリースを保護します。ベースラインは、テキスト、フォント、画像、レイアウトの意図しない変更を検出し、ビルドごとの手動 QA の必要性を減らします。
最も信頼性の高い結果を得るには、構造チェック、テキスト抽出、視覚比較を組み合わせます。
アプローチの簡単な比較
| 方法 | 速度 | 感度 | 最適な用途 |
|---|---|---|---|
| 構造比較 | 高速 | 高い: オブジェクトレベルの変更を検出 | 同一ドキュメントの 2 つのバージョンが構造的に同一であることを確認しなければならない回帰テスト |
| テキスト抽出 | 高速 | 中程度: 通常、レイアウト変更は無視 | 意味的内容と表の検証 |
| 視覚差分 | 遅い | 高い: コンテンツとレンダリング/レイアウト変更の両方を検出 | 視覚的な回帰の検出 |
ドキュメント構造の比較
PdfDocument.DocumentsAreEqual を使用して、PDF オブジェクトグラフ、PDF バージョン、ドキュメントセキュリティストア (DSS) を比較しつつ、時間依存のドキュメントプロパティは無視します。このメソッドは、ドキュメントメタデータ、trailer ID、その他の自動生成プロパティも無視します。
このメソッドは、予期しないオブジェクトが追加または削除されていないことを保証する必要がある PDF ドキュメントテストのワークフローに最適です。DocumentsAreEqual はファイルおよびストリームのオーバーロードをサポートし、暗号化された PDF も比較できます。
この手法を示す完全な例は Docotic.Pdf のサンプルにあります。通常の .NET アプリケーションでの使い方に加えて、サンプルでは Native AOT での DocumentsAreEqual アプリケーションの使用方法も示しています。
抽出したテキストによる PDF の検証
ドキュメント全体から一度に、またはページごとに順番に テキストを抽出 し、文字列を比較します。抽出処理を細かく調整するために、フッターがある矩形を除外するなどのテキスト抽出オプションを使えます。比較しやすくするために、抽出したテキストを行や単語に分割してもかまいません。
構造化チェックでは、まず各チャンク、単語、文字について位置、フォント、その他の 詳細情報 を含めてテキストを抽出します。その後、抽出した各要素を対応するベースライン要素と比較します。
視覚差異の検出
まず PDF ページを画像に変換 し、各画像をベースライン画像と比較します。ImageSharp.Compare や Magick.NET などの専用ライブラリを使って画像差分を検出します。
対応する各ピクセルが両方の画像で一致しなければならないよう、厳密なピクセル単位比較を推奨します。要件によっては小さなレンダリング差異を許容できる場合もありますが、その場合は比較ロジックを調整して微小差を許容できます。ただし、正確なピクセル一致が最も信頼性の高い結果を提供します。
完全なピクセル比較を実行せずに 2 つの画像が同一である可能性を高速に判定するために、ハッシュを事前チェックとして使うことも検討してください。レンダリングした各画像に対して SHA-256 ハッシュを計算し、ハッシュが一致すれば画像はほぼ確実に同じです。ハッシュが異なる場合は、完全なピクセル単位比較を実行します。
結論
Docotic.Pdf は、.NET で PDF を作成・操作するための包括的で多層的なツールキットを提供します。開発者は、Core API による低レベル制御、Layout API による高レベルのドキュメント生成、あるいは Web 技術を前提としたワークフロー向けの HTML から PDF への変換を選択できます。
ライブラリは、画像ベースの PDF、テンプレート駆動の生成、注釈、リンク、ブックマーク、JavaScript アクション、オープンアクションなどの豊富な対話機能もサポートします。
信頼性を確保するために、Docotic.Pdf には PDF 出力をテストするためのメソッドが含まれており、アプリケーションの変更が回帰や予期しない差異を導入しないようにできます。