## Drucken mit Java

+ andere TechDocs
+ Grafik mit Java
+

Ansteuerung eines Druckers von Java aus.

JDK Version 1.0 beinhaltete keinerlei Druckerunterstützung.
JDK Version 1.1 bot rudimentäre Druckerunterstützung mit der Klasse '`java.awt.PrintJob`'.
Mit J2SE Version 1.2 wurde das Package '`java.awt.print`' eingeführt.
Mit J2SE Version 1.3 wurden die Klassen '`JobAttributes`' und '`PageAttributes`' hinzugefügt.
Mit J2SE Version 1.4 wurde mit dem 'Java Print Service API' ('JPS') erweitert.

### Inhalt

1. Drucken mit JDK-1.1-Funktionen (AWT Printing API)
   1. Grundsätzliches
   2. JDK-1.1-Programmierbeispiel
2. Drucken mit dem J2SE-1.2-'print'-Package
   1. Grundsätzliches
   2. J2SE-1.2-Programmierbeispiel
3. Drucken mit den J2SE-1.4-'JPS'-Packages
   1. Grundsätzliches
   2. J2SE-1.4-Programmierbeispiel zum Drucken von Grafik
   3. J2SE-1.4-Programmierbeispiel zum Drucken eines Dokuments
4. 'Printable'-Hilfsklasse für die J2SE-Programmierbeispiele
5. PostScript, PDF und andere Dokumentformate lesen, schreiben und drucken

### Drucken mit JDK-1.1-Funktionen (AWT Printing API)

#### Grundsätzliches

Das JDK 1.1 bietet nur sehr rudimentäre Druckerunterstützung. Wie der 'Java-AWT-Printing'-Beschreibung entnommen werden kann, gibt es nur die eine Klasse '`java.awt.PrintJob`' und nur wenige Zusatzfunktionen. Die wichtigsten Funktionen sind:

`getToolkit().getPrintJob()` | Startet einen vom Betriebssystem abhängigen Dialog zu Druckereinstellungen und liefert '`PrintJob`'. Läuft nur in den Klassen `Components` und `Window` und daraus abgeleiteten Klassen (z.B. `Frame`).

`PrintJob.getPageResolution()`
`PrintJob.getPageDimension()`

'`getPageResolution()`' liefert die Druckauflösung in dpi (Dots per Inch).
'`getPageDimension()`' liefert die Größe der Papierseite in Pixeln.
Leider ist die Definition dieser Werte nicht einheitlich.
Mit neuen J2SE-Versionen und unter Windows 2000 werden meistens die tatsächlich beim Druck erreichbaren Werte für die Druckauflösung und die Pixelzahlen returniert (also z.B. 72 dpi und 595 x 842 Pixel). Daraus kann dann auch die Größe der Papierseite berechnet werden (z.B. 595 px / 72 dpi * 2,54 cm/Inch = 21 cm).
Bei älteren JDK-Versionen oder anderen Betriebssystemen wird eventuell die mit dem aktuellen Drucker theoretisch maximal mögliche Auflösung (z.B. 600 dpi) und die Zahl der Pixel für 72 dpi und US-Letter-Format returniert, obwohl in Bildschirmauflösung und auf eine andere Papiergröße gedruckt wird.
In beiden Fällen kann mit JDK-1.1-Funktionen leider nicht die hohe Auflösung des Druckers genutzt werden, sondern nur eine wesentlich kleinere (z.B. 72 dpi statt 600 dpi).

`PrintJob.getGraphics()` | Liefert ein '`Graphics`'-Objekt. Hierüber wird mit den üblichen AWT-Funktionen gezeichnet.
`Graphics.dispose()` | '`Graphics.dispose()`' startet das Ausdrucken der Seite.
`PrintJob.end()` | '`PrintJob.end()`' ist aufzurufen, wenn alle Seiten gedruckt wurden und der Druckjob beendet ist.

#### JDK-1.1-Programmierbeispiel

Das folgende Beispiel geht davon aus, dass '`PrintJob.getPageResolution()`' die für den Ausdruck korrekte Auflösung returniert. In anderen Fällen muss es angepasst werden.

Es werden zuerst einige ermittelte Werte ausgedruckt, dann ein Rahmen, der bei korrekten Werten 2 cm Abstand von allen vier Seiten einhält und zuletzt ein Kreis und zwei Linien, die etwas schräg verlaufen, um eine eventuelle Treppenstruktur zu verdeutlichen, falls die Auflösung des Druckers zu gering ist.

Da die Generierung des Bildes mit geringer Auflösung erfolgt, sind die gezeichneten Linien sehr breit. Die Beispiele der nächsten Kapitel zeichnen mit dünneren Linien.

Soll nicht (wie in diesem Beispiel) aus einer Java-Applikation, sondern aus einem im Browser betriebenen Java-Applet gedruckt werden, muss beachtet werden, dass dafür vorher die Sicherheitseinstellungen angepasst werden müssten.

    /* PrintWithJDK11.java: Drucken mit JDK-1.1-Funktionen */

    import java.awt.*;
    import java.awt.event.*;

    public class PrintWithJDK11 extends Frame
    {
      public static void main( String[] args )
      {
        PrintWithJDK11 wnd = new PrintWithJDK11( "Drucken mit JDK-1.1-Funktionen" );
        wnd.setSize( 500, 150 );
        wnd.setVisible( true );
      }

      public PrintWithJDK11( String sFensterTitel )
      {
        super( sFensterTitel );
        Button bttn = new Button( "Button betätigen, um Ausdruck einer Testseite zu starten ..." );
        add( BorderLayout.CENTER, bttn );
        bttn.addActionListener(
          new ActionListener() {
            public void actionPerformed( ActionEvent ev ) {
              druckeTestseite(); } } );
        addWindowListener(
          new WindowAdapter() {
            public void windowClosing( WindowEvent ev ) {
              dispose();
              System.exit( 0 ); } } );
      }

      void druckeTestseite()
      {
        PrintJob prjob = getToolkit().getPrintJob( this, "Testseite", null );
        if( null != prjob )
        {
          final int iScreenResol           = getToolkit().getScreenResolution();
          final int iPageResol             = prjob.getPageResolution();
          final Dimension dimScreenSize    = getToolkit().getScreenSize();
          final Dimension dimPageDimension = prjob.getPageDimension();
          Graphics pg = prjob.getGraphics();
          if( null != pg && 0 < iPageResol )
          {
            int iAddY = 20;
            int iRand = (int)Math.round( iPageResol * 2. / 2.54 );  // 2 cm Rand
            int iPosX = iRand + iRand/4;                            // Textposition
            int iPosY = iPosX - iAddY/2;
            int iWdth = dimPageDimension.width  - iRand * 2;        // innere Breite
            int iMidY = dimPageDimension.height / 2;
            pg.setFont( new Font( "SansSerif", Font.PLAIN, iAddY*2/3 ) );
            pg.drawString( "Betriebssystem: "
                           + System.getProperty( "os.name" ) + " "
                           + System.getProperty( "os.version" ), iPosX, iPosY+=iAddY );
            pg.drawString( "Java-Version: JDK "
                           + System.getProperty( "java.version" ), iPosX, iPosY+=iAddY );
            pg.drawString( "getScreenResolution: "
                           + iScreenResol + " dpi", iPosX, iPosY+=iAddY );
            pg.drawString( "getScreenSize: "
                           + dimScreenSize.width  + " x "
                           + dimScreenSize.height + " Pixel", iPosX, iPosY+=iAddY );
            pg.drawString( "PrintJob.getPageResolution: "
                           + iPageResol + " dpi", iPosX, iPosY+=iAddY );
            pg.drawString( "PrintJob.getPageDimension: "
                           + dimPageDimension.width  + " x "
                           + dimPageDimension.height + " Pixel", iPosX, iPosY+=iAddY );
            pg.drawString( "errechnete Papiergröße: "
                           + Math.round( 254. * dimPageDimension.width  / iPageResol / 10. ) + " x "
                           + Math.round( 254. * dimPageDimension.height / iPageResol / 10. ) + " mm",
                           iPosX, iPosY+=iAddY );
            pg.drawRect( iRand, iRand, iWdth, dimPageDimension.height - iRand * 2 );
            pg.drawLine( iRand, iMidY + iWdth/50, dimPageDimension.width - iRand, iMidY - iWdth/50 );
            pg.drawLine( iRand, iMidY - iWdth/50, dimPageDimension.width - iRand, iMidY + iWdth/50 );
            iWdth -= 4;
            pg.drawOval( iRand + 2, dimPageDimension.height - iRand - iWdth - 2, iWdth, iWdth );
            pg.dispose();
          }
          prjob.end();
        }
      }
    }

### Drucken mit dem J2SE-1.2-'print'-Package

#### Grundsätzliches

Mit J2SE Version 1.2 wurde das Package '`java.awt.print`' eingeführt.
Mit J2SE Version 1.3 wurden die Klassen '`JobAttributes`' und '`PageAttributes`' hinzugefügt.

Ausführlichere Beschreibungen finden Sie in 'Sun's Printing Tutorial' und in 'Sun's Programmer's Guide Printing'.
Weitere Hinweise finden Sie im 'Java Magazin' und im 'Linux-Magazin'.

Die Grundzüge der Java-2D-Grafik-Programmierung werden in 'Sun's Java 2D Homepage' und in 'Sun's Programmer's Guide to the Java 2D API' erläutert.

Das Package '`java.awt.print`' bietet folgende Interfaces und Klassen:

Interfaces
`Pageable` | Erleichtert die Verwaltung mehrseitiger Ausdrucke mit unterschiedlichen Papierformaten. Ist in '`Book`' implementiert.
`Printable` | Deklariert die zum Ausdrucken verwendete '`Printable.print()`'-Funktion und die Rückgabewerte '`PAGE_EXISTS`' und '`NO_SUCH_PAGE`'.
`PrinterGraphics` | Erweitert das der '`Printable.print()`'-Funktion übergebene '`Graphics`'-Objekt um die Funktion '`getPrinterJob()`'.
Klassen
`PrinterJob` | Kontrolliert das Ausdrucken. Eigenschaften des Druckers und der Papiergröße können erfragt und eingestellt werden. Bietet die Funktionen '`pageDialog()`' und '`printDialog()`', über die Dialoge des Betriebssystems zur Druckereinstellungen aufgerufen werden können.

`Paper`
`PageFormat`

'`Paper`' und '`PageFormat`' beschreiben die Größe und unbedruckbare Randbreite des Papiers.
'`Paper`' beschreibt das ursprüngliche Papier, während bei
'`PageFormat`' die eingestellte Orientierung (z.B. '`PORTRAIT`', '`LANDSCAPE`') berücksichtigt ist.
Beide Klassen verwenden als Einheit 1/72 Zoll (ca. 0,353 mm), das entspricht etwa einem typografischen Punkt.

`Book` | Implementiert '`Pageable`' und erleichtert die Verwaltung mehrseitiger Ausdrucke mit unterschiedlichen Papierformaten.
Mehrfach definierte Funktionen

`getPrinterJob()`

'`getPrinterJob()`' gibt es mehrfach.
Verwechseln Sie '`getPrinterJob()`' nicht mit dem oben verwendeten '`getPrintJob()`' (ohne '`er`') aus den Klassen '`java.awt.Toolkit`' und '`java.awt.PrintGraphics`'.
'`getPrinterJob()`' ist in der Klasse '`PrinterJob`' als statische Funktion enthalten und wird meist zu Beginn aufgerufen, im Beispiel unten im Konstruktor in der Zeile '`prjob = PrinterJob.getPrinterJob();`'.
Außerdem ist es im Interface '`PrinterGraphics`' enthalten, so dass auch in der '`Printable.print()`'-Funktion der '`PrinterJob`' ermittelt werden kann, im Beispiel unten in der Zeile:
`PrinterJob prjob = ((PrinterGraphics)g2).getPrinterJob();`

`print()`

Auch '`print()`' gibt es mehrfach.
Es ist in der Klasse '`PrinterJob`' enthalten (ohne Parameter) und initiiert den Ausdruckvorgang aller Seiten, im Beispiel unten aufgerufen in der Zeile '`prjob.print();`'.
Die eigentliche Generierung der einzelnen Druckseiten erfolgt in der durch das Interface '`Printable`' deklarierten Funktion:
`public int print( Graphics g, PageFormat pf, int page )`

#### J2SE-1.2-Programmierbeispiel

Der untenstehende Sourcecode wird in eine Datei mit dem Namen '`PrintWithJ2SE12.java`' gespeichert.
Zusätzlich muss sich im gleichen Verzeichnis die Datei '`MyPrintableObject.java`' befinden, deren Sourcecode unten im Kapitel 'Printable'-Hilfsklasse für die J2SE-Programmierbeispiele gezeigt ist und welche die zu druckende Grafik kreiert.

Kompiliert und gestartet wird mit:

`javac PrintWithJ2SE12.java java PrintWithJ2SE12 java PrintWithJ2SE12 1 noDialog `

Wird '`PrintWithJ2SE12`' ohne Parameter gestartet, werden zwei Dialoge zur Druckerkonfiguration aufgerufen und es wird versucht, mit 288 dpi eine Testseite zu drucken.
Als erster Parameter kann eine Integer-Zahl übergeben werden, welche als Multiplikator von 72 dpi die Druckauflösung ändert (1 = 72 dpi, 4 = 288 dpi, ...). Bei kleinen Werten erhöht sich die Breite der Linien. dpi-Werte höher als die physikalische Auflösung des Druckers machen natürlich keinen Sinn. Implementiert ist die Auflösungseinstellung im Beispiel durch die '`Graphics.scale()`'-Funktion in der Klasse '`MyPrintableObject`'.
Wird irgendetwas als zweiter Parameter übergeben, werden die Druckerkonfigurationsdialoge übergangen. Anders als bei den oben beschriebenen JDK-1.1-Druckfunktionen besteht bei den J2SE-Funktionen diese Möglichkeit. Nur so kann zum Beispiel von JSP (Java Server Pages) aus gedruckt werden.

    /* PrintWithJ2SE12.java: Drucken mit J2SE-1.2-Funktionen */

    import java.awt.print.*;

    public class PrintWithJ2SE12
    {
      private PrinterJob prjob;
      private PageFormat pfUse;

      public static void main( String[] args )
      {
        int iResMul = 4;  // 1 = 72 dpi; 4 = 288 dpi
        if( 0 < args.length )
          try { iResMul = Integer.parseInt( args[0] ); }
          catch( Exception ex ) { }
        PrintWithJ2SE12 myPrint = new PrintWithJ2SE12();
        if( 1 < args.length || myPrint.setupDialogs() )
          try {
            myPrint.print( iResMul );
          } catch( Exception ex ) {
            System.err.println( ex.getMessage() );
            System.exit( 1 );
          }
        System.exit( 0 );
      }

      public PrintWithJ2SE12()
      {
        prjob = PrinterJob.getPrinterJob();
        pfUse = prjob.defaultPage();
      }

      public boolean setupDialogs()
      {
        PageFormat pfDflt = pfUse;
        pfUse = prjob.pageDialog( pfDflt );
        return ( pfUse == pfDflt ) ? false : prjob.printDialog();
      }

      public void print( int iResMul )
      throws PrinterException
      {
        // See file MyPrintableObject.java:
        MyPrintableObject myPrObj = new MyPrintableObject();
        myPrObj.iResMul = iResMul;
        prjob.setPrintable( myPrObj, pfUse );
        prjob.print();
      }
    }

### Drucken mit den J2SE-1.4-'JPS'-Packages

#### Grundsätzliches

Mit J2SE Version 1.4 wurde mit dem 'Java Print Service API' ('JPS') erweitert. JPS besteht aus den vier Packages:
'`javax.print`', '`javax.print.attribute`', '`javax.print.attribute.standard`' und '`javax.print.event`'.

JPS benutzt weiterhin das '`java.awt.print`'-Package aus J2SE Version 1.2, schafft aber einen geordneten Überbau, um leichter Drucker mit passenden Eigenschaften zu finden und bestimmte Dokumenttypen einfacher drucken oder auch als Stream zum Beispiel in eine PostScript-Datei ausgeben zu können.

Es gibt sechs grundsätzlich verschiedene JPS-Mechanismen mit den im Folgenden genannten typischerweise verwendeten Funktionen:

| Drucken | Stream (z.B. in Datei)

2D-Grafik mit '`PrinterJob`':

`PrinterJob.getPrinterJob()
PrinterJob.setPrintable()
PrinterJob.lookupPrintServices()
PrinterJob.setPrintService()
PrinterJob.pageDialog()
PrinterJob.printDialog()
PrinterJob.print()
`

`PrinterJob.getPrinterJob()
PrinterJob.lookupStreamPrintServices()
StreamPrintServiceFactory.getPrintService()
PrinterJob.setPrintService()
PrinterJob.print()
`

2D-Grafik mit '`DocPrintJob`':

`DocFlavor.SERVICE_FORMATTED...
PrintServiceLookup
.lookupPrintServices()
PrintService.createPrintJob()
SimpleDoc(Printable,...)
DocPrintJob.print()
`

`DocFlavor.SERVICE_FORMATTED...
StreamPrintServiceFactory
.lookupStreamPrintServiceFactories()
StreamPrintServiceFactory.getPrintService()
StreamPrintService.createPrintJob()
SimpleDoc(Printable,...)
DocPrintJob.print()
`

Dokument mit '`DocPrintJob`'
(z.B. Text-, Bild-, PostScript-Datei):

`DocFlavor.INPUT_STREAM...
PrintServiceLookup
.lookupPrintServices()
PrintService.createPrintJob()
SimpleDoc(FileInputStream,...)
DocPrintJob.print()
`

`DocFlavor.INPUT_STREAM...
StreamPrintServiceFactory
.lookupStreamPrintServiceFactories()
StreamPrintServiceFactory.getPrintService()
StreamPrintService.createPrintJob()
SimpleDoc(FileInputStream,...)
DocPrintJob.print()
`

#### J2SE-1.4-Programmierbeispiel zum Drucken von Grafik

Der untenstehende Sourcecode wird in eine Datei mit dem Namen '`PrintWithJ2SE14Graphics.java`' gespeichert.
Zusätzlich muss sich im gleichen Verzeichnis die Datei '`MyPrintableObject.java`' befinden, deren Sourcecode unten im Kapitel 'Printable'-Hilfsklasse für die J2SE-Programmierbeispiele gezeigt ist und welche die zu druckende Grafik kreiert.

Kompiliert und gestartet wird mit:

`javac PrintWithJ2SE14Graphics.java java PrintWithJ2SE14Graphics java PrintWithJ2SE14Graphics 2 np java PrintWithJ2SE14Graphics ps `

'`PrintWithJ2SE14Graphics`' zeigt im Kommandozeilenfenster einen Text, der die möglichen Kommandozeilenparameter erklärt.

Bei der Funktion '`PrintServiceLookup.lookupPrintServices()`' ist eine Besonderheit zu beachten:
Falls einer der untersuchten Drucker nicht untersucht werden kann, etwa weil er sich nicht als bereit meldet, dann returniert diese Funktion nach einem TimeOut gar kein Ergebnis, obwohl andere Drucker vielleicht bereit waren. In diesem Fall verwendet der folgende Sourcecode den als 'Default' markierten Drucker.

Der folgende Beispiel-Sourcecode ist aus drei Gründen umfangreicher, als für reale Applikationen nötig wäre:

1.: Es wird viel im Kommandozeilenfenster angezeigt, um das Verständnis zu erleichtern.
2.: Die Kommandozeilenparameter müssen geparst werden.
3.: Es kann wahlweise sowohl als PostScript-Datei als auch auf dem Drucker ausgegeben werden.

    /* PrintWithJ2SE14Graphics.java: Drucken von Grafik mit J2SE 1.4 */

    import java.util.*;
    import java.io.*;
    import javax.print.*;
    import javax.print.attribute.*;
    import javax.print.attribute.standard.*;

    public class PrintWithJ2SE14Graphics
    {
      public static void main( String args[] )
      {
        new PrintWithJ2SE14Graphics( args );
      }

      public PrintWithJ2SE14Graphics( String args[] )
      {
        final String sCrLf              = System.getProperty( "line.separator" );
        final String sPrintFile         = "PrintFile.ps";
        final String sErrNoPrintService = sCrLf
                                        + "Es ist kein passender Print-Service installiert.";
        System.out.println(
          sCrLf + "Drucken eines Grafikobjekts entweder mit dem Drucker oder als PostScript-Datei."
        + sCrLf + "Ohne Kommandozeilenparameter werden alle gefundenen Print-Services aufgelistet"
        + sCrLf + "und ein Druckerdialog gestartet."
        + sCrLf + "Eine Zahl >= 0 steuert den zu dieser Zahl gehoerenden PrintService/Drucker an."
        + sCrLf + "Mit irgendeinem Buchstaben als Kommandozeilenparameter wird eine Ausgabedatei "
        + sCrLf + "im PostScript-Format erzeugt."
        + sCrLf + "Wird als zweiter Parameter np (no printing) angegeben, wird nicht gedruckt."
        + sCrLf );

        // Commandline parameter:
        String s2ndParm = null;    // second commandline parameter
        int idxPrintService = -1;  // -1 means: no parameter
        if( null != args && 0 < args.length )
        {
          // Check first commandline parameter (PrintService index):
          if( null != args[0] )
          {
            idxPrintService = -2;  // -2 means: not a number
            try {                  // nr means: PrintService index
              idxPrintService = Integer.parseInt( args[0] );
            }
            catch( Exception ex ) {
            }
          }
          // Check second commandline parameter ('np'):
          if( 1 < args.length )
            s2ndParm = args[1];
        }

        // Set DocFlavor and print attributes:
        DocFlavor flavor = DocFlavor.SERVICE_FORMATTED.PRINTABLE;
        PrintRequestAttributeSet aset = new HashPrintRequestAttributeSet();
        aset.add( MediaSizeName.ISO_A4 );

        try {

          if( -2 == idxPrintService )
          {
            // Print to Stream (here to PostScript File):
            StreamPrintServiceFactory[] prservFactories =
              StreamPrintServiceFactory.lookupStreamPrintServiceFactories(
                flavor, DocFlavor.BYTE_ARRAY.POSTSCRIPT.getMimeType() );
            if( null == prservFactories || 0 >= prservFactories.length )
            {
              System.err.println( sErrNoPrintService );
              System.exit( 2 );
            }
            System.out.println( "Stream-PrintService-Factory:" );
            for( int i=prservFactories.length-1; i>=0; i-- )
              System.out.println( "  " + prservFactories[i]
                                + " (" + prservFactories[i].getOutputFormat() + ")" );
            FileOutputStream   fos = new FileOutputStream( sPrintFile );
            StreamPrintService sps = prservFactories[0].getPrintService( fos );
            System.out.println( "Stream-PrintService:" );
            System.out.println( "  " + sps + " (" + sps.getOutputFormat() + ")" );
            printPrintServiceAttributesAndDocFlavors( sps );
            DocPrintJob pj = sps.createPrintJob();
            Doc doc = new SimpleDoc( new MyPrintableObject(), flavor, null );
            pj.print( doc, aset );
            fos.close();
            System.out.println( "Ausgabedatei '" + sPrintFile
                              + "' ist erfolgreich generiert." );
          }
          else
          {
            // Print to PrintService (e.g. to Printer):
            PrintService   prservDflt = PrintServiceLookup.lookupDefaultPrintService();
            PrintService[] prservices = PrintServiceLookup.lookupPrintServices( flavor, aset );
            if( null == prservices || 0 >= prservices.length )
              if( null != prservDflt )
              {
                System.err.println( "Nur Default-Printer, da lookupPrintServices fehlgeschlagen." );
                prservices = new PrintService[] { prservDflt };
              }
              else
              {
                System.err.println( sErrNoPrintService );
                System.exit( 3 );
              }
            System.out.println( "Print-Services:" );
            for( int i=0; i<prservices.length; i++ )
              System.out.println( "  " + i + ":  " + prservices[i] +
                                  (( prservDflt != null && prservDflt.equals( prservices[i] ) ) ? " (Default)" : "") );
            PrintService prserv = null;
            if( 0 <= idxPrintService && idxPrintService < prservices.length )
              prserv = prservices[idxPrintService];
            else
            {
              if( !Arrays.asList( prservices ).contains( prservDflt ) )  prservDflt = null;
              prserv = ServiceUI.printDialog( null, 50, 50, prservices, prservDflt, null, aset );
            }
            if( null != prserv )
            {
              System.out.println( "Ausgewaehlter Print-Service:" );
              System.out.println( "      " + prserv );
              printPrintServiceAttributesAndDocFlavors( prserv );
              if( null == s2ndParm || !s2ndParm.equalsIgnoreCase( "np" ) )
              {
                DocPrintJob pj = prserv.createPrintJob();
                Doc doc = new SimpleDoc( new MyPrintableObject(), flavor, null );
                pj.print( doc, aset );
                System.out.println( "Grafik ist erfolgreich gedruckt." );
              }
            }
          }

        } catch( PrintException pe ) {
          System.err.println( pe );
        } catch( IOException ie ) {
          System.err.println( ie );
        }
        System.exit( 0 );
      }

      private void printPrintServiceAttributesAndDocFlavors( PrintService prserv )
      {
        String s1=null, s2;
        Attribute[] prattr = prserv.getAttributes().toArray();
        DocFlavor[] prdcfl = prserv.getSupportedDocFlavors();
        if( null != prattr && 0 < prattr.length )
          for( int i=0; i<prattr.length; i++ )
            System.out.println( "      PrintService-Attribute["+i+"]: "
                                + prattr[i].getName() + " = " + prattr[i] );
        if( null != prdcfl && 0 < prdcfl.length )
          for( int i=0; i<prdcfl.length; i++ )
          {
            s2 = prdcfl[i].getMimeType();
            if( null != s2 && !s2.equals( s1 ) )
              System.out.println( "      PrintService-DocFlavor-Mime["+i+"]: " + s2 );
            s1 = s2;
          }
      }
    }

#### J2SE-1.4-Programmierbeispiel zum Drucken eines Dokuments

Mit JPS können bestimmte Dateitypen sehr einfach gedruckt werden, ohne dass die Druckgrafik manuell erzeugt werden muss.
Gibt es für den gewünschten Dateityp einen passenden 'StreamPrintService', kann die Datei unbearbeitet diesem übergeben werden und entweder auf dem Drucker ausgegeben oder zum Beispiel als PostScript-Datei gespeichert werden. Fehlt der passende 'StreamPrintService', gibt es die Fehlermeldung: 'invalid flavor'.

Die Dateiformate JPEG, PNG und GIF können fast immer so gedruckt werden, manchmal auch TXT und PostScript, aber HTML, PDF und andere nur in Sonderfällen. Für welche Dateiformate 'StreamPrintServices' zur Verfügung stehen, hängt vom Betriebssystem, den installierten Druckertreibern und von der Java-Implementierung ab. Zum Beispiel Unterstützung für PostScript gibt es defaultmäßig unter den modernen Linux-Installationen, aber nicht bei einfachen Windows-Installationen ohne zusätzliche Treiber.

    /* PrintWithJ2SE14Document.java: Drucken eines Dokuments mit J2SE 1.4 */

    import java.util.*;
    import java.io.*;
    import javax.print.*;
    import javax.print.attribute.*;
    import javax.print.attribute.standard.*;

    public class PrintWithJ2SE14Document
    {

      public static void main( String args[] )
      {
        new PrintWithJ2SE14Document( args );
      }

      public PrintWithJ2SE14Document( String args[] )
      {
        final String sErrNoPrintService =
          "\nZu diesem Dateityp ist kein passender Print-Service installiert.";
        final String sPrintFile = "PrintFile.ps";
        final String[] ssFileExtensionsAccepted =
          { "JPEG", "JPG", "PNG", "GIF", "TXT", "HTM", "HTML", "PS", "PDF" };
        final DocFlavor[] docFlavorsAccepted =
          { DocFlavor.INPUT_STREAM.JPEG, DocFlavor.INPUT_STREAM.JPEG,
            DocFlavor.INPUT_STREAM.PNG,  DocFlavor.INPUT_STREAM.GIF,
            DocFlavor.INPUT_STREAM.TEXT_PLAIN_HOST,
            DocFlavor.INPUT_STREAM.TEXT_HTML_HOST,
            DocFlavor.INPUT_STREAM.TEXT_HTML_HOST,
            DocFlavor.INPUT_STREAM.POSTSCRIPT,
            DocFlavor.INPUT_STREAM.PDF };
        DocFlavor flavor = null;
        int i, idxPrintService=-1;

        // Check first commandline parameter (input file):
        if( null != args && 0 < args.length && null != args[0]
            && 0 < (i = args[0].lastIndexOf( '.' )) )
        {
          String sInputFilenameExtension = args[0].substring( ++i ).toUpperCase();
          for( i=0; i<ssFileExtensionsAccepted.length; i++ )
            if( ssFileExtensionsAccepted[i].equals( sInputFilenameExtension ) )
            {
              flavor = docFlavorsAccepted[i];
              break;
            }
        }
        if( null == flavor )
        {
          System.out.println( "Drucken eines Dokuments entweder mit dem Drucker oder "
                            + "als PostScript-Datei." );
          System.out.println( "Erster Kommandozeilenparameter: Dokument-Datei." );
          System.out.println( "Erlaubt sind die Dateitypen:" );
          System.out.print(   "  " + ssFileExtensionsAccepted[0] );
          for( i=1; i<ssFileExtensionsAccepted.length; i++ )
            System.out.print( ", " + ssFileExtensionsAccepted[i] );
          System.out.println( "." );
          System.out.println( "Ohne zweiten Parameter wird eine Ausgabedatei im "
                            + "PostScript-Format erzeugt." );
          System.out.println( "Eine Zahl >= 0 als zweiter Parameter steuert den zu "
                            + "dieser Nummer gehoerenden " );
          System.out.println( "Print-Service (z.B. Drucker) an." );
          System.exit( 1 );
        }
        System.out.println( "" );
        System.out.println( "Eingangsdatei '" + args[0] + "':" );
        System.out.println( "  MIME-Typ '" + flavor.getMimeType() + "'" );

        // Check second commandline parameter (PrintService index):
        if( 1 < args.length )
          try {
            idxPrintService = Integer.parseInt( args[1] );
          }
          catch( Exception ex ) {
          }

        // Set print attributes:
        PrintRequestAttributeSet aset = new HashPrintRequestAttributeSet();
        aset.add( MediaSizeName.ISO_A4 );

        try {

          if( 0 > idxPrintService )
          {
            // Print to Stream (here to PostScript File):
            StreamPrintServiceFactory[] prservFactories =
              StreamPrintServiceFactory.lookupStreamPrintServiceFactories(
                flavor, DocFlavor.BYTE_ARRAY.POSTSCRIPT.getMimeType() );
            if( null == prservFactories || 0 >= prservFactories.length )
            {
              System.err.println( sErrNoPrintService );
              System.exit( 2 );
            }
            System.out.println( "Stream-PrintService-Factory:" );
            for( i=prservFactories.length-1; i>=0; i-- )
              System.out.println( "  " + prservFactories[i]
                                + " (" + prservFactories[i].getOutputFormat() + ")" );
            FileOutputStream   fos = new FileOutputStream( sPrintFile );
            StreamPrintService sps = prservFactories[0].getPrintService( fos );
            System.out.println( "Stream-PrintService:" );
            System.out.println( "  " + sps + " (" + sps.getOutputFormat() + ")" );
            printPrintServiceAttributesAndDocFlavors( sps );
            DocPrintJob pj = sps.createPrintJob();
            FileInputStream fis = new FileInputStream( args[0] );
            Doc doc = new SimpleDoc( fis, flavor, null );
            pj.print( doc, aset );
            fos.close();
            System.out.println( "Ausgabedatei '" + sPrintFile
                              + "' ist erfolgreich generiert." );
          }
          else
          {
            // Print to PrintService (e.g. to Printer):
            PrintService   prservDflt = PrintServiceLookup.lookupDefaultPrintService();
            PrintService[] prservices = PrintServiceLookup.lookupPrintServices( flavor, aset );
            if( null == prservices || 0 >= prservices.length )
              if( null != prservDflt )
              {
                System.err.println( "Nur Default-Printer, da lookupPrintServices fehlgeschlagen." );
                prservices = new PrintService[] { prservDflt };
              }
              else
              {
                System.err.println( sErrNoPrintService );
                System.exit( 3 );
              }
            System.out.println( "Print-Services:" );
            for( i=0; i<prservices.length; i++ )
              System.out.println( "  " + i + ":  " + prservices[i] +
                                  (( prservDflt != null && prservDflt.equals( prservices[i] ) ) ? " (Default)" : "") );
            PrintService prserv = null;
            if( 0 <= idxPrintService && idxPrintService < prservices.length )
              prserv = prservices[idxPrintService];
            else
            {
              if( !Arrays.asList( prservices ).contains( prservDflt ) )  prservDflt = null;
              prserv = ServiceUI.printDialog( null, 50, 50, prservices, prservDflt, null, aset );
            }
            if( null != prserv )
            {
              System.out.println( "Ausgewaehlter Print-Service:" );
              System.out.println( "      " + prserv );
              printPrintServiceAttributesAndDocFlavors( prserv );
              DocPrintJob pj = prserv.createPrintJob();
              FileInputStream fis = new FileInputStream( args[0] );
              Doc doc = new SimpleDoc( fis, flavor, null );
              pj.print( doc, aset );
              System.out.println( "Dokument '" + args[0] + "' ist erfolgreich gedruckt." );
            }
          }

        } catch( PrintException pe ) {
          System.err.println( pe );
        } catch( IOException ie ) {
          System.err.println( ie );
        }
        System.exit( 0 );
      }

      private void printPrintServiceAttributesAndDocFlavors( PrintService prserv )
      {
        String s1=null, s2;
        Attribute[] prattr = prserv.getAttributes().toArray();
        DocFlavor[] prdfl  = prserv.getSupportedDocFlavors();
        if( null != prattr && 0 < prattr.length )
          for( int i=0; i<prattr.length; i++ )
            System.out.println( "      PrintService-Attribute["+i+"]: "
                                + prattr[i].getName() + " = " + prattr[i] );
        if( null != prdfl && 0 < prdfl.length )
          for( int i=0; i<prdfl.length; i++ )
          {
            s2 = prdfl[i].getMimeType();
            if( null != s2 && !s2.equals( s1 ) )
              System.out.println( "      PrintService-DocFlavor-Mime["+i+"]: " + s2 );
            s1 = s2;
          }
      }
    }

### 'Printable'-Hilfsklasse für die J2SE-Programmierbeispiele

Die im Folgenden gezeigte das Interface '`Printable`' implementierende Hilfsklasse wird in mehreren der vorangegangenen J2SE-Programmierbeispielen benutzt.

Speichern Sie den Sourcecode in der Datei '`MyPrintableObject.java`' im gleichen Verzeichnis wie das J2SE-Programmierbeispiel.

    /* MyPrintableObject.java: Printable-Hilfsklasse für J2SE-Programmierbeispiele */

    import java.awt.*;
    import java.awt.print.*;

    public class MyPrintableObject implements Printable
    {
      public int iResMul = 4;  // 1 = 72 dpi; 4 = 288 dpi

      @Override
      public int print( Graphics g, PageFormat pf, int iPage )
      throws PrinterException
      {
        final int    FONTSIZE = 12;
        final double PNT_MM   = 25.4 / 72.;
        if( 0 != iPage )
          return NO_SUCH_PAGE;
        try {
          int iPosX = 1;
          int iPosY = 1;
          int iAddY = FONTSIZE * 3/2 * iResMul;
          int iWdth = (int)Math.round( pf.getImageableWidth()  * iResMul ) - 3;
          int iHght = (int)Math.round( pf.getImageableHeight() * iResMul ) - 3;
          int iCrcl = Math.min( iWdth, iHght ) - 4 * iResMul;
          Graphics2D g2    = (Graphics2D)g;
          PrinterJob prjob = ((PrinterGraphics)g2).getPrinterJob();
          g2.translate( pf.getImageableX(), pf.getImageableY() );
          g2.scale( 1.0 / iResMul, 1.0 / iResMul );
          g2.setFont( new Font( "SansSerif", Font.PLAIN, FONTSIZE * iResMul ) );
          g2.setColor( Color.black );
          g2.drawRect( iPosX, iPosY, iWdth, iHght );
          g2.drawLine( iPosX, iHght/2 + iWdth/50, iPosX + iWdth, iHght/2 - iWdth/50 );
          g2.drawLine( iPosX, iHght/2 - iWdth/50, iPosX + iWdth, iHght/2 + iWdth/50 );
          g2.drawOval( iPosX + 2*iResMul, iHght - iCrcl - 2*iResMul, iCrcl, iCrcl );
          iPosX += iAddY;
          iPosY += iAddY / 2;
          g2.drawString( "PrinterJob-UserName: " + prjob.getUserName(),
                         iPosX, iPosY+=iAddY );
          g2.drawString( "Betriebssystem: "
                         + System.getProperty( "os.name" ) + " "
                         + System.getProperty( "os.version" ), iPosX, iPosY+=iAddY );
          g2.drawString( "Java-Version: JDK "
                         + System.getProperty( "java.version" ), iPosX, iPosY+=iAddY );
          g2.drawString( "Width/Height: "
                         + dbldgt( pf.getWidth() )  + " / "
                         + dbldgt( pf.getHeight() ) + " points = "
                         + dbldgt( pf.getWidth()  * PNT_MM ) + " / "
                         + dbldgt( pf.getHeight() * PNT_MM ) + " mm",
                         iPosX, iPosY+=iAddY );
          g2.drawString( "Imageable Width/Height: "
                         + dbldgt( pf.getImageableWidth() )  + " / "
                         + dbldgt( pf.getImageableHeight() ) + " points = "
                         + dbldgt( pf.getImageableWidth()  * PNT_MM ) + " / "
                         + dbldgt( pf.getImageableHeight() * PNT_MM ) + " mm",
                         iPosX, iPosY+=iAddY );
          g2.drawString( "Imageable X/Y: "
                         + dbldgt( pf.getImageableX() ) + " / "
                         + dbldgt( pf.getImageableY() ) + " points = "
                         + dbldgt( pf.getImageableX() * PNT_MM ) + " / "
                         + dbldgt( pf.getImageableY() * PNT_MM ) + " mm",
                         iPosX, iPosY+=iAddY );
          g2.drawString( "versuchte Druckauflösung: "
                         + 72 * iResMul + " dpi", iPosX, iPosY+=iAddY );
        } catch( Exception ex ) {
          throw new PrinterException( ex.getMessage() );
        }
        return PAGE_EXISTS;
      }

      private static double dbldgt( double d )
      {
        return Math.round( d * 10. ) / 10.;  // show one digit after point
      }
    }

### PostScript, PDF und andere Dokumentformate lesen, schreiben und drucken

Java-Hilfstools zum Lesen und Schreiben von PostScript- und PDF-Dateien (Adobe Portable Document Format) sowie anderen Dokumentformaten sind aufgelistet unter:
http://schmidt.devlib.org/java/document-libraries.html.

Der Ausdruck von PDF-Dateien ist zum Beispiel möglich mit PDFBox (http://www.pdfbox.org).

Weitere Themen: andere TechDocs | Grafikausgabe mit Java
© 1998-2007 Torsten Horn, Aachen