如何从 .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

许可证问题的处理

您可以先使用 免费试用,在投入生产后再切换到永久许可证。

基础设置(您的前 5 行代码)

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。

使用 Annotator 类加载源 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

相关教程