完整的可運作範例可在 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 在第二次檢查時仍可見。
其他資源
- 使用案例:Sanitize 與作者移除在 PDF 中繼資料的比較 (.NET)
- 文件:移除所有偵測到的中繼資料套件
- 文件:移除特定的中繼資料屬性
- GitHub:strip-pdf-metadata-dotnet
- API 參考
結論
.NET 上的 PDF 中繼資料清理並非僅靠一個名稱模糊的 API 呼叫。若需對外部傳輸徹底清除,請選擇 Sanitize();若必須保留 Title 與 Subject,則使用 RemoveProperties,且在 Save 後務必先檢查再驗證作者類型欄位。將範例倉庫複製下來,在示範的合約 PDF 上執行,然後將相同的方法搬入您的上傳服務,並在移除計數周圍加入日誌記錄。