【问题标题】:PDFBox not detecting image in pagePDFBox未检测到页面中的图像
【发布时间】:2015-05-28 07:03:45
【问题描述】:

我正在尝试使用 PDFBox 检测 this pdf 中的图像。 pdf 有两个空白图像,一个在左侧(在文本“把这个放在盒子里”下面),另一个在右边(在文本“把这个放在盒子外面”下面)。这是我用来检测图像的代码:

PDPage page = (PDPage) catalog.getAllPages().get(0);
PDStream contents = page.getContents();
PDFStreamParser parser = new PDFStreamParser(contents.getStream());
parser.parse();
List<Object> tokens = parser.getTokens();

PDResources resources = page.getResources();
Map<String, PDXObjectImage> images = resources.getImages();
if(null != images){
        Iterator<String> it = images.keySet().iterator();
        while(it.hasNext()){
            String key = it.next();
            System.out.println("Key >>>>>>>>>>>>>> "+key);
        }
}

我能够检测到第二张图片。但是,没有检测到第一张图像。问题是什么?我确定pdf是正确的。我多次创建它,但我仍然面临同样的问题。我使用 Sketch 创建了 pdf。

谢谢。

【问题讨论】:

  • 不应该遍历所有页面吗?

标签: java pdfbox


【解决方案1】:

总之

我能够检测到第二张图片。但是,没有检测到第一张图像。有什么问题?

实际上两个页面图像使用相同的图像资源,只是拉伸到不同的尺寸。

详细说明

如果您查看页面的内容流,您会在最后看到:

q
720 0 0 970 832 126 cm
/Im1 Do
Q
q
512 0 0 128 144 968 cm
/Im1 Do
Q

前四行在位置 832 处绘制图像资源 Im1,126 拉伸到 720 x 970,最后四行在位置处绘制相同的图像资源 Im1 144、968 拉伸到 512 x 128。

做什么

您仅查看页面资源以查找页面图像的方法是不合适的,因为

  • 正如您所见,单个图像资源可能会在拉伸到不同尺寸的页面上多次使用,
  • 一个页面上可能根本不使用图像资源(例如,某些文档有一个从所有页面引用的大型资源字典;对于给定页面,可能不会使用许多资源),
  • 图像可以内联到内容流中;您的方法根本看不到这些图像,并且
  • form Xobjects 或 patterns 可能会显示在您的页面上,它们可能在各自的资源中分别有图像;由于您只查看直接页面资源中包含的图像资源,因此您的方法也不会找到它们。

PDFBox 示例PrintImageLocations 中提供了更好的解决方案(仅对内联和可能带有图案的图像失败),您的文件的输出是

*******************************************************************
Found image [Im1]
position = 832.0, 128.0
size = 360px, 462px
size = 720.0, 970.0
size = 10.0in, 13.472222in
size = 254.0mm, 342.19446mm

*******************************************************************
Found image [Im1]
position = 144.0, 128.0
size = 360px, 462px
size = 512.0, 128.0
size = 7.111111in, 1.7777778in
size = 180.62222mm, 45.155556mm

此示例使用 PDFBox PDFStreamEngine 来解析处理的内容以绘制页面。

【讨论】:

  • 感谢您的解决方案。快速提问。我假设 PDFStreamEngine 的 processStream() 方法正在调用 processOperator() 方法。那么有没有办法将额外的参数传递给 processOperator() 方法呢?我想将一个 byte[] 传递给它,以便我可以在方法中使用 byte[]。
  • 我想传递一个字节[],以便我可以用字节[]替换图像。
  • 如果我是你,我会尽量不要那样更改 PDFBox API,因为 A 你必须在更新 PDFBox 版本时一次又一次地引入更改利用; B 您的项目中使用 PDFBox 的其他代码可能会因您的更改而出现原始 API 和打嗝。 C 这种信息并不真正属于那里,将信息和关注点保留在它所属的程序层中。 DPDFStreamEngine 及其派生的类并不是真正针对更改内容,而只是*分析它。
  • 那我该如何替换图片呢?我能够检测到这两个图像的唯一方法是在 processOperator() 方法中。还是我应该自己实现相同的方法?不确定这是否是正确的方法。
  • 图像替换有不同的难度。最简单的方法是仅替换图像资源。这在您的情况下是不够的,因为相同的资源被使用了两次。因此,您将不得不编辑内容流。在您的特定情况下,编辑页面内容流就足够了(在某些情况下,还必须考虑其他对象的内容流)。您是在寻找通用解决方案还是特定于您的 PDF 的解决方案?
猜你喜欢
  • 2020-12-03
  • 1970-01-01
  • 1970-01-01
  • 2017-03-24
  • 1970-01-01
  • 2021-01-31
  • 1970-01-01
相关资源
最近更新 更多