Skip to main content

By clicking Submit, you agree to the developerWorks terms of use.

The first time you sign into developerWorks, a profile is created for you. Select information in your profile (name, country/region, and company) is displayed to the public and will accompany any content you post. You may update your IBM account at any time.

All information submitted is secure.

  • Close [x]

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerworks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

By clicking Submit, you agree to the developerWorks terms of use.

All information submitted is secure.

  • Close [x]

Magic with Merlin: Printing in JDK 1.4, Part 1

The new Java Print Service API offers a happy ending to the Java printing saga

John Zukowski (jaz@zukowski.net), President, JZ Ventures, Inc., JZ Ventures, Inc.
John Zukowski
John Zukowski does strategic Java consulting for JZ Ventures, Inc.. His latest book is "Java Collections" (Apress, May 2001).

Summary:  It seems like every new release of the Java platform since 1.1 has brought changes to the platform's printing support framework. Merlin is no exception. In this month's Magic with Merlin, John Zukowski begins a two-part discussion of the latest capabilities.

View more content in this series

Date:  01 Mar 2002
Level:  Introductory
Also available in:   Japanese

Activity:  18248 views
Comments:  

If you've been working with the Java platform for some time, you're probably as frustrated as I am by the endless succession of changes to the print API. Merlin brings yet another set of print capabilities and techniques to the Java platform. Dubbed the Java Print Service API, this latest iteration has been working its way through the Java Community Process since 1999. Fortunately, the new API is a positive addition and should represent the final significant change to printing support for some time.

Printing with the new Print Service API involves a three-part process of discovery, specification, and printing. An optional fourth part involves notification as a printing task progresses. All the classes and interfaces we'll be working with in this article are in the javax.print package or one of its subpackages (see Resources).

Locating a printer

The first step to executing a print job is to identify the printer or set of printers you want to print to. Printer objects are called print services, and the identification process is called a lookup. The support class for the lookup task is aptly named PrintServiceLookup. To look up the print service, you would use one of the three methods shown in Listing 1.


Listing 1. Looking up a print service
  public static final PrintService 
    lookupDefaultPrintService()
  public static final PrintService[] 
    lookupPrintServices(DocFlavor flavor, AttributeSet attributes)
  public static final MultiDocPrintService[] 
    lookupMultiDocPrintServices(DocFlavor[] flavors, 
        AttributeSet attributes)

Each of the three methods shown is used for a different task:

  • lookupDefaultPrintService() returns the default print service.

  • lookupPrintServices() returns the set of printers that support printing a specific document type (such as GIF) with a specific set of attributes (such as two sided).

  • lookupMultiDocPrintServices() provides support for printing multiple documents at once.

After you've located the print service you want to use, you need to create a print job. You'll later send output to this job. The PrintService returned by the lookup can be used to create the job with its createPrintJob() method, as shown here:

  PrintService printService = 
    PrintServiceLookup.lookupDefaultPrintService();
  DocPrintJob job = printService.createPrintJob();


Specifying the output format

In addition to specifying where to print, you must specify the format of your print documents. This is where the DocFlavor class (or one of its subclasses) will come in handy. The DocFlavor class is used to identify the MIME (Multipurpose Internet Mail Extensions) type of the object you want to print. The MIME type describes how electronic data should be interpreted. You may have run across MIME types when working with e-mail and attachments, but the MIME specification describes a more general-purpose mechanism for identifying data forms.

Merlin provides seven subclasses of DocFlavor as inner classes of itself to define formats. These classes can be broken up into three subsets of MIME types: byte-oriented, character-oriented, and service-oriented. The byte-oriented flavors are:

  • BYTE_ARRAY
  • INPUT_STREAM
  • URL

The character-oriented ones are:

  • CHAR_ARRAY
  • READER
  • STRING

And the service-oriented inner class is SERVICE_FORMATTED.

Inner classes within inner classes

Each flavor type supports its own set of MIME types. These MIME types are defined, yet again, as inner classes. There are 19 byte-oriented flavors, as follows:

  • AUTOSENSE
  • GIF
  • JPEG
  • PCL
  • PDF
  • PNG
  • POSTSCRIPT
  • TEXT_HTML_HOST
  • TEXT_HTML_US_ASCII
  • TEXT_HTML_UTF_16
  • TEXT_HTML_UTF_16BE
  • TEXT_HTML_UTF_16LE
  • TEXT_HTML_UTF_8
  • TEXT_PLAIN_HOST
  • TEXT_PLAIN_US_ASCII
  • TEXT_PLAIN_UTF_16
  • TEXT_PLAIN_UTF_16BE
  • TEXT_PLAIN_UTF_16LE
  • TEXT_PLAIN_UTF_8

The character-oriented streams are less dramatic, providing just two formats:

  • TEXT_HTML
  • TEXT_PLAIN

The service-oriented streams includes three formats:

  • PAGEABLE
  • PRINTABLE
  • RENDERABLE_IMAGE

You configure the flavor as shown here (in this example, as a PNG image):

DocFlavor flavor = DocFlavor.INPUT_STREAM.PNG;


Specifying the print attributes

When printing, you can specify attributes that describe how you want to print a document. Example attributes include number of copies, which pages to print, and the document image type (for example, landscape versus portrait). To specify attributes, you need to work with one of two classes:

  • DocAttributeSet specifies the characteristics for a single document.
  • PrintRequestAttributeSet specifies the characteristics of a single print job.

To specify the attributes for a print run, you create an instance of the appropriate set (DocAttributeSet or PrintRequestAttributeSet) and fill it with the desired attributes for your print run. Reasonable defaults will be configured for those attributes you don't specify. The javax.print.attribute package holds about 70 different attributes, each of which is defined as a separate class. Each attribute works with one or more of the attribute sets. In addition to the two attribute sets described in this article, two other sets are available for querying information. The javax.print.attribute package provides a common place to look for all the types.

Below we see a print run that uses the PrintRequestAttributeSet and prints five copies of an object:

  PrintRequestAttributeSet pras = new HashPrintRequestAttributeSet();
  pras.add(new Copies(5));

Be sure to look in the javax.print.attribute package for a list of all the available attributes.


Setting the content

The Doc interface provides the data to the print job. The implementor of the interface is the SimpleDoc class. With a single constructor, you provide the content as the first parameter, the flavor as the second, and the attributes as the third. The constructor is as follows:

public SimpleDoc(Object printData, DocFlavor flavor, 
  DocAttributeSet attributes)

That leaves the question of the data. And the answer depends on the DocFlavor. If you specified a flavor of DocFlavor.INPUT_STREAM, then the data would be identified by its InputStream. If your flavor was DocFlavor.BYTE_ARRAY, then the data would be a byte array (byte [ ]).

So, to print a PNG image file, you would use the syntax shown in Listing 2.


Listing 2. Setting the content
  DocFlavor flavor = DocFlavor.INPUT_STREAM.PNG;
  String filename = ...;
  FileInputStream fis = new FileInputSteam(filename);
  DocAttributeSet das = new HashDocAttributeSet();
  Doc doc = new SimpleDoc(fis, flavor, das);


Printing

Once you've identified the printer and specified the output format, attributes, and content, the only thing left to do is print. The actual print job is executed through the print() method of the DocPrintJob, retrieved from the PrintService, as shown in Listing 3.


Listing 3. A print job
  DocPrintJob job = ...;
  PrintRequestAttributeSet pras = ...;
  Doc doc = ...;
  job.print(doc, pras);


By calling print() you trigger the mechanism to send your content to the print service in a separate thread.


Printer dialog

One thing noticeably absent so far is any mention of the print dialog. The dialog is the system popup that allows you to configure printer attributes graphically. Figure 1 shows a print dialog for the new Java Print Service API.


Figure 1. Printer dialog
Printer dialog

Interestingly, the printer dialog's default behavior has changed with the new API: by default the dialog is not shown. So we must use the ServiceUI class to create a print dialog like the one shown above.

The ServiceUI class provides a single method to display the printer selection dialog:

printDialog(GraphicsConfiguration gc, int x, int y, 
  PrintService[] services, PrintService defaultService, 
  DocFlavor flavor, PrintRequestAttributeSet attributes)

You then use the returned PrintService to obtain the DocPrintJob to print with, as shown in Listing 4.


Listing 4. Printing with dialog
  String filename = ...;
  PrintRequestAttributeSet pras = ...;
  DocFlavor flavor = ...;
  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 = new FileInputStream(filename);
    DocAttributeSet das = new HashDocAttributeSet();
    Doc doc = new SimpleDoc(fis, flavor, das);
    job.print(doc, pras);
  }



A working example

We'll close with a working example that will let you to try out the new Print Service API's capabilities. The following code essentially combines all our prior code examples into one runnable program. When you run the program, be sure to pass the name of a PNG image file on the command line. If you'd rather print a different format, just change the DocFlavor.


Listing 5. A printing example
import javax.print.*;
import javax.print.attribute.*;
import java.io.*;

public class Printing {
  public static void main(String args[]) throws Exception {
    String filename = args[0];
    PrintRequestAttributeSet pras = 
      new HashPrintRequestAttributeSet();
    DocFlavor flavor = DocFlavor.INPUT_STREAM.PNG;
    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 = new FileInputStream(filename);
      DocAttributeSet das = new HashDocAttributeSet();
      Doc doc = new SimpleDoc(fis, flavor, das);
      job.print(doc, pras);
      Thread.sleep(10000);
    }
    System.exit(0);
  }
}


In the next installment of Magic with Merlin, you'll learn how to print the contents of a screen or component. We'll also discuss event handling tasks related to printing, and I'll show you how to remove the sleep() call from your printing operations.

Note: Just because the PDF DocFlavor exists doesn't mean you can use it to print a PDF file. When you lookup the PrintService for the PDF flavor, it will report unsupported flavor. That means there is no print service for the flavor. Sun doesn't provide one for PDF files. To the best of my knowledge, nobody else makes one available either. Until such a time as someone does, you can't print PDF files using the new Print Service API


Resources

  • Learn how to use the complete Java Print Service API. See the formal documentation from Sun Microsystems.

  • The JSR-006 Unified Printing API offers a glimpse into the origins of the new printing service.

  • If you don't know much about design patterns, you can start learning with David Gallardo's "Design patterns 101" tutorial, exclusively from developerWorks.

  • Peruse John Zukowski's complete collection of tips for working with Merlin.

  • You'll find hundreds of articles about every aspect of Java programming in the developerWorks Java technology zone.

About the author

John Zukowski

John Zukowski does strategic Java consulting for JZ Ventures, Inc.. His latest book is "Java Collections" (Apress, May 2001).

Report abuse help

Report abuse

Thank you. This entry has been flagged for moderator attention.


Report abuse help

Report abuse

Report abuse submission failed. Please try again later.


developerWorks: Sign in


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Select information in your profile (name, country/region, and company) is displayed to the public and will accompany any content you post. You may update your IBM account at any time.

Choose your display name

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


Rate this article

Comments

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Java technology
ArticleID=10641
ArticleTitle=Magic with Merlin: Printing in JDK 1.4, Part 1
publish-date=03012002
author1-email=jaz@zukowski.net
author1-email-cc=