如何在 .NET 中清除 PDF 文件的批註

當 PDF 中充斥著審閱者的評論、標記與標註時,文件很快就會變得難以閱讀。無論您是在準備法律簡報、最終研究論文,或是企業報告,通常都需要在發布或存檔前 清除批註。在本教學中,您將學會如何使用 GroupDocs.Annotation for .NET 清除 PDF 批註、為何此函式庫優於其他方案,以及如何處理常見的陷阱。

快速解答

  • 刪除所有 PDF 批註的最快方法是什麼? 呼叫 annotator.Save(outputPath, new SaveOptions { AnnotationTypes = AnnotationType.None })。
  • 開始使用是否需要授權? 不需要 – 免費試用版可用於開發與小規模測試。
  • 支援哪些 .NET 版本? .NET Framework 4.5+、.NET Core 3.1+、.NET 5/6/7。
  • 可以保持原始檔案不變嗎? 可以 – API 總是寫入全新清潔檔案,來源檔案保持完整。
  • GroupDocs.Annotation 支援多少種檔案格式? 超過 50 種輸入與輸出格式,包括 PDF、DOCX、XLSX、PPTX 以及各類影像。

什麼是「清除批註」?

清除批註 指以程式方式移除 PDF 中的每一個批註物件,使最終檔案僅保留原始內容與版面配置。此操作會產生一個沒有批註層的全新 PDF,並保留頁面順序、字型與內嵌影像。

為何使用 GroupDocs.Annotation for .NET?

GroupDocs.Annotation 支援 50+ 檔案格式,且可在不將整份文件載入記憶體的情況下處理高達 200 MB 的 PDF,提供記憶體效能佳的解決方案,適合多執行緒環境。相較於一般 PDF 函式庫,它內建批註類型過濾、批次處理,且在清理後保留原始版面的正確率達 99.9 %。

前置條件

  • GroupDocs.Annotation .NET 函式庫(v25.4.0 或更新版)
  • Visual Studio(任意版本)或其他相容 .NET 的 IDE
  • 基本的 C# 語法與 using 陳述式概念
  • 一個包含至少一個批註的範例 PDF(可使用 Adobe Acrobat、Foxit,或免費的 Edge PDF 檢視器加入批註)

設定 GroupDocs.Annotation

安裝(簡易方式)

選項 1:NuGet 套件管理員主控台

Install-Package GroupDocs.Annotation -Version 25.4.0

選項 2:.NET CLI(如果您偏好指令列)

dotnet add package GroupDocs.Annotation --version 25.4.0

處理授權問題

您可以先使用 免費試用,在投入正式環境時再切換至永久授權。

基本設定(前五行程式碼)

Annotator 類別是代表已載入記憶體的 PDF 文件的入口點,提供讀取、編輯與儲存批註的方法。

using GroupDocs.Annotation;

string sourceDocumentPath = "YOUR_DOCUMENT_DIRECTORY/ANNOTATED";
using (Annotator annotator = new Annotator(sourceDocumentPath))
{
    // Your annotation removal magic happens here
}

專業提示: using 陳述式會自動釋放 Annotator 實例,關閉檔案句柄,避免在大量檔案迴圈處理時產生記憶體洩漏。

如何使用 GroupDocs.Annotation 清除 PDF 中的所有批註?

SaveOptions 類別讓您自訂文件的儲存方式,包括保留或捨棄哪些批註類型。AnnotationType 為列舉,列出所有支援的批註類別,如 Highlight、Comment、Strikeout 等。

載入來源 PDF 後,將 SaveOptions.AnnotationTypes 設為 AnnotationType.None,再呼叫 annotator.Save(outputPath, saveOptions)。此單行指令會移除整個批註層,保留原始文字、影像與版面,並將清潔的 PDF 寫入指定位置,且不會修改來源檔案。

annotator.Save(resultFilePath, new SaveOptions { AnnotationTypes = AnnotationType.None });

主要步驟:逐步移除批註

理解問題

清除批註會產生一個 全新 PDF 版本,其中不再包含批註物件。此舉會產生以下可量化的效益:

  1. 檔案大小縮減 – 清理後通常減少 5‑15 % 的容量。
  2. 完整性保留 – 頁面順序、字型與影像保持完全不變。
  3. 中繼資料移除 – 所有與批註相關的中繼資料皆被剔除。
  4. 不影響原檔 – 原始檔案保持不變,對於稽核追蹤相當重要。

步驟 1:正確設定檔案路徑(正確做法)

正確的路徑處理可避免最常見的「找不到檔案」錯誤。Path.Combine 會產生跨平台的路徑字串,讓相同程式碼在 Windows、macOS 與 Linux 上皆可執行。

inputFilePath 變數保存帶批註的 PDF 位置,resultFilePath 則指向清潔 PDF 的輸出位置。

using System.IO;

string documentDirectory = "YOUR_DOCUMENT_DIRECTORY";
string outputDirectory = "YOUR_OUTPUT_DIRECTORY";

// Define paths for source and result documents
string annotatedPdfPath = Path.Combine(documentDirectory, "ANNOTATED");
string resultFilePath = Path.Combine(outputDirectory, "result.pdf");

為何使用 Path.Combine? 它會自動插入正確的目錄分隔符(\ 或 /),避免因雙分隔符導致的執行時例外。

步驟 2:載入文件

Annotator 類別是 GroupDocs.Annotation 的核心物件,負責解析 PDF 並公開其批註集合。

using GroupDocs.Annotation;
using GroupDocs.Annotation.Options;

using (Annotator annotator = new Annotator(annotatedPdfPath))
{
    // The next step happens here
}

背後運作原理: 當您實例化 Annotator 時,函式庫會串流檔案、在記憶體中建立每個批註的表示,並為後續修改做好準備。對於超過 100 MB 的 PDF,此步驟可能需要數秒鐘。

步驟 3:魔法一行(移除全部批註)

以下這行程式碼即可清除所有批註並寫入清潔檔案:

annotator.Save(resultFilePath, new SaveOptions() { AnnotationTypes = AnnotationType.None });
  • annotator.Save – 依目前狀態寫出新 PDF。
  • new SaveOptions() – 讓您調整儲存流程;預設設定已能滿足大多數情境。
  • AnnotationTypes = AnnotationType.None – 關鍵旗標,告訴引擎省略所有批註物件。

替代做法(僅移除特定類型)

若您想保留評論但捨棄標記,可使用位元 OR 組合欲排除的類型。

// Remove only highlights and text annotations, keep others
annotator.Save(resultFilePath, new SaveOptions() { 
    AnnotationTypes = AnnotationType.Highlight | AnnotationType.Text 
});

完整範例程式碼

以下方法示範了完整的端對端清理流程,您可以直接嵌入任何 .NET 主控台或 Web 專案中使用。

using System.IO;
using GroupDocs.Annotation;
using GroupDocs.Annotation.Options;

public void RemoveAllAnnotations()
{
    string documentDirectory = "YOUR_DOCUMENT_DIRECTORY";
    string outputDirectory = "YOUR_OUTPUT_DIRECTORY";
    
    string annotatedPdfPath = Path.Combine(documentDirectory, "ANNOTATED");
    string resultFilePath = Path.Combine(outputDirectory, "result.pdf");
    
    using (Annotator annotator = new Annotator(annotatedPdfPath))
    {
        annotator.Save(resultFilePath, new SaveOptions() { AnnotationTypes = AnnotationType.None });
    }
    
    Console.WriteLine($"Clean document saved to: {resultFilePath}");
}

疑難排解:當問題發生時

如何修復「找不到檔案」錯誤?

在建立 Annotator 前先驗證來源 PDF 是否存在,這樣可避免建構子拋出例外。

if (!File.Exists(annotatedPdfPath))
{
    throw new FileNotFoundException($"Source document not found: {annotatedPdfPath}");
}

如何處理「未找到批註」的結果?

先檢查批註計數。若文件確實沒有批註,清理步驟會產生與原檔相同的副本。

using (Annotator annotator = new Annotator(annotatedPdfPath))
{
    var annotations = annotator.Get();
    Console.WriteLine($"Found {annotations.Count} annotations");
    
    if (annotations.Count == 0)
    {
        Console.WriteLine("No annotations to remove");
        return;
    }
    
    // Proceed with removal...
}

如何提升大型檔案的效能?

處理 150 頁、數百筆批註的 PDF 可能會佔用大量記憶體。可採用批次處理、提升應用程式記憶體上限,或以非同步方式執行。

// For multiple files, process asynchronously
public async Task ProcessMultipleFiles(string[] filePaths)
{
    var tasks = filePaths.Select(async filePath => 
    {
        await Task.Run(() => RemoveAnnotationsFromFile(filePath));
    });
    
    await Task.WhenAll(tasks);
}

真實情境應用

法律文件準備

律師事務所常收到帶有多筆審閱意見的合約。提交法院前,必須在保留法律條文與頁碼的前提下,將所有標記全部剔除。

專業提示: 先將原始帶批註的版本存檔以符合法規要求,清潔版才是提交用的最終文件。

學術出版

研究人員在稿件上會留下大量同行評審意見。期刊要求提交乾淨的手稿,您可以在投稿前自動移除高亮、評論與便利貼。

企業報告最終化

執行摘要會經歷多輪審閱。向利害關係人展示的最終 PDF 必須去除內部評論,以維持專業形象。

內容管理系統

若您建置文件入口網站,可提供「審閱模式」顯示批註,與「發布模式」隱藏批註。上述程式碼可即時產生乾淨副本,實現無縫切換。

進階技巧與最佳化

選擇性批註移除

有時只需要刪除特定類型的批註(例如高亮)。AnnotationTypes 屬性接受多個旗標的組合。

// Remove only highlights and strikethrough, keep comments
var saveOptions = new SaveOptions() 
{ 
    AnnotationTypes = AnnotationType.Highlight | AnnotationType.Strikeout 
};

annotator.Save(resultFilePath, saveOptions);

批次處理多個文件

當資料夾內有數十個帶批註的 PDF 時,可迴圈遍歷每個檔案,套用相同的清理邏輯,並記錄處理結果。

public void CleanAllDocumentsInFolder(string inputFolder, string outputFolder)
{
    var pdfFiles = Directory.GetFiles(inputFolder, "*.pdf");
    
    foreach (var file in pdfFiles)
    {
        var fileName = Path.GetFileName(file);
        var outputPath = Path.Combine(outputFolder, $"clean_{fileName}");
        
        using (var annotator = new Annotator(file))
        {
            annotator.Save(outputPath, new SaveOptions() { AnnotationTypes = AnnotationType.None });
        }
        
        Console.WriteLine($"Processed: {fileName}");
    }
}

大型文件的記憶體最佳化

對於超過 200 MB 的 PDF,請監控記憶體使用量,並在每個檔案處理完畢後呼叫 GC.Collect() 以釋放非受控資源。

public void ProcessLargeDocument(string inputPath, string outputPath)
{
    GC.Collect(); // Clean up before starting
    
    using (var annotator = new Annotator(inputPath))
    {
        var initialMemory = GC.GetTotalMemory(false);
        
        annotator.Save(outputPath, new SaveOptions() { AnnotationTypes = AnnotationType.None });
        
        var finalMemory = GC.GetTotalMemory(false);
        Console.WriteLine($"Memory used: {(finalMemory - initialMemory) / 1024 / 1024} MB");
    }
    
    GC.Collect(); // Clean up after processing
}

生產環境的最佳實踐

如何實作健全的錯誤處理?

捕捉特定例外、記錄詳細資訊,並在發生錯誤時繼續處理其他檔案,而非中斷整個批次。

try
{
    using (var annotator = new Annotator(inputPath))
    {
        annotator.Save(outputPath, new SaveOptions() { AnnotationTypes = AnnotationType.None });
    }
}
catch (FileNotFoundException ex)
{
    Console.WriteLine($"Input file not found: {ex.Message}");
    // Log the error, notify user, etc.
}
catch (UnauthorizedAccessException ex)
{
    Console.WriteLine($"Permission denied: {ex.Message}");
    // Handle permission issues
}
catch (Exception ex)
{
    Console.WriteLine($"Unexpected error: {ex.Message}");
    // Log full exception details
}

如何安全管理設定?

將檔案路徑、授權金鑰與其他設定存於 appsettings.json 或環境變數中,避免硬編碼於程式碼。

// In appsettings.json
{
    "DocumentSettings": {
        "InputDirectory": "C:\\Documents\\Input",
        "OutputDirectory": "C:\\Documents\\Output",
        "BackupOriginals": true
    }
}

// In your code
var config = Configuration.GetSection("DocumentSettings");
var inputDir = config["InputDirectory"];
var outputDir = config["OutputDirectory"];

如何加入日誌與監控?

整合 ILogger 或第三方監控服務(如 Serilog、Application Insights),以捕捉處理時間、成功率與記憶體消耗等指標。

public void RemoveAnnotationsWithLogging(string inputPath, string outputPath)
{
    var stopwatch = System.Diagnostics.Stopwatch.StartNew();
    
    try
    {
        using (var annotator = new Annotator(inputPath))
        {
            var annotationCount = annotator.Get().Count;
            Console.WriteLine($"Processing {inputPath} - Found {annotationCount} annotations");
            
            annotator.Save(outputPath, new SaveOptions() { AnnotationTypes = AnnotationType.None });
            
            stopwatch.Stop();
            Console.WriteLine($"Successfully processed in {stopwatch.ElapsedMilliseconds}ms");
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine($"Failed to process {inputPath}: {ex.Message}");
        throw;
    }
}

接下來該做什麼?

現在您已能可靠地 清除 PDF 批註,可以將工作流程延伸至:

  • 建置自動化文件審閱管線,將帶批註與清潔版本同時存檔。
  • 與 SharePoint 或其他 DMS 平台整合,強制執行清潔副本政策。
  • 開發 UI 工具,讓最終使用者在移除前先預覽批註。

兩行程式碼的簡易清理,加上 GroupDocs.Annotation 強大的格式支援,使此方案成為任何需要維持文件純淨的企業的理想選擇。

常見問與答

問:我可以移除除 PDF 之外的其他檔案類型的批註嗎?
答:可以。GroupDocs.Annotation 亦支援 Word、Excel、PowerPoint 與影像格式;只要更換輸入檔案副檔名,即可使用相同的 API 呼叫。

問:移除批註會改變原始版面嗎?
答:不會。函式庫僅移除批註層,文字、影像與頁面結構皆保持不變。

問:如何只刪除特定類型的批註?
答:將 AnnotationTypes 設為欲排除類型的位元組合,例如 AnnotationType.Highlight | AnnotationType.Strikeout。

問:此程序會修改來源 PDF 嗎?
答:不會。原始檔案永遠不會被覆寫,清潔的 PDF 會寫入您在 Save 中指定的路徑。

問:效能會隨文件大小如何變化?
答:對於最高 200 MB 的 PDF,清理通常在標準 2.5 GHz CPU 上於 5 秒內完成。更大的檔案建議使用批次處理與非同步執行以提升效能。

其他資源


最後更新: 2026-06-01
測試環境: GroupDocs.Annotation 25.4.0 for .NET
作者: GroupDocs

相關教學