.net 是否可以修改 PDF 表单字段名称?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2343657/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Is it possible to modify PDF Form Field Names?
提问by ncyankee
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]
这是情况。我有一个带有自动生成的 pdf 表单字段名称的 PDF。问题是这些名称对用户不是很友好。它们看起来像: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.
我希望能够更改它们,使它们类似于网站地址。我可以访问 ABCPDF 并且我有使用 iTextSharp 的经验,但是我尝试使用这些 API 来执行此操作(访问表单字段并尝试重命名),但似乎不可能。
Does anybody have any experience trying to do this via an API of some sort (preferably open source). Code is .Net also.
有没有人有任何尝试通过某种 API(最好是开源)来做到这一点的经验。代码也是.Net。
回答by Jay Riggs
The good news: you can change field names in iTextSharp.
好消息:您可以在 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.
不过,您实际上无法编辑 PDF。您会读入现有的 PDF,更新内存中的字段名称,然后写出您修改后的 PDF。要更改字段名称,请调用 AcroFields.RenameField 方法。
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,
我使用您的示例字段名称测试了上面的代码段,但它不起作用。去掉句号,它确实有效。我不确定是否有解决方法,但这对您来说可能是个问题,
回答by Alberto Rossini
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.
AcroForm 字段的全名未明确存储在字段中。它实际上是从一个字段层次结构中派生出来的,左边出现一个点分隔的祖先列表。
Simply renaming a field from 'topmostSubform[0].Page1[0].Website_Address[0]' to 'WebsiteAddress' is therefore unlikely to produce a correct result.
因此,简单地将字段从 'topmostSubform[0].Page1[0].Website_Address[0]' 重命名为 'WebsiteAddress' 不太可能产生正确的结果。
You'll find section 8.6.2 'Field Dictionaries' of the PDF reference provides a good explanation of how field naming works ;-)
您会发现 PDF 参考的第 8.6.2 节“字段词典”很好地解释了字段命名的工作原理;-)
Basically, each field in an AcroForm is define by a dictionary, which may contain certain optional entries pertaining to a field's name.
基本上,AcroForm 中的每个字段都由字典定义,其中可能包含与字段名称相关的某些可选条目。
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.
键“/T”指定部分名称。在您的问题中,“topmostSubform[0]”、“Page1[0]”和 Website_Address[0] 都代表部分名称。
键“/TU”为字段指定了一个替代的“用户友好”名称,它可以代替实际的字段名称来标识用户界面中的字段。
Instead of renaming the field in question, think about adding a /TU entry!
与其重命名有问题的字段,不如考虑添加一个 /TU 条目!
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.
下面的示例使用 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
Changing "/TU:text"to "/T:text"will set a field's partial name.
更改"/TU:text"为"/T:text"将设置字段的部分名称。
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.
可以在此处找到使用 C# 和 VB.NET 编写的函数示例: Doc.GetInfo、Doc.SetInfo。另请参阅有关对象路径的文档。
回答by Sola Oderinde
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
这完成了工作
回答by Caveman
Maybe you can consider this:
也许你可以考虑这个:
- iText is not free, in a propietarysoftware enviroment (2.1.7 it/s last 'free' version).
- AbcPDF is not free too.
- iText 在专有软件环境中不是免费的(2.1.7 it/s 最后一个“免费”版本)。
- AbcPDF 也不是免费的。
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:
我不得不说我们有 AbcPDF 许可证,我们在我们的 Java 项目中也使用 iText 2.1.7 ......所以我可以说我同意以前的答案,但是,你不能使用/购买这个产品,你可以尝试将名称替换为纯 pdf 代码(作为纯 txt 文件),遵循 PDF 规范:
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.
“FIELD_MODIF”是放置新名称的地方。
回答by Gordon Smith
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...
尽管您无法使用 javascript 重命名字段,但您可以添加新字段并删除现有字段。您还可以在文档之间剪切和粘贴。所以...
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
注意:
重命名字段可能会更改 getNthFieldName 的字段顺序,因此请先获取这些。
一组单选按钮是一个字段 (getField("Groupname")),要获取同一组中的第 n 个使用 getField("Groupname.n"),您需要这些作为位置矩形。适用于所有的属性可以设置为 enmase。
addField 参数有:字段名称、字段类型、页面、位置矩形)
示例中每组有9个单选按钮
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.
二。将要重命名的字段剪切并粘贴到空白 pdf(我假设上面有一页)。运行脚本。剪切并粘贴回去。
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
如果在运行脚本时保持两个文档都打开,您可能需要将 app.activeDocs[0] 更改为 app.activeDocs[1] 或将“doc”替换为“this”
回答by Ervin Bodvai
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:
最好的方法是存储 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
回答by Rowan
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 helpyou do this, and from a little bit of searching it appears that iText will indeed let you rename form fields.
是的,可以重命名表单字段。我没有任何可以帮助您解决此问题的源代码 API 的经验,但我公司的PDF SDK 可以帮助您做到这一点,并且从一点点搜索来看,iText 确实可以让您重命名表单字段。
回答by DerekE
Here is a java example found in the book, "iText in Action"
这是在“iText in Action”一书中找到的一个java示例
This is taken from their example source code for the book and helped me immensely with this same issue. part2.chapter06.ConcatenateForms2
这是从他们的示例源代码中获取的,这对我解决同样的问题有很大帮助。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();
}

