English 中文(简体)
Is it possible to modify PDF Form Field Names?
原标题:

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.

最佳回答

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,

问题回答

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.

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

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.

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

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

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.

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();
}

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]);
        }                   
    }
}




相关问题
Manually implementing high performance algorithms in .NET

As a learning experience I recently tried implementing Quicksort with 3 way partitioning in C#. Apart from needing to add an extra range check on the left/right variables before the recursive call, ...

Anyone feel like passing it forward?

I m the only developer in my company, and am getting along well as an autodidact, but I know I m missing out on the education one gets from working with and having code reviewed by more senior devs. ...

How do I compare two decimals to 10 decimal places?

I m using decimal type (.net), and I want to see if two numbers are equal. But I only want to be accurate to 10 decimal places. For example take these three numbers. I want them all to be equal. 0....

Exception practices when creating a SynchronizationContext?

I m creating an STA version of the SynchronizationContext for use in Windows Workflow 4.0. I m wondering what to do about exceptions when Post-ing callbacks. The SynchronizationContext can be used ...

Show running instance in single instance application

I am building an application with C#. I managed to turn this into a single instance application by checking if the same process is already running. Process[] pname = Process.GetProcessesByName("...

How to combine DataTrigger and EventTrigger?

NOTE I have asked the related question (with an accepted answer): How to combine DataTrigger and Trigger? I think I need to combine an EventTrigger and a DataTrigger to achieve what I m after: when ...

热门标签