2017-07-02 4 views
0

Ich verwende iText 7 http://itextpdf.com/ Bibliotheken: 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 im Projekt, das setzt das Hintergrundbild der Dokumentseite und speichert mehrere ähnliche Seiten im selben Dokument (pdf-Datei). Die BilddateiiText 7 Lesehintergrundbild aus JAR-Datei

final String IMAGE = "/resources/image.jpg"; 

muss als Ressource in der JAR-Datei gespeichert werden. Das Imagedata Objekt erzeugt das Verfahren erstellen (java.awt.Image Bild, java.awt.Color Farbe) unter Verwendung von com.itextpdf.io.image.ImageDataFactory:

ImageData imgData = ImageDataFactory.create(new Main().loadImage(IMAGE), true); 

den Code des java.awt. image.BufferedImage loadimage (String imagefilename) Methode ist:

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; 
} 

die Imagedata Objekt wird in der Schleife verwendet:

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(); 

Das Problem ist, dass, nachdem ich das Programm von der jAR-Datei ausgeführt, habe ich ein pdf-Dokument, das ist mu ch größer, als wenn ich das Programm von IDE direkter Bildreferenz (81 Mbyte vs 9 MBytes für 17 seitiges Dokument) laufe:

ImageData imgData = ImageDataFactory.create("src/resources/image.jpg"); 

Wenn Sie ein Imagedata-Objekt aus der Bytes des Bildes erstellen die Methode erstellen mit (byte [] Bytes, boolean recoverImage) von com.itextpdf.io.image.ImageDataFactory:

ImageData imgData = ImageDataFactory.create(new Main().loadImageByte(IMAGE), true); 

und [use Byte] loadImageByte (String imagefilename) Methode:

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; 
} 

die si Das Ergebnis des resultierenden PDF-Dokuments ist klein, sowohl wenn Sie das Programm von der IDE ausführen, als auch wenn Sie von der JAR-Datei starten. Im letzteren Fall öffnet sich das Dokument jedoch nicht, Adobe Acrobat 9 gibt einen Fehler "Nicht genügend Daten für ein Bild" (und die Bytes beider Dokumente sind unterschiedlich).

Was ist der Grund für den Unterschied zwischen Dateigröße und ist es eine Möglichkeit, ein kleine Größe pdf-Dokument von Programm zu erhalten aus einer Jar-Datei zu beginnen?

+0

Ich müsste alles im Detail durchgehen, um sicher zu sein, aber eine mögliche Erklärung für verschiedene Dateigrößen ist, dass das Bild im Fall einer kleineren Größe einmal als XOBject gespeichert und im gesamten Dokument referenziert wird Bei der größeren Datei wird das Bild jedes Mal vollständig hinzugefügt. –

+0

In Bezug auf Ihren zweiten Versuch über 'loadImageByte' gehen Sie mit' is.available() 'vor, um die Größe der Ressourcendatei zu bestimmen. Dies ist jedoch falsch. 'Is.available()' könnte einen kleineren Wert zurückliefern, abhängig von der tatsächlich verwendeten 'InputStream' Klasse, und die tatsächlich verwendete' InputStream' Klasse könnte sich bei Läufen von IDE mit Ressourcen im Dateisystem unterscheiden und läuft von jar mit Ressourcen, die in einem JAR-Archiv komprimiert sind. – mkl

+0

Haben Sie die Bilddatei zur Reproduktion des Problems freigegeben? – mkl

Antwort

0

Das Problem wird durch die Verwendung PdfImageXObject gelöst Bilddaten zu wickeln:

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(); 
} 

Die Inspektion der resultierenden PDF-Dateien im PDFXplorer zeigt, dass, wenn Sie die gleiche Vordergrundbild auf das mit der mehrfach Document Objekt hinzufügen add(Image image) Methode werden die Bilder als Referenzen auf ein einzelnes PDF-XObject hinzugefügt. Gleichzeitig erstellt eine ähnliche Mehrfachaddition des Hintergrundbilds an das Objekt PdfCanvas mit der Methode addImage(ImageData image, Rectangle rect, boolean asInline) mehrere verschiedene PDF XObject-Instanzen. Achten Sie auf den Unterschied in den Argumenten dieser Methoden. Eine Analyse des iText 7-Bibliotheksquellcodes zeigte, dass die Klasse Image über ein Mitglied PdfXObject verfügt, das jedes Mal erstellt wird, wenn eine Image Instanz erstellt wird, die Klasse ImageData jedoch nicht mit der entsprechenden PdfXObject verknüpft ist.