該頁面可以包含自動翻譯的文字。

在 C# 和 VB.NET 中合併 PDF 文檔

企業經常合併 PDF 文件以進行文件歸檔。雖然 PDF 合併聽起來像是一項簡單的任務,但這裡存在著許多陷阱。您應該正確組合表單欄位、書籤、圖層和其他 PDF 物件。您還應該避免重複的物件以獲得緊湊的輸出檔案。

Docotic.Pdf 庫 處理所有合併的細微差別。它允許您只需幾行 C# 或 VB.NET 程式碼即可組合 PDF 文件。

合併PDF文件

Docotic.Pdf 附帶免費和付費許可證。在 下載 C# .NET PDF 函式庫 頁面取得該庫和免費的限時許可證金鑰。

Docotic.Pdf 函式庫 9.5.17548-dev 回歸測試 14,726 已通過 NuGet 總下載量 4,514,921

PDF 合併基礎知識

PdfDocument.Append 方法可讓您從檔案、串流或位元組陣列追加 PDF 文件。還有用於附加受保護文件和合併表單欄位的選項。

合併兩個 PDF 文件

此範例程式碼展示如何在 C# 中合併 PDF 檔案:

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

嘗試 GitHub 中的 合併兩個 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 模式,函式庫會合併並同步衝突的控制 項。即,當您變更一個控制項時,第二個控制項將具有相同的值。

減少合併的 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的前兩頁:

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

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

pdf.Save(pathToFile);

另一個解決方案涉及 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 頁面合併到一個頁面上。使用 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 文件中。這也是有可能的。您也可以新增指向 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 下載頁面 取得評估許可證金鑰並下載該庫。