如何使用 PDFbox 1.8.11 查找 PDF 中哪个图像字段插入了图像,哪个没有附加图像?

How do I find which image field in PDF has image inserted and which one has no images attached using PDFbox 1.8.11?

我有一个 PDF,里面有图像字段。我没有使用带 javascript 的 PDPushButton 来附加图片,因为如果我这样做,按钮的顶层将被我附加的图片替换,这不是我想要的。因此,我明确使用了 Adob​​e LiveCycle Designer 中可用的 ImageField。我可以使用 PDFBox 提取附加在其上的文件,但我无法找到任何方法来查看哪些图像字段附加了文件,哪些没有附加文件。例如,如果我这里有以下代码:

ImageField[1]、ImageField[2]、ImageField[3]

我想看类似的东西 ImageField[1]: 空, ImageField[2]: 是的, ImageField[3]: trueenter code here

等,假设 ImageField[2] 和 ImageField[3] 附有图像。

下面是我正在处理的代码:

我有一个常数:

然后我遍历整组图像字段名称并查看哪个字段是 PDXObjectImage 的实例,然后如果它是 PDXObjectImage 那么我检查是否 object.getRGBImage().getHeight() > 0 假设只有上传的文件的高度 > 1,这意味着已附加文件。

private static String[] IMAGE_FIELD_ROW = {"ImageField1[0]","ImageField2[0]",....} => 100行字符串值,例如"ImageField3[0]", "ImageField4[0]", ...等等

    for(int i = 0; i<IMAGE_FIELD_ROW.length; i++)
    {
        if(field.getPartialName().equals(IMAGE_FIELD_ROW[i]))
        {
            Map<String, PDAppearanceStream> stateAppearances = field.getWidget().getAppearance().getNormalAppearance();
            for (Map.Entry<String, PDAppearanceStream> entry: stateAppearances.entrySet())
            {
                PDAppearanceStream appearance = entry.getValue();
                PDResources resources = appearance.getResources();
                 if (resources == null)
                     return;
                 Map<String, PDXObject> xObjects = resources.getXObjects();
                 if (xObjects == null)
                     return;

                 for (Map.Entry<String, PDXObject> entryNew : xObjects.entrySet())
                 {
                     PDXObject xObject = entryNew.getValue();
                     System.out.println("printing out the xobject name: "+ entryNew.getKey());


                     if (xObject instanceof PDXObjectForm)
                     {

                         PDXObjectForm form = (PDXObjectForm)xObject;
                         PDResources resources2 = form.getResources();
                         if (resources2 == null)
                             return;
                         Map<String, PDXObject> xObjects2 = resources2.getXObjects();
                         if (xObjects2 == null)
                         {
                             return;
                         }
                         for (Map.Entry<String, PDXObject> entry2 : xObjects2.entrySet())
                         {

                             PDXObject xObject2 = entry2.getValue();

                             if (xObject2 instanceof PDXObjectForm)
                             {
                                 continue;
                             }
                             else if (xObject2 instanceof PDXObjectImage)
                             {
                                 PDXObjectImage ig = (PDXObjectImage)xObject2;
                                 if(ig.getRGBImage().getHeight() >  0)
                                 {
                                     images.put(field.getPartialName(), "true");
                                 }
                                 else
                                 {
                                     images.put(field.getPartialName(), null);
                                 }

                                 //imageIds.add(imageId);
                             }
                             else
                             {
                                continue;
                             }

                     }

                 }
            }

        }
        }
    }

Images 是一个地图变量:Mapimages。

我的代码文件也很大,所以我不想通过粘贴整个文件来压倒任何人。下面是我正在使用的示例 PDF 文件的保管箱 link:

https://www.dropbox.com/s/g2wqm8ipsp8t8l5/GSA%20500%20PDF_v4.pdf?dl=0

您的 PDF 是一个混合 AcroForm/XFA 文档;其中 XFA 部分使用带有 imageEdit 用户界面的字段,而 AcroForm 部分使用按钮字段。

因此,它允许您通过两种方式检查是否设置了图像字段:查看 AcroForm 按钮并检查它们的图像外观,或者检索 XFA XML 并检查它。

检查 XFA XML

最初我确实忽略了问题标题中的 PDFBox 版本并为 PDFBox 2 实现了它。0.x。然而,事实证明,相同的代码可用于 PDFBox 1.8.11,只是可能会抛出一些额外的异常,因此必须考虑。

后一个选项,即检查 XFA XML,实际上对于手头的文档来说更容易一些。只需在 XML 中搜索具有相关名称的元素并检查其内容。作为一项额外的完整性检查,可以验证元素的内容类型属性:

boolean isFieldFilledXfa(Document xfaDom, String fieldName) {
    NodeList fieldElements = xfaDom.getElementsByTagName(fieldName);
    for (int i = 0; i < fieldElements.getLength(); i++) {
        Node node = fieldElements.item(i);
        if (node instanceof Element) {
            Element element = (Element) node;
            if (element.getAttribute("xfa:contentType").startsWith("image/")) {
                return element.getTextContent().length() > 0;
            }
        }
    }
    return false;
}

(CheckImageFieldFilled辅助方法)

有了它你可以查看你的文档:

PDDocument document = PDDocument.load(SOURCE);
PDAcroForm acroForm = document.getDocumentCatalog().getAcroForm();
Document xfaDom = acroForm.getXFA().getDocument();

System.out.println("Filled image fields from ImageField1..ImageField105:");
for (int i=1; i < 106; i++) {
    if (isFieldFilledXfa(xfaDom, "ImageField" + i)) {
        System.out.printf("* ImageField%d\n", i);
    }
}

(CheckImageFieldFilled测试方法testCheckXfaGsa500Pdf_v4)

输出:

Filled image fields from ImageField1..ImageField105:
* ImageField1
* ImageField3
* ImageField6

检查 AcroForm 外观

此处的实现仅适用于 PDFBox 2。0.x。内容流解析器 classes 的结构在 2.0.0 中进行了相当大的修改,使此代码的 back-port 变为 1。8.x 有点乏味。

要检查按钮外观是否确实 显示 图像(并且其资源 中不仅有图像 ),可以使用一个简单的 PDFGraphicsStreamEngine subclass 像这样:

public class WidgetImageChecker extends PDFGraphicsStreamEngine
{
    public WidgetImageChecker(PDAnnotationWidget widget) {
        super(widget.getPage());
        this.widget = widget;
    }

    public boolean hasImages() throws IOException {
        count = 0;
        PDAppearanceStream normalAppearance = widget.getNormalAppearanceStream();
        processChildStream(normalAppearance, widget.getPage());
        return count != 0;
    }

    @Override
    public void drawImage(PDImage pdImage) throws IOException {
        count++;
    }

    @Override
    public void appendRectangle(Point2D p0, Point2D p1, Point2D p2, Point2D p3) throws IOException { }

    @Override
    public void clip(int windingRule) throws IOException { }

    @Override
    public void moveTo(float x, float y) throws IOException {  }

    @Override
    public void lineTo(float x, float y) throws IOException { }

    @Override
    public void curveTo(float x1, float y1, float x2, float y2, float x3, float y3) throws IOException {  }

    @Override
    public Point2D getCurrentPoint() throws IOException { return null; }

    @Override
    public void closePath() throws IOException { }

    @Override
    public void endPath() throws IOException { }

    @Override
    public void strokePath() throws IOException { }

    @Override
    public void fillPath(int windingRule) throws IOException { }

    @Override
    public void fillAndStrokePath(int windingRule) throws IOException { }

    @Override
    public void shadingFill(COSName shadingName) throws IOException { }

    final PDAnnotationWidget widget;
    int count = 0;
} 

(CheckImageFieldFilled帮手class)

有了它你可以创建一个这样的检查方法:

boolean isFieldFilledAcroForm(PDAcroForm acroForm, String fieldName) throws IOException {
    for (PDField field : acroForm.getFieldTree()) {
        if (field instanceof PDPushButton && fieldName.equals(field.getPartialName())) {
            for (final PDAnnotationWidget widget : field.getWidgets()) {
                WidgetImageChecker checker = new WidgetImageChecker(widget);
                if (checker.hasImages())
                    return true;
            }
        }
    }
    return false;
}

(CheckImageFieldFilled辅助方法)

并像这样使用它:

PDDocument document = PDDocument.load(SOURCE);
PDAcroForm acroForm = document.getDocumentCatalog().getAcroForm();

System.out.println("Filled image fields (AcroForm) from ImageField1..ImageField105:");
for (int i=1; i < 106; i++) {
    if (isFieldFilledAcroForm(acroForm, "ImageField" + i + "[0]")) {
        System.out.printf("* ImageField%d\n", i);
    }
}

(CheckImageFieldFilled 测试 testCheckAcroFormGsa500Pdf_v4)

输出,如上:

Filled image fields (AcroForm) from ImageField1..ImageField105:
* ImageField1
* ImageField3
* ImageField6