Kết quả tệp pdf nhỏ với BufferdImage lớn


8

Tôi đang cố gắng thực hiện OCR trên pdf. Có 2 bước trong mã:

  1. Chuyển đổi tập tin pdf sang tập tin tiff
  2. Chuyển đổi tiff thành văn bản

Tôi đã sử dụng ghost4j cho bước đầu tiên, và sau đó tess4j cho bước thứ hai. tất cả đều hoạt động tốt, cho đến khi tôi bắt đầu chạy nó đa luồng, và sau đó xảy ra ngoại lệ lạ. Tôi đọc ở đây: https://sourceforge.net/p/tess4j/discussion/1202293/thread/44cc65c5/ rằng ghost4j không phù hợp với đa luồng, vì vậy tôi đã thay đổi bước đầu tiên để làm việc với PDFBox.

Vì vậy, bây giờ mã của tôi trông giống như:

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();

Tôi đang cố chạy mã này với tệp pdf 800 kb và khi kiểm tra bộ nhớ sau

BufferedImage bufferedImage = pdfRenderer.renderImageWithDPI(0, 300);

nó tăng lên hơn 500 MB !! nếu tôi đang lưu BufferedImage này vào đĩa thì đầu ra có kích thước 1 MB ... vì vậy khi thử chạy mã này với 8 luồng, tôi cũng nhận được ngoại lệ kích thước heap java ...

Tôi đang thiếu gì ở đây? Tại sao tệp 1 MB dẫn đến tệp hình ảnh 500 MB? Tôi đã cố gắng chơi với DPI và giảm chất lượng nhưng tệp vẫn rất lớn ... Có thư viện nào khác có thể hiển thị pdf thành tiff không và tôi có thể thực thi 10 luồng mà không gặp vấn đề về bộ nhớ không?

Các bước để tái sản xuất:

  1. Tải xuống tệp sơ yếu lý lịch CEO Linkedin từ đây - https://gofile.io/?c=TtA7XQ
  2. Tôi đã sử dụng mã này:

    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");
    }

và đầu ra là:

Ứng dụng bắt đầu ....... Bộ nhớ đã sử dụng: 42 MB

Trước .... Bộ nhớ đã sử dụng: 107 MB

BufferedImage .... Bộ nhớ đã sử dụng: 171 MB

Trong ví dụ này không phải là 500 MB, mà là pdf 70 kb, khi tôi cố gắng chỉ hiển thị một trang, bộ nhớ tăng lên khoảng 70 MB ... nó không tỷ lệ ...


2
Vui lòng chia sẻ tệp PDF. Có lẽ nếu có một kích thước đầu ra kích thước hình ảnh lớn?
Tilman Hausherr

Bạn có thể kiểm tra kích thước của bạn BufferedImagesau khi kết xuất?
TA

3
Lưu ý rằng mức tiêu thụ bộ nhớ cao không nhất thiết chỉ ra rò rỉ bộ nhớ. Có lẽ trang chứa một đối tượng bitmap cần nhiều bộ nhớ để giải mã? PDFBox có mẫu phụ khi hiển thị ở kích thước nhỏ hơn không? Nếu không, kết xuất ở kích thước nhỏ có thể không giúp ...
haraldK

1
Pdfbox không được lấy mẫu theo mặc định nhưng nó có thể được kích hoạt trong PDFRenderer.
Tilman Hausherr

1
@NicolasFilotto kích hoạt mẫu phụ trong PDFRenderer. Nhưng mẫu phụ có lẽ không phải là một ý tưởng tốt cho OCR.
Tilman Hausherr

Câu trả lời:


0

Kích thước 3300 X 2550 của một byte cho mỗi pixel sẽ cung cấp khoảng 70_000_000 byte. Với 150 dpi, người ta sẽ có 22 inch x 17 inch, quá lớn.

Vì vậy, tỷ lệ hình ảnh xuống khoảng. Bộ nhớ 17 MB:

    float scale = 0.5f;
    BufferedImage bufferedImage = pdfRenderer.renderImage(page, scale, ImageType.BINARY);

Lưu nó pnghơn là tiffđể xem liệu điều đó làm cho một sự khác biệt.


OP muốn làm OCR, vì vậy 300dpi là một lựa chọn tốt. Nhưng bạn nói đúng về loại hình ảnh, tôi đã đưa ra đề xuất tương tự trong PDFBOX-4739. (Nó cũng xuất hiện rằng các hình ảnh được lưu không nén)
Tilman Hausherr

@TilmanHausherr Tôi một phần thực hiện OCR với 150 dpi thành công nhưng thực sự 300 dpi là chuẩn mực. Sử dụng ByteArrayOutputStream như trên cũng có thể rất tốn kém,
Joop Eggen

0

Vấn đề đã được giải quyết trong cuộc thảo luận trong PDFBOX-4739 :

  • sử dụng ImageIOUtils.writeImage()thay vì ImageIO.write()(bạn sẽ cần các tiểu dự án công cụ), vì ImageIO không nén các tệp TIFF. ImageIOUtils cố gắng sử dụng LZW hoặc CCITT, tùy thuộc vào hình ảnh nguồn.
  • hoàn toàn không lưu hình ảnh: có một doOCR()phương thức lấy tham số BufferedImage làm tham số, vì vậy không cần phải lưu lại.
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.