Gelegentlich stoßen wir auf extrem große PDF-Dateien, die mit vollständigen, hochauflösenden Bildern gefüllt sind (das Ergebnis des Scannens von Dokumenten). Zum Beispiel habe ich eine 1,7 GB PDF mit 3500 Bildern. Das Laden des Dokuments dauert etwa 50 Sekunden, aber das Zählen der Bilder dauert etwa 15 Minuten.Schnellste Methode zum Zählen von PDF-Bildern mit der PDFBox 2.x
Ich bin sicher, das ist, weil die Bild-Bytes als Teil der API-Aufrufe gelesen werden. Gibt es eine Möglichkeit, die Bildanzahl zu extrahieren, ohne die Bildbytes tatsächlich zu lesen?
PDFBox Version: 2.0.2
Beispielcode:
@Test
public void imageCountIsCorrect() throws Exception {
PDDocument pdf = readPdf();
try {
assertEquals(3558, countImages(pdf));
// assertEquals(3558, countImagesWithExtractor(pdf));
} finally {
if (pdf != null) {
pdf.close();
}
}
}
protected PDDocument readPdf() throws IOException {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
FileInputStream stream = new FileInputStream("large.pdf");
PDDocument pdf;
try {
pdf = PDDocument.load(stream, MemoryUsageSetting.setupMixed(1024 * 1024 * 250));
} finally {
stream.close();
}
stopWatch.stop();
log.info("PDF loaded: time={}s", stopWatch.getTime()/1000);
return pdf;
}
protected int countImages(PDDocument pdf) throws IOException {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
int imageCount = 0;
for (PDPage pdPage : pdf.getPages()) {
PDResources pdResources = pdPage.getResources();
for (COSName cosName : pdResources.getXObjectNames()) {
PDXObject xobject = pdResources.getXObject(cosName);
if (xobject instanceof PDImageXObject) {
imageCount++;
if (imageCount % 100 == 0) {
log.info("Found image: #" + imageCount);
}
}
}
}
stopWatch.stop();
log.info("Images counted: time={}s,imageCount={}", stopWatch.getTime()/1000, imageCount);
return imageCount;
}
Wenn ich die countImages Methode zu verlassen sich auf die COSName ändern, vervollständigt die Zählung in weniger als 1 s, aber ich bin ein wenig unsicher sich auf das Präfix des Namens verlassen. Dies scheint ein Nebenprodukt des pdf-Encoder zu sein und nicht PDFBox (ich jeden Hinweis nicht, um es in ihrem Code finden konnte):
if (cosName.getName().startsWith("QuickPDFIm")) {
imageCount++;
}
Als Randbemerkung, Ihr Code zählt nur die unmittelbare Bitmap-Bild * Ressourcen * pro Seite . Es besteht weder aus eingebetteten Bildern noch aus Bildern, die in Objekten oder Mustern enthalten sind. Auf der anderen Seite muss eine Bildressource nicht auf einer Seite verwendet werden. Daher werden manchmal auch zu viele Bilder gezählt. Bei einer generischen Lösung müssen Sie den Content-Stream berücksichtigen. – mkl
Ahh, das würde einige der Inkonsistenzen erklären, die ich zwischen Bildzählungen gefunden habe, als ich eine benutzerdefinierte Implementierung von PDFGraphicsStreamEngine zum Zählen von Bildern verwendet habe. Ich werde diesen Code untersuchen, um herauszufinden, was ich vermisse. Vielen Dank! –
Was ich im Sinn habe ist, das ExtractImages-Beispiel zu modifizieren und alles zu entfernen, was Image-Objekte erzeugt, und 'addOperator (new DrawObject());' mit einem 'DrawObject extends GraphicsOperatorProcessor'-Prozessor aufzurufen, der die xobjects nicht erzeugen würde, wenn es ein ist Bild aber würde Formen folgen. Siehe den Quellcode von org.apache.pdfbox.contentstream.operator.DrawObject. –