Warm tip: This article is reproduced from serverfault.com, please click

c#-如何更改在Adobe Acrobat中创建的修订注释的修订文本

(c# - How to change redaction text of a redact annotation created in Adobe Acrobat)

发布于 2020-12-21 19:36:10

更新:2021-01-15-增加了赏金

我正在尝试更改修订注释,以更改应用修订时被刻录为PDF的基础文本。在Acrobat中,你可以设置“编辑代码”的集合,这些代码可用于标识为什么将某些内容标记为已编辑。我的目标是使用系统定义的值覆盖用户选择的内容。该代码将在应用修订之前运行。

在我的尝试中,我发现Acrobat产品中的“预览”在将光标悬停在编辑框上时是Acrobat独有的,大多数其他查看器都不会显示预览。似乎还与应用的实际修订分开维护了预览。我不需要更改预览中显示的文本,只需更改应用修订后显示的内容即可。

我增加了150个声誉的赏金,因为我认为我自己无法制定解决方案。我最初的问题指定了iText7,因为那是使我自己尝试中最接近的库。尽管我更喜欢使用iText7,但我还将考虑使用我可以合理访问的其他库的解决方案(如果需要的话,我确实可以用很小的预算购买另一个库)。

我保留了最初的问题以及后续的后续操作。感谢你提供的任何帮助。

如果你需要一个示例进行测试,则此DropBox文件夹中有一个名为的文件01 - Original.pdf,你可以将其用作源文档。期望的结果是能够将应用“原始编辑文本”中的删节时出现的文本更改为任何其他值,例如“新文本”。

原始问题:

我正在尝试使用来更改PDF中每个修订注释中包含的文本iText7PdfRedactAnnotation对象有一个称为的方法SetOverlayText(),看起来它应该可以执行我想要的操作。因此,我写了一个方法,可以打开PDF,循环浏览页面,然后循环浏览每个页面上的注释,并检查注释是否为PdfRedactAnnotation如果是,它将调用SetOverlayText()

调试并查看批注属性时,我可以看到OverlayText肯定已更改。但是,当我打开文件并通过将游标悬停在修订标记上来检查覆盖文本时,原始覆盖文本仍然存在。

在此处输入图片说明

另外,如果我应用修订,原始的覆盖文本就是被刻录到页面中的内容。

但是,当我右键单击注释(在应用修订之前)时,覆盖文本立即被更新为新文本:

在此处输入图片说明

至此,当我应用修订时,是将新文本刻录到PDF中。

有什么方法可以以编程方式触发“修订注释”更新,而无需打开并右键单击每个更新?我在下面包含了我的代码。感谢你提供任何可能提供的建议。

PdfDocument pdfDoc = new PdfDocument(new PdfReader(@"C:\temp\Test - Original.pdf"), new PdfWriter(@"C:\temp\Test - Output.pdf"));
Document doc = new Document(pdfDoc);
int pageCount = pdfDoc.GetNumberOfPages();
for (int i = 1; i <= pageCount; i++)
{
    var annotations = pdfDoc.GetPage(i).GetAnnotations();
    foreach(var annotation in annotations)
    {
        if (annotation is PdfRedactAnnotation)
        {
            PdfRedactAnnotation redact = (PdfRedactAnnotation)annotation;
            redact.SetOverlayText(new PdfString("New Text"));
        }
    }
}
doc.Close();

更新:截至2021-01-07的调查结果

正如@mkl的答案所指出的那样,PDF编辑注释规范阐明了基础编辑注释DOM条目。OverlayText只是等式的一部分。如果使用OverlayText,则必须定义一个DA元素(DA是一个提供OverlayText格式信息的字符串)。最后,如果定义了RO,它将取代几乎所有其他独立的显示条目。

我的测试文档是使用Acrobat DC Pro制作的,方法是在Acrobat中手动添加修订。这样做会产生一个Redact批注,其中包含所有上述条目。此DropBox文件夹中可以找到我的测试文档的副本

(旁注:在我最初的问题中,我提到将鼠标悬停在编辑区的红色矩形上,以预览应用的编辑区的外观...在多个浏览器和其他PDF查看器(如Foxit Reader)中进行测试后,它看起来像“预览”仅在Acrobat产品中支持通过将鼠标悬停在红色轮廓上来应用时的外观外观,所有其他经过测试的查看器将仅显示红色边框,将光标悬停在红色边框上则没有任何反应。应用编辑功能后,只能在其他程序中查看上面显示的矩形。

额外的测试表明,悬停预览与编辑详细信息本身是分开维护的,Acrobat尝试使悬停详细信息与基础注释保持同步。最好在测试时忽略悬停预览,并在应用修订后参考结果。)

@mkl推荐删除RO条目以尝试让OverlayText优先的建议是一个好主意,但不幸的是它没有用。与我的原始结果没有显着差异。

探究了iText7的PdfRedactAnnotation之后,我发现以下方法都导致对Redact对象的RO条目的引用:

PdfRedactAnnotation redact = (PdfRedactAnnotation)annotation;
redact.GetRolloverAppearanceObject();
redact.GetRedactionRolloverAppearance();
redact.GetPdfObject().Get(PdfName.RO);
redact.GetAppearanceDictionary().Get(PdfName.R);

(通过检查相等性比较器,我确认它们实际上是完全相同的引用。作为引用类型,它们true在使用进行测试时都返回了==)。

在进一步的测试中,我得出的结论是,RO属性必须在内部存储相同OverlayText的副本。如果你有两个具有不同原始值的修订,则可以将RO元素从一个修订“复制”到另一个:

PdfObject ro = firstRedact.GetPdfObject().Get(PdfName.RO);
secondRedact.GetPdfObject().Put(PdfName.RO, ro);

如果执行此操作并应用编辑,则第一个编辑中的“覆盖文本”将替换第二个中的“覆盖文本”。其他RO元素值也将被复制(例如BBox,它定义了黑色矩形的尺寸)...但是至少可以调整这些元素。

问题仍然是RO的iText7 PdfObject具有7个子元素,并且它们中的任何一个或它们的后代元素似乎都没有暴露我要更改的文本。

我的最终测试是是否可以将RO元素从一个PDF复制到另一个PDF(以便可以使用带有已配置所需RO“重叠文本”的注释的第二个源PDF),但是看起来间接对象不喜欢.Put()放入其他文档中。

因此,现在,我只能尝试找到一种方法来访问/更改存储在RO中的文本,或者从另一个文档中克隆一个预配置的RO。

Questioner
Chronicide
Viewed
0
mkl 2021-01-18 02:59:13

规格说明了什么?

编辑注释OverlayText条目指定为

钥匙 类型 价值
叠加文字 文字字串 (可选)文本字符串,指定在删除受影响的内容之后应在编辑区域上绘制的覆盖文本。如果存在RO条目,则将忽略此条目。

(ISO 32000-2,表195-特定于修订注释的附加条目)

也许在源PDF中,修订注释具有RO优先权。

此外,该表还说明了有关DA条目的信息:

钥匙 类型 价值
DA 字节串 (如果存在OverlayText,则为必需,否则被忽略)在删除受影响的内容后绘制覆盖文本时,用于格式化覆盖文本的外观字符串(请参见12.7.4.3,“可变文本”)。如果存在RO条目,则将忽略此条目。

因此,如果使用OverlayText,则还必须确保已设置DA默认外观字符串。你是否?


在同一表中RO条目指定为

钥匙 类型 价值
反渗透 溪流 (可选)一个XObject表单,它指定此修订注释的覆盖外观。应用此修订并删除了受影响的内容之后,应绘制覆盖外观,以使其原点与注释矩形的左下角对齐。此XObject形式不一定与其他注释外观相关,并且可以或可以不存在于AP词典中。该条目优先于ICOverlayTextDAQ条目。

那么现在该怎么办?

根据上面发布的详细信息,一个显而易见的选择是为更改后的修订注释创建一个修订覆盖XObject(RO)。你可以通过替换你的

if (annotation is PdfRedactAnnotation)
{
    PdfRedactAnnotation redact = (PdfRedactAnnotation)annotation;
    redact.SetOverlayText(new PdfString("New Text"));
}

经过

if (annotation is PdfRedactAnnotation)
{
    PdfRedactAnnotation redact = (PdfRedactAnnotation)annotation;
    redact.SetOverlayText(new PdfString("New Text"));
    Rectangle rectangle = redact.GetRectangle().ToRectangle();
    PdfStream stream = redact.GetRedactRolloverAppearance();
    if (stream != null)
    {
        rectangle = stream.GetAsArray(PdfName.BBox).ToRectangle();
    }
    PdfFormXObject redactionOverlay = new PdfFormXObject(rectangle);
    redactionOverlay.GetPdfObject().Put(PdfName.Matrix, new PdfArray(new double[] { 1, 0, 0, 1, -rectangle.GetX(), -rectangle.GetY() }));
    using (Canvas canvas = new Canvas(redactionOverlay, pdfDocument))
    {
        PdfCanvas pdfCanvas = canvas.GetPdfCanvas();
        pdfCanvas.SetFillColorGray(0);
        pdfCanvas.Rectangle(rectangle);
        pdfCanvas.Fill();
        pdfCanvas.SetFillColorGray(1);
        canvas.Add(new Paragraph("New Text"));
    }

    stream = redactionOverlay.GetPdfObject();
    redact.SetRolloverAppearance(stream);
    redact.SetDownAppearance(stream);
    redact.SetRedactRolloverAppearance(stream);
}

在Acrobat中编辑后的结果:

截屏

通过调整使用的填充色段落样式,可以使外观与Adobe Acrobat生成的外观更加接近(或者可以完全根据自己的设计生成外观)。

当心,我只有一个相当旧的Adobe Acrobat版本v9.5,因此,当前版本可能不接受上述生成的修订外观,或至少以不同的方式应用它。