Java 如何知道某个字段是否位于特定页面上?

Java 如何知道某个字段是否位于特定页面上?,java,pdfbox,Java,Pdfbox,PDFbox内容流是每页完成的,但字段来自目录中的表单,而目录中的表单来自pdf文档本身。因此,我不确定哪些字段位于哪些页面上,这会导致将文本写入错误的位置/页面 我正在处理每页的字段,但不确定哪些字段在哪些页面上 有没有办法知道哪个字段在哪个页面上?或者,有没有办法只获取当前页面上的字段 谢谢大家! 标记 代码段: PDDocument pdfDoc = PDDocument.load(file); PDDocumentCatalog docCatalog = pdfDoc.getDocume

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();
}
PDDocument pdfDoc=PDDocument.load(文件);
PDDocumentCatalog docCatalog=pdfDoc.getDocumentCatalog();
PDAcroForm acroForm=docCatalog.getAcroForm();
//获取字段名
List fieldList=acroForm.getFields();
列表页面=pdfDoc.getDocumentCatalog().getAllPages();
用于(第页:页){
PDPageContentStream contentStream=新的PDPageContentStream(pdfDoc,page,true,true);
processFields(acroForm、fieldList、contentStream、page);
contentStream.close();
}
PDFbox内容流是每页完成的,但字段来自目录中的表单,而目录中的表单来自pdf文档本身。所以我不确定哪些字段在哪些页面上

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

PDFBox 1.8.x 不幸的是,PDFBox在其
PDAcroForm
PDField
对象中仅表示此对象结构,不提供对关联页面的轻松访问。不过,通过访问底层结构,您可以构建连接

以下代码应明确说明如何执行此操作:

@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);
    }
}
快速方法

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

(与1.8.x代码不同,这里的安全方法只是搜索单个字段的页面。如果在代码中必须确定多个小部件的页面,则应创建一个查找
Map
,与1.8.x代码类似。)

示例文件 fast方法失败的文档:


快速方法适用的文档:

同意此答案可能对OP没有帮助(一年后),但如果其他人遇到此问题,以下是解决方案:

PDDocumentCatalog catalog = doc.getDocumentCatalog();

int pageNumber = catalog.getAllPages().indexOf(yourField.getWidget().getPage());

单个或多个小部件的通用解决方案(单个页面的重复限定名称)

本例使用Lucee(cfml)

非常感谢mkl,因为他上面的回答非常宝贵,没有他的帮助,我不可能构建这个函数

调用函数:pageForSignature(doc,fieldName),它将返回字段名所在的页码。如果未找到fieldName,则返回-1

  <cfscript>
  try{

  /*
  java is used by using CreateObject()
  */

  variables.File = CreateObject("java", "java.io.File");

  //references lucee bundle directory - typically on tomcat: /usr/local/tomcat/lucee-server/bundles
  variables.PDDocument = CreateObject("java", "org.apache.pdfbox.pdmodel.PDDocument", "org.apache.pdfbox.app", "2.0.18")

  function determineSafe(doc, widget){

    var i = '';
    var widgetObject = widget.getCOSObject();
    var pages = doc.getPages();
    var annotation = '';
    var annotationObject = '';

    for (i = 0; i < pages.getCount(); i=i+1){

    for (annotation in pages.get(i).getAnnotations()){
        if(annotation.getSubtype() eq 'widget'){
            annotationObject = annotation.getCOSObject();
            if (annotationObject.equals(widgetObject)){
                return i;
            }
        }
    }

    }
    return -1;
  }

  function pageForSignature(doc, fieldName){
    try{
    var acroForm = doc.getDocumentCatalog().getAcroForm();
    var field = '';
    var widget = '';
    var annotation = '';
    var pageNo = '';

    for(field in acroForm.getFields()){

    if(field.getPartialName() == fieldName){

        for(widget in field.getWidgets()){

           for(annotation in widget.getPage().getAnnotations()){

             if(annotation.getSubtype() == 'widget'){

                pageNo = determineSafe(doc, widget);
                doc.close();
                return pageNo;
             }
           }

        }
    }
  }
return -1;  
}catch(e){
    doc.close();
writeDump(label="catch error",var='#e#');
  }
} 

doc = PDDocument.init().load(File.init('/**********/myfile.pdf'));

//returns no,  page numbers start at 0
pageNo = pageForSignature(doc, 'twtzceuxvx');

writeDump(label="pageForSignature(doc, fieldName)", var="#pageNo#");
</cfscript

试一试{
/*
java通过使用CreateObject()来使用
*/
variables.File=CreateObject(“java”、“java.io.File”);
//参考lucee bundle目录-通常在tomcat上:/usr/local/tomcat/lucee服务器/bundles
variables.PDDocument=CreateObject(“java”、“org.apache.pdfbox.pdmodel.PDDocument”、“org.apache.pdfbox.app”、“2.0.18”)
函数确定安全(文档、小部件){
var i=“”;
var widgetObject=widget.getCOSObject();
var pages=doc.getPages();
var注释=“”;
var annotationObject='';
对于(i=0;i如果一个字段在多个页面上有多个窗口小部件,那么您会得到哪个窗口小部件?@mkl这是一个好问题。文档说它将得到“作为该字段一部分的单个关联窗口小部件”。不完全清楚在您指代“作为该字段一部分的单个关联窗口小部件”的情况下会发生什么听起来好像涵盖了小部件对象合并到字段对象的情况。这种合并只允许包含单个小部件的表单字段。是的……我目前在一个项目中努力解决这个问题,我遇到了一个pdf,其中小部件没有与其相关联的页面(或其他内容,.getPage()返回null)好的,我已经查看了源代码。A
getWidget
返回合并到字段字典中的小部件或Kids数组中的第一个小部件,或者如果Kids数组为空,则返回
null
。B
getPage
返回P条目中引用的页面。该条目通常是可选的。因此,
null
是一个将每隔一段时间发生一次。其值
getPage
返回的条目是可选的。如果使用的是来自野外的PDF,则很可能至少与
PDPage
实例一样频繁地获得
null
。您使用的是哪个版本..在pdfbox 2.x版本中,我没有找到任何方法getAllPages of PDDocumentCatalog cl
List<PDAnnotationWidget>  widget=field.getWidgets();
PDDocumentCatalog catalog = doc.getDocumentCatalog();
for(int i=0;i<widget.size();i++) {
int pageNumber = 1+ catalog.getPages().indexOf(field.getWidgets().get(i).getPage());
}
  <cfscript>
  try{

  /*
  java is used by using CreateObject()
  */

  variables.File = CreateObject("java", "java.io.File");

  //references lucee bundle directory - typically on tomcat: /usr/local/tomcat/lucee-server/bundles
  variables.PDDocument = CreateObject("java", "org.apache.pdfbox.pdmodel.PDDocument", "org.apache.pdfbox.app", "2.0.18")

  function determineSafe(doc, widget){

    var i = '';
    var widgetObject = widget.getCOSObject();
    var pages = doc.getPages();
    var annotation = '';
    var annotationObject = '';

    for (i = 0; i < pages.getCount(); i=i+1){

    for (annotation in pages.get(i).getAnnotations()){
        if(annotation.getSubtype() eq 'widget'){
            annotationObject = annotation.getCOSObject();
            if (annotationObject.equals(widgetObject)){
                return i;
            }
        }
    }

    }
    return -1;
  }

  function pageForSignature(doc, fieldName){
    try{
    var acroForm = doc.getDocumentCatalog().getAcroForm();
    var field = '';
    var widget = '';
    var annotation = '';
    var pageNo = '';

    for(field in acroForm.getFields()){

    if(field.getPartialName() == fieldName){

        for(widget in field.getWidgets()){

           for(annotation in widget.getPage().getAnnotations()){

             if(annotation.getSubtype() == 'widget'){

                pageNo = determineSafe(doc, widget);
                doc.close();
                return pageNo;
             }
           }

        }
    }
  }
return -1;  
}catch(e){
    doc.close();
writeDump(label="catch error",var='#e#');
  }
} 

doc = PDDocument.init().load(File.init('/**********/myfile.pdf'));

//returns no,  page numbers start at 0
pageNo = pageForSignature(doc, 'twtzceuxvx');

writeDump(label="pageForSignature(doc, fieldName)", var="#pageNo#");
</cfscript