当前位置: 首页 > 知识库问答 >
问题:

PDF AcroForm字段首先在Acrobat中修改,然后在iText7中修改后变为空白

淳于飞文
2023-03-14
@Override
public void draw(DrawContext drawContext) {
    super.draw(drawContext);

    PdfAcroForm form = PdfAcroForm.getAcroForm(drawContext.getDocument(), true);
    PdfFormField field = isMultiline
            ?   PdfFormField.createMultilineText(drawContext.getDocument(), getOccupiedAreaBBox(), fieldName, "")
            :   PdfFormField.createText(drawContext.getDocument(), getOccupiedAreaBBox(), fieldName, "");
    field.setFontSize(defaultFontSize - 1);
    form.addField(field);
}

我的一个要求是允许以编程方式扁平化表单(显然是在人类用户填写了表单之后),这样编辑就会在之后被禁用。

PdfDocument pdf = ... // Read a PDF stream and get the document object
PdfAcroForm form = PdfAcroForm.getAcroForm(pdf, false);
form.flattenFields();
pdf.close()

----------编辑------------

这个问题显然是由Adobe Reader引起的:由于某种原因,它在保存字段定义时没有/XObject子类型,iText7在Form.FlattenFields()方法中检查该子类型。
这就是Eclipse调试器中字段字符串的样子:

由IText7生成:<>>/subtype/form/type/xobject>>

由Acrobat Reader保存:<>>>>>>

  if(xObject != null && xObject.getPdfObject().get(PdfName.Subtype) != null) {
    [...]
    canvas.addXObject(xObject, ...);
  }
Map<String,PdfFormField> fields = form.getFormFields();
Set<String> keys = new HashSet<>(fields.keySet());      // avoids concurrent modifications

for(String fieldName : keys) {
    PdfFormField field = fields.get(fieldName);
    PdfDictionary fieldObject = field.getPdfObject();

    PdfFormField newField = field.isMultiline() 
            ? PdfFormField.createMultilineText(pdf, fieldObject.getAsRectangle(PdfName.Rect), fieldName, 
                    field.getValueAsString(), defaultFont, defaultFontSize)
            : PdfFormField.createText(pdf, fieldObject.getAsRectangle(PdfName.Rect), fieldName, 
                    field.getValueAsString(), defaultFont, defaultFontSize);

    form.replaceField(fieldName, newField);
}

form.flattenFields();

虽然字体信息不是动态设置的,但这是另一回事。

共有1个答案

陶宜民
2023-03-14

所以最后我用iText Rups打开了PDF。看起来Acrobat Reader确实设置了子类型,但它是/widget。我找到的最后一个解决办法是手动将子类型设置为/XObject,然后调用form.flatten()。这也保留了字段上的字体信息。

请注意,手动更改子类型可能会破坏其他内容。我不是一个PDF专家,所以我不能确定。然而,现在我只是改变了子类型和扁平化的权利,所以这应该不是一个大问题。

这段代码的最终版本如下所示:

for(String fieldName : keys) {
    PdfFormField field = fields.get(fieldName);
    PdfDictionary fieldObject = field.getPdfObject();

    if(fieldObject.get(PdfName.Subtype) != PdfName.XObject) {
        fieldObject.put(PdfName.Subtype, PdfName.XObject);
    }
}

form.flattenFields();
pdf.close();
 类似资料:
  • 本文向大家介绍MATLAB输入字符串,在C中进行修改,然后输出,包括了MATLAB输入字符串,在C中进行修改,然后输出的使用技巧和注意事项,需要的朋友参考一下 示例 在此示例中,我们说明了MATLAB MEX中的字符串操作。我们将创建一个MEX函数,该函数接受来自MATLAB的字符串作为输入,将数据复制到C字符串中,对其进行修改,然后将其转换回mxArrayMATLAB端。 此示例的主要目的是说明

  • 我有一个片段,它添加了一个选项到选项菜单。当单击此选项时,将打开一个对话框片段。对话框将原始片段设置为其目标片段。如果在对话片段打开时没有发生方向变化,则目标片段与预期的一样,但是在方向变化之后,目标片段被设置为对话片段本身,而不是先前设置的片段。结果,当试图将目标片段强制转换为被设置为目标片段的片段时,我得到了一个classCastException。我需要在对话框中获取目标片段,因为它实现了一

  • 通过此功能可以设置网站后台的访问路径 这里填写你需要设置的后台访问域名,例如:admin.domain.com 在该域名解析到您的网站服务器后,只能通过该域名登陆 配置保存在/caches/configs/system.php中,修改参数admin_url可手动取消绑定

  • 问题内容: 让我们从一个简单的测试用例开始: 任何人都在乎猜测什么将作为输出打印(在底部显示,以免立即破坏惊喜)。 问题是: 为什么原始和包装的整数表现不同? 为什么反射访问与直接访问返回不同的结果? 最困扰我的人-为什么String表现得像原始的而不是像? 结果(java 1.5): 问题答案: 内联编译时常量(在javac编译时)。参见JLS,尤其是15.28定义了常量表达式,而13.4.9讨

  • 在vue3中, 如果我按上面的写法,将currentOptional赋值到了myOptionalList中后, 清空currentOptional,发现myOptionalList也会被清空 我知道这是引用传递的问题,解决方法是进行深拷贝, 但是我有点疑惑,我记得vue2中好像不存在这种问题啊, 是我记错了吗

  • 我使用空手道进行自动化测试,并利用Gitlab CI/CD管道在不同的管道中运行。是否可以在gitlab控制台中编辑输出? 现在,当空手道测试在管道中运行时,输出是典型的maven下载依赖项。 我希望输出显示空手道测试场景,并显示通过/失败测试的绿色/红色。