Ich versuche, OCR für PDFs durchzuführen. Der Code besteht aus 2 Schritten:
- Konvertieren Sie PDF in TIFF-Dateien
- Konvertieren Sie tiff in Text
Ich habe Ghost4j für den ersten Schritt und dann Tess4j für den zweiten Schritt verwendet. Alles funktionierte großartig, bis ich anfing, es mit mehreren Threads auszuführen, und dann traten seltsame Ausnahmen auf. Ich habe hier gelesen: https://sourceforge.net/p/tess4j/discussion/1202293/thread/44cc65c5/, dass ghost4j nicht für Multithreading geeignet ist, daher habe ich den ersten Schritt geändert, um mit PDFBox zu arbeiten.
Jetzt sieht mein Code so aus:
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();
Ich versuche, diesen Code mit einer 800-KB-PDF-Datei auszuführen und beim Überprüfen des Speichers nach dem
BufferedImage bufferedImage = pdfRenderer.renderImageWithDPI(0, 300);
es erhöht sich auf mehr als 500 MB !! Wenn ich dieses BufferedImage auf der Festplatte speichere, hat die Ausgabe eine Größe von 1 MB. Wenn ich also versuche, diesen Code mit 8 Threads auszuführen, erhalte ich auch die Ausnahme für die Größe des Java-Heapspeichers ...
Was fehlt mir hier? Warum führt eine 1-MB-Datei zu einer 500-MB-Bilddatei? Ich habe versucht, mit der DPI zu spielen und die Qualität zu verringern, aber die Datei ist immer noch sehr groß ... Gibt es eine andere Bibliothek, die PDF in TIFF rendern kann und die ich 10 Threads ohne Speicherprobleme ausführen könnte?
Schritte zum Reproduzieren:
- Laden Sie die Lebenslaufdatei des Linkedin-CEO von hier herunter - https://gofile.io/?c=TtA7XQ
Ich habe dann diesen Code verwendet:
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"); }
und die Ausgabe ist:
App gestartet ....... Verwendeter Speicher: 42 MB
Vorher .... Verwendeter Speicher: 107 MB
BufferedImage .... Verwendeter Speicher: 171 MB
In diesem Beispiel sind es nicht 500 MB, sondern ein PDF von 70 KB. Wenn ich versuche, nur eine Seite zu rendern, erhöht sich der Speicher um ca. 70 MB ... es ist nicht proportional ...
BufferedImage
nach dem Rendern überprüfen ?