java - 如何仅重命名pdf中第一个找到的重复acrofield?

标签 java pdf itext

在我的 PDF 中,我有一个名为 Text1 的重复字段。现在我想将第一个找到的名为 Text1 的 acrofield 重命名为 foobar。名称为 Text1 的另一个字段应保持不变,以便我的新表单包含字段 Text1 和 foobar。

我正在使用 itext 库,并且有重命名函数,但此方法会将名称为 Text1 的所有字段重命名为 foobar。

如果有人想用我的pdf来测试它,here is a link .

public class RenameField
{
    public static final String SRC = "c:\\test_duplicate_field2.pdf";
    public static final String DEST = "c:\\test_duplicate_field_mod.pdf";

    public static void main(String[] args)
        throws DocumentException, IOException
    {
        File file = new File(DEST);
        file.getParentFile().mkdirs();
        new RenameField().manipulatePdf(SRC, DEST);
    }

    public void manipulatePdf(String src, String dest)
        throws DocumentException, IOException
    {
        PdfReader reader = new PdfReader(src);
        PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(dest));
        AcroFields form = stamper.getAcroFields();
        form.renameField("Text1", "foobar");
        stamper.close();
        reader.close();
        reader = new PdfReader(dest);
        form = reader.getAcroFields();
        Map<String, AcroFields.Item> fields = form.getFields();
        for (String name : fields.keySet()) {
            System.out.println(name);
        }
    }
}

另一种方法是迭代 AcroField.Items。如果某个项目有多个值字典(在这种情况下该字段存在多次),则更改将完成。

for (Map.Entry<String, AcroFields.Item> entry: fieldMap.entrySet())
{
    // extract Values for Field
    String fieldKey = entry.getKey();

    AcroFields.Item item = entry.getValue();
    PdfDictionary dict;

    int numberOfDuplicates = item.values.size();

    if (numberOfDuplicates > 1) {
        for (int i = 0; i < numberOfDuplicates; i++) {
            if (i == 0) {
                log.info("first field wont be changed");
            } else {
                log.info("renaming field " + fieldKey + " round " + i );
                item.getMerged(i).put(PdfName.T, new PdfString(fieldKey + "_" + i ));
                item.getValue(i).put(PdfName.T, new PdfString(fieldKey + "_" + i));                     
                form.regenerateField(fieldKey); 
            }
        }
    }
}

但这会导致与上面使用 itext 中的 renameField 函数的方法产生相同的结果,两个字段名称都会更改。在调试过程中,我可以看到该项目的两个值字典具有相同的对象 ID,因此当我更改字典 [0] 的值时,字典 [1] 中的值也会更改

enter image description here

最佳答案

On my PDF I have a duplicate field named Text1

正如布鲁诺已经在评论中解释的那样,这是错误的。您的 PDF 只有一个名为“Text1”的字段:

34 0 obj
<</DA(/Helv 12 Tf 0 g)/FT/Tx/Kids[28 0 R 29 0 R]/T(Text1)>>
endobj

这个字段有两个子字段

28 0 obj
<</F 4/MK<<>>/P 3 0 R/Parent 34 0 R/Rect[70.305 698.209 220.305 720.209]/Subtype/Widget/Type/Annot>>
endobj
29 0 obj
<</DA(/Helv 12 Tf 0 g)/F 4/MK<<>>/P 3 0 R/Parent 34 0 R/Rect[240.02 697.453 390.02 719.453]/Subtype/Widget/Type/Annot>>
endobj 

这些 child 只是小部件注释,它们本身并不是字段。

因此,您的请求

sample code how to rename one of the two widgets annotations instead of the field

没有意义:没有两个可以重命名的,因为只有字段被命名,并且只有一个字段。

您要做的就是创建一个名为“foobar”的新字段(复制原始字段的所有属性,除了KidsT),然后移动其中之一将 Text1 child 发送到 foobar。

针对您的用例的示例代码:

PdfReader reader = new PdfReader(resource);

PdfDictionary form = reader.getCatalog().getAsDict(PdfName.ACROFORM);
PdfArray fields = form.getAsArray(PdfName.FIELDS);
for (PdfObject object: fields)
{
    PdfDictionary field = (PdfDictionary) PdfReader.getPdfObject(object);
    if ("Text1".equals(field.getAsString(PdfName.T).toString()))
    {
        PdfDictionary newField = new PdfDictionary();
        PRIndirectReference newFieldRef = reader.addPdfObject(newField);
        fields.add(newFieldRef);
        newField.putAll(field);
        newField.put(PdfName.T, new PdfString("foobar"));
        PdfArray newKids = new PdfArray();
        newField.put(PdfName.KIDS, newKids);
        PdfArray kids = field.getAsArray(PdfName.KIDS);
        PdfObject widget = kids.remove(0);
        newKids.add(widget);
        PdfDictionary widgetDict = (PdfDictionary) PdfReader.getPdfObject(widget);
        widgetDict.put(PdfName.PARENT, newFieldRef);
        break;
    }
}

PdfStamper stamper = new PdfStamper(reader, result);
stamper.close();

( SameFieldTwice.java 方法 testWidgetToField)

显然,对于通用可用的解决方案,还有很多工作要做。

关于java - 如何仅重命名pdf中第一个找到的重复acrofield?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31402602/

相关文章:

javascript - Acrobat Javascript 保存和退出按钮

jackson - java.io.IOException : UT010029: Stream is closed

java - 如果我检查字符串的引用,有人可以帮助我,那么确切的答案是什么以及为什么?

java - 将宏图转换为 gwt

java - 无法在 Swagger 上查看根 API 端点

android - 从 Android 应用程序中读取 PDF

c# - Windows 通用应用程序 (UWP) 中的 HTML 到 PDF

java - 如何从操作类设置itext pdf文件名

asp.net - 奇数单元格未添加到 PDF

java - "postpone"任务真的那么难(或 "wait for idle")