gpt4 book ai didi

java - 如何知道某个字段是否在特定页面上?

转载 作者:搜寻专家 更新时间:2023-11-01 01:34:43 25 4
gpt4 key购买 nike

PDFbox 内容流是按页完成的,但字段来自目录的表单,目录来自 pdf 文档本身。所以我不确定哪些字段在哪些页面上,也不确定它会导致将文本写到不正确的位置/页面。

即。我正在处理每页的字段,但不确定哪些字段在哪些页面上。

有没有办法知道哪个字段在哪个页面上?或者,有没有办法只获取当前页面上的字段?

谢谢!

标记

代码片段:

PDDocument pdfDoc = PDDocument.load(file);
PDDocumentCatalog docCatalog = pdfDoc.getDocumentCatalog();
PDAcroForm acroForm = docCatalog.getAcroForm();

// Get field names
List<PDField> fieldList = acroForm.getFields();
List<PDPage> pages = pdfDoc.getDocumentCatalog().getAllPages();
for (PDPage page : pages) {
PDPageContentStream contentStream = new PDPageContentStream(pdfDoc, page, true, true, true);
processFields(acroForm, fieldList, contentStream, page);
contentStream.close();
}

最佳答案

The PDFbox content stream is done per page, but the fields come from the form which comes from the catalog, which comes from the pdf doc itself. So I'm not sure which fields are on which pages

原因是 PDF 包含定义表单的全局对象结构。此结构中的表单字段可能在 0、1 或更多实际 PDF 页面上具有 0、1 或更多可视化效果。此外,在只有 1 个可视化的情况下,允许合并字段对象和可视化对象。

PDFBox 1.8.x

不幸的是,PDACroFormPDField 对象中的 PDFBox 仅表示此对象结构,无法轻松访问相关页面。不过,通过访问底层结构,您可以建立连接。

下面的代码应该清楚地说明如何做到这一点:

@SuppressWarnings("unchecked")
public void printFormFields(PDDocument pdfDoc) throws IOException {
PDDocumentCatalog docCatalog = pdfDoc.getDocumentCatalog();

List<PDPage> pages = docCatalog.getAllPages();
Map<COSDictionary, Integer> pageNrByAnnotDict = new HashMap<COSDictionary, Integer>();
for (int i = 0; i < pages.size(); i++) {
PDPage page = pages.get(i);
for (PDAnnotation annotation : page.getAnnotations())
pageNrByAnnotDict.put(annotation.getDictionary(), i + 1);
}

PDAcroForm acroForm = docCatalog.getAcroForm();

for (PDField field : (List<PDField>)acroForm.getFields()) {
COSDictionary fieldDict = field.getDictionary();

List<Integer> annotationPages = new ArrayList<Integer>();
List<COSObjectable> kids = field.getKids();
if (kids != null) {
for (COSObjectable kid : kids) {
COSBase kidObject = kid.getCOSObject();
if (kidObject instanceof COSDictionary)
annotationPages.add(pageNrByAnnotDict.get(kidObject));
}
}

Integer mergedPage = pageNrByAnnotDict.get(fieldDict);

if (mergedPage == null)
if (annotationPages.isEmpty())
System.out.printf("i Field '%s' not referenced (invisible).\n", field.getFullyQualifiedName());
else
System.out.printf("a Field '%s' referenced by separate annotation on %s.\n", field.getFullyQualifiedName(), annotationPages);
else
if (annotationPages.isEmpty())
System.out.printf("m Field '%s' referenced as merged on %s.\n", field.getFullyQualifiedName(), mergedPage);
else
System.out.printf("x Field '%s' referenced as merged on %s and by separate annotation on %s. (Not allowed!)\n", field.getFullyQualifiedName(), mergedPage, annotationPages);
}
}

注意,PDFBox PDAcroForm 表单字段处理有两个缺点:

  1. PDF 规范允许将表单定义为深树的全局对象结构,即实际字段不必是根的直接子级,但可以通过内部树节点组织。 PDFBox 忽略这一点并期望字段是根的直接子项。

  2. 有些 PDF,尤其是较旧的 PDF,不包含字段树,而是仅通过可视化小部件注释引用页面中的字段对象。 PDFBox 在其 PDACroForm.getFields 列表中看不到这些字段。

附注: @mikhailvshis answer正确显示您可以使用 PDField.getWidget().getPage() 从字段小部件中检索页面对象,并使用 catalog.getAllPages().indexOf 确定其页码.虽然速度很快,但此 getPage() 方法有一个缺点:它从小部件注释字典的可选条目中检索页面引用。因此,如果您处理的 PDF 是由填充该条目的软件创建的,那么一切都很好,但如果 PDF 创建者没有填充该条目,您得到的只是一个 null 页面。

PDFBox 2.0.x

在 2.0.x 中,一些访问相关元素的方法发生了变化,但整体情况没有变化,要安全地检索小部件的页面,您仍然必须遍历页面并找到引用注释的页面。

安全方法:

int determineSafe(PDDocument document, PDAnnotationWidget widget) throws IOException
{
COSDictionary widgetObject = widget.getCOSObject();
PDPageTree pages = document.getPages();
for (int i = 0; i < pages.getCount(); i++)
{
for (PDAnnotation annotation : pages.get(i).getAnnotations())
{
COSDictionary annotationObject = annotation.getCOSObject();
if (annotationObject.equals(widgetObject))
return i;
}
}
return -1;
}

快速方法

int determineFast(PDDocument document, PDAnnotationWidget widget)
{
PDPage page = widget.getPage();
return page != null ? document.getPages().indexOf(page) : -1;
}

用法:

PDAcroForm acroForm = document.getDocumentCatalog().getAcroForm();
if (acroForm != null)
{
for (PDField field : acroForm.getFieldTree())
{
System.out.println(field.getFullyQualifiedName());
for (PDAnnotationWidget widget : field.getWidgets())
{
System.out.print(widget.getAnnotationName() != null ? widget.getAnnotationName() : "(NN)");
System.out.printf(" - fast: %s", determineFast(document, widget));
System.out.printf(" - safe: %s\n", determineSafe(document, widget));
}
}
}

( DetermineWidgetPage.java )

(与 1.8.x 代码相比,这里的安全方法只是搜索单个字段的页面。如果在您的代码中您必须确定许多小部件的页面,您应该创建一个查找 Map 就像在 1.8.x 中一样。)

示例文档

快速方法失败的文档:aFieldTwice.pdf

快速方法适用的文档:test_duplicate_field2.pdf

关于java - 如何知道某个字段是否在特定页面上?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22074449/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com