iText 7 считывает фоновое изображение из файла jar
Я использую iText 7 http://itextpdf.com/ library: itext7-io-7.0.2.jar, itext7-kernel-7.0.2.jar, itext7-layout-7.0.2.jar, slf4j-api-1.7.25.jar, slf4j-simple-1.7.25.jar в проекте, который устанавливает фоновое изображение страницы документа и сохраняет несколько похожих страниц в одном документе (pdf-файл). Файл изображения
final String IMAGE = "/resources/image.jpg";
должен храниться как ресурс в jar-файле. Объект ImageData создается с помощью метода create (java.awt.Image image, java.awt.Color color) из com.itextpdf.io.image.ImageDataFactory:
ImageData imgData = ImageDataFactory.create(new Main().loadImage(IMAGE), true);
Код метода java.awt.image.BufferedImage loadImage(String imageFilename):
private BufferedImage loadImage(String imageFilename) {
BufferedImage img = null;
try {
img = javax.imageio.ImageIO.read(getClass().getResourceAsStream(imageFilename));
} catch (IOException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
return img;
}
Объект ImageData используется в цикле:
Document document = ... (get Document object)
PdfDocument pdf = document.getPdfDocument();
PageSize pageSize = pdf.getDefaultPageSize();
PdfPage page = pdf.addNewPage();
for (int i = 0; i < documents.size(); i++) {
PdfCanvas canvas = new PdfCanvas(page);
canvas.addImage(imgData, pageSize, false);
... (add document body)
if (i < documents.size() - 1) {
page = pdf.addNewPage();
document.add(new AreaBreak(AreaBreakType.NEXT_PAGE));
}
}
document.close();
Проблема в том, что после запуска программы из jar-файла я получаю pdf-документ, который намного больше, чем когда я запускаю программу из IDE с использованием прямой ссылки на изображение (81 МБайт против 9 МБайт для 17-страничного документа):
ImageData imgData = ImageDataFactory.create("src/resources/image.jpg");
Если вы создаете объект ImageData из байтов изображения, используя метод create(byte[] bytes, boolean recoverImage) com.itextpdf.io.image.ImageDataFactory:
ImageData imgData = ImageDataFactory.create(new Main().loadImageByte(IMAGE), true);
и используйте метод byte[] loadImageByte(String imageFilename):
private byte[] loadImageByte(String imageFilename) {
byte[] dataBytes = null;
try {
InputStream is = getClass().getResourceAsStream(imageFilename);
dataBytes = new byte[is.available()];
is.read(dataBytes);
} catch (IOException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
return dataBytes;
}
Размер получающегося pdf-документа невелик как при запуске программы из IDE, так и при запуске из jar-файла. Однако в последнем случае документ не открывается, Adobe Acrobat 9 выдает ошибку "Недостаточно данных для изображения" (и байты обоих документов различаются).
В чем причина различий в размерах файлов и есть ли способ получить pdf-документ небольшого размера программой, начиная с jar-файла?
1 ответ
Проблема решается с помощью PdfImageXObject
обернуть данные изображения:
public static final String IMAGE = "/resources/image.jpg";
public static final String DEST = "result.pdf";
public static void main(String[] args) throws FileNotFoundException {
int pageNumber = 5;
PdfWriter writer = new PdfWriter(DEST);
PdfDocument pdf = new PdfDocument(writer);
Document document = new Document(pdf, PageSize.A4.rotate());
ImageData imgData = ImageDataFactory.create(new Main().loadImageByte(IMAGE), true);
/*Wrapping image data in a PdfImageXObject*/
PdfImageXObject imgObject = new PdfImageXObject(imgData);
/*Calculate the page area for the image - the image size will change*/
PageSize pageSize = pdf.getDefaultPageSize();
Rectangle rectangle = new Rectangle(pageSize.getWidth(), pageSize.getHeight());
/*Loop*/
PdfPage page = pdf.addNewPage();
for (int i = 0; i < pageNumber; i++) {
PdfCanvas canvas = new PdfCanvas(page);
/*Add background image as PdfImageXObject*/
canvas.addXObject(imgObject, rectangle);
(PDF building blocks adding)
if (i < pageNumber - 1) {
page = pdf.addNewPage();
document.add(new AreaBreak(AreaBreakType.NEXT_PAGE));
}
}
document.close();
}
Проверка полученных PDF-файлов в PDFXplorer показывает, что при добавлении того же изображения переднего плана к Document
возражать несколько раз с add(Image image)
метод, изображения добавляются как ссылки на один PDF XObject. В то же время аналогичное многократное добавление фонового изображения к PdfCanvas
объект с addImage(ImageData image, Rectangle rect, boolean asInline)
Метод создает несколько разных экземпляров PDF XObject. Обратите внимание на разницу в аргументах этих методов. Анализ исходного кода библиотеки iText 7 показал, что Image
класс имеет PdfXObject
член, который создается каждый раз, когда Image
экземпляр создан, но ImageData
класс не связан с соответствующим PdfXObject
,