iTextSharp PdfCopy使只读字段可编辑

iTextSharp PdfCopy使只读字段可编辑,pdf,itextsharp,Pdf,Itextsharp,我正在编写一些使用iTextSharp连接PDF文件的代码。我遇到了一个问题,其中包含一些只读字段和一个可编辑字段(我相信它们是AcroFields)。在输出文件中,所有字段都是可编辑的 以下是我使用的代码(我已将其简化为仅阅读一份PDF): 关于如何保存字段属性有什么想法吗?看起来iText和Adobe Reader对表单字段结构的解释不同。例如,查看具有一个子项的父字段: (对象24从AcroForm字典字段数组中引用。对象130从页面字典注释数组中引用。) 因此,我们有两个名为PageD

我正在编写一些使用iTextSharp连接PDF文件的代码。我遇到了一个问题,其中包含一些只读字段和一个可编辑字段(我相信它们是AcroFields)。在输出文件中,所有字段都是可编辑的

以下是我使用的代码(我已将其简化为仅阅读一份PDF):


关于如何保存字段属性有什么想法吗?

看起来iText和Adobe Reader对表单字段结构的解释不同。例如,查看具有一个子项的父字段:

(对象24从AcroForm字典字段数组中引用。对象130从页面字典注释数组中引用。)

因此,我们有两个名为
PageDataCollection1[0].txtCity
的字段对象,对象24和130,小部件注释合并到后者中

iText使用其Ff
0
将终端字段对象(对象130)视为完全负责

另一方面,Adobe Reader使用其DA值而不是Ff值,认为终端字段对象(对象130)仅部分负责。相反,使用父级Ff
1
,这意味着只读

在复制文档页面的过程中,层次结构被展平,使不同的解释可见


特别地,我想说iText的行为在这里是正确的

Adobe Reader的行为可以通过规范中的以下部分来证明:

如果不同的字段字典是具有相同名称的共同祖先的后代,并且没有自己的部分字段名(T条目),则它们可能具有相同的完全限定字段名。这些字段字典是同一基础字段的不同表示形式;它们只应在指定其视觉外观的属性上有所不同。特别是,具有相同完全限定字段名的字段词典应具有相同的字段类型(FT)、值(V)和默认值(DV

(第12.7.3.2节字段名称)

可能Adobe Reader试图通过忽略没有部分字段名的子字段中的其他属性,强制同一字段的不同表示形式仅在指定其视觉外观的属性上有所不同

但是,由于字段没有不同的表示形式,因此这里不需要此度量


“这里对物体结构有另一种解释,”rhens建议道

没有两个字段同名:对象24是字段字典,对象130是小部件注释

IMO这种解释与PDF规范不符,尽管它可以解释Adobe Reader的行为

虽然表单字段的子数组实际上可能包含子字段或小部件,但在我看来,对象130必须被视为一个字段(其自身合并了小部件),而不是字段对象24的小部件

要检查某个kid dictionary对象是子字段还是仅仅是一个小部件,仅在kid中查找特定于小部件的条目是不够的:这些条目也可以位于一个子字段中,该子字段中合并了单个小部件。因此,必须检查kid中的字段特定条目

在本例中,子对象130确实具有字段特定的条目(首先是字段类型FT,但也具有字段标志Ff),因此,应将其视为子字段



P.>所有人都说过,Adobe确实可能认为这个物体只是一个小部件(如上所述,它将解释这种行为)。但是,如上所述,这种解释不会受到规范的启发。但它可能是受到了大量来自野外的文档的启发,这些文档错误地在它们的普通窗口小部件中添加了特定于字段的条目,并要求按照设计显示这种解释。

感谢您的详细分析!是否有可能告诉iText更喜欢/Ff的父级值?或者,也许有一种方法可以检查此值并逐个字段手动设置。或者我应该尝试另一个PDF库吗?是否有可能告诉iText更喜欢/Ff的父级值据我所知:否。-或者也许有一种方法可以检查此值并逐个字段手动设置。-由于iText也允许您在较低级别上操作PDF,所以这没有问题。-还是我应该尝试另一个PDF库毕竟这取决于你。@mkl你的分析是正确的,但我确实认为本文是错误的。没有两个字段同名:对象24是字段字典,对象130是小部件注释。PDF规范未定义注释的Ff条目。它仅为字段字典定义。因此,Adobe Reader使用父对象的值是有道理的。我将编辑您的答案以反映这一点。规范的这一部分确认字段字典及其相关小部件注释不可能存在重叠条目。“为方便起见,当一个字段只有一个关联的小部件注释时,字段字典和注释字典的内容可以合并为一个字典,其中包含与字段和注释相关的条目。注意:这不会造成歧义,因为这两种字典的内容不一致。”“飞。”@rhens,没关系。针对我的具体情况,我创建了一个子类PdfReader,它为每个AcroField的注释选择父类的值,这就完成了。
public static void Concat(string outputFilePath, string inputFilePath)
{
    using (var document = new Document())
    {
        using (var fileStream = new FileStream(outputFilePath, FileMode.Create, FileAccess.ReadWrite))
        using (var copier = new PdfCopy(document, fileStream))
        {
            copier.SetMergeFields();
            document.Open();

            var reader = new PdfReader(inputFilePath);
            copier.AddDocument(reader);
            copier.AddJavaScript(reader.JavaScript);

            copier.Close();
        }
        document.Close();
    }
}