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

C# および VB.NET で PDF ドキュメントを結合する

ビジネスでは、ドキュメントのアーカイブ化のために PDF ファイルを結合することがよくあります。PDF の結合は簡単な作業のように思えますが、落とし穴がたくさんあります。フォーム フィールド、ブックマーク、レイヤー、およびその他の PDF オブジェクトを適切に結合する必要があります。また、コンパクトな出力ファイルを取得するには、重複したオブジェクトを避ける必要があります。

Docotic.Pdf ライブラリ は、すべてのマージのニュアンスを処理します。これにより、わずか数行の C# または VB.NET コードで PDF ドキュメントを結合できます。

PDF ドキュメントの結合

Docotic.Pdf には 無料および有料のライセンス が付属しています。ライブラリをダウンロードし、評価ライセンス キーを取得するには、Docotic.Pdf のダウンロード ページ にアクセスしてください。

Docotic.Pdf ライブラリ 9.4.17467-dev 回帰テスト 14,760人が合格 NuGet の合計ダウンロード数 4,415,970

PDF マージの基本

PdfDocument.Append メソッドを使用すると、ファイル、ストリーム、またはバイト配列から PDF ドキュメントを追加できます。保護されたファイルを追加したり、フォーム フィールドをマージしたりするオプションもあります。

2 つの PDF ファイルを結合する

このサンプル コードは、C# で PDF ファイルを結合する方法を示しています。

using var pdf = new PdfDocument("first.pdf");
pdf.Append("second.pdf");
pdf.Save("merged.pdf");

GitHub の 2 つの PDF ドキュメントを結合する コード サンプルをお試しください。

PDF ストリームの結合

前の例は、ファイル パスではなくストリームで動作するように簡単に変更できます。ストリームをマージするためのヘルパー メソッドは次のとおりです。

void Merge(Stream first, Stream second, Stream result)
{
    using var pdf = new PdfDocument(first);
    pdf.Append(second);
    pdf.Save(result);
}

複数の PDF ファイルを結合する

Append メソッドを繰り返し呼び出して、複数の PDF ファ イルを追加できます:

string[] filesToMerge = ..;
using var pdf = new PdfDocument();
foreach (string file in filesToMerge)
    pdf.Append(file);

// PdfDocument() 呼び出しによって追加された空のページを削除します
pdf.RemovePage(0);

pdf.Save(pathToFile);

暗号化された PDF ファイルを結合する

暗号化されたドキュメントをマージするための Append オーバーロードがあります:

using var pdf = new PdfDocument();
pdf.Append("encrypted.pdf", new PdfStandardDecryptionHandler("password"));
pdf.Save("merged.pdf");

詳細については、C# および VB.NET で PDF ドキュメントを復号化する の記事をご覧ください。

PDF フォームの結合

PDF ドキュメント内のすべてのフォーム フィールドには、一意の名前が必要です。そのため、結合するドキュメントに同じ名前のフィールドが含まれていると、問題が発生する可能性があります。Docotic.Pdf は、競合するフォーム コントロールに対して次の結合戦略を提供します:

  • 追加されたコントロールが既存のコントロールと競合する場合、名前を変更する
  • 追加されたコントロールを既存のコントロールにマージ
  • 追加されたコントロールをフラット化
  • コントロールを追加しない
  • コントロールをそのまま追加

デフォルトでは、ライブラリは競合時に追加されたコントロールの名前を変更しま す。PdfMergingOptions クラスを使用して、別の戦略を選択 できます:

using var pdf = new PdfDocument("form.pdf");

var decryptionHandler = new PdfStandardDecryptionHandler(string.Empty);
var mergingOptions = new PdfMergingOptions()
{
    ControlMergingMode = PdfControlMergingMode.CopyAsKids
};
pdf.Append("form.pdf", decryptionHandler, mergingOptions);

pdf.Save("merged.pdf");

CopyAsKids モードでは、ライブラリは競合するコント ロールをマージして同期します。つまり、1 つのコントロールを変更すると、2番目のコントロールの値が同じ になります。

結合された PDF ファイルの縮小

PDF ドキュメントには、フォントや画像などの同一のオブジェクトが含まれている場合があります。このようなドキュメントを結合すると、結果のドキュメントには同じオブジェクトのコピーが含まれます。PdfDocument.ReplaceDuplicateObjects() メソッドを使用して、結合結果を最適化します。

using var pdf = new PdfDocument("2024-05-28.pdf");
pdf.Append("2024-05-29.pdf");

pdf.ReplaceDuplicateObjects();

pdf.Save("merged.pdf");

出力ファイルのサイズをさらに小さくすることもできます。たとえば、使用されていないフォント グリフを削除したり、画像を圧縮したりできます。C# および VB.NET で PDF ドキュメントを圧縮する の記事で、サポートされている圧縮オプションについてお読みください。

PDF マージのカスタマイズ

Docotic.Pdf には、PDF ページの抽出、並べ替え、または削除を行うメソッドが用意されています。これらの メソッドをAppend メソッドと共に使用して、カスタム PDF マージ タスクを実装できます。

特定の PDF ページの追加

Docotic.Pdf では、PDF ドキュメントの一部を結合することもできます。結合方法はいくつかあります。たと えば、追加された PDF ドキュメントを分割して、抽出したページを追加できます。次の C# ヘル パーは、選択したページを PdfDocument に追加します:

private static void AppendPart(PdfDocument pdf, string filePath, params int[] pagesToAppend)
{
    using var streamToAppend = new MemoryStream();
    using var other = new PdfDocument(filePath);
    using var extracted = other.CopyPages(pagesToAppend);
    var options = new PdfSaveOptions
    {
        UseObjectStreams = false
    };
    extracted.Save(streamToAppend, options);

    pdf.Append(streamToAppend);
}

または、PDF ドキュメント全体を追加して、不要なページを削除することもできます。次のコード サンプルは、second.pdf の最初の 2 ページを追加します。

using var pdf = new PdfDocument(@"first.pdf");

int pageCountBefore = pdf.PageCount;
pdf.Append(@"second.pdf");
pdf.RemovePages(pageCountBefore + 2);

pdf.Save(pathToFile);

もう 1 つの解決策は、PDF の面付けに関するものです。これについては、対応するセクション で読むことができます。

PDF の先頭に追加

Append メソッドは常に現在のドキュメントの末尾にページ を追加します。PDF ファイルを異なる順序で結合するにはどうすればよいでしょうか。Append呼び出しの順 序を変更できる場合があります。 つまり、

pdf.Append("first.pdf");
pdf.Append("second.pdf");

の代わりに

pdf.Append("second.pdf");
pdf.Append("first.pdf");

を使用します。

または、結合後にページを並べ替えることもできます。この C# コードは、追加された PDF ドキュメントを先頭に移動します:

using var pdf = new PdfDocument(@"second.pdf");

int pageCountBefore = pdf.PageCount;
pdf.Append(@"first.pdf");
pdf.MovePages(pageCountBefore, pdf.PageCount - pageCountBefore, 0);

pdf.Save(pathToFile);

PDF ページの順序変更に関する関連コード サンプル:

PDF の配置

Docotic.Pdf を使用すると、複数の PDF ページを 1つのページにまとめることができま す。PdfDocument.CreateXObject(PdfPage) メソッドを使用して、既存のページに基づいて PdfXObject オブ ジェクトを作成します。次に、このオブジェクトを希望のスケーリングで描画します。サンプル コード:

using var src = new PdfDocument(@"src.pdf");
using var dest = new PdfDocument();
PdfXObject firstXObject = dest.CreateXObject(src.Pages[0]);
PdfXObject secondXObject = dest.CreateXObject(src.Pages[1]);

PdfPage page = dest.Pages[0];
page.Orientation = PdfPaperOrientation.Landscape;
double halfOfPage = page.Width / 2;
page.Canvas.DrawXObject(firstXObject, 0, 0, halfOfPage, page.Height, 0);
page.Canvas.DrawXObject(secondXObject, halfOfPage, 0, halfOfPage, page.Height, 0);

dest.Save("result.pdf");

GitHub から関連する ページから XObject を作成する サンプル プロジェクトをテストします。

添付ファイルとしてマージ

場合によっては、PDF ファイルを添付ファイルとして別のファイルに埋め込む必要があります。それも可能です。PDF ページに埋め込まれたファイルへのリンクを追加することもできます:

using var pdf = new PdfDocument();

PdfFileSpecification first = pdf.CreateFileAttachment("first.pdf");
pdf.SharedAttachments.Add(first);

var bounds = new PdfRectangle(20, 70, 100, 100);
PdfFileSpecification fs = pdf.CreateFileAttachment("second.pdf");
pdf.Pages[0].AddFileAnnotation(bounds, fs);

pdf.Save("attachments.pdf");

GitHub の PDF添付ファイル グループで、関連するコード サンプルを見つけることができます。

並列スレッドでのマージ

多数の PDF ファイルをマージする場合、コードを並列化できま す。PdfDocument クラスはスレッドセーフではありません。そのた め、異なるスレッドで個別の PdfDocument オブジェクトを使用する必要があります。詳細について は、PDF ドキュメントを並列スレッドで結合する コード サンプルを参照してください。

このコードは、PDF ストリームを並列に結合する方法を示しています。

Stream[] documentsToMerge = ..;

int rangeSize = 50;
while (documentsToMerge.Length > rangeSize)
{
    int partitionCount = (int)Math.Ceiling(documentsToMerge.Length / (double)rangeSize);
    var result = new Stream[partitionCount];

    var partitioner = Partitioner.Create(0, documentsToMerge.Length, rangeSize);
    Parallel.ForEach(partitioner, range =>
    {
        int startIndex = range.Item1;
        int count = range.Item2 - range.Item1;
        result[startIndex / rangeSize] = MergeToStream(documentsToMerge, startIndex, count);
    });
    documentsToMerge = result;
}

using PdfDocument final = GetMergedDocument(documentsToMerge, 0, documentsToMerge.Length);
final.Save("merged.pdf");


private static Stream MergeToStream(Stream[] streams, int startIndex, int count)
{
    using PdfDocument pdf = GetMergedDocument(streams, startIndex, count);

    var result = new MemoryStream();

    var options = new PdfSaveOptions
    {
        UseObjectStreams = false // 中間ドキュメントの書き込みを高速化
    };
    pdf.Save(result, options);
    return result;
}

private static PdfDocument GetMergedDocument(Stream[] streams, int startIndex, int count)
{
    var pdf = new PdfDocument();
    try
    {
        for (int i = 0; i < count; ++i)
        {
            var s = streams[startIndex + i];
            pdf.Append(s);
            s.Dispose();
        }

        pdf.RemovePage(0);

        pdf.ReplaceDuplicateObjects();

        return pdf;
    }
    catch
    {
        pdf.Dispose();
        throw;
    }
}

上記のコードは、入力ドキュメントを rangeSize サイズのグループに分割します。次に、コードは各グループを並列で中間ドキュメントにマージします。このプロセスは、入力ドキュメントの数が単純なマージに十分小さくなるまで続きます。

並列ソリューションは、必ずしもシングルスレッド バージョンよりも高速であるとは限りません。結果は、入力ドキュメントの数とそのサイズによって異なる場合があります。サンプル コードでは、rangeSize パラメーターの最適値は、より大きくなったり小さくなったりする可能性があります。最も効果的な実装を見つけるには、アプリケーションのベンチマークを行う必要があります。

結論

Docotic.Pdf ライブラリ を使用すると、C# および VB.NET で PDF ドキュメントを結合できます。ファイル、ストリーム、またはバイト配列を結合できます。暗号化されたファイル、PDF フォーム、特定の PDF ページを結合できます。Docotic.Pdf は、結果のファイルを圧縮してディスク領域を節約するのにも役立ちます。

GitHub の Docotic.Pdf サンプル リポジトリ からコード サンプルをお試しください。評価ライセンス キーを取得し、ライブラリをダウンロードするには、Docotic.Pdf ダウンロード ページ にアクセスしてください。