【发布时间】:2016-10-19 20:06:41
【问题描述】:
我正在尝试创建一个包含字段的简单 pdf 多页文档。为此,我有一个模板 pdf,在代码中我根据需要多次克隆此模板以创建文档本身。
问题在于在其中插入一些数据。我尝试插入文档的数据类型不应该在页面之间改变。相反,它在所有页面中保持静态,就像表示此文档包含的页面数的“Pages”数字一样。
现在,在我的 pdf 模板中,我有一些文本字段,例如“Shipper1”和“Pages”。我希望能够将我的数据插入此文本字段,以便文档中的所有页面在其“Shipper1”和“Pages”字段中都有此值。
我的代码目前仅在第一页上执行此操作。它完美地显示了数据。另一方面,当我转到另一个页面时,那里没有显示数据。它只是显示一个空字段。
这是我启动 pdf 文档的代码:
static void initiatePdf() {
// Initiate a new PDF Box object and get the acro form from it
File file = new File(Constants.Paths.EMPTY_DOC)
PDDocument tempDoc
Evaluator evaluator = new Evaluator(metaHolder)
int numPages = evaluator.getNumOfPagesRequired(objects)
FieldRenamer renamer = new FieldRenamer()
PDResources res = new PDResources()
COSDictionary acroFormDict = new COSDictionary()
List<PDField> fields = []
Closure isFieldExist = {List<PDField> elements, String fieldName ->
elements.findAll{it.getFullyQualifiedName() == fieldName}.size() > 0
}
for(int i = 0; i < numPages; i++) {
tempDoc = new PDDocument().load(file)
PDDocumentCatalog docCatalog = tempDoc.getDocumentCatalog()
PDAcroForm acroForm = docCatalog.acroForm
PDPage page = (PDPage) docCatalog.getPages().get(0)
renamer.setCurrentForm(acroForm)
if(i == 0) {
res = acroForm.getDefaultResources()
acroFormDict.mergeInto(acroForm.getCOSObject())
renamer.renameFields(1)
} else
renamer.renameFields(i*10+1)
List<PDField> newFields = acroForm.fields.findAll { PDField newField ->
isFieldExist(fields, newField.getFullyQualifiedName()) == false
}
fields.addAll(newFields)
document.addPage(page)
}
PDAcroForm acroForm = new PDAcroForm(document, acroFormDict);
acroForm.setFields(fields)
acroForm.setDefaultResources(res);
document.documentCatalog.setAcroForm(acroForm)
}
首先有几件事:
metaHolderinstance 保存所有的信息
位于 acro 表单内的字段。信息是:字段名称、字段小部件宽度、字段字体和字体大小
evaluator 只是Evaluator 类的实例。其目的是分析动态数据并决定需要多少页才能包含所有文本数据。
这是我尝试用文本填充字段的地方:
static void populateData() {
def properties = ["$Constants.Fields.SHIPPER" : "David"]
FieldPopulater populater = new FieldPopulater(document, metaHolder)
populater.populateStaticFields(properties)
}
FieldPopulator 类:
package app.components
import app.StringUtils
import app.components.entities.DGObject
import app.components.entities.FieldMeta
import org.apache.pdfbox.pdmodel.PDDocument
import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm
import org.apache.pdfbox.pdmodel.interactive.form.PDField
/**
* Created by David on 18/10/2016.
*/
class FieldPopulater {
PDAcroForm acroForm
FormMetaHolder metaHolder
FieldPopulater(PDDocument document, FormMetaHolder metaHolder) {
this.acroForm = document.getDocumentCatalog().acroForm
this.metaHolder = metaHolder
}
void populateStaticFields(properties) {
List<PDField> fields = []
properties.each {fieldName, data ->
FieldMeta fieldMeta = metaHolder.getMetaData(fieldName)
fields = acroForm.fields.findAll { PDField field ->
String currentName = field.getFullyQualifiedName()
char lastChar = currentName[-1]
if(Character.isDigit(lastChar)) {
currentName = currentName.substring(0,currentName.size()-1)
}
currentName == fieldName
}
if(fields.size() > 1) {
int counter = 1
String tempData = data
String currentFitData
while(tempData.isEmpty() != true) {
int maxWords = Utils.getMaxWords(tempData, fieldMeta)
currentFitData = StringUtils.getTextByWords(tempData, maxWords)
tempData = StringUtils.chopTextByWords(tempData, maxWords)
PDField field = fields.find{it.getFullyQualifiedName()[-1] == "$counter"}
field?.setValue(currentFitData)
counter++
}
} else {
PDField tempField = fields[0]
tempField.setValue(data)
}
}
}
}
结果是,在第一页中,“Shipper”字段的值为“David” 在第二页中,“发货人”字段为空。
这是一张图片。第一页:
第二页:
这里有什么问题?
更新:我尝试将每个新的 acro 表单的小部件添加到当前页面,以便每个字段都有一些代表该字段的子小部件,但它仍然不起作用。
// All the widgets that are associated with the fields
List<PDAnnotationWidget> widgets = acroForm.fields.collect {PDField field -> field.getWidgets().get(0)}
page.annotations.addAll(widgets)
更新:我还尝试将字段的当前小部件添加到父字段的小部件集合中。代码如下:
List<PDAnnotationWidget> widgets = []
// All the widgets that are associated with the fields
acroForm.fields.each {PDField field ->
PDAnnotationWidget widget = field.widgets.get(0)
// Adding the following widget to the page and to the field's list of annotation widgets
widgets.add(widget)
fields.find {it.getFullyQualifiedName() == field.getFullyQualifiedName()}?.widgets.add(widget)
}
page.annotations.addAll(widgets)
【问题讨论】:
-
这里已经很晚了,所以只是一个快速提示:要在页面之间具有相同的值,您的字段需要有多个注释小部件,即每个页面上都有一个。该字段必须具有这些小部件作为孩子。每个页面都必须在其注释列表中包含此小部件。获取一些具有此类功能的现有表单文档(或使用 Adobe Acrobat 创建一个),并使用 PDFDebugger 进行查看。
-
我尝试按照您所说的进行操作,即将 acro 表单的小部件添加到页面,但问题仍然存在。我在帖子中添加了我编写的代码
-
不需要每个页面都有一个单独的小部件。 IE。该字段必须有两个孩子小部件。我给自己做了一个备忘录来扩展 acroform 示例。
-
好的,我完全按照您所说的进行了尝试,但问题是当我检查每个父字段具有的小部件数量时,在最后阶段,它等于 1。所以这意味着我没有添加孩子们的小部件正确地添加到父字段。我在帖子中添加了新代码
-
当一个字段需要多个小部件时,您需要使用
new PDAnnotationWidget()创建小部件。这些小部件必须添加到列表中,并且该列表必须分配给带有setWidgets()的字段。对于每个小部件,您必须调用setRectangle()和setPage()。
标签: pdf groovy textfield pdfbox