是否可以修改 PDF 表单字段名称?

发布于 2024-08-23 06:40:37 字数 278 浏览 10 评论 0原文

情况是这样的。我有一个 PDF,其中包含自动生成的 pdf 表单字段名称。问题是这些名称不太用户友好。它们看起来像: topmostSubform[0].Page1[0].Website_Address[0]

我希望能够更改它们,使它们类似于 WebsiteAddress。我可以访问 ABCPDF 并且有使用 iTextSharp 的经验,但我尝试使用这些 API 来执行此操作(访问表单字段并尝试重命名),但似乎不可能。

有没有人有尝试通过某种 API(最好是开源的)来做到这一点的经验。代码也是.Net。

Here's the situation. I have a PDF with automatically generated pdf form field names. The problem is that these names are not very user friendly. They look something like :
topmostSubform[0].Page1[0].Website_Address[0]

I want to be able to change them so that they are something like WebsiteAddress. I have access to ABCPDF and I have experience with iTextSharp, but I have tried using these API's to do this (access form fields and try to rename), but it does not seem as if it is possible.

Does anybody have any experience trying to do this via an API of some sort (preferably open source). Code is .Net also.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

凉宸 2024-08-30 06:40:37

好消息:您可以在 iTextSharp 中更改字段名称。

但您实际上无法编辑 PDF。您将读取现有的 PDF,更新内存中的字段名称,然后写出修改后的 PDF。要更改字段名称,请调用 AcroFields.RenameField 方法。

下面是一个片段:

PdfReader reader = new PdfReader(PDF_PATH);
using (FileStream fs = new FileStream("Test Out.pdf", FileMode.Create)) {
    PdfStamper stamper = new PdfStamper(reader, fs);
    AcroFields fields = stamper.AcroFields;
    fields.RenameField("oldFieldName", "newFieldName");
    stamper.Close();
}

现在有坏消息:您可以在重命名的字段中使用的字符似乎受到限制。

我用您的示例字段名称测试了上面的代码片段,但它不起作用。不过去掉句号,它确实有效。我不确定是否有解决方法,但这对您来说可能是个问题,

The good news: you can change field names in iTextSharp.

You can't actually edit a PDF though. You'd read in an existing PDF, update your field names in memory and then write out your revised PDF. To change a field name call the AcroFields.RenameField method.

Here's a snippet:

PdfReader reader = new PdfReader(PDF_PATH);
using (FileStream fs = new FileStream("Test Out.pdf", FileMode.Create)) {
    PdfStamper stamper = new PdfStamper(reader, fs);
    AcroFields fields = stamper.AcroFields;
    fields.RenameField("oldFieldName", "newFieldName");
    stamper.Close();
}

Now the bad news: there appear to be limitations in the characters you can use in the renamed fields.

I tested the snippet above with your example field name and it didn't work. Remove the periods though and it does work. I'm not sure if there's a workaround but this may be a problem for you,

余生一个溪 2024-08-30 06:40:37

AcroForm 字段的全名未显式存储在字段中。它实际上源自字段的层次结构,左侧显示有点分隔的祖先列表。

因此,简单地将字段从“topmostSubform[0].Page1[0].Website_Address[0]”重命名为“WebsiteAddress”不太可能产生正确的结果。

您会发现 PDF 参考的第 8.6.2 节“字段字典”很好地解释了字段命名的工作原理;-)

基本上,AcroForm 中的每个字段都是由字典定义的,字典可能包含与某个字段相关的某些可选条目。字段的名称。

  • 键“/T”指定部分名称。在您的问题中,“topmostSubform[0]”、“Page1[0]”和 Website_Address[0] 均代表部分名称。

  • 键“/TU”指定字段的替代“用户友好”名称,可用于代替实际字段名称来标识用户界面中的字段。

不要重命名有问题的字段,而是考虑添加 /TU 条目!

下面的示例使用 ABCpdf 迭代 AcroForm 中的所有字段,并根据字段的部分名称将备用名称插入到字段中。

VBScript:

Set theDoc = CreateObject("ABCpdf7.Doc")
theDoc.Read "myForm.pdf"

Dim theFieldIDs, theList
theFieldIDs = theDoc.GetInfo(theDoc.Root, "Field IDs")
theList = Split(theFieldIDs, ",")

For Each fieldID In theList
    thePartialName = theDoc.GetInfo(fieldID, "/T:text")
    theDoc.SetInfo fieldID, "/TU:text", thePartialName
Next

theDoc.Save "output.pdf"
theDoc.Clear

"/TU:text" 更改为 "/T:text" 将设置字段的部分名称。

使用 C# 和 VB.NET 编写的所用函数的示例可以在此处找到:
Doc.GetInfoDoc.SetInfo。另请参阅有关对象路径的文档。

The full name of an AcroForm field isn't explicitly stored within a field. It's actually derived from a hierarchy of fields, with a dot delimited list of ancestors appearing on the left.

Simply renaming a field from 'topmostSubform[0].Page1[0].Website_Address[0]' to 'WebsiteAddress' is therefore unlikely to produce a correct result.

You'll find section 8.6.2 'Field Dictionaries' of the PDF reference provides a good explanation of how field naming works ;-)

Basically, each field in an AcroForm is define by a dictionary, which may contain certain optional entries pertaining to a field's name.

  • Key '/T' specifies the partial name. In your question, 'topmostSubform[0]', 'Page1[0]', and Website_Address[0], all represent partial names.

  • Key '/TU' specifies an alternative 'user-friendly' name for fields, which can be used in place of the actual field name for identifying fields in a user interface.

Instead of renaming the field in question, think about adding a /TU entry!

The example below uses ABCpdf to iterate through all the fields in an AcroForm and insert an alternate name into a field based on its partial name.

VBScript:

Set theDoc = CreateObject("ABCpdf7.Doc")
theDoc.Read "myForm.pdf"

Dim theFieldIDs, theList
theFieldIDs = theDoc.GetInfo(theDoc.Root, "Field IDs")
theList = Split(theFieldIDs, ",")

For Each fieldID In theList
    thePartialName = theDoc.GetInfo(fieldID, "/T:text")
    theDoc.SetInfo fieldID, "/TU:text", thePartialName
Next

theDoc.Save "output.pdf"
theDoc.Clear

Changing "/TU:text" to "/T:text" will set a field's partial name.

Examples written in C# and VB.NET of the functions used can be found here:
Doc.GetInfo, Doc.SetInfo. See also the documentation on Object Paths.

执笏见 2024-08-30 06:40:37

我昨天遇到了这个问题,在尝试了论坛和其他人的答案后,但没有取得任何进展。我的代码看起来像这样。

// Open up the file and read the fields on it.
var pdfReader = new PdfReader(PATH_TO_PDF);
var fs = new FileStream(pdfFilename, FileMode.Create, FileAccess.ReadWrite)
var stamper = new PdfStamper(pdfReader, fs);
var pdfFields = stamper.AcroFields;

//I thought this next line of code I commented out will do it
//pdfFields.RenameField("currentFieldName", "newFieldName");

// It did for some fields, but returned false for others.
// Then I looked at the AcroFields.RenameField method in itextSharp source and noticed some restrictions. You may want to do the same.
//  So I replaced that line  pdfFields.RenameField(currentFieldName, newFieldName); with these 5 lines

AcroFields.Item item = pdfFields.Fields[currentFieldName];
PdfString ss = new PdfString(newFieldName, PdfObject.TEXT_UNICODE);
item.WriteToAll(PdfName.T, ss, AcroFields.Item.WRITE_VALUE | AcroFields.Item.WRITE_MERGED);
item.MarkUsed(pdfFields, AcroFields.Item.WRITE_VALUE);
pdfFields.Fields[newFieldName] = item;

这就完成了工作

I had the problem yesterday and after trying out answers in the forum and others but made no headway. My code looked like this.

// Open up the file and read the fields on it.
var pdfReader = new PdfReader(PATH_TO_PDF);
var fs = new FileStream(pdfFilename, FileMode.Create, FileAccess.ReadWrite)
var stamper = new PdfStamper(pdfReader, fs);
var pdfFields = stamper.AcroFields;

//I thought this next line of code I commented out will do it
//pdfFields.RenameField("currentFieldName", "newFieldName");

// It did for some fields, but returned false for others.
// Then I looked at the AcroFields.RenameField method in itextSharp source and noticed some restrictions. You may want to do the same.
//  So I replaced that line  pdfFields.RenameField(currentFieldName, newFieldName); with these 5 lines

AcroFields.Item item = pdfFields.Fields[currentFieldName];
PdfString ss = new PdfString(newFieldName, PdfObject.TEXT_UNICODE);
item.WriteToAll(PdfName.T, ss, AcroFields.Item.WRITE_VALUE | AcroFields.Item.WRITE_MERGED);
item.MarkUsed(pdfFields, AcroFields.Item.WRITE_VALUE);
pdfFields.Fields[newFieldName] = item;

And that did the job

话少情深 2024-08-30 06:40:37

也许您可以考虑这一点:

  • iText 不是免费的,在专有软件环境中(2.1.7 it/s 最后一个“免费”版本)。
  • AbcPDF 也不是免费的。

我不得不说,我们有 AbcPDF 许可证,并且我们在 Java 项目中也使用 iText 2.1.7...所以我可以说我同意以前的答案,但是,如果您不能使用/购买此产品,您可以尝试将名称替换为纯 pdf 代码(作为纯 txt 文件),遵循 PDF 规范:

签名字段示例:

35 0 obj
<<
/AP <<
/N 37 0 R
>>
/DA (/TimesRoman 0 Tf 0 g)
/F 4
/FT /Sig
/P 29 0 R
/Rect [ 86 426 266 501 ]
/Subtype /Widget
/T (FIELD_MODIF)
/Type /Annot
/V 36 0 R
>>
endobj

其中“FIELD_MODIF”是放置新名称的位置。

Maybe you can consider this:

  • iText is not free, in a propietary software enviroment (2.1.7 it/s last 'free' version).
  • AbcPDF is not free too.

I have to say that we have AbcPDF license, and we use iText 2.1.7 too in our Java projects... so I can say I agree with previous answers, BUT, it you can't use/buy this products, you can try to replace the name into the pure pdf code (as a plain txt file), following PDF specification:

Example for a signature field:

35 0 obj
<<
/AP <<
/N 37 0 R
>>
/DA (/TimesRoman 0 Tf 0 g)
/F 4
/FT /Sig
/P 29 0 R
/Rect [ 86 426 266 501 ]
/Subtype /Widget
/T (FIELD_MODIF)
/Type /Annot
/V 36 0 R
>>
endobj

Where "FIELD_MODIF" it's the place where put the NEW name.

薄暮涼年 2024-08-30 06:40:37

尽管您无法使用 JavaScript 重命名字段,但您可以添加新字段和删除现有字段。您还可以在文档之间进行剪切和粘贴。所以...

一个。开发重命名脚本,例如:

    var doc = app.activeDocs[0];
    var fnames = new Array();
    for ( var i = 0; i < doc.numFields - 1; i++) {      
        fnames[i] = doc.getNthFieldName(i);
    }
    for (var i = 0; i < doc.numFields - 1; i++){        
        var f = doc.getField(fnames[i] + ".0");
        var nfn = fnames[i].replace("1","2");
        var rb = doc.addField(nfn,"radiobutton",0,f.rect)
        for ( var j = 1; j < 9; j++){//Add the other 8
            f = doc.getField(fnames[i] + "." + j);
            doc.addField(nfn,"radiobutton",0,f.rect)
        }
        rb.setExportValues([1,2,3,4,5,6,7,8,9]);
        rb.borderStyle = f.borderStyle;
        rb.strokeColor = f.strokeColor;
        rb.fillColor = f.fillColor;
        doc.removeField(fnames[i]);
        console.println(fnames[i] + " to " + nfn);
    }

注:
重命名字段可能会更改 getNthFieldName 的字段顺序,因此请先获取这些字段。
一组单选按钮是一个字段 (getField("Groupname")),要获取同一组中的第 n 个单选按钮,请使用 getField("Groupname.n"),您需要这些作为位置矩形。可以设置适用于所有人的属性。
addField参数为:字段名称、字段类型、页面、位置矩形)
在示例中,每组

Two 有 9 个单选按钮。将要重命名的字段剪切并粘贴到空白 pdf 中(我假设上面有一页)。运行脚本。剪切并粘贴回来。

如果运行脚本时保持两个文档都打开,您可能需要将 app.activeDocs[0] 更改为 app.activeDocs[1] 或将“doc”替换为“this”

Although you can't rename fields using javascript you can add new fields and delete existing fields. You can also cut and paste between documents. So...

One. Develop renaming script, e.g.:

    var doc = app.activeDocs[0];
    var fnames = new Array();
    for ( var i = 0; i < doc.numFields - 1; i++) {      
        fnames[i] = doc.getNthFieldName(i);
    }
    for (var i = 0; i < doc.numFields - 1; i++){        
        var f = doc.getField(fnames[i] + ".0");
        var nfn = fnames[i].replace("1","2");
        var rb = doc.addField(nfn,"radiobutton",0,f.rect)
        for ( var j = 1; j < 9; j++){//Add the other 8
            f = doc.getField(fnames[i] + "." + j);
            doc.addField(nfn,"radiobutton",0,f.rect)
        }
        rb.setExportValues([1,2,3,4,5,6,7,8,9]);
        rb.borderStyle = f.borderStyle;
        rb.strokeColor = f.strokeColor;
        rb.fillColor = f.fillColor;
        doc.removeField(fnames[i]);
        console.println(fnames[i] + " to " + nfn);
    }

Notes:
Renaming fields may change order of fields for getNthFieldName, so get these first.
A group of radiobuttons is one field (getField("Groupname")), to get the n'th in the same group use getField("Groupname.n"), you need these for the position rectangle. Properties which apply to all can be set enmase.
addField parameters are: field name, field type, page, position rectangle)
In the example there are 9 radiobuttons in each group

Two. Cut and paste the fields you want to rename to a blank pdf (I've assumed one page above). Run the script. Cut and paste back.

You may need to change app.activeDocs[0] to app.activeDocs[1] or replace "doc" with "this" if keeping both documents open when running the script

思慕 2024-08-30 06:40:37

最好的方法是存储字段矩形,然后创建具有所需名称和存储矩形位置的新字段,新字段将与旧字段位于同一位置,ta da:)
这是代码:

Sub CreateNewField()
 Create = "var f = this.getField('" & oldFieldName & "'); var rect = f.rect; 
 this.addField('" & newFieldName & "','text',0,rect);"
 FormFields.ExecuteThisJavascript Create
 DeleteField 'sub to delete old field
End Sub

best way is to store fields rect and then create new field with desired name and stored rect position, new field will be on same position as old field, ta da :)
here is the code:

Sub CreateNewField()
 Create = "var f = this.getField('" & oldFieldName & "'); var rect = f.rect; 
 this.addField('" & newFieldName & "','text',0,rect);"
 FormFields.ExecuteThisJavascript Create
 DeleteField 'sub to delete old field
End Sub
俏︾媚 2024-08-30 06:40:37

是的,可以重命名表单字段。我对源代码 API 没有任何经验可以帮助您解决此问题,但我的公司 PDF SDK 可以帮助您做到这一点,经过一点搜索,发现 iText 确实可以让您重命名表单字段

Yes, it's possible to rename form fields. I don't have any experience with an source code API that will help you with this, but my companies PDF SDK can help you do this, and from a little bit of searching it appears that iText will indeed let you rename form fields.

女中豪杰 2024-08-30 06:40:37

这是书中找到的一个 java 示例,“iText in Action”,

它取自该书的示例源代码,对我解决同样的问题有很大帮助。 part2.chapter06.ConcatenateForms2

public static void main(String[] args)
    throws IOException, DocumentException {
    // Create a PdfCopyFields object
    PdfCopyFields copy
        = new PdfCopyFields(new FileOutputStream(RESULT));
    // add a document
    PdfReader reader1 = new PdfReader(renameFieldsIn(DATASHEET, 1));
    copy.addDocument(reader1);
    // add a document
    PdfReader reader2 = new PdfReader(renameFieldsIn(DATASHEET, 2));
    copy.addDocument(reader2);
    // Close the PdfCopyFields object
    copy.close();
    reader1.close();
    reader2.close();
}


private static byte[] renameFieldsIn(String datasheet, int i)
    throws IOException, DocumentException {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    // Create the stamper
    PdfStamper stamper = new PdfStamper(new PdfReader(datasheet), baos);
    // Get the fields
    AcroFields form = stamper.getAcroFields();
    // Loop over the fields
    Set<String> keys = new HashSet<String>(form.getFields().keySet());
    for (String key : keys) {
        // rename the fields
        form.renameField(key, String.format("%s_%d", key, i));
    }
    // close the stamper
    stamper.close();
    return baos.toByteArray();
}

Here is a java example found in the book, "iText in Action"

This is taken from their example source code for the book and helped me immensely with this same issue. part2.chapter06.ConcatenateForms2

public static void main(String[] args)
    throws IOException, DocumentException {
    // Create a PdfCopyFields object
    PdfCopyFields copy
        = new PdfCopyFields(new FileOutputStream(RESULT));
    // add a document
    PdfReader reader1 = new PdfReader(renameFieldsIn(DATASHEET, 1));
    copy.addDocument(reader1);
    // add a document
    PdfReader reader2 = new PdfReader(renameFieldsIn(DATASHEET, 2));
    copy.addDocument(reader2);
    // Close the PdfCopyFields object
    copy.close();
    reader1.close();
    reader2.close();
}


private static byte[] renameFieldsIn(String datasheet, int i)
    throws IOException, DocumentException {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    // Create the stamper
    PdfStamper stamper = new PdfStamper(new PdfReader(datasheet), baos);
    // Get the fields
    AcroFields form = stamper.getAcroFields();
    // Loop over the fields
    Set<String> keys = new HashSet<String>(form.getFields().keySet());
    for (String key : keys) {
        // rename the fields
        form.renameField(key, String.format("%s_%d", key, i));
    }
    // close the stamper
    stamper.close();
    return baos.toByteArray();
}
飞烟轻若梦 2024-08-30 06:40:37

这对我使用 iText 7 有用:

PdfReader reader = new PdfReader("Source.pdf");

using (FileStream fs = new FileStream("Dest.pdf", FileMode.Create))
{
    using (var pdfDoc = new PdfDocument(reader, new PdfWriter(fs)))
    {
        PdfAcroForm pdfForm = PdfAcroForm.GetAcroForm(pdfDoc, true);
        pdfDoc.GetWriter().SetCloseStream(true);
        
        var Fields = pdfForm.GetFormFields().Select(x => x.Key).ToArray();
        
        for (int i = 0; i < Fields.Length; i++)
        {
            pdfForm.RenameField(Fields[i], "new_" + Fields[i]);
        }                   
    }
}

This worked for me using iText 7:

PdfReader reader = new PdfReader("Source.pdf");

using (FileStream fs = new FileStream("Dest.pdf", FileMode.Create))
{
    using (var pdfDoc = new PdfDocument(reader, new PdfWriter(fs)))
    {
        PdfAcroForm pdfForm = PdfAcroForm.GetAcroForm(pdfDoc, true);
        pdfDoc.GetWriter().SetCloseStream(true);
        
        var Fields = pdfForm.GetFormFields().Select(x => x.Key).ToArray();
        
        for (int i = 0; i < Fields.Length; i++)
        {
            pdfForm.RenameField(Fields[i], "new_" + Fields[i]);
        }                   
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文