このページには自動翻訳されたテキストを含めることができます。

.NET PDFジェネレーター

Docotic.Pdf を使用すると、ページ、コンテナ、テキストスパン、画像、リンク、ヘッダー、フッター、表、リストなどの構造要素を組み合わせて PDF ドキュメントを生成できます。これらの要素は、Docotic.Pdf 用の無料アドオンである Layout API を通じて利用できます。この API は、再利用可能なカスタムコンポーネントもサポートしています。

Docotic.PdfがPDFを生成する仕組みの図解:画像、表、テキストなどの要素を配置すると、ライブラリがそのレイアウトからPDFを生成します

Layout APIを使用すると、流暢なアプローチでC#またはVB.NETコードのみを使用してドキュメントを完全に定義できます。この説明に基づくと、アドオンが提供するPDFジェネレーターは、シンプルなページから高度に構造化されたPDFレポートまで、任意の複雑なレイアウトを持つドキュメントを生成できます。

PDF生成の基本

Layout API を使用して PDF ドキュメントを生成するには、無料の Layout アドオンが必要です。コアライブラリとアドオンを使用するには、ライセンスキーも必要です。無料トライアルキーまたは購入済みのキーのいずれかを使用できます。

アドオンをインストールする

推奨される方法は、NuGetからアドオンをインストールすることです。

Install-Package BitMiracle.Docotic.Pdf.Layout

パッケージマネージャーは依存関係を自動的に処理します。

アドオンを手動でインストールする場合は、まず Docotic.Pdf バイナリを含む ZIP アーカイブをダウンロードしてください。アーカイブを解凍し、以下の DLL への参照を追加してください。

  • BitMiracle.Docotic.Pdf.dll
  • Layout add-on サブフォルダーにある BitMiracle.Docotic.Pdf.Layout.dll

ライセンスキーを取得する

ライブラリをお試しいただくには、Docotic.Pdfのダウンロードページにあるフォームにご記入の上、期間限定の無料ライセンスキーをお申し込みください。既にライセンスをご購入済みの方は、ご購入後に提供されたコードをご利用ください。

Layoutアドオンは無料で、追加のライセンスは不要です。既にお持ちのDocotic.PdfライセンスでLayout APIをご利用いただけます。

こんにちは、世界! Layout API を使って

以下は、APIを使用して「Hello, world!」というおなじみのフレーズを含むPDFを生成するサンプルコードです。

BitMiracle.Docotic.LicenseManager.AddLicenseData("PUT-LICENSE-HERE");

PdfDocumentBuilder.Create().Generate("hello.pdf", doc => doc.Pages(pages =>
{
    pages.Content().Text("Hello, world!");
}));

このコードは、テキストが左上隅に配置された1ページのPDFファイルを生成します。

コードサンプルを理解する

サンプルでは、​​まずライセンスキーを追加します。ライセンスがない場合、Docotic.Pdfライブラリは何も生成しません。PDF生成コードは次の行から始まります。

このコードは、静的メソッドPdfDocumentBuilder.Create()を呼び出してドキュメントビルダーのインスタンスを作成します。Generateメソッドの呼び出しによってPDF生成プロセスが開始されます。このメソッドは、生成するファイル名とAction<Document>型のデリゲートという2つのパラメータを受け取ります。アドオンはGenerate呼び出しの結果としてhello.pdfを生成します。

PDFのレイアウトを知るために、ドキュメントビルダーはDocumentインスタンスを引数としてデリゲートを呼び出します。デリゲートのコードがドキュメントの内容を構成します。このサンプルでは、​​デリゲートはPagesメソッドを使用して、ドキュメントページのレイアウトを定義する別のデリゲートをビルダーに渡します。

ビルダーは、Pagesメソッドに渡されたデリゲートをPageLayoutインスタンスを引数として呼び出します。このインスタンスは、ドキュメント内の1つ以上のページを表します。ページ数は、各ページに追加されるコンテンツによって異なります。

ページデリゲートは、Content メソッドを呼び出して、ページ(複数可)の主要コンテンツのレイアウトコンテナにアクセスします。コンテナの Text メソッドをチェーン呼び出しすることで、サンプルテキストスパンがページに追加されます。レイアウトコンテナの動作の詳細については、レイアウトコンテナに関するガイドを参照してください。

ドキュメントビルダーは、主要コンテンツレイアウトコンテナに追加されたすべてのデータを格納するために必要なページ数だけ、コンテンツを自動的にページに分割します。このサンプルでは、​​1ページで十分なので、出力は正確に1ページになります。

基本的なサンプルを超える一般的なタスク

サンプルコードはまず PdfDocumentBuilder インスタンスを作成し、次に Generate メソッドを呼び出して PDF を生成します。PDF 生成を開始する前に、ビルダーの設定を行うことができます。

例えば、ビルダーに暗号化ハンドラーを指定することで、暗号化されたPDFを作成できます。また、ビルダーが生成するドキュメントに含めるメタデータを指定することもできます。ビルダーのカスタマイズ方法の詳細については、別の記事を参照してください。

サンプルコードではプライマリコンテンツスロットのレイアウトコンテナのみを使用していますが、他のコンテンツスロットも利用可能です。コンテンツスロットにアクセスするための PageLayout メソッドの一覧は以下のとおりです。

  • Background() - 他のコンテンツで覆われる背景レイヤーを返します。
  • Header() - すべてのページに共通するヘッダーを返します。
  • Content() - メインページのコンテンツスロットを返します。
  • Footer() - すべてのページに共通するフッターを返します。
  • Foreground() - 他のコンテンツの上に表示される前景レイヤーを返します。

生成されるPDFのページ数に影響するのは、メインコンテンツスロットの内容のみです。ドキュメントビルダーは、Content()で指定されたスロット以外のすべてのスロットを各ページで繰り返します。コンテンツスロットの詳細については、ページレイアウトの記事を参照してください。

多くのドキュメントでは、ページごとに異なるレイアウトが使用されます。たとえば、最初のページは表紙のようなデザインで、それ以降のページはよりシンプルなレイアウトになっている場合があります。また、表専用のページを設けたり、セクションごとに異なる背景を適用したりするドキュメントもあります。このようなドキュメントをDocotic.PdfとLayoutアドオンで生成するには、Document.Pagesメソッドを複数回呼び出します。サンプルリポジトリには、動作例があります。

コードの整理

サンプルコードのような短いコードであれば、関数呼び出しを連鎖させたり、ラムダ式をネストしたりしても問題ありません。しかし、より大規模なコードを作成する場合は、コードを複数のメソッドに分割する方が便利な場合があります。これにより、コードの可読性と保守性が向上します。

以下は、「Hello, world!」サンプルコードをメソッドに分割した場合の例です。

public void GeneratePdf()
{
    BitMiracle.Docotic.LicenseManager.AddLicenseData("PUT-LICENSE-HERE");

    PdfDocumentBuilder.Create().Generate("hello.pdf", BuildDocument);
}

private void BuildDocument(Document doc)
{
    doc.Pages(BuildPages);
}

private void BuildPages(PageLayout pages)
{
    pages.Content().Text("Hello, world!");
}

Docotic.Pdf Layout API を使用して PDF を生成する理由

Layout APIは、PDFフォーマットの内部構造を理解する必要なく、構成可能なビルディングブロックからPDFを生成できる、開発者にとって使いやすい最新の方法です。高いパフォーマンスと、決定論的で予測可能な動作でPDFをレイアウトします。このAPIは、大量のドキュメント生成シナリオで活用できます。

このAPIは、Docotic.Pdfと無料のLayoutアドオンを併用することで利用可能です。Docotic.PdfとLayoutアドオンはどちらも、安全でないコードブロックを含まない、100%マネージドコードDLLです。Layout APIは、ブラウザやSkiaバイナリなどのサードパーティ製外部依存関係を一切持たずに実装されているため、軽量でオーバーヘッドが少なく、導入とメンテナンスが容易なソリューションとなっています。

APIの概要

Layout APIは、流暢で使いやすいAPIです。柔軟なレイアウト要素を用いて、ドキュメントのレイアウトをコードで完全に記述できます。ジェネレーターはコンテンツをフローさせ、ページを自動的に分割し、結果をPDFとしてレンダリングします。

Layoutアドオンは、宣言型のフローベースレイアウトシステムを採用しています。レイアウト要素には、リスト、列、行、表、画像、テキストスパン、ヘッダーとフッター、コンテナなどが含まれます。要素を正確な座標に手動で配置するのではなく、要素の動作を記述します。ドキュメントビルダーは、最終的なレイアウトを計算し、PDFを作成します。

フローベースレイアウトシステムにより、レイアウトはページサイズとコンテンツに合わせて自動的に調整されます。このシステムのおかげで、このアドオンは複雑で構造化されたルールベースのレイアウトに優れています。異なる種類のコンテナをネストし、可読性を損なうことなく高度な構造を構築できます。

Layout APIを使用する場合、ほとんどの呼び出しを連結できます。これにより、従来のAPIよりも簡潔で表現力豊かなコードを作成できます。チェーン内の呼び出し順序は重要です。すべてが厳密に型付けされているため、コンパイル時の安全性が確保され、コードのリファクタリングが容易になります。また、Layout API を使用するコードは単体テストを実行できます。

レイアウトの実装をさらに簡潔にするには、API に独自のメソッドを追加し、それを基に簡潔で表現力豊かな DSL を構築できます。

位置決めと DSL の作成に関する詳細は、コンテナのサイズ、位置、配置、レンダリング動作を制御する方法を解説した記事を参照してください。

.NETのバージョンとプラットフォームのサポート

.NET Standard 2.1以降のフレームワークをターゲットとするプロジェクトでは、Layout APIを使用できます。つまり、Layoutアドオンは.NET 5から.NET 10まで互換性があります。さらに、.NET Core 3.0以降もサポートされています。

Layout APIを使用すると、ASP.NET Core、MAUIアプリ、Unity、Xamarin、およびコンソールアプリケーションでPDFを生成できます。Layoutアドオンを搭載したDocotic.Pdfは、Windows、macOS、およびLinuxでPDFを生成できます。

クラウドプラットフォームとDockerイメージ

Docotic.PdfとLayoutアドオンは、サーバーレス環境を含むAzureおよびAWSクラウド環境で動作します。ライブラリとアドオンは、動的なハードウェア変更、オートスケーリング、その他のクラウドネイティブなランタイム機能を完全にサポートしています。

ほとんどのクラウド環境では、無制限ライセンスが必要です。ライセンスに関するFAQでは、クラウドアプリケーションに適したライセンスの選択方法について説明しています。

Layout APIはDockerコンテナ内でそのまま動作します。ライブラリとLayoutアドオンをコンテナ内で実行する場合、PDF生成に特別な設定は必要ありません。

PDFファイルにテキストを追加する

テキストは、あらゆるPDFドキュメントの基本的な要素です。LayoutContainerクラスのTextメソッドを使用すると、コンテンツスロットにテキストを追加できます。

タイトル、キャプション、プレーン、ハイパーリンク、強調表示、脚注などのテキストスタイル例に囲まれた文書ページのイラスト

テキストスパン

「Hello, world」のサンプルでは、​​LayoutContainer.Text(string) オーバーロードを使用して、ページの主要コンテンツにテキストを追加しました。次に、Text メソッドの別のオーバーロードを見てみましょう。

public static void GenerateTextPdf()
{
    PdfDocumentBuilder.Create().Generate("text-spans.pdf", doc => doc.Pages(pages =>
    {
        pages.Content().Text(AddTextSpans);
    }));
}

private static void AddTextSpans(TextContainer text)
{
    text.Line("About VB.NET")
        .Style(t => t.Strong);

    text.Span("VB.NET is a multi-paradigm, object-oriented language ");
    text.Span("that runs on .NET, Mono, and the ");
    text.Hyperlink(
        ".NET Framework",
        new Uri("https://dotnet.microsoft.com/download/dotnet-framework"));
    text.Line(".");

    text.Span("Released by Microsoft in 2002, ");
    text.Line("it continues the lineage of the original Visual Basic language.");
}

このコードは、TextContainer クラスの Span メソッドと Line メソッドを使用して、現在の行にテキストを追加します。Line メソッドは、現在の行を完成させる機能も備えています。また、サンプルコードでは Hyperlink メソッドを使用して、特定のテキストスパンに外部リソースへのリンクを添付しています。

サンプルコードが Style メソッドを使用して最初の行に強力な書式設定を適用している点に注目してください。テキストスタイルの概念について、さらに詳しく見ていきましょう。

テキストスタイル

テキストスタイルを使用すると、テキストの外観をカスタマイズできます。TextStyle クラスには、フォントサイズ、文字間隔、色、その他のテキストプロパティを変更するためのメソッドが用意されています。TextStyle オブジェクトは不変であるため、メソッドを呼び出すたびに新しいスタイルインスタンスが生成されます。テキストスタイルは、さまざまなレイアウトレベルに適用できます。

PdfDocumentBuilder.Create().Generate("text-styles.pdf", doc =>
{
    doc.Pages(pages =>
    {
        pages.TextStyle(TextStyle.Parent.FontSize(30));

        pages.Content()
            .TextStyle(TextStyle.Parent.FontColor(new PdfRgbColor(0, 0, 255)))
            .Text(text =>
            {
                text.Span("Hello,");

                text.Span("World!")
                    .Style(TextStyle.Parent.Underline());
            });
    });
});

TextStyle.Parent プロパティは、すべてのテキストプロパティが未定義となる特殊なスタイルを返します。上記のサンプルでは、​​30ポイントのフォントサイズで「Hello, World!」というテキストが青色で表示され、2番目の単語に下線が引かれています。

これは、コードが以下の処理を行っているためです。

  • ページレベルでフォントサイズを30ポイントに設定、
  • プライマリコンテンツスロットのテキストカラーを青色に設定、
  • 最後のテキストスパンに下線スタイルを適用。

後続の各スタイルは、TextStyle.Parent プロパティを通じて前のスタイルを継承します。

TextStyle クラスのメソッドを使用すると、テキストの方向を右から左に変更するなど、さまざまな操作が可能です。サンプルリポジトリにある テキストスタイルの継承 の別の例も参照してください。

タイポグラフィ

TextStyle クラスは、関連付けられたフォントを除くすべてのテキストプロパティのカスタマイズをサポートしています。既定のフォントを変更するには、Document.TextStyleWithFont メソッドを使用して、特定のフォントに基づいたテキストスタイルを作成します。オペレーティングシステムにインストールされているフォントを使用することも、ファイルまたはストリームから読み込むこともできます。

フォントベースのスタイルを作成した後、追加のオプションプロパティを適用し、結果として得られたスタイルをテキストスパンに適用できます。この C# サンプルでは、​​システムフォントを使用する方法を示しています。

PdfDocumentBuilder.Create().Generate("text-style-with-font.pdf", doc =>
{
    var font = SystemFont.Family("Calibri");
    var style = doc.TextStyleWithFont(font).FontSize(30);

    doc.Pages(pages =>
    {
        pages.Content().Text(text =>
        {
            text.Span("Hello,");

            text.Span("World!")
                .Style(style);
        });
    });
});

TextStyleWithFont メソッドには、生成されるドキュメントにフォントをどのように埋め込むかを指定するオプションのパラメータがあります。デフォルトでは、ライブラリは以下の動作をします。

  • TrueType/OpenType フォントの場合は、使用されているグリフを埋め込みます。
  • Type1 および CFF フォントの場合は、すべてのグリフを埋め込みます。
  • PDF に組み込まれているフォント (Base14 フォント) の場合は、グリフを埋め込みません。

これらのデフォルト設定により、TrueType および OpenType フォントを使用するドキュメントは、大きなフォントを使用してもサイズが小さくなる場合があります。カスタムフォントローダー、フォールバックフォント、およびグリフが欠落した場合のハンドラーを指定することもできます。PDF ドキュメントでのフォント管理の詳細については、サンプルリポジトリのサンプルコードを参照してください。

Layout API には、定義済みのスタイル集が用意されており、Typography クラスを通じてアクセスおよび変更できます。

PdfDocumentBuilder.Create().Generate("typography.pdf", doc =>
{
    doc.Typography(t =>
    {
        var fontsPath = Environment.GetFolderPath(Environment.SpecialFolder.Fonts);
        var arialFont = new FileInfo(Path.Combine(fontsPath, "arial.ttf"));

        t.Document = doc.TextStyleWithFont(arialFont);
        t.Header = t.Parent.FontSize(20).FontColor(new PdfGrayColor(20));
        t.Footer = t.Footnote;
    });

    doc.Pages(pages =>
    {
        pages.Header().AlignCenter().Text("Header");

        pages.Content().Text(t =>
        {
            t.Line("Title").Style(t => t.Title);
            t.Line("Heading 1").Style(t => t.Heading1);
            t.Line("Regular");
        });

        pages.Footer()
            .Height(20)
            .AlignCenter()
            .Text(t => t.CurrentPageNumber());
    });
});

定義済みのスタイルを上書きするには、ドキュメント全体にタイポグラフィを設定することをお勧めしますが、必須ではありません。テキストスパンレベルでテキストスタイルを適用することも可能です。

Typography クラスを使用すると、テキストスタイルの参照を変数に格納する必要はありません。代わりに、Document.Typography メソッドを使用して必要なスタイルを登録し、後で Typography オブジェクトのプロパティからアクセスできます。PDF ドキュメントを生成する際に、定義済みおよびカスタムのテキストスタイルを使用する方法については、Typography のサンプルを参照してください。

レポートや請求書など、実際の多くのPDF文書にはヘッダーとフッターが含まれています。このセクションでは、PDFにヘッダーとフッターを追加する方法を説明します。

public static void GeneratePdfWithHeaderAndFooter()
{
    PdfDocumentBuilder.Create()
        .Generate("header-footer.pdf", doc => doc.Pages(pages =>
    {
        pages.Size(PdfPaperSize.A6).Margin(10);

        BuildPagesHeader(pages.Header());
        BuildPagesFooter(pages.Footer());

        pages.Content().Text("Hello, world!");
    }));
}

public static void BuildPagesHeader(LayoutContainer header)
{
    header.TextStyle(TextStyle.Parent.FontSize(8))
        .AlignRight()
        .Text(t =>
        {
            t.Line($"Created by: {Environment.UserName}");
            t.Line($"Date: {DateTime.Now}");
        });
}

public static void BuildPagesFooter(LayoutContainer footer)
{
    footer.AlignRight().Text(text =>
    {
        text.Style(t => t.Parent.FontColor(new PdfRgbColor(255, 0, 0)));

        text.CurrentPageNumber();
        text.Span(" / ");
        text.PageCount();
    });
}

BuildPagesHeader メソッドは、ヘッダーテキストのフォントサイズを小さく設定します。ヘッダーコンテンツは2行で構成され、1行目には現在のユーザー名、2行目には現在の日付が表示されます。テキストは右揃えです。

このコードでは、ヘッダーのサイズを明示的に指定していないことに注意してください。ヘッダーはページ幅全体から左右の余白を差し引いた領域を占め、高さはテキスト行の高さによって決まります。

BuildPagesFooter メソッドは、PDFフッターに現在のページ番号を表示する方法を示しています。ライブラリは、現在のページ番号と総ページ数を自動的に計算します。これらの値は、TextContainer オブジェクトの CurrentPageNumber メソッドと PageCount メソッドを使用して取得できます。

Layout API では、ページ番号の書式設定も可能です。例えば、16進数のページ番号は次のように表示できます。

text.CurrentPageNumber().Format(p => "0x" + p?.ToString("x2"));

サンプルリポジトリには、PDFにヘッダーとフッターを追加する別の例が含まれています。その例では、ページ番号をローマ数字で表示しています。

画像の挿入

ことわざにもあるように、一枚の画像は多くの言葉に代わるものです。見積書や領収書には、会社のロゴやその他の重要な画像を掲載することがよくあります。この例では、シンプルで見栄えの良い画像を使用します。

画像を使用するには、まずドキュメントに画像を追加する必要があります。ライブラリはファイルまたはストリームから画像を読み込むことができます。サポートされているのはラスター形式のみです。PNG、JPEG、JPEG 2000、BMP、GIF、TIFFに対応しています。

Imageオブジェクトを取得したら、コンテナのImageメソッドを呼び出すことで、1つまたは複数のレイアウトコンテナのコンテンツとして設定できます。他のコンテンツと同様に、画像の拡大縮小、回転、パディングの追加、配置を行うことができます

PdfDocumentBuilder.Create().Generate("image-with-text.pdf", doc =>
{
    var imageFile = new FileInfo("red-flowers-at-butterfly-world.jpg");
    var image = doc.Image(imageFile);

    doc.Pages(pages =>
    {
        pages.Size(PdfPaperSize.A6);
        pages.Content().Column(c =>
        {
            c.Spacing(20);

            c.Item()
                .AlignCenter()
                .Text("Hello, world!")
                .FontSize(20);

            c.Item()
                .AlignCenter()
                .MaxWidth(200)
                .Image(image);
        });
    });
});

サンプルコードでは、プライマリコンテンツスロットにテキストと画像の両方を使用しています。しかし、レイアウトコンテナにはテキストのみ、または画像のみしか格納できません。ページのプライマリコンテンツスロットに両方を含めるには、複合コンテナが必要です。

ここでは、Columnコンテナを使用して、テキストと画像を縦に並べて配置しています。ColumnコンテナのItemメソッドは、サブコンテナを提供します。Itemメソッドを一度呼び出すとテキスト用のコンテナが作成され、もう一度呼び出すと画像用のコンテナが作成されます。すべてのサブコンテナを含む複合コンテナがメインコンテンツになります。

サンプルコードを実行するには、サンプルリポジトリから花の画像をダウンロードし、アプリの作業ディレクトリに配置してください。

オンライン画像

画像ファイルではなく画像URLのみをお持ちの場合は、画像をメモリストリームにダウンロードし、そのストリームからImageを作成します。次の例は、Layout APIでオンライン画像を使用する方法を示しています。

public static async Task AddImageWithTextFromUrl()
{
    using var http = new HttpClient();
    using var stream = await http.GetStreamAsync("url/to/image");

    var memoryStream = new MemoryStream();
    await stream.CopyToAsync(memoryStream);
    memoryStream.Position = 0;

    PdfDocumentBuilder.Create().Generate("online-image-with-text.pdf", doc =>
    {
        var image = doc.Image(memoryStream);

        doc.Pages(pages =>
        {
            pages.Size(PdfPaperSize.A6);
            pages.Content().Column(c =>
            {
                c.Spacing(20);

                c.Item()
                    .AlignCenter()
                    .Text("Hello, world!")
                    .FontSize(20);

                c.Item()
                    .AlignCenter()
                    .MaxWidth(200)
                    .Image(image);
            });
        });
    });
}

このメソッドは非同期処理(URLからの画像のダウンロード)を実行するため、voidではなくasync Taskとして宣言されています。呼び出し元は、PDF生成が正しく完了するように、このメソッドをawaitする必要があります。ご自身のコードでは、同様のメソッドが値を返す場合もあります。その場合は、async Task<TResult>として宣言されます。

リストを作成する

リストとは何でしょうか?リストとは、番号付きの項目が縦に並んだものと考えることができます。レイアウト API にはリスト用の特別なコンテナ タイプはありませんが、他の 複合コンテナ を使用して簡単に実装できます。

var dayNames = DateTimeFormatInfo.InvariantInfo.DayNames;
var dayNamesSpain = DateTimeFormatInfo.GetInstance(new CultureInfo("es-ES")).DayNames;

PdfDocumentBuilder.Create().Generate("list.pdf", doc => doc.Pages(pages =>
{
    pages.Size(PdfPaperSize.A6);
    pages.Content().Column(column =>
    {
        for (int i = 0; i < dayNames.Length; i++)
        {
            column.Item().Row(row =>
            {
                row.Spacing(5);
                row.AutoItem().Text($"{i + 1}.");
                row.RelativeItem().Text(t =>
                {
                    t.Line(dayNames[i]);
                    t.Line($"In Spain they call it {dayNamesSpain[i]}");
                });
            });
        }
    });
}));

サンプルコードは、リストを行の列として作成します。各行には2つの項目が含まれます。最初の項目(左側)には項目番号、2番目の項目(右側)には項目テキストが表示されます。コードは、各行の項目間の間隔を明示的に設定しています。

項目を配置するには、Rowコンテナで各項目のサイズを明示的に指定するか、計算する必要があります。この例では、AutoItemメソッドとRelativeItemメソッドを使用しています。その結果、行コンテナは最初の項目に必要な幅を計算し、残りの幅を2番目の項目に使用します。

この方法を使用し、必要に応じて行の外観を調整することで、ドキュメントのレイアウトとスタイルに最適なリストを作成できます。

テーブルを作る

多くのPDF文書には表が含まれていますが、これは当然のことです。表はデータの明瞭さと整理を向上させるからです。このセクションでは、Layout APIを使用してPDFに表を作成する方法を説明します。

public static void AddTable()
{
    PdfDocumentBuilder.Create().Generate("table.pdf", doc => doc.Pages(pages =>
    {
        pages.Size(PdfPaperSize.A6);

        var color = new PdfGrayColor(75);
        pages.Content().Padding(20).Table(t =>
        {
            t.Columns(c =>
            {
                c.RelativeColumn(4);
                c.RelativeColumn(1);
                c.RelativeColumn(4);
            });

            t.Header(h =>
            {
                h.Cell().Background(color).Text("Month");
                h.Cell().Background(color).Text("Days");
                h.Cell().Background(color).Text("First Day");
            });

            var year = DateTime.Now.Year;
            for (int yearDiff = 0; yearDiff < 4; yearDiff++)
            {
                for (int i = 11; i >= 0; i--)
                {
                    var stats = GetMonthStats(year - yearDiff, i);

                    t.Cell().Text(stats.Item1);
                    t.Cell().Text(stats.Item2);
                    t.Cell().Text(stats.Item3);
                }
            }
        });
    }));
}

private static (string, string, string) GetMonthStats(int year, int monthIndex)
{
    return (
        $"{DateTimeFormatInfo.InvariantInfo.MonthNames[monthIndex]} {year}",
        DateTime.DaysInMonth(year, monthIndex + 1).ToString(),
        new DateTime(year, monthIndex + 1, 1).DayOfWeek.ToString()
    );
}

このサンプルコードは、今年と過去3年間の各月に関する基本情報を表示するシンプルな表を作成します。コードは、相対的な幅を持つ3つの列を定義しています。左端と右端の列は、中央の列の4倍の幅になっています。

また、ヘッダーセルを追加し、各セルのテキストと背景色を指定することで、表のヘッダーも定義しています。表が1ページに収まらない場合、表が占めるすべてのページにヘッダーが繰り返されます。この動作は、サンプルコードによって生成されたPDFで確認できます。

行の作成には、2つのシンプルなループが使用されています。外側のループは年を順に処理し、内側のループは月を逆順に処理します。内側のループは各月の情報を取得し、3つのセルを追加して1行を作成します。

詳細については、表コンテナの機能について詳しく解説した記事をご覧ください。

PDF文書は、読者が同じファイル内の別の場所にジャンプできる内部リンクをサポートしています。PDFビューアでは、これらのリンクはクリック可能なテキストまたは画像要素として表示されます。ハイパーリンクと同様の機能を持ちますが、外部ウェブサイトを指すのではなく、文書内を移動します。

PDF内の内部リンクの図解。リンクアイコンとリンク先アイコンで接続されたドキュメントセクションを表示

多くのPDF文書では、ブックマークや目次として内部リンクが使用されており、読者がセクション間を素早く移動できるようになっています。Layout APIを使用して文書のセクションにリンクを追加する方法は次のとおりです。

PdfDocumentBuilder.Create().Generate("link.pdf", doc =>
{
    doc.Pages(pages =>
    {
        pages.Content().Column(c =>
        {
            const string SectionName = "Chapter 1";
            c.Item().SectionLink(SectionName).Text("Link");

            c.Item().PageBreak();

            c.Item().Section(SectionName).Text("Target");
        });
    });
});

このサンプルコードは、1ページ目のテキストを、指定された名前のセクションへのリンクにします。これは、テキストを含むレイアウトコンテナのSectionLinkメソッドを呼び出すことで実現されます。この時点では、セクションは存在していても存在していなくても構いません。テキストはPDFビューアでクリック可能になります。

次に、コードは2ページ目のテキストを、同じ名前のセクションの開始位置としてマークします。テキストの表示や動作は変わりませんが、1ページ目のリンクのターゲットになります。これは、対応するレイアウトコンテナのSectionメソッドを呼び出すことで実現されます。

この例では、リンクとそのターゲットはどちらもテキストスパンですが、セクションとリンクは任意のレイアウトコンテナ上に作成できます。画像を含むコンテナ、テーブルコンテナ、または独自に作成したコンテナでも構いません。

サンプルリポジトリで、PDF目次を作成する方法の例をご覧ください。

複雑なPDFレイアウトの設計

Layout API は、さまざまなレイアウトコンテナを提供しており、これらを組み合わせて任意の複雑な PDF ドキュメントを作成できます。また、独自のカスタムコンポーネントで API を拡張することも可能です。

このページのサンプルは、意図的にシンプルなものになっています。詳細な部分に気を取られることなく、基本的な考え方に集中できるよう、分かりやすいドキュメントを作成することを目的としています。より複雑な PDF を生成するために、異なるコンテナをどのように組み合わせるかを確認したい場合は、GitHub のサンプルリポジトリにある対応するサンプルをご覧ください。

組み込みのコンテナに加えて、カスタムレイアウトコンポーネントを定義して使用することもできます。これらのコンポーネントは、データとレイアウトロジックの両方を単一のクラスにカプセル化したい場合に特に便利です。すべてを一箇所にまとめることで、コンポーネントの理解、変更、再利用が容易になり、複雑なレイアウトを柔軟に処理できるようになります。

カスタムレイアウトコンポーネントを作成するには、クラスに ILayoutComponent インターフェイスを実装します。PDF を生成する際、ライブラリはインターフェイスの Compose メソッドを呼び出し、LayoutContext オブジェクトを提供します。このオブジェクトを使用すると、コード内でレイアウト要素を作成したり、生成中のドキュメントに関する情報にアクセスしたりできます。

レイアウトにカスタムレイアウトコンポーネントを追加するには、LayoutContainer クラスの Component メソッドを呼び出します。サイズや位置に関しては、カスタムコンポーネントはテキストや画像と同じように動作します。

ILayoutComponent インターフェイスを使用したカスタムコンポーネントの実装例については、レイアウトコンポーネント サンプルを参照してください。

PDFを作成するその他の方法

Docotic.Pdfは、さまざまな状況に適した複数のPDF作成方法を提供しています。このセクションでは、Layout APIを使用すべき場合と、他の方法の方が適している場合について説明します。

Layout APIを優先すべき場合

Docotic.Pdf Layout API は、構造化されたレイアウトから PDF を生成するための強力なツールです。テキスト、画像、コンテナ、テーブルを組み合わせて、任意の複雑なネスト構造を持つドキュメントを作成できます。生成プロセスは高速で、メモリ使用量も少なく、動作も予測可能です。

Docotic.Pdf と Layout アドオンは、軽量で完全に自己完結型のパッケージです。この API は、PDF 生成に外部ライブラリやブラウザを必要としません。そのため、.NET マイクロサービス、クラウドアプリケーション(特にサーバーレスアプリケーション)、およびフットプリントサイズが重要なその他の環境において、最適な選択肢となります。

ドキュメントのレイアウトはコードで定義されているため、そのあらゆる部分を単体テストできます。レイアウトロジックは他のコードと同様に再利用でき、データとレイアウトの動作の両方を カスタムコンポーネント にカプセル化できます。

レイアウトAPIの代替案

Docotic.Pdf を使用したすべての PDF 作成方法 の詳細な比較については、専用の記事をご覧ください。以下に、最もよく使用される代替方法をいくつかご紹介します。

  • HTMLからPDFへの変換
    既存のHTML/CSSテンプレートを再利用できます。チームが既にHTML/CSSでドキュメントを作成しており、それらのドキュメントのPDF版が必要な場合は、HTMLからPDFへの変換を選択してください。

  • 低レベルPDF生成
    PDFの構造とコンテンツに関して、ライブラリ内で利用可能な最大限の制御機能を提供します。ピクセルレベルの位置決めや複雑なベクターグラフィックが必要な場合に選択してください。この方法は、パフォーマンスが重要なシナリオや、最小限のファイルサイズが求められる場合に推奨されます。

  • テンプレートベースのPDF生成
    ドキュメントの要素をデザインしたり配置したりすることなく、迅速かつ予測可能な方法でドキュメントに入力できます。承認済みテンプレートやコンプライアンス管理テンプレートなど、事前に定義された PDF 構造があり、テキスト フィールドの変更、プレースホルダーの置換、関連ドキュメントの添付、および同様のタスクを実行するだけでよい場合に、このオプションを選択してください。

  • PDFの結合と構成
    既存の要素を組み合わせてPDFを作成できます。画像、スキャンしたページ、その他のPDFファイルを1つのファイルに結合する必要がある場合にご利用ください。

他のPDF生成ソリューションとの比較

このセクションには、2つの比較表が含まれています。1つは重要なポイントをまとめたもので、もう1つは、Layoutアドオンを搭載したDocotic.Pdfが、他の一般的なPDF生成ソリューションとどのように比較されるかについての詳細で体系的な情報を示したものです。

主な比較ポイント

PDFを作成するための優れた選択肢は、無料のものも含めて数多く存在します。しかし、署名、暗号化、文書の結合といった機能はツールによって異なり、真にニーズに合ったツールを選ぶには限界があります。

解決 使用時期 最適な用途
Docotic.Pdf(Layoutアドオン付き) 高品質で高性能なレイアウトエンジンで、最適化されたPDFを生成でき、署名、暗号化、プラットフォームを跨いだPDF編集を高度にサポートしている場合 高品質な請求書、レポート、明細書、その他類似文書の生成と、優れた開発者エクスペリエンスを提供します。エンタープライズグレードのPDF処理とプロフェッショナルなサポートが必要な場合に最適です
PDFsharp + MigraDoc 基本的なPDF生成のための無料のMITライセンスライブラリが必要で、デジタル署名や最新の暗号化アルゴリズムを必要としない場合 オープンソースプロジェクトや予算制約のあるプロジェクトにおけるシンプルな文書作成
QuestPDF PDF生成専用の最新レイアウトエンジンが必要で、編集、署名、暗号化は不要である場合 MITライセンスまたは低価格の商用ライセンスによる高品質PDF生成。ただし、生成以外の機能はすべて別途処理されることを条件とする
iText PDFの生成と処理の両方に対応できる、成熟した機能豊富なPDFツールキットが必要で、AGPL/GPLv3ライセンスの下でソリューションをオープンソース化するか、高価な商用ライセンスを購入するかのどちらかを選択できる場合 iText APIに既に精通しているチーム(そのため、習得の難しさに影響されない)

詳細比較

表をよく読んで、より広い文脈を理解し、独自の結論を導き出してください。

  Docotic.Pdf(Layout付き) PDFsharp + MigraDoc QuestPDF iText
PDF機能 フル機能のPDFライブラリ PDF生成と限定的な編集 PDF生成のみ 豊富なPDF機能
レンダリングモデル 最新の宣言型リテインドモードレイアウトエンジン ボックスベースのレイアウトエンジン 最新の宣言型リテインドモードレイアウトエンジン ボックスベースのレイアウトエンジン + レンダラーツリー
APIの種類 Fluent API 命令型API Fluent API 命令型API
開発者エクスペリエンス 素晴らしい。APIは洗練されていて、モダンで、直感的です 良い。API設計は従来通りだ 素晴らしい。APIは洗練されていて、モダンで、直感的です 満足できる。APIは冗長で過度に複雑だ
フォントサブセット化 サポートされています。デフォルトでは、使用されているグリフのみが埋め込まれます サポートされていません。不必要に大きなPDFファイルが生成される可能性があります サポートされています。デフォルトでは、使用されているグリフのみが埋め込まれます サポートされています。デフォルトでは、使用されているグリフのみが埋め込まれます
右から左へのコンテンツ方向(RTL) サポート対象 サポートされていません サポート対象 サポート対象
デジタル署名 サポート対象、LTVおよび外部署名を含む サポートされていません サポートされていません LTVや外部署名を含むサポート対象
暗号化/権限 完全サポート RC4暗号化のみに対応しており、AESや証明書には対応していません サポートされていません 完全サポート
外部依存関係 なし なし SkiaSharp / Skiaベースのコンポーネント なし
サポート 見込み客および顧客に対する専門的なサポート。最上位ライセンスに対する優先サポート コミュニティサポート。専門家によるサポートは別途購入可能です GitHubを通じたコミュニティサポート AGPL版についてはコミュニティによるサポート、商用ライセンス保有者については専門家によるサポートを提供
ライセンス 商用利用可、対象となる利用ケースには無料ライセンスが適用されます MIT 個人および小規模企業向けMITライセンス。大規模企業には商用ライセンスが必要 オープンソース利用にはAGPL、プロプライエタリプロジェクトには高額な商用ライセンス
開発者ライセンス 全てのライセンスを持つ無制限の開発者 全てのライセンスを持つ無制限の開発者 MITプランでは開発者数無制限、Professionalプランでは開発者数10名、Enterpriseプランでは開発者数無制限 AGPL版では開発者数は無制限。商用ライセンスでは開発者ごとのライセンスとなります

結論

Docotic.PdfとLayoutアドオンを組み合わせることで、C#およびVB.NETでPDFを生成するための、最新かつ高性能で高品質な方法を実現できます。このライブラリは、レポート、明細書、請求書などの各種ドキュメントを生成できます。洗練された使いやすいAPIは、優れた開発者エクスペリエンスを提供します。Docotic.Pdfとそのアドオンについては、Bit Miracleが提供するプロフェッショナルなサポートをご利用いただけます。

他のPDF生成ソリューションとは異なり、Docotic.Pdfはフル機能のPDF APIです。生成されたPDFに、LTV(長期検証)対応の署名を含むデジタル署名を付加できます。Docotic.Pdfは、USBトークンやスマートカードなどのセキュアなハードウェアに保存された証明書を使用できます。また、Microsoft Azure Key VaultやAWS Key Management Service(KMS)などのクラウドベースのハードウェアセキュリティモジュール(HSM)もサポートしています。

Docotic.Pdfを使用すると、スプレッドシートや音声メモなどの補足資料を生成されたPDFに添付できます。ウェブページや同様のインターフェースにドキュメントを表示するには、ドキュメントの1つまたは複数のページからサムネイル画像を作成できます

次のステップ:

  • Layout API の コードサンプル を参照してください。
  • 構成可能なビルディングブロックによる PDF 生成と 他の PDF 作成方法 を比較してください。
  • ご質問、ご意見、または特殊なケースについては、お問い合わせ までご連絡ください。