我有一个PDF,其中包含图像字段。我没有使用带有JavaScript的PDPushButton来附加图片,因为如果这样做,按钮的顶层将替换为我所附加的图片,这不是我想要的。因此,我明确地使用了Adobe LiveCycle Designer中可用的ImageField。我可以使用PDFBox提取附加在其上的文件,但是我无法找到任何方式查看哪些图像字段具有附加文件,而哪些没有。例如,如果我在这里有以下代码:
ImageField [1],ImageField [2],ImageField [3]
我想看类似的东西
ImageField [1]:空,
ImageField [2]:是的,
ImageField [3]:正确enter code here
等,假设ImageField [2]和ImageField [3]都附有图像。
下面是我正在处理的代码:
我有一个常数:
然后我遍历整个图像字段名称,看看哪个字段是PDXObjectImage的实例,然后如果它是PDXObjectImage,则我检查那个object.getRGBImage()。getHeight()> 0假设仅上载的文件高度> 1,表示已附加文件。
私有静态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文件的保管箱链接:
https://www.dropbox.com/s/g2wqm8ipsp8t8l5/GSA%20500%20PDF_v4.pdf?dl=0
答案 0 :(得分:0)
您的PDF是AcroForm / XFA的混合文档; XFA部件使用带有imageEdit用户界面的字段,而AcroForm部件使用按钮字段。
因此,它提供了两种方法来检查是否设置了图像字段:查看AcroForm按钮并检查其外观以查看图像,或者检索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
此处的实现仅适用于PDFBox2.0.x。内容流解析器类的结构在2.0.0中已进行了全面改进,使该代码的反向移植到1.8.x有点乏味。
要检查按钮外观是否真正显示 图像(并且不仅在资源中包含图像 ),可以使用简单的PDFGraphicsStreamEngine
这样的子类:
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;
}
使用它可以创建如下检查方法:
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