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,

Другие вопросы по тегам