如何使用 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 来附加图片,因为如果我这样做,按钮的顶层将被我附加的图片替换,这不是我想要的。因此,我明确使用了 Adobe 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
我有一个 PDF,里面有图像字段。我没有使用带 javascript 的 PDPushButton 来附加图片,因为如果我这样做,按钮的顶层将被我附加的图片替换,这不是我想要的。因此,我明确使用了 Adobe 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