PDFBox блокирует входной файл JPEG до выхода из приложения
Я использую PDFBox RC2 в среде Windows 7, Java 1.8_66. Я использую его для создания PDF-файла из коллекции файлов изображений размером 200 точек на дюйм, как JPEG, так и PNG.
Оказывается, что при добавлении файлов JPEG в PDF, подпрограмме PDImageXObject.createFromFile() не удается закрыть дескриптор внутреннего файла, таким образом блокируя файл изображения на время существования приложения. При добавлении файлов PNG в PDF проблем нет.
Вот пример кода, который воспроизводит проблему. Используя проводник процессов (из sysinternals), просмотрите дескрипторы открытых файлов для процесса java.exe и запустите этот код. Мой тест использует около 20 полноразмерных файлов JPEG. Обратите внимание, что после выхода из метода несколько заблокированных файлов все еще остаются позади.
public Boolean CreateFromImages_Broken(String pdfFilename, String[] imageFilenames) {
PDDocument doc = new PDDocument();
for (String imageFilename : imageFilenames) {
try {
PDPage page = new PDPage();
doc.addPage(page);
PDImageXObject pdImage = PDImageXObject.createFromFile(imageFilename, doc);
// at this point, if the imageFilename is a jpeg, pdImage holds onto a handle for
// the given imageFilename and that file remains locked until the application is closed
try (PDPageContentStream contentStream = new PDPageContentStream(doc, page)) {
float scale = (float)72.0 / 200;
page.setMediaBox(new PDRectangle((int)(pdImage.getWidth() * scale), (int)(pdImage.getHeight() * scale)));
contentStream.drawImage(pdImage, 0, 0, pdImage.getWidth()*scale, pdImage.getHeight()*scale);
}
} catch (IOException ioe) {
return false;
}
}
try {
doc.save(pdfFilename);
doc.close();
} catch (IOException ex) {
return false;
}
return true;
}
1 ответ
В качестве обходного пути я рассмотрел исходный код для обработки PNG и JPEG, и мне удалось реализовать его, что, похоже, работает для обоих типов файлов:
public Boolean CreateFromImages_FIXED(String pdfFilename, String[] imageFilenames) {
PDDocument doc = new PDDocument();
for (String imageFilename : imageFilenames) {
FileInputStream fis = null;
try {
PDPage page = new PDPage();
doc.addPage(page);
PDImageXObject pdImage = null;
// work around JPEG issue by opening up our own stream, with which
// we can close ourselves instead of PDFBOX leaking it. For PNG
// images, the createFromFile seems to be OK
if (imageFilename.toLowerCase().endsWith(".jpg")) {
fis = new FileInputStream(new File(imageFilename));
pdImage = JPEGFactory.createFromStream(doc, fis);
} else {
pdImage = PDImageXObject.createFromFile(imageFilename, doc);
}
try (PDPageContentStream contentStream = new PDPageContentStream(doc, page)) {
float scale = (float)72.0 / 200;
page.setMediaBox(new PDRectangle((int)(pdImage.getWidth() * scale), (int)(pdImage.getHeight() * scale)));
contentStream.drawImage(pdImage, 0, 0, pdImage.getWidth()*scale, pdImage.getHeight()*scale);
if (fis != null) {
fis.close();
fis = null;
}
}
} catch (IOException ioe) {
return false;
}
}
try {
doc.save(pdfFilename);
doc.close();
} catch (IOException ex) {
return false;
}
return true;
}