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

时间:2010-02-26 17:52:36

标签: .net pdf itextsharp abcpdf

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

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

是否有人尝试通过某种API(最好是开源)尝试这样做。代码也是.Net。

9 个答案:

答案 0 :(得分:10)

好消息:您可以在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();
}

现在是坏消息:您可以在重命名的字段中使用的字符存在限制。

我使用您的示例字段名称测试了上面的代码段,但它无效。删除期间虽然它确实有效。我不确定是否有解决方法,但这对您来说可能是一个问题,

答案 1 :(得分:6)

AcroForm字段的全名未明确存储在字段中。它实际上是从一个字段层次结构派生出来的,左边是一个以点分隔的祖先列表。

只需将'topmostSubform [0] .Page1 [0] .Website_Address [0]'中的字段重命名为'WebsiteAddress'就不太可能产生正确的结果。

你会发现PDF参考的第8.6.2节“字段字典”提供了字段命名如何工作的一个很好的解释; - )

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

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

  • Key'/ 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。另请参阅Object Paths上的文档。

答案 2 :(得分:6)

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

// 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;

这就完成了工作

答案 3 :(得分:3)

也许你可以考虑这个:

  • iText不是免费的,在 propietary 软件环境中(2.1.7 it / s last'free'版本)。
  • 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”在哪里放置新名称。

答案 4 :(得分:2)

虽然您无法使用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的字段顺序,因此请先获取这些字段 一组radiobuttons是一个字段(getField(“Groupname”)),要获得同一组中的n'使用getField(“Groupname.n”),您需要这些用于位置矩形。适用于所有人的属性可以设置为enmase addField参数有:字段名称,字段类型,页面,位置矩形)
在该示例中,每组中有9个radiobutton

<强>两个即可。将要重命名的字段剪切并粘贴到空白pdf(我假设上面有一页)。运行脚本。剪切并粘贴。

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

答案 5 :(得分:1)

最好的方法是存储字段rect然后创建具有所需名称和存储的rect位置的新字段,新字段将与旧字段位于相同位置,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

答案 6 :(得分:0)

是的,可以重命名表单字段。我没有任何使用源代码API的经验可以帮助您解决这个问题,但是我的公司PDF SDK can help您这样做,并且从一点点搜索看来iText will indeed let you rename form fields

答案 7 :(得分:0)

以下是本书中的“iText in Action”

中的java示例

这是从他们的书的示例源代码中获取的,并且极大地帮助了我同样的问题。 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();
}

答案 8 :(得分:0)

这对我使用 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]);
        }                   
    }
}