# PDF-Generierung und Drucken



## Skyzen (31. Dez 2013)

Hallo alle zusammen,
ich bin noch ein Java-Anfänger und bin neu hier im Forum, habe mir aber schon oft Beiträge hier durch gelesen. Bevor jetzt die Kommentare kommen, in anderen Posts erst einmal zu schauen und Google zu verwenden, das habe ich zu diesen Problemen, die ich hier habe die letzten drei Tage gemacht und keine für mich optimale Lösung gefunden oder eine welche ich verstanden habe.

*Grundsätzlich über das Programm:*
Ich habe ein Programm geschrieben, welches mir auf der GUI Daten aus einer Datenbank in einer Tabelle ausgibt. Es gibt außerdem die Buttons Speichern und Drucken. Bei Speichern kann der Anwender über einen FileChooser den Pfad wählen, an welchen dann eine PDF-Datei mit der Tabelle angelegt wird.
Beim Drucken möchte ich, dass der Standard-Druck-Dialog auf geht, in welchem der Anwender den gewünschten Drucken auswählen kann und dann das PDF-File gedruckt wird. Hierbei soll dieses aber nicht gespeichert werden, also habe ich es mir so vorgestellt, auch ein PDF-File der Tabelle zu generieren und automatisch in einen temp-Ordner oder so ähnlich zu speichern, dieses dann über einen Druck-Dialog zu drucken, und anschließend das File wieder zu löschen.
Für die PDF-Generierung habe ich in Eclipse, im Java Build Path, die Libraries für iText 5.4.5 geladen.

*1. Frage:*
Die PDF-Generierung funktioniert, wenn ich das Programm in Eclipse ausführ, einwandfrei, doch wenn ich eine runable -jar Datei erzeuge und das Programm darüber ausführ, funktioniert die PDF-Generierung nicht, besser gesagt das Fenster öffnet sich erst garnicht, aber wenn ich den Inhalt meiner Methode createPDF() auskommentier und damit eine jar-Datei erzeug, öffnet sich das Fenster. Insofern gehe ich davon aus, dass es irgendein Problem mit meiner createPDF() Methode gibt. 
Hat das was mit den Libraries zu tun oder an was liegt das sonst, da es ja funktioniert, wenn ich es über Eclipse ausführen lass?
Hier der Programmausschnitt meiner Methode createPDF():


```
private void createPDF(final File file) { 
        Thread t = new Thread() {
        	@Override
			public void run() {
        		tabelle = new PdfPTable(myTableModel.getColumnCount()); 
	            tabelle.setWidthPercentage(100); 
	            tabelle.getDefaultCell().enableBorderSide(Rectangle.BOX); 
	            
	            // Titel 
	            df = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT); 
	            head = new Paragraph("Tabelle - " + df.format(new GregorianCalendar().getTime()), new Font(FontFamily.HELVETICA, 14, Font.BOLD)); 
	            head.setSpacingAfter(15f);
	            
                // Spaltentitel 
                for (int i = 0; i < colNames.length; i++) { 
                    cell = new PdfPCell(new Phrase(colNames[i], new Font(FontFamily.HELVETICA, 10))); 
                    cell.setBackgroundColor(BaseColor.LIGHT_GRAY); 
                    tabelle.addCell(cell); 
                }
                
                // Tabelleninhalt 
                for (int colCnt = myTableModel.getColumnCount(), rowCnt = myTableModel.getRowCount(), i = 0; i < rowCnt; i++) { 
                    for (int j = 0; j < colCnt; j++) { 
                        try{
	                    	String value = myTableModel.getValueAt(i, j).toString();
	                    	tabelle.addCell(new Phrase(value, new Font(FontFamily.HELVETICA, 10)));
                        } catch (NullPointerException e) {
                        	tabelle.addCell(new Phrase("", new Font(FontFamily.HELVETICA, 10)));
                        }
                    } 
                } 

                document = new Document(PageSize.A4, 20, 20, 15, 15);
                try {
                    PdfWriter.getInstance(document, new FileOutputStream(file));
                    document.open();
                    document.add(head);
                    document.add(tabelle);
                    document.close();
                } catch (DocumentException e) { 
                    e.printStackTrace(); 
                } catch (FileNotFoundException e) {
					e.printStackTrace();
				}
            }
        }; 
        t.start();
	}
```

*2. Frage:*
Welche Funktion verwendet man am besten zum Drucken? Ich bin zum einen auf PrintJob gestoßen, da hatte ich aber das Problem dass ich nicht wusste, wie ich diesem mein PDF-File zum Drucken übergeben kann. Ich denk mir dass das irgendwie gehen *muss*, aber ich hab absolut nichts gefunden. Wahrscheinlich war ich einfach zu dumm dafür. Weiß einer wie das geht oder gibt es einen besseren Weg?


```
file = new File("temp/print.pdf");
	createPDF(file);
	PrinterJob pj = PrinterJob.getPrinterJob();
	if (pj.printDialog()) {
		try {
			pj.print();
		}
		catch (IOException e) {
			e.printStackTrace();
		}
	}
	file.delete();
```

*3. Frage:*
Da ich mit dem PrintJob nicht weiter gekommen bin, mach ich es über folgenden Dialog, das funktioniert auch, nur leider wenn ich dann Drucke, wird das PDF-File auch geöffnet, was ich nicht möchte.


```
file = new File("temp/print.pdf");
	createPDF(file);
	Desktop.getDesktop().print(file);
```

Es wär echt klasse wenn mir jemand weiter helfen könnte


----------



## Fab1 (31. Dez 2013)

zur 1. Frage: Grundsätzlich wird bei einer Runnable Jar alle .jars automatisch mit eingebunden. (per Jar in Jar Loader), daher vermute ich mal nicht das es daran liegt. Ich könnte mir vorstellen, dass das übergebene File Objekt vielleicht Null ist. Das kann eventuell an einem fehlerhaften Pfad liegen, der zwar in Eclipse funktioniert, aber in der Jar dann halt nicht mehr.

Um dies zu überprüfen würde ich deine .jar mal mit der Console starten. Sollte mit 
	
	
	
	





```
java -jar deineJar.jar
```
 funktionieren. Hierbei würde man in der Console dann auch eine entsprechende Fehlermeldung sehen. Alternativ könnte man die System.err Ausgaben auch in eine Textdatei umleiten. Hierfür muss eben mit System (Java Platform SE 7 ) ein anderer Stream übergeben werden. Mit Console starten wäre aber einfacher.

Zu deinen Anderen Fragen kann ich leider nichts sagen. Ich hätte auch die getDestop().print() Methode verwendet. Viel Erfolg weiterhin bei deiner Suche.


----------



## Emperiz (31. Dez 2013)

Kleine Notiz zur Funktionsweise:
Alternativ könntest du auch den (Um)weg über die Auszeichnungssprache "LaTeX" gehen. Die ist wie z.B. HTML auch leicht zu erlernen.

Du würdest dann im Grunde nur ein kleines Frontend für die Sprache in Java schreiben. Sprich: Textdatei mit LaTeX-Code erzeugen und kompilieren. Fertig ist das PDF.

Vorteil ist, dass man LaTeX auch sonst immer mal gebrauchen kann. Sei es für Arbeiten oder Präsentationen. Nützt dir also auch außerhalb deines Projektes etwas.
Klarer Nachteil wäre natürlich, dass der LaTeX-Compiler auf dem Einsatzsystem installiert sein muss.


----------



## Skyzen (3. Jan 2014)

@Fab1:
Danke für den Tipp, damit konnte ich schon mal ausschließen, dass das File Null ist das ich übergebe. Habe den Konstruktor der Methode createPDF() mal leer gelassen und den Filepath in der Methode deklarirt, so dass es mir die PDF immer auf dem Desktop speichert. 
ABER dadurch dass ich es dann mal über die Konsole ausgeführt habe ist folgende Fehlermeldung gekommen:







Also wenn ich das richtig interprtiere hat es doch etwas mit den PDF-Libraries zu tun die ich importier oder? Oder liegt es an etwas anderem und was kann ich jetzt dagegen machen?

@Emperiz:
Danke für den Tipp, aber dafür habe ich leider gerade keine Zeit und Lust mich in was neues einzuarbeiten.


----------



## Manfred (3. Jan 2014)

Hallo!
Das Coding hier sollte den Druck eines PDFs erledigen!

```
import java.io.File;
import java.io.FileInputStream;

import javax.print.Doc;
import javax.print.DocFlavor;
import javax.print.DocPrintJob;
import javax.print.PrintService;
import javax.print.PrintServiceLookup;
import javax.print.SimpleDoc;

public class PDFPrint {
    public static void main(String[] args) throws Exception {
    	File file = new File("C:\\file.pdf");
    	String printername = "Druckername hier her";
    	new PDFPrint().printPdf(file, printername);
    	System.out.println("Fertig");
    }
 
    public void printPdf(File file, String printername) throws Exception{
    	DocFlavor flavor = DocFlavor.INPUT_STREAM.AUTOSENSE;
        PrintService[] services = PrintServiceLookup.lookupPrintServices(flavor, null);
        FileInputStream psStream = new FileInputStream(file);  
  
        if (services.length > 0)
        {
            PrintService myService = null;
            for(PrintService service : services) {
                System.out.println(service.getName());
                if(service.getName().contains(printername)) {
                    myService = service;
                    break;
                }
            }
            if(myService==null)
            	System.out.println("Printer not found");
            else{
	            DocPrintJob printJob = myService.createPrintJob();
	            Doc document = new SimpleDoc(psStream, flavor, null);
	            printJob.print(document, null);
            }
        }
        else
        {
            System.out.println("No PDF printer available.");
        }
    }
}
```
lg
Manfred


----------



## Manfred (3. Jan 2014)

Skyzen hat gesagt.:


> @Fab1:
> Danke für den Tipp, damit konnte ich schon mal ausschließen, dass das File Null ist das ich übergebe. Habe den Konstruktor der Methode createPDF() mal leer gelassen und den Filepath in der Methode deklarirt, so dass es mir die PDF immer auf dem Desktop speichert.
> ABER dadurch dass ich es dann mal über die Konsole ausgeführt habe ist folgende Fehlermeldung gekommen:
> 
> ...



Eindeutig fehlt das iText.jar im JAR File! Sieh mal nach direkt im exportierten JAR ob es drinnen ist! Falls du mit Eclipse arbeitest, nimm "Export runnable JAR" diese nimmt alle verlinkten Bibliotheken mit in das Jar!


----------



## Skyzen (4. Jan 2014)

@Manfred:
Vielen Dank für deinen zweiten Tipp mit der runable Jar-Datei, da werden tatsächlich alle Libraries mit übernommen und das Programm läuft 
Zu deinem ersten Tipp bzgl. des Drucks, das muss ich noch ausprobieren, melde mich dann nochmal


----------



## Skyzen (4. Jan 2014)

@Manfred:
Ich habe das jetzt mal mit deiner Variante zum Drucken versucht.
Folgende Methode drucken() wird bei Button-Klick ausgeführt:

```
private void drucken(){
	file = new File("temp/print.pdf");
    DocFlavor flavor = DocFlavor.INPUT_STREAM.AUTOSENSE;
    PrintService[] services = PrintServiceLookup.lookupPrintServices(flavor, null);
        
	try {
		psStream = new FileInputStream(file);
	} catch (FileNotFoundException e) {
		e.printStackTrace();
	}  
  
	PrinterJob pj = PrinterJob.getPrinterJob();
	String printername = "";
	if(pj.printDialog()){
		printername = pj.getPrintService().getName();
	}
        
    if(services.length > 0){
        PrintService myService = null;
        for(PrintService service : services) {
            if(service.getName().contains(printername)) {
                 myService = service;
                 break;
            }
        }
        if(myService == null){
            System.out.println("Printer not found");
        } else{
            DocPrintJob printJob = myService.createPrintJob();
            Doc document = new SimpleDoc(psStream, flavor, null);
            try {
			    printJob.print(document, null);
	        } catch (PrintException e) {
			    e.printStackTrace();
		    }
        }
    } else{
        System.out.println("No PDF printer available.");
    }
}
```
Ich hatte deine Methode ein bisschen abgeändert. Ich habe keine Parameter mehr, sondern deklarier das Attribut file in der Methode und das Attribut printername deklarier ich, indem ich erst einen Drucker-Dialog öffne, in welchem ich meinen Drucken auswähl und den Namen dann in printername speicher.
Leider druckt es mir das File noch nicht aus, aber ich glaub der Drucker reagiert darauf, da er nämlich angefängt zu arbeiten, wenn ich die Drucken-Methode ausführe, indem er die Aufwärmphase des Druckers gestartet hat.
Insofern ist meine Vermutung, dass es irgend etwas mit dem File zu tun hat und es liegt *sicher* nicht an meinem Pfad und in der PDF-Datei steht auch eine Tabelle drin, denn wenn ich die folgende Syntax in meine Druck-Methode schreib, zieht es sich das selbe File und druckt es aus. (Nur will ich diese Lösung ja nicht haben, da damit ja auch immer die PDF-Datei geöffnet wird.)

```
file = new File("temp/print.pdf");
createPDF(file);
PrinterJob pjo = PrinterJob.getPrinterJob();
		
if (pjo.printDialog()) {
	try {
		Desktop.getDesktop().print(file);
	} catch (IOException e) {
		e.printStackTrace();
	}
}
```
Ich hatte mir noch gedacht es mal zu versuchen in Zeile 3 anstatt:

```
DocFlavor flavor = DocFlavor.INPUT_STREAM.AUTOSENSE;
```
ein PDF zu übergeben

```
DocFlavor flavor = DocFlavor.INPUT_STREAM.PDF;
```
aber das hat auch nicht funktioniert.

Weiß vllt noch jemand an was es liegen kann, oder was ich noch falsch habe? Denn ich glaub mit der Variante bin ich auf dem richtigen Weg wenn ich mich nicht irre


----------



## Manfred (7. Jan 2014)

Wenn du die Klasse, so wie ich sie gepostet habe ausführst, gehts dann auch nicht?


----------



## Skyzen (7. Jan 2014)

Hey, also ich hab das als erstes probiert, des funktioniert auch nicht. Habe es jetzt nochmal identisch mit deiner Klasse gemacht, nur den Filepath und den Printername geändert:

```
import java.io.File;
import java.io.FileInputStream;
import javax.print.Doc;
import javax.print.DocFlavor;
import javax.print.DocPrintJob;
import javax.print.PrintService;
import javax.print.PrintServiceLookup;
import javax.print.SimpleDoc;
 
public class PDFPrint {
    public static void main(String[] args) throws Exception {
        File file = new File("temp/print.pdf");
        String printername = "Samsung SCX-4x21 Series";
        new PDFPrint().printPdf(file, printername);
        System.out.println("Fertig");
    }
 
    public void printPdf(File file, String printername) throws Exception{
        DocFlavor flavor = DocFlavor.INPUT_STREAM.AUTOSENSE;
        PrintService[] services = PrintServiceLookup.lookupPrintServices(flavor, null);
        FileInputStream psStream = new FileInputStream(file);  
  
        if (services.length > 0)
        {
            PrintService myService = null;
            for(PrintService service : services) {
                System.out.println(service.getName());
                if(service.getName().contains(printername)) {
                    myService = service;
                    break;
                }
            }
            if(myService==null)
                System.out.println("Printer not found");
            else{
                DocPrintJob printJob = myService.createPrintJob();
                Doc document = new SimpleDoc(psStream, flavor, null);
                printJob.print(document, null);
            }
        }
        else
        {
            System.out.println("No PDF printer available.");
        }
    }
}
```
Hab wieder das gleiche Problem, und zwar reagiert der Drucker irgendwie auf die Anfrage, denn er startet mit der Aufwärmphase 
Weiß echt nicht an was es liegen kann finde auch absolut nichts brauchbares dazu 
Fällt dir vllt noch was gutes ein oder weißt du an was das liegt?


----------



## Manfred (9. Jan 2014)

Seltsam, bei mir funktioniert das so!
Andere Lösungen würden eine Software z.B. von qoppa benötigen, die du aber kaufen musst!


----------



## Skyzen (9. Jan 2014)

Nachdem ich die letzten Tage wieder damit verbracht habe nach einer Lösung zu suchen, ist mir aufgefallen, dass deine Variante so auf jeden Fall die richtige ist. Warum es noch nicht funktioniert bin ich mir nicht sicher, denn ich habe mal ein ähnlichen Programm-Code von jemandem im Forum getestet, bei welchem aber ein Bild mit Format "PNG" gedruckt wird und das funktioniert einwandfrei, aber wenn ich das auf "PDF" abänder habe ich wieder das gleiche Problem, der Drucker startet den Druckvorgang aber druckt dann nichts.
Hier mal der andere Programmcode zum drucken eines PNG-Bilds:

```
public static void main(String[] args) throws Exception {
        File file = new File("uhr.png");
        printPDF(file);
    }

    public static void printPDF(File file) {
        PrintRequestAttributeSet pras = new HashPrintRequestAttributeSet();
        DocFlavor flavor = DocFlavor.INPUT_STREAM.GIF;
        PrintService printService[] = PrintServiceLookup.lookupPrintServices(flavor, pras);
        PrintService defaultService = PrintServiceLookup.lookupDefaultPrintService();
        PrintService service = ServiceUI.printDialog(null, 200, 200, printService, defaultService, flavor, pras);
        if (service != null) {
            DocPrintJob job = service.createPrintJob();
            FileInputStream fis;
            try {
                fis = new FileInputStream(file);
                DocAttributeSet das = new HashDocAttributeSet();
                Doc doc = new SimpleDoc(fis, flavor, das);
                job.print(doc, pras);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
```

Ich bin noch auf eins gestoßen bei meinen weiteren Nachforschungen. Und zwar funktioniert das drucken von Bildern mit dieser Methode wohl einwandfrei und das drucken von PDF auch, solange man es nicht auf Windows macht, haben manche festgestellt. 

@Manfred: Kann es sein, dass du es nicht auf einem Windows Betriebssystem gemacht hast?


----------

