舊有方式令人痛苦

想像一位合規主管需要驗證共享磁碟中的每份合約是否在每頁都帶有 「CONFIDENTIAL」 文字與公司標誌。現行流程如下:

  1. 在檢視器中開啟檔案。
  2. 翻閱每一頁尋找該文字或圖像。
  3. 在試算表中記錄備註。
  4. 重複上步驟,處理成千上萬的 PDF、Word 檔與簡報。

只要漏掉一個浮水印,就可能觸發昂貴的審查,而人工工作量輕易超過 每週 8 小時,即使是小團隊亦是如此。此外,旋轉文字、斷字或以圖像形式儲存的標誌常常逃過肉眼檢查,讓組織面臨風險。

有更好的方式

GroupDocs.Watermark for .NET 消除所有猜測步驟。其與格式無關的引擎能讀取超過 100 種文件類型,定位文字、圖像乃至樣式化的浮水印,並透過簡潔的 API 暴露所有相關的中繼資料。以下教學示範如何以少量精簡程式碼取代手動迴圈,實現自動化、可重複的工作流程。

前置條件

  • .NET 6.0 或更新版本。
  • GroupDocs.Watermark NuGet 套件(dotnet add package GroupDocs.Watermark)。
  • (可選)臨時授權 – 請參閱本文結尾的連結。

新方式:自動化浮水印稽核

以下示範四個核心操作。每個程式區塊都是可直接放入主控台應用程式、CI 步驟或背景服務的獨立範例。

步驟 1 – 掃描所有浮水印

首先需要完整的清單。Search() 方法會回傳一個集合,每筆條目包含文字(或圖像)、位置、旋轉角度、頁碼與原始圖像尺寸。

using (var wk = new Watermarker(filePath))
{
    var all = wk.Search();
    Console.WriteLine($"Found {all.Count} watermark(s) in " +
        $"'{Path.GetFileName(filePath)}':");
    int i = 0;
    foreach (var wm in all)
    {
        Console.WriteLine($"  #{++i}: {(wm.Text ?? "[image]")} ");
        Console.WriteLine($"     Page {wm.PageNumber}, " +
            $"Pos X={wm.X}, Y={wm.Y}, Rot={wm.RotateAngle}°");
        Console.WriteLine($"     Size {wm.Width}×{wm.Height}");
        if (wm.ImageData != null)
            Console.WriteLine($"     Image bytes {wm.ImageData.Length}");
    }
}

關鍵點:對於一般的 50 頁 PDF,迴圈執行時間不到一秒。

步驟 2 – 驗證必須的文字浮水印

合規政策常要求特定字句(例如 「CONFIDENTIAL」)。TextSearchCriteria 搭配 SkipUnreadableCharacters 能自動處理斷字或旋轉文字。

using (var wk = new Watermarker(filePath))
{
    var crit = new TextSearchCriteria(expectedPhrase);
    crit.SkipUnreadableCharacters = true;   // 忽略 OCR 雜訊
    var hits = wk.Search(crit);
    bool ok = hits.Count > 0;
    Console.WriteLine($"  [{(ok ? "PASS" : "FAIL")}] " +
        $"'{expectedPhrase}' found {hits.Count} time(s)");
    return ok;
}

只要字句出現至少一次,方法即回傳 true,給予即時的 PASS/FAIL 標記。

步驟 3 – 驗證公司標誌

標誌通常以點陣圖形式存在,且因壓縮可能略有差異。ImageDctHashSearchCriteria 會為參考標誌產生感知雜湊,並以可設定的容差進行比對。

using (var wk = new Watermarker(filePath))
{
    var crit = new ImageDctHashSearchCriteria(logoPath);
    crit.MaxDifference = 0.9;   // 容忍中度縮放 / 顏色偏移
    var matches = wk.Search(crit);
    bool ok = matches.Count > 0;
    Console.WriteLine($"  [{(ok ? "PASS" : "FAIL")}] " +
        $"logo instances: {matches.Count}");
    return ok;
}

即使是低解析度的標誌副本也能被辨識。

步驟 4 – 產生完整合規報告

實務政策往往結合多項要求。以下程式碼示範四項格式規則——文字存在、字型、大小與粗體樣式——每項皆透過 TextSearchCriteriaTextFormattingSearchCriteria.And() 結合:

using (var wk = new Watermarker(filePath))
{
    int passed = 0, failed = 0;

    var txtCrit = new TextSearchCriteria(expectedPhrase);
    bool hasText = wk.Search(txtCrit).Count > 0;
    Console.WriteLine($"  [{(hasText ? "PASS" : "FAIL")}] Text present");
    if (hasText) passed++; else failed++;

    var fontCrit = new TextFormattingSearchCriteria { FontName = expFont };
    bool hasFont = wk.Search(txtCrit.And(fontCrit)).Count > 0;
    Console.WriteLine($"  [{(hasFont ? "PASS" : "FAIL")}] Font {expFont}");
    if (hasFont) passed++; else failed++;

    var sizeCrit = new TextFormattingSearchCriteria { MinFontSize = minSize };
    bool hasSize = wk.Search(txtCrit.And(sizeCrit)).Count > 0;
    Console.WriteLine($"  [{(hasSize ? "PASS" : "FAIL")}] Size >= {minSize}");
    if (hasSize) passed++; else failed++;

    var boldCrit = new TextFormattingSearchCriteria { FontBold = true };
    bool hasBold = wk.Search(txtCrit.And(boldCrit)).Count > 0;
    Console.WriteLine($"  [{(hasBold ? "PASS" : "FAIL")}] Bold formatting");
    if (hasBold) passed++; else failed++;

第五條規則驗證頁面覆蓋率——浮水印必須出現在每一頁。最後彙總所有結果:

    var perPage = wk.Search(txtCrit);
    var pages = new HashSet<int>();
    foreach (var wm in perPage)
        if (wm.PageNumber.HasValue) pages.Add(wm.PageNumber.Value);
    var allPages = wk.Search();
    int max = 0;
    foreach (var wm in allPages)
        max = Math.Max(max, wm.PageNumber ?? 0);
    bool full = max > 0 && pages.Count == max;
    Console.WriteLine($"  [{(full ? "PASS" : "FAIL")}] " +
        $"Pages covered {pages.Count}/{max}");
    if (full) passed++; else failed++;

    string verdict = failed == 0 ? "COMPLIANT" : "NON-COMPLIANT";
    Console.WriteLine($"\nResult: {verdict} " +
        $"({passed} passed, {failed} failed)");
}

報告可匯出為 JSON、CSV,或直接送入工單系統。


前後對照:舊方式 vs. 新方式

手動審查 自動化稽核
時間 以小時計算每批次 以秒計算每檔案
準確度 人為錯誤頻發 決定性 API
可擴展性 受限於少量文件 可處理數千份
所需程式碼 無(但勞力密集) 約 30 行 C#
輸出 僅視覺檢查 結構化 PASS/FAIL 報告

對比相當明顯:過去需要整個工作天的工作,現在只要背景工作即可完成。


真實案例:法律合約資料庫

一家律師事務所於共享資料夾中保存 15 000 份合約。其政策要求每頁都出現字句 「CONFIDENTIAL – CLIENT XYZ」 與事務所印章。透過將上述程式碼片段整合至每晚執行的 PowerShell 腳本,該事務所達成:

  • 100 % 偵測 到缺失的標記(先前有 8 % 漏檢)。
  • 零人工工時 用於稽核。
  • 稽核軌跡 儲存至內部 SharePoint 清單,以備未來法規審查。
// 每晚工作排程的入口點範例
var folder = @"\\fileserver\Contracts";
foreach (var pdf in Directory.GetFiles(folder, "*.pdf", SearchOption.AllDirectories))
{
    // 重新使用步驟 1‑4 的方法
    ScanAll(pdf);
    VerifyText(pdf, "CONFIDENTIAL – CLIENT XYZ");
    VerifyLogo(pdf, @"C:\Logos\firm-seal.png");
    RunReport(pdf);
}

腳本可無人值守執行,並於每晨寄送摘要郵件。


你還能用 GroupDocs.Watermark 做什麼?

除了稽核之外,範例專案亦示範了如何以程式方式 取代移除 浮水印。下方螢幕截圖展示了在真實 PDF 上的兩種操作:

文字取代 — 舊浮水印已更新為新文字、字型與顏色

目標移除 — 只刪除同時符合文字與格式條件的浮水印

同一 API 可支援的其他情境:

  • 加入隱形追蹤浮水印,嵌入唯一 ID 以便洩漏追蹤。
  • 批次取代過時的標誌,遍佈整個檔案庫。
  • 產生合規證書(PDF 格式),於稽核成功後自動生成。
  • 與 Azure Functions 或 AWS Lambda 整合,實現無伺服器處理。

每個情境皆使用相同的核心 API——只要更換搜尋條件或浮水印類型即可。


結論

過去需要團隊逐頁翻閱、手寫備註、且風險高的工作,現在只要幾秒鐘的程式碼即可產出可稽核的 PASS/FAIL 報告。使用 GroupDocs.Watermark for .NET,您將獲得:

  • 每個浮水印的完整可視化。
  • 可靠的文字、樣式文字與圖像偵測。
  • 自動化的合規報告。
  • 以程式方式更新或移除浮水印的能力。

立即試用,將浮水印合規流程從頭痛問題轉變為可重複的服務。


後續步驟

  • 試用免費 API 版 – 在此取得臨時授權:Temp License
  • 閱讀完整文件 以了解進階選項:Docs
  • 探索 .NET API 參考,掌握所有類別與方法:API Reference
  • 在 GitHub 上克隆範例專案,查看完整的主控台應用程式:GitHub Samples
  • 在社群論壇提問或分享使用案例Forum