小 pdf 文件产生巨大的 BufferdImage

Lio*_*r Y 8 java ocr bufferedimage tesseract pdfbox

我正在尝试对 pdf 执行 OCR。代码中有2个步骤:

  1. 将 pdf 转换为 tiff 文件
  2. 将 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();
Run Code Online (Sandbox Code Playgroud)

我正在尝试使用 800 kb pdf 文件运行此代码,并在检查内存后

BufferedImage bufferedImage = pdfRenderer.renderImageWithDPI(0, 300);
Run Code Online (Sandbox Code Playgroud)

它提高到 500 MB 以上!!如果我将此 BufferedImage 保存到磁盘,则输出大小为 1 MB...因此,当尝试使用 8 个线程运行此代码时,我也会遇到 Java 堆大小异常...

我在这里缺少什么?为什么 1 MB 的文件会产生 500 MB 的图像文件?我尝试使用 DPI 并降低质量,但文件仍然很大......是否有任何其他库可以将 pdf 渲染为 tiff,并且我可以执行 10 个线程而不会出现内存问题?

重现步骤:

  1. 从这里下载 Linkedin CEO 简历文件 - https://gofile.io/?c=TtA7XQ

  2. 我比使用这个代码:

    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");
    }
    
    Run Code Online (Sandbox Code Playgroud)

输出是:

应用程序启动.......已用内存:42 MB

之前....已用内存:107 MB

BufferedImage....已用内存:171 MB

在这个例子中,它不是 500 MB,而是 70 kb 的 pdf,当我尝试只渲染一页时,内存增加了大约 70 MB……这不成比例……

Joo*_*gen 0

每个像素一个字节的尺寸 3300 X 2550 将提供大约 70_000_000 字节。如果是 150 dpi,则尺寸为 22 英寸 x 17 英寸,太大了。

因此,将图片缩小到大约。17 MB 内存:

    float scale = 0.5f;
    BufferedImage bufferedImage = pdfRenderer.renderImage(page, scale, ImageType.BINARY);
Run Code Online (Sandbox Code Playgroud)

将其另存为png而不是tiff看看是否有区别。