PDF-Generierung (itext) - läuft unter Eclipse, bei har aber leere Seite

Tueftler

Mitglied
Hallo zusammen,
Meine Anwendung mit itext 7 erzeugt mit Daten aus einer Datenbank automatisch PDFs, die ich mit dem Acrobat-Reader anzeige. Unter Eclipse erzeugte PDFs lassen sich fehlerfrei anzeigen, sobald ich die Applikation jedoch in eine Executable Jar umwandle meldet derAcrobat Reader, dass die Seite leer ist. Ein Pfadproblem kann das nicht sein, denn ein unter Eclipse erzeugtes PDF wird von der Jar überschrieben. Hat jemand einen Ansatzpunkt zum Suchen des Fehlers oder, besser noch, eine Lösung? Könnte das eventuell mit dem Text file encoding (eingestellt ist utf8) zusammenhängen?
 
Hier nun der Code zu der eingangs gestellten Frage, der unter Eclipse einwandfrei läuft:
Java:
public class Formular {
    private PdfWriter writer;
    private PdfReader reader;
    private Document doc;
    private PdfDocument pdf;
    private PageSize ps;
    private PdfPage page;
    private PdfCanvas canvas;
    private float xpunkt,ypunkt;
    private String DEST;
    private String SRC="rsc/BlankoRechnung.pdf";
    private PdfAcroForm form;
    private Rectangle pageSize;
    private Map<String, PdfFormField> felder;
    private float len;
    private PdfFont font=null,bold;
    private float rand=43f;
    private boolean mail;
    private String kunde,strasse,ort,rechnr,rechdat,netto,mwst;
    private String,ende1,ende2;
    private ArrayList orders;
    private ArrayList<String>allFontsList=new ArrayList<String>();
    private String fontPath=null;
    private String AvenirBold,AvenirMedium,AvenirRegular;

    public Formular(boolean mail,String DEST,ArrayList arr) {
        // Nur, damit ich die Übersicht behalte
        kunde=""+arr.get(0);    
        strasse=""+arr.get(1);
        ort=""+arr.get(2);  
        rechnr=""+arr.get(3);  
        rechdat=""+arr.get(4);
        orders=(ArrayList)arr.get(5);
        netto=""+arr.get(6);
        mwst=""+arr.get(7);
        betrag=""+arr.get(8);
        ende1=""+arr.get(9);
        ende2=""+arr.get(10);
        this.DEST=DEST;
        this.mail=mail;
        try {
            writer = new PdfWriter(DEST);
            if(mail)    {
                reader = new PdfReader(SRC);
                pdf = new PdfDocument(reader,writer);
            }else pdf = new PdfDocument(writer);
            ps=PageSize.A4;
            doc = new Document(pdf,ps);
            doc.setMargins(20, 20, 20, 20);
            if(iniFont()) manipulierePdf();
            doc.close();
        } catch (Exception e) {e.printStackTrace();}   
    }
    private boolean iniFont() {
        boolean fontOk=false;
        java.net.URL fontUrl = this.getClass().getClassLoader().getResource("rsc/Avenir_Next.ttc");
        if (fontUrl != null) {
            fontOk=true;
            fontPath=fontUrl.getPath();
            AvenirBold=fontPath+",0";
            AvenirMedium=fontPath+",5";
            AvenirRegular=fontPath+",7";
          try {
                    TrueTypeCollection ttcObject=new TrueTypeCollection(fontPath);
                    for(int i=0;i<ttcObject.getTTCSize();i++) {
                        FontProgram fontp=ttcObject.getFontByTccIndex(i);
                        FontNames namen=fontp.getFontNames();
                        allFontsList.add(namen.getFontName());
                    }
            } catch (IOException e) {e.printStackTrace();}
        } else {
            new Messagebox("AvenirFonts nicht gefunden!","PDFs konnten nicht erstellt werden");
        }
        return fontOk;
    }

    private void setText(float xpos,float ypos,float schriftSize,String schrift,String txt) throws IOException{
        canvas.beginText().setFontAndSize(PdfFontFactory.createFont(schrift), schriftSize)
            .moveText(xpos, pageSize.getHeight() - ypos)
            .showText(txt)
            .endText();
    }

    private void setLine(float xpos,float ypos,float bigLen) throws IOException{
        canvas.setStrokeColor(Color.BLACK)
                .setLineWidth(.2f)
                .moveTo(xpos, pageSize.getHeight() - ypos)
                .lineTo(xpos+bigLen,pageSize.getHeight() -  ypos).stroke();
    }

    private void manipulierePdf() throws IOException{
        float ypos=0f;
            ypos=154f;
            PdfPage page = null;
            if(mail) {
                page = pdf.getPage(1);
                pageSize = page.getPageSize();
            }else {
                page = pdf.addNewPage(ps);
                pageSize = ps;
            }
            canvas = new PdfCanvas(page);
            setText(85f,154f,11f,AvenirRegular,kunde);
            ypos+=14F;
            setText(85f,168f,11f,AvenirRegular,strasse);
            ypos+=15F;
            setText(85f,ypos,11f,AvenirRegular,ort);
            String dateStr="Ort den "+rechdat;
            float txtLen=getLen(dateStr,1);
            float xpos=pageSize.getWidth()-txtLen-rand;
            ypos=257F;
            setText(xpos,ypos,11f,AvenirRegular,dateStr);
            ypos=320f;
            setText(85f,ypos,18f,AvenirMedium,"Rechnung");
            setText(175f,ypos,11f,AvenirMedium,rechnr);

            // Draw orders
           ypos=345.5f;
           boolean multiOrder=(orders.size()>1)?true:false;
           float bigLen=0F;
           for(Object o: orders) {
                ArrayList order=(ArrayList)o;
                ypos+=16.5F;
                String posten=""+order.get(0);
                String preis=""+order.get(1);
                xpos=85f;
                setText(xpos,ypos,11f,AvenirRegular,posten);
                txtLen=getLen(preis,1);
                if(txtLen>bigLen)bigLen=txtLen;
                xpos=pageSize.getWidth()-txtLen-rand;
                setText(xpos,ypos,11f,AvenirRegular,preis);
        }
        if(multiOrder) {
            ypos+=8f;
            bigLen+=12f;
            xpos=pageSize.getWidth()-bigLen-rand;
            setLine(xpos,ypos,bigLen);
            ypos+=16.5f;
            xpos=373f;
            setText(xpos,ypos,11f,AvenirRegular,"Summe");
            txtLen=getLen(netto,1);
            if(txtLen>bigLen)bigLen=txtLen;
            xpos=pageSize.getWidth()-txtLen-rand;
            setText(xpos,ypos,11f,AvenirRegular,netto);
        }
        ypos+=24f;
        xpos=373f;
        setText(xpos,ypos,11f,AvenirRegular,"+ 19 % MwSt.");
        String mst=mwst;
        txtLen=getLen(mst,1);
        xpos=pageSize.getWidth()-txtLen-rand;
        setText(xpos,ypos,11f,AvenirRegular,mst);
        ypos+=8f;
        xpos=pageSize.getWidth()-bigLen-rand;
        setLine(xpos,ypos,bigLen);
        ypos+=16.5f;
        xpos=373f;
        setText(xpos,ypos,11f,AvenirBold,"Gesamtsumme");
        String ges=""+betrag;
        txtLen=getLen(ges,2);
        xpos=pageSize.getWidth()-txtLen-rand;
        setText(xpos,ypos,11f,AvenirBold,ges);
        txtLen=getLen(ges,2);
        if((txtLen+12f)>bigLen)bigLen=txtLen+12f;
        xpos=pageSize.getWidth()-bigLen-rand;
        ypos+=8f;
        setLine(xpos,ypos,bigLen);
        ypos+=4f;
        setLine(xpos,ypos,bigLen);
        ypos+=100f;
        xpos=85f;
        setText(xpos,ypos,11f,AvenirRegular,ende1);
        ypos+=14f;
        setText(xpos,ypos,11f,AvenirRegular,ende2);
       
        //Draw watermark
        Paragraph p = new Paragraph("Dummy-Rechnung").setFontSize(60);
        canvas.saveState();
        PdfExtGState gs1 = new PdfExtGState().setFillOpacity(0.2f);
        canvas.setExtGState(gs1);
        doc.showTextAligned(p,
                pageSize.getWidth() / 2, pageSize.getHeight() / 2,
                pdf.getPageNumber(page),
                TextAlignment.CENTER, VerticalAlignment.MIDDLE, 45);
        canvas.restoreState();
    }

    private String getDatum() {
        LocalDate localDate = LocalDate.now();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy");
        return new String("Aßling, den "+localDate.format(formatter));
    }
    private float getLen(String txt,int schrift) {
        PdfFont font;
        float t=0.0f;
        try {
            if(schrift==2)font = PdfFontFactory.createFont(AvenirBold, true);
            else font = PdfFontFactory.createFont(AvenirRegular, true);
            GlyphLine glyphLine = font.createGlyphLine(txt);
            int width = 0;
            for (int i = 0; i < glyphLine.size(); i++){
                Glyph glyph = glyphLine.get(i);
                width += glyph.getWidth();
            }
            t = width * 11.0f / 1000.0f;
        } catch (IOException e) {e.printStackTrace();}
        return t;
    }

    public static void viewPdf(String datei) {
        try {
            Desktop desktop = Desktop.getDesktop();
            if (desktop != null && desktop.isSupported(Desktop.Action.OPEN)) {
                desktop.open(new File(datei));
            } else {
                System.err.println("PDF-Datei kann nicht angezeigt werden!");
            }
        } catch (IOException ex) {ex.printStackTrace();}
    }
}
 
schau dir mal die Examples an!

Step 2!!
Java:
// step 1
       // Specifying the page size
       Document document = new Document(PageSize.LETTER);
       // step 2
       PdfWriter.getInstance(document, new FileOutputStream(RESULT));
       // step 3
       document.open();
       // step 4
       document.add(new Paragraph("Hello World"));
       // step 5
       document.close();
 
Yo no hablo alemán...

schau seinen code an und schau dir das tutorial an...
- PdfWriter greift auf die Instanz ... er erstellt ein object
- Document wird verwenden ... er verwendet PdfDocument
...

ob das hilft oder nicht kann ich nicht sagen da ich die lib iText nicht kenne...
 
Yo no hablo alemán...

schau seinen code an und schau dir das tutorial an...
- PdfWriter greift auf die Instanz ... er erstellt ein object
- Document wird verwenden ... er verwendet PdfDocument
...

ob das hilft oder nicht kann ich nicht sagen da ich die lib iText nicht kenne...
Bravo, du hast ein Beispiel gefunden, welches nichts mit seinem Code zu tun hat 😛
 
sehe ich das richtig, dass die Rechnung im Artefakt der Anwendung liegen soll?

Code:
 private String SRC="rsc/BlankoRechnung.pdf";

es scheint mir ein Pfad und/bzw. ein Rechteproblem vorzuliegen.
Was passiert, wenn du als Pfad einen spezifischen String wie: C:\\temp\\BlankoRechnung.pdf nutzt?
 
Grad gesehen, das Blanko-Pdf lädst du gar nicht als Resource, nur den Font...

Wenn beides eine Resource ist, solltest du beides so laden (und auf die richtigen Pfade achten und Vorliegen in der jar achten) - wenn nicht, solltest du sichergehen, das der relativen Pfad auch stimmt.
 
Nein, ein Pfadproblem kann das nicht sein, weil:
1. ich erstelle ein PDF, sagen wir 'test.pdf' im Verzeichnis 'pdfs' unter eclipse. Resultat: Das Ergebnis ist fehlerlos und im Reader anzeigbar.
2. Aus dem unveränderten Code mach ich ebenfalls unter eclipse einen executable File und wiederhole die Generierung des PDFs. Resultat: im Verzeichnis 'pdfs' hat die Datei 'test.pdf' nun 0 Bytes.
Dies ist beliebig oft reproduzierbar: Mit eclipse alles ok, mit der jar 0 Bytes.
Es macht auch keinen Unterschied, ob ich ein vorhandenes pdf manipuliere oder ein neues erstelle (mein Code macht je nach Übergabeparameter das eine oder das andere).Es ist auch egal, ob die pdf-Sourcedatei Bestandteil des jars ist oder nicht, ob ich mit dem Classloader arbeite oder nicht. Nicht die Source ist das Problem, sondern die Destination-Datei (auch dann, wenn keine Source geladen wird). Das pdf wird zwar korrekt im Dateiensystem abgelegt, mit eclipse aber auch gefüllt, mit jar jedoch nicht.
 
Zuletzt bearbeitet:
Bibliotheken sind auch alle korrekt geladen, wenn das "executable" jar ausgeführt wird?

maven oder eigene Zusammenstellung?

Vergiss nicht, Eclipse ist eine IDE und nicht nur ein Editor....
 
Der Unterschied Zwischen Ausführen mit Eclipse und Ausführen als Jar sind die Pfade, von denen geladen wird - Ich würde fast meine Hand ins Feuer legen, das das Problem dort liegt 😉

Zumindest die Fonts werden immer geladen - und für die macht es sehr wohl einen Unterschied, wie sie geladen werden.

Gibt es denn irgendwelche Exceptions?
 
Die iText 7 jars hab ich zwar von Hand in den BuildPath gesetzt,unter eclipse gibt es jedoch keinerlei exceptions. Aussichtsreicher scheint mir der Hinweis auf die Fonts/Rechte. Zur Zeit entwickle ich auf einem mac von dessen OS und der Schriftenverwaltung ich so gut wie keine Ahnung habe. Ich hab aber mal gehört, dass die Rechte an den Schriften rechnergebunden sind. Es kann daher sein, dass ich eine Kopie einer Schrift zwar in ein Package packen kann und die dann auch da läuft, im jar aber nicht, weil die ja sonst portable wäre. Weiss jemand, wie ich für itext 7 die Verweise auf die Originalschriften korrekt codiere?Kleine Schwierigkeit: Mein Programm ist eine Client-Server-Anwendung.Die Schriften gibts auf allen Clients,ich weiss aber nicht, ob die überall gleich organisiert sind (ob die Pfade überall gleich sind).
 
unter eclipse gibt es jedoch keinerlei exceptions.
Natürlich nicht, da läuft es ja auch...

Aussichtsreicher scheint mir der Hinweis auf die Fonts/Rechte.
Den Font lädst du aus der Jar - aber liegt der überhaupt in der jar und wird er daraus richtig geladen?

Das könnte das Problem sein, nicht irgendwelche Rechte.

Erweiter das Programm mal um ein paar Debug-Ausgaben (über Standardausgabe, nicht irgendwie grafisch), dann kann man etwas besser sehen, was passiert.
 
Deshalb habe ich ja den Hinweis gegeben, dass er doch mal bitte einen genauen Pfad, ala C:\\temp... angeben soll und nicht src\....pdf

Wenn du aus dem Jar als Ressource lesen willst, heißt das:
Code:
ClassLoader classLoader = getClass().getClassLoader();
    File file = new File(classLoader.getResource(fileName).getFile());
 
Hab ne LOG-Datei für alle catches angelegt. Damit hab ich den Fehler gefunden:
Font file file:/Applications/myApplication/my.jar!/rsc/Avenir_Next.ttc not found.Font
Das 'Warum' bleibt immer noch unklar.Ebenso: Wo kommt das Ausrufezeichen hinter dem Namen der Jar her?
(mrBrown hat die Wette gewonnen)
 
Das warum: die Dateien werden nicht in die Jar gepackt oder der Pfad ist falsch. vermutlich, weil Eclipse sie nicht passend erkennt oder weil rsc der Resourcen-Ordner ist und nicht im Resourcen-Ordner liegt.

Das Ausrufezeichen: das ist nur das Kennzeichnen des Pfades, dass dort die Pfade innerhalb der jar beginnen
 
Zuletzt bearbeitet:
er lädt es nicht als Ressource... siehe Quelltext.....

Die Exception verrät, dass der Pfad bestimmt nicht passt.

:/Applications/myApplication/my.jar!/rsc/Avenir_Next.ttc not found.Font
 
Zuletzt bearbeitet:
ich hab mal bei Java was nachgelesen....

Bundling Physical Fonts with Your Application
Sometimes, an application cannot depend on a font being installed on the system, usually because the font is a custom font that is not otherwise available. In this case, you must bundle the font files with your application.

Use one of these methods to create a Font object from an existing physical font:

Font java.awt.Font.createFont(int fontFormat, InputStream in);
Font java.awt.Font.createFont(int fontFormat, File fontFile);

To create a Font object from a TrueType font, the formal parameter fontFormat must be the constant Font.TRUETYPE_FONT. The following example creates a Font object from the TrueType font file A.ttf:

Font font = Font.createFont(Font.TRUETYPE_FONT, new File("A.ttf"));

Accessing the font directly from a file is simpler and more convenient. However, you might require an InputStream object if your code is unable to access file system resources, or if the font is packaged in a Java Archive (JAR) file along with the rest of the application or applet.

The createFont method creates a new Font object with a point size of 1 and style PLAIN. This base font can then be used with the Font.deriveFont methods to derive new Font objects with varying sizes, styles, transforms and font features. For example:

try {
//Returned font is of pt size 1
Font font = Font.createFont(Font.TRUETYPE_FONT, new File("A.ttf"));

//Derive and return a 12 pt version:
//Need to use float otherwise
//it would be interpreted as style

return font.deriveFont(12f);

} catch (IOException|FontFormatException e) {
// Handle exception
}
 
Manuel.R:
Erst einmal vielen Dank für Deine Mühe. Mir scheint, das ist zwar eine Lösung, nur nicht für mein Problem; denn hier wird beschrieben, wie man Exotenschriften (etwa den Coca Cola Schriftzug) für alle user der Application verfügbar macht. Dass das eine TrueType-Schrift ist, ist hier wohl eher Zufall.Außerdem: Als itext- und mac-Neuling gehe ich noch unsicher mit den TrueTypeCollections (nicht TrueTypeFonts) um, die mir bei Entwicklungen unter Windows noch nicht untergekommen sind. Ich fürchte, dass es mir auch nicht hilft, einen AWT-Font zu generieren, weil ich nicht weiss, ob itext mit diesen Fonts überhaupt was anfangen kann.
Die Schrift-Collection hab ich jetzt testhalber mal in das Image-Package getan und sowohl ein Bild als auch die FontCollection geladen. Dazu habe ich folgende Befehle geschrieben:
URL fontUrl = ClassLoader.getSystemResource( "img/fontCollectionName" );
URL imgUrl = ClassLoader.getSystemResource( "img/bildName" );
Das Resultat: Das Bild wird geladen, der Font nicht.
Ich stricke den Ladevorgang mal auf einen inputStream um, wenn das hilft, schreib ich die Lösung hier rein, wenn nicht, leg ich die Schrift einfach auf den Server und lade von dort.
 
Das Resultat: Das Bild wird geladen, der Font nicht.
Ich stricke den Ladevorgang mal auf einen inputStream um, wenn das hilft, schreib ich die Lösung hier rein, wenn nicht, leg ich die Schrift einfach auf den Server und lade von dort.
Relevant ist der Teil nach dem getResource 😉

In deiner ursprünglichen Variante machst du ein File daraus - vermutlich liegt es daran.
 
In deiner ursprünglichen Variante machst du ein File daraus - vermutlich liegt es daran.
Nö, in meiner ursprünglichen Variante mach ich ein URL-Object, extrahiere den Path als String, den ich an den Konstruktor der iText-Klasse TrueTypeCollection übergebe. Der Konstruktor dieser Klasse kann statt des Strings auch ein byte[] vertragen. Der Unterschied: Mit URL (wie auch mit File) übergebe ich gleichsam nur eine Referenz auf den Speicherort an den Konstruktor, mit byte[] die tatsächlichen Daten. By the way, hab den getResource tatsächlich auch mit File getestet.file.exists() gab false zurück. Meine Schlussfolgerung: Das Problem liegt NICHT nach getResource, sondern getResource ist das Problem. Deshalb ist mein Vorhaben jetzt: die ttc Datei in einen ByteStream laden, den Stream in ein Array umwandeln und das an den Konstruktor übergeben.
 
Problem gefunden. Der Fehler war weder in java noch in itext, sondern: Offenbar sind Adobe-Schriften doch geschützt, mit anderen Schriften läuft auch die jar einwandfrei.
 
Problem gefunden. Der Fehler war weder in java noch in itext, sondern: Offenbar sind Adobe-Schriften doch geschützt, mit anderen Schriften läuft auch die jar einwandfrei.
Das klingt nicht nach dem eigentlichem Fehler - vor allem lief es ja in Eclipse problemlos und die Fehlermeldung enthält ein "file ... not found". Aber wenns jetzt klappt 😉

Nö, in meiner ursprünglichen Variante mach ich ein URL-Object, extrahiere den Path als String
Stimmt, mea culpa 😉 kommt aber aufs gleiche hinaus

Der Konstruktor dieser Klasse kann statt des Strings auch ein byte[] vertragen. Der Unterschied: Mit URL (wie auch mit File) übergebe ich gleichsam nur eine Referenz auf den Speicherort an den Konstruktor, mit byte[] die tatsächlichen Daten. By the way, hab den getResource tatsächlich auch mit File getestet.file.exists() gab false zurück. Meine Schlussfolgerung: Das Problem liegt NICHT nach getResource, sondern getResource ist das Problem. Deshalb ist mein Vorhaben jetzt: die ttc Datei in einen ByteStream laden, den Stream in ein Array umwandeln und das an den Konstruktor übergeben.
Wenn getResource fehlschlägt, würde auch getResourceAsStream fehlschlagen.
Das getResource nicht fehlschlägt, sieht man daran, dass die zurückgegebene URL nicht null ist. Das Problem lag also danach (und das "danach" mein dem Umgang mit der URL) 😉
 

Zurück
Oben