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

如何使用 C# 和 VB.NET 建立 PDF 文檔

本文介紹了使用 Docotic.Pdf 程式庫在 .NET 中建立 PDF 文件的幾種方法。 Docotic.Pdf 是一個高效能的純 C# .NET 函式庫,無需任何外部依賴,即可用於建立、編輯、轉換和處理 PDF 文件。

圖示突出了使用 Docotic.Pdf 建立 PDF 和實現文件自動化。

以下各節將介紹使用 Docotic.Pdf 建立 PDF 的主要方法:

  • 使用核心 API,它提供對文字、圖形和 PDF 內部結構的底層控制。此選項最適合自訂佈局、包含大量圖形的文件以及需要高級功能的文件。
  • 使用進階的 Layout API,它支援段落、表格、頁首、頁尾和自動分頁。如果您需要建立結構化的文件而無需手動計算位置,此 API 是理想之選。
  • 將 HTML 轉換為 PDF,並支援 SVG 和其他 Web 格式。如果您的解決方案已經產生 HTML 文檔,並且您需要這些 HTML 和 CSS 文件的 PDF 版本,則此方法尤其有用。
  • 從影像建立 PDF。此方法適用於掃描文件、基於影像的報告、收據以及任何以柵格影像開始的工作流程。
  • 合併或拆分 PDF。這對於組裝報告、處理使用者上傳內容、合併相關文件以及重構大型 PDF 來說是一個不錯的選擇。
  • 從模板建立 PDF。當需要批量產生格式一致的文件(例如收據、稅務表格、僱傭合約和其他可重複使用的文件類型)時,這種方法非常有效。

本指南也涵蓋以下主題:

使用 Core API 建立 PDF

Core API 是 Docotic.Pdf 建立 PDF 的基礎。它透過 Canvas API 提供對 PDF 畫布上文字、圖像和向量圖形放置的完全底層控制。此繪圖 API 是 Core API 的子集,提供用於為頁面和其他帶有畫布的物件添加內容的各種方法和屬性。除了渲染之外,Core API 還支援註釋、表單欄位、圖層、書籤和其他 PDF 功能。

以下 C# 程式碼使用三個基本操作創建了一個簡單的 PDF:在頁面畫布上繪製文字、放置圖像和渲染向量圖形。

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 應用程式中使用 Layout API 產生 PDF

使用 HTML 轉 PDF API 將 Web 內容轉換為 PDF

Docotic.Pdf 及其免費的 HtmlToPdf 外掛程式提供了一個現代化的、高品質的基於 Chrome 的 HTML 轉 PDF 引擎。您可以使用該外掛程式提供的 API,將現代 HTML 和其他網頁內容(例如 SVG 或 WebP 圖像)轉換為高品質的 PDF 文件。

HTML 轉換 PDF API 可以從完整的 HTML 頁面或 HTML 片段建立 PDF。您可以轉換來自 URL、原始 HTML 字串和本機 HTML 檔案的內容。後兩種方式可以輕鬆地從 HTML 模板產生 PDF。

查看如何從 HTML 範本產生 PDF 的範例:

public static async Task HelloHtmlTemplate()
{
    static string GetUserName()
    {
        // Replace with real logic: form input, API call, config, etc.
        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-to-PDF概述

從圖像創建 PDF

Docotic.Pdf 提供了一種靈活且對開發者友好的方式來將圖像轉換為 PDF。該程式庫透過核心 API 支援 JPEG、BMP、GIF、PNG、TIFF 和 JPEG 2000 影像格式。

圖示展示了 Docotic.Pdf 如何將多個影像檔案轉換為單一 PDF 文件。

當 PDF 格式支援時,Docotic.Pdf 會直接嵌入圖像字節,避免像素解碼和重新編碼,保留原始壓縮效果。該庫還會盡可能保留色彩空間。

此外,透過 HTML 轉 PDF API,Docotic.Pdf 也支援 SVG 和 WebP 格式。當您需要將圖像與標籤或描述並排顯示時,佈局 API 可以幫助您輕鬆排列和對齊元素。

如何將多張圖片合併到一個PDF檔案中

使用 Docotic.Pdf,您可以輕鬆地將一組圖像轉換為單個 PDF 文件,並將每張圖片放置在單獨的頁面上。

以下範例從文件中載入圖像,並將每張圖片繪製在單獨的頁面上。每張圖片都會縮放以適應頁面,並居中顯示,從而實現簡潔一致的佈局。

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 中新增圖像時,如果任何圖像可能包含多頁,請使用 OpenImage 方法而不是 CreateImage 方法。

以下程式碼示範如何將 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、目標位置(連結目標)和嵌入文件。有關更多詳細資訊以及如何減少合併後 PDF 文件大小的指導,請參閱合併 P​​DF 文章。

數位簽章的 PDF 檔案無法合併,否則會使現有簽章失效。為了保留簽名,請建立 PDF 檔案包,而不是附加文件。另一種方法是先合併 PDF 文件,然後對合併後的文件套用新的數位簽章

Docotic.Pdf 還允許您將頁面複製並提取到新文件中。與複製頁面關聯的所有內容都會保留,包括註釋、表單控制項、結構化內容、圖層和其他相關資料。有關實際範例,請參閱關於在.NET中分割PDF的文章。該文章還解釋瞭如何提取或刪除頁面。

使用 PDF 模板

PDF範本是預先設計好的PDF文件,可作為建立新文件的基礎架構。當您需要產生佈局一致的PDF文件,同時提供不同的數據時,PDF模板非常有用。如果您希望將視覺設計與資料本身分離,PDF範本也是一個不錯的選擇。

範本可以是表單式PDF,也可以是不含表單的靜態PDF。兩種類型的模板用途相同。此外,表單式範本包含互動式元素,如果沒有進行扁平化處理,這些元素可能會收集使用者資訊。

從基於表單的範本建立 PDF

基於表單的範本通常包含 AcroForms,這是一種標準且廣泛支援的互動式 PDF 表單類型。要從此類模板產生 PDF,通常需要:

  • 填寫每個佔位符字段
  • 展平欄位以防止進一步編輯
  • 將結果儲存為新的 PDF

以下 C# 程式碼透過名稱尋找佔位符文字字段,為其賦值,展平字段,並保存結果,從而從模板建立 PDF:

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

如果您的範本不包含表單字段,您將直接在頁面畫布上繪製名稱和其他資料。靜態 PDF 範本通常包含固定的視覺佔位符,例如文字、影像或空白區域。要從模板生成 PDF,您需要以程式設計方式填充這些空白區域並替換佔位符文字和圖像。

空白區域

使用 Canvas API 在空白區域放置文字和圖像。在只需要進行少量更改(例如添加姓名和照片)的簡單情況下,這種方法非常有效。您需要知道區域的座標和大小,為了正確放置文本,可能需要先測量文本長度,然後再進行相應的對齊。

處理可變長度或多行文字更具挑戰性,但仍然可行。透過結合 DrawTextDrawString 和文字測量方法,您可以根據需要自動換行和定位文字。如果您的範本包含多個此類區域,請考慮使用其他方法,例如使用 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 = "新文字"; 直接賦值。之後,將文字方塊展平以防止進一步編輯。

新增互動元素

互動式功能可將靜態 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 文件內的頁面或指定目標位置。它們對於交叉引用和內部導航非常有用。

以下 C# 程式碼建立了一個從首頁到索引為 5 的頁面的連結:

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 操作)會開啟一個網頁 URL。您可以使用 PdfPage.AddHyperlink 方法為 PDF 頁面新增超連結。除此之外,其操作方法與內部連結相同。

書籤

書籤(也稱為大綱)是特殊的快捷方式或鏈接,可以幫助讀者快速導航到特定章節或頁面。當讀者點擊書籤時,檢視器應用程式會跳到文件的指定位置。

大綱顯示在檢視器的書籤面板中,並提供類似書籍目錄的層級式導航樹,但具有互動性。 PDF 大綱可以包含主書籤和巢狀書籤,從而更輕鬆地組織大型文件。

以下範例顯示如何使用 C# 和 Docotic.Pdf 在 PDF 中建立書籤。該程式碼創建了三個頂級書籤。第二個書籤包含一個嵌套書籤。

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。它用於表單驗證、計算、使用者介面對話框和小型自動化任務。

您可以將腳本附加到註解、書籤、表單控制項或開啟操作。使用 Docotic.Pdf,您可以將 JavaScript 程式碼嵌入 PDF 中。此程式碼可以驗證表單輸入、計算值、顯示或隱藏字段,或執行檢視器互動。

共用 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 參考文件提供了許多可用的方法。請注意,非 Adob​​e 的檢視器通常只支援 API 的一部分。

開放行動

開啟操作是指 PDF 檢視器在開啟文件時所執行的操作。典型用途包括開啟到特定頁面、執行 JavaScript 初始化例程或設定檢視器首選項。開啟操作的類型沒有限制。

以下範例展示如何建立 GoTo 開啟操作。該程式碼在第二頁添加文本,並設定一個開啟操作,使檢視器在開啟 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 檔案。加密控制誰可以開啟文件以及他們可以對文件執行哪些操作,而簽章則證明文件的建立者或核准者,並確認文件未被竄改。

密碼保護可讓您在建立過程中設定存取規則。您可以設定一個開啟密碼來限制檢視權限,並設定一個擁有者密碼來定義諸如列印、複製、編輯或填寫表單等權限。憑證加密提供更強大的、針對特定收件人的保護,尤其適用於在不依賴共享密碼的情況下向多人分發機密 PDF 文件。更多詳情,請參閱關於使用密碼和證書加密 PDF 的文章。

數位簽章在建立時即可增強文件的真實性和完整性。 Docotic.Pdf 可以使用來自檔案、Windows 應用程式商店、硬體令牌、HSM 或雲端金鑰服務的憑證對 PDF 檔案進行簽署。您可以新增時間戳記和長期驗證數據,以便簽名在文件產生後很長一段時間內仍然可驗證。此外,Docotic.Pdf 還支援外部簽章工作流程,包括 PKCS#11 和雲端 KMS。

設定 PDF 元數據

PDF 元資料是嵌入在文件中的描述性訊息,例如標題、作者、主題、關鍵字、建立日期等欄位。它可以幫助軟體、搜尋引擎和文件管理系統在不開啟文件的情況下了解文件的內容。

PDF 文件可以同時包含兩種元資料系統:

  • XMP 元數據
  • 文件資訊字典(Info 字典)

使用 Docotic.Pdf 在 PDF 文件中新增 XMP 元資料的流程示意圖。

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 字典,請設定 preferXmp: false

pdf.SyncMetadata(preferXmp: true);

有關該方法同步哪些屬性的詳細信息,請參閱SyncMetadata文檔中的「備註」部分。

配置頁面標籤和檢視器首選項

新建立的 PDF 檔案可以透過明確的頁碼、精細的檢視器設定以及選擇合適的頁面佈局來更有效地呈現文件內容。這些設定會影響讀者首次查看和瀏覽文件的方式。

頁面標籤

頁面標籤是元數據,用於告知 PDF 檢視器每頁應顯示哪個標籤。當可見頁碼必須與實際頁碼不同時,請使用頁面標籤。例如,您希望 PDF 的前言部分使用 i, ii, iii,而正文部分使用 1, 2, 3

以下 C# 程式碼示範如何為 PDF 頁面新增標籤:前三頁使用小寫羅馬數字,其餘頁面使用從 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 和其他檢視器可能會忽略這些首選項。

頁面佈局和頁面模式

頁面版面配置決定了文件開啟時的頁面排列方式:一次顯示一頁、單欄連續顯示或跨頁顯示。頁面模式控制開啟時顯示哪些使用者介面面板:書籤/大綱、附件、縮圖或不顯示任何面板。

以下是如何指定已建立的 PDF 檔案以跨頁顯示(左頁在前)並在開啟時顯示縮圖面板:

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 物件的 SaveSignAndSaveTimestampAndSave 方法將使用預設值。這些預設值經過精心選擇,適用於大多數場景,但您可能仍然需要進行調整。

有關可用選項及其預設值的詳細信息,請參閱 PdfSaveOptions 類別 的文檔。以下部分重點介紹一些更重要的選項並提供實用建議。

PDF版本

Docotic.Pdf 預設使用物件流來提高檔案壓縮率。因此,該庫預設會建立 PDF 1.5 檔案和流。

PDF 1.5 需要 Adob​​e 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 版本儲存,必須同時停用物件流。如果文件包含更高版本中引入的功能,庫將不會使用舊版本。

檔案大小縮減

當幾個儲存選項設定為 true 時,Docotic.Pdf 會產生更小的檔案(以位元組):RemoveUnusedObjectsOptimizeIndirectObjectsWriteWithoutFormattingUseObjectStreams

以下是如何產生不包含未引用物件和多餘空白的 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 進行比較,防止版本發布過程中出現內容和佈局方面的回歸問題。基準 PDF 有助於檢測文字、字體、圖像或佈局中的意外更改,從而減少每次建置時進行手動品質保證 (QA) 的需求。

結合結構檢查、文字擷取和視覺比較,可獲得最可靠的結果。

方法快速比較

方法 速度 敏感度 最適合
結構比較 快速地 高:能夠偵測到物件層級的變化 迴歸測試必須確認同一文件的兩個版本在結構上完全相同。
文字擷取 快速地 中等:通常忽略佈局更改 驗證語意內容和表格
視覺差異 慢點 高:能夠同時偵測到內容和渲染/佈局的變化 捕捉視覺退化

比較文件結構

使用 PdfDocument.DocumentsAreEqual 可以比較 PDF 物件圖、PDF 版本和文件安全儲存 (DSS),同時忽略與時間相關的文件屬性。此方法也會忽略文件元資料、尾部 ID 和其他自動產生的屬性。

此方法非常適合必須確保沒有新增或刪除意外物件的 PDF 文件測試工作流程。 DocumentsAreEqual 支援檔案和串流重載,並且可以比較加密的 PDF。

Docotic.Pdf 範例中提供了一個演示此技術的完整範例。除了展示如何在常規 .NET 應用程式中使用此方法外,該範例還示範如何在原生 AOT 應用程式中使用 DocumentsAreEqual

透過提取的文本驗證 PDF

一次從整個文件中提取文本,或逐頁提取,並比較字串。您可以使用文字擷取選項來微調擷取過程,例如排除包含頁尾的矩形區域。為了方便比較,您可以將提取的文字拆分為行或單字。

對於結構化檢查,首先提取包含位置、字體以及其他詳細資訊的文字區塊、單字或字元。然後將每個提取的元素與相應的基線元素進行比較。

檢測視覺差異

首先將 PDF 頁面渲染成影像,並將每張影像與基準影像進行比較。使用 ImageSharp.Compare 或 Magick.NET 等專用函式庫來偵測影像差異。

最好進行嚴格的逐像素比較,確保兩張影像中每個對應的像素都完全一致。如果允許存在較小的渲染差異,可以調整比較邏輯以容忍細微差別,但精確的像素相等性能夠提供最可靠的結果。

可以考慮使用雜湊值作為快速預檢,在不進行完整像素比較的情況下判斷兩張影像是否可能相同。計算每張渲染圖像的 SHA-256 雜湊值,如果雜湊值匹配,則幾乎可以肯定兩張圖像相同。如果雜湊值不同,則進行完整的逐像素比較。

結論

Docotic.Pdf 提供了一套全面的多層工具包,用於在 .NET 中建立和操作 PDF 檔案。開發人員可以選擇使用 Core API 進行底層控制,使用 Layout API 進行高級文件生成,或將 HTML 轉換為 PDF,以適應已基於 Web 技術構建的工作流程。

該庫還支援基於圖像的 PDF、模板驅動生成,以及豐富的互動式功能,例如註釋、連結、書籤、JavaScript 操作和開啟操作。

為了確保可靠性,Docotic.Pdf 包含用於測試 PDF 輸出的方法,從而避免應用程式中的變更引入回歸問題或意外差異。