Я пытаюсь выполнить OCR для PDF-файлов. В коде есть 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();
Я пытаюсь запустить этот код с файлом PDF размером 800 Кб, и при проверке памяти после
BufferedImage bufferedImage = pdfRenderer.renderImageWithDPI(0, 300);
он увеличивается до более чем 500 МБ !! если я сохраняю этот BufferedImage на диск, размер вывода составляет 1 МБ ... поэтому при попытке запустить этот код с 8 потоками я получаю исключение java размера кучи также ...
Что мне здесь не хватает? почему файл размером 1 МБ приводит к файлу изображения размером 500 МБ? Я пытался поиграть с DPI и снизить качество, но файл все еще очень большой ... Есть ли какая-нибудь другая библиотека, которая может рендерить pdf в tiff и могла бы выполнить 10 потоков без проблем с памятью?
Шаги для воспроизведения:
- Загрузите отсюда файл резюме генерального директора Linkedin - 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 МБ
До .... Использованная память: 107 МБ
BufferedImage .... Используемая память: 171 МБ
В данном примере это не 500 МБ, а pdf размером 70 КБ , когда я пытаюсь визуализировать только одну страницу, увеличение памяти примерно на 70 МБ ... это не пропорционально ...