完整的可運作範例可在 GitHub 上取得: strip-pdf-metadata-dotnet

介紹

PDF 中繼資料清理是針對 .NET 的 GroupDocs.Metadata 工作流程,可從 C# 服務中清除 PDF 的 Info 目錄與 XMP 身分欄位。當合約 PDF 從內部磁碟離開時,Author、Creator、Producer、Keywords 以及 XMP 封包常會一起被帶走。瀏覽器清理工具與快速的 Acrobat 檢查看似成功,卻仍可能留下 XMP 中原始作者的名稱。當合作夥伴在另一個檢視器中開啟檔案時,我發現「已清理」的草稿仍在 Author 欄位顯示 Alice Example,就發生了這種情況。

GroupDocs.Metadata for .NET 為 C# 服務在同一個 Metadata 物件上提供兩種明確的清理強度:Sanitize() 用於完整清除偵測到的套件,RemoveProperties 則在必須保留 Title 與 Subject 但不允許保留個人身分時使用。本文比較這兩種方法,並說明檢查與驗證步驟,以確保結果可稽核。

您將獲得可在 .NET 8 上執行的範例、針對外部傳輸與適合存檔的清理之決策規則,以及在 Save 後檢查 Author / Person.Creator 的驗證斷言,而不會因 PDF 引擎的 Creator/Producer 指紋而產生錯誤。

為何 PDF 中繼資料清理很重要

對外部檔案分享、多租戶下載以及受規範管理的存檔,都需要可重複執行的中繼資料移除 API,而非僅靠桌面點擊。此做法在以下情境中特別有價值:

  • Partner portals:在 PDF 跨越信任邊界前徹底清除
  • Records search:保留 Title/Subject,同時移除作者類型欄位
  • Incident response:在誤傳後證明已移除 Author
  • CI gates:當驗證回傳 false 時使建置失敗

單行政策(「remove metadata」)會隱藏 Sanitize 與選擇性清除之差異。在程式碼審查中明確命名清理強度,可防止無聲地刪除存檔仍需的 Keywords。

前置條件

在開始之前,請確保您已具備:

  • .NET 8 SDK
  • GroupDocs.Metadata 26.8.0(temporary license)
  • 仍包含 Info 或 XMP 身分欄位的 PDF
  • Visual Studio 2022 或 VS Code(可選)

安裝

透過 NuGet 安裝 GroupDocs.Metadata:

dotnet add package GroupDocs.Metadata --version 26.8.0

或從範例專案的 .csproj 還原。若要進行不受限制的 Save,請將環境變數 LIC_METADATA_VALID 設為包含 GroupDocs.Metadata.Product.Family.lic 的資料夾路徑。

方法 1 - 清理前檢查

先以唯讀方式列出 PDF 實際攜帶的欄位,這樣您就能了解其內容。瀏覽器工具常會遺漏 XMP;此清單作為前後檢查的基準。

using var metadata = new Metadata(inputPath);
var properties = metadata.FindProperties(p =>
    p.Tags.Contains(Tags.Person.Creator) ||
    p.Tags.Contains(Tags.Tool.Software) ||
    p.Tags.Contains(Tags.Content.Title) ||
    p.Tags.Contains(Tags.Content.Subject) ||
    string.Equals(p.Name, "Author", StringComparison.OrdinalIgnoreCase) ||
    string.Equals(p.Name, "Creator", StringComparison.OrdinalIgnoreCase) ||
    string.Equals(p.Name, "Producer", StringComparison.OrdinalIgnoreCase) ||
    string.Equals(p.Name, "Keywords", StringComparison.OrdinalIgnoreCase));

foreach (var property in properties)
{
    Console.WriteLine($"{property.Name} = {property.Value}");
}

要點:

  • Tags plus names:將標籤檢查與 Author / Keywords 的相等比較混合,以因應以不同方式標記欄位的產生者
  • No mutation:對於乾跑模式與支援工單皆安全
  • Shared filters:之後在移除斷言中可重複使用相同的概念

方法 2 - 清除所有偵測到的中繼資料

當 PDF 必須在無任何作者痕跡的情況下離開時,使用 Sanitize()。此呼叫會清除已辨識的套件,包括 Info 目錄欄位與 API 偵測到的 XMP,之後您再儲存為新檔案。

using var metadata = new Metadata(inputPath);
int removed = metadata.Sanitize();
Console.WriteLine(removed);
metadata.Save(outputPath);

要點:

  • One call:對於外部傳輸的介面而言只需一次呼叫
  • Log the count:操作人員可辨識已清理的輸入與大規模清除的差異
  • Expect tool stamps:Save 後,Creator/Producer 可能會顯示 PDF 引擎的 Tool.Software 值

最佳使用情境:合作夥伴下載、公開連結、跨租戶交換。

方法 3 - 僅移除作者類型屬性

當 Title、Subject 與 Keywords 仍需供搜尋使用時,使用 RemoveProperties 只剝除個人身分資訊,而非清除所有套件。

using var metadata = new Metadata(inputPath);
int removed = metadata.RemoveProperties(p =>
    p.Tags.Contains(Tags.Person.Creator) ||
    p.Tags.Contains(Tags.Person.Editor) ||
    string.Equals(p.Name, "Author", StringComparison.OrdinalIgnoreCase) ||
    string.Equals(p.Name, "Creator", StringComparison.OrdinalIgnoreCase) ||
    string.Equals(p.Name, "Producer", StringComparison.OrdinalIgnoreCase));
Console.WriteLine(removed);
metadata.Save(outputPath);

要點:

  • Predicate is reviewable:程式碼審查可清楚看到哪些身分欄位被移除
  • Descriptive fields stay:此篩選條件保留 Title/Subject/Keywords
  • Same SDK:不需額外的函式庫即可實作選擇性路徑

最佳使用情境:內部存檔、流通草稿、禁止 Author 但允許關鍵字的政策。

如何在 Save 後證明已移除 Author?

重新開啟已清理的 PDF,僅搜尋 Author / Person.Creator / Person.Editor。若皆不存在則輸出 True。不要將剩餘的 Creator/Producer Tool.Software 指紋視為清除失敗——Save 可能會以 PDF 引擎名稱重新寫入這些欄位。此區別可確保 CI 中的合規檢查保持正確,並避免因引擎自行加上工具欄位而產生誤報。

using var metadata = new Metadata(inputPath);
var leftovers = metadata.FindProperties(p =>
    p.Tags.Contains(Tags.Person.Creator) ||
    p.Tags.Contains(Tags.Person.Editor) ||
    string.Equals(p.Name, "Author", StringComparison.OrdinalIgnoreCase));

Console.WriteLine(!leftovers.Any());

要點:

  • Ask the right question:詢問「Author 是否已移除?」而非「Creator 是否為空?」
  • Second open:在 Save 後再次開啟驗證,而非僅在記憶體中檢查
  • CI friendly:使用單一布林值供測試與日誌使用

在 Sanitize 與 RemoveProperties 之間的選擇

問題 偏好 Sanitize 偏好 RemoveProperties
檔案是否離開公司? 是 僅在必須保留描述性欄位時
存檔搜尋是否需要 Title? 否 是
政策規定「中繼資料中不得有個人」? 兩者皆可,之後驗證 是,使用針對個人的斷言
操作員想要一鍵式操作? 是 在具名路由後包裝

strip-pdf-metadata-dotnet 是一個可執行的 .NET 示範,將四個步驟串接於 Resources/contract-with-metadata.pdf,讓您在一次控制台執行中看到檢查、清除、選擇性移除與驗證。

常見錯誤

  • Trusting a browser cleaner alone:僅信任瀏覽器清理工具 → XMP 常會存留下來。
  • Verifying Creator/Producer names:驗證 Creator/Producer 名稱 → Save 後的引擎指紋會導致誤判失敗。
  • One predicate forever:永遠使用同一個斷言 → 當出現新產生者時需重新檢視身分欄位名稱。
  • Skipping license setup for Save:省略 Save 的授權設定 → 評估模式會阻止不受限制的寫入;請設定 LIC_METADATA_VALID 以進行完整管線測試。
  • Skipping inspect:省略檢查 → 若沒有事前清單,就無法判斷 Sanitize 是移除 7 個欄位還是 0 個,因為檔案可能已經乾淨。

在示範檔案 contract-with-metadata.pdf 中,授權執行時通常會在檢查階段列印 Author 與 Keywords,Sanitize 的移除計數約為 7,且 Author 為主的驗證會回傳 True。選擇性作者移除則會顯示較小的計數(約 3),而 Title 與 Subject 在第二次檢查時仍可見。

其他資源

結論

.NET 上的 PDF 中繼資料清理並非僅靠一個名稱模糊的 API 呼叫。若需對外部傳輸徹底清除,請選擇 Sanitize();若必須保留 Title 與 Subject,則使用 RemoveProperties,且在 Save 後務必先檢查再驗證作者類型欄位。將範例倉庫複製下來,在示範的合約 PDF 上執行,然後將相同的方法搬入您的上傳服務,並在移除計數周圍加入日誌記錄。