【发布时间】:2020-04-24 20:56:06
【问题描述】:
我正在尝试对 pdf 执行 OCR。 代码中有2个步骤:
- 将 pdf 转换为 tiff 文件
- 将 tiff 转换为文本
第一步我使用ghost4j,第二步使用tess4j。 一切都很好,直到我开始多线程运行它,然后发生了奇怪的异常。 我在这里读到:https://sourceforge.net/p/tess4j/discussion/1202293/thread/44cc65c5/ 说ghost4j不适合多线程,所以我把第一步改成使用PDFBox。
所以现在我的代码如下所示:
PDDocument doc = PDDocument.load(this.bytes);
PDFRenderer pdfRenderer = new PDFRenderer(doc);
BufferedImage bufferedImage = pdfRenderer.renderImageWithDPI(0, 300);
ByteArrayOutputStream os = new ByteArrayOutputStream();
ImageIO.write(bufferedImage, "tiff", os);
os.flush();
os.close();
bufferedImage.flush();
我正在尝试使用 800 kb pdf 文件运行此代码,并且在检查内存后
BufferedImage bufferedImage = pdfRenderer.renderImageWithDPI(0, 300);
它增加到超过 500 MB!如果我将此 BufferedImage 保存到磁盘,则输出大小为 1 MB...所以当尝试使用 8 个线程运行此代码时,我也会遇到 java 堆大小异常...
我在这里缺少什么?为什么一个 1 MB 的文件会产生一个 500 MB 的图像文件?我尝试使用 DPI 并降低质量,但文件仍然很大...... 是否有任何其他库可以将 pdf 呈现为 tiff,并且我可以执行 10 个线程而不会出现内存问题?
重现步骤:
-
从这里下载 Linkedin CEO 简历文件 - https://gofile.io/?c=TtA7XQ
-
我没有使用此代码:
private static void test() throws IOException { printUsedMemory("App started..."); File file = new File("linkedinceoresume.pdf"); try (PDDocument doc = PDDocument.load(file)) { PDFRenderer pdfRenderer = new PDFRenderer(doc); printUsedMemory("Before"); for (int page = 0; page < 1; ++page) { BufferedImage bufferedImage = pdfRenderer.renderImageWithDPI(page, 76, ImageType.GRAY); ByteArrayOutputStream os = new ByteArrayOutputStream(); ImageIO.write(bufferedImage, "tiff", os); os.flush(); os.close(); bufferedImage.flush(); } } finally { printUsedMemory("BufferedImage"); } } private static void printUsedMemory(String text) { long freeMemory = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory(); long mb = freeMemory / 1000000; System.out.println(text + "....Used memory: " + mb + " MB"); }
输出是:
应用程序已启动.......已用内存:42 MB
之前....已用内存:107 MB
BufferedImage....已用内存:171 MB
在这个例子中,它不是 500 MB,而是 70 kb 的 pdf,当我尝试只渲染一页时,内存增加了大约 70 MB...这不成比例...
【问题讨论】:
-
请分享PDF文件。也许如果有一个巨大的图像尺寸输出尺寸?
-
渲染后可以查看
BufferedImage的尺寸吗? -
请注意,高内存消耗不一定表示内存泄漏。也许页面包含需要大量内存来解码的位图对象? PDFBox 在以较小尺寸渲染时是否对图像进行二次采样?如果没有,以小尺寸渲染可能无济于事......
-
Pdfbox 默认不进行二次采样,但可以在 PDFRenderer 中启用。
-
@NicolasFilotto 在 PDFRenderer 中激活子采样。但是二次采样对于 OCR 来说可能不是一个好主意。
标签: java ocr tesseract pdfbox bufferedimage