Java
Print Service
(JPS), introduced in JDK 1.4, is an API intended for printing
on all Java platforms. It includes the Java 2 Print API, which was used before
the introduction of JPS. This article explains how client and server
applications can locate and select printers that have the capabilities
specified by the appropriate attributes.

Features

JPS APIs are based on the unified printing model described
in JSR 6. These APIs use the
extendable, industry standard attribute set specified in the Internet Printing
Protocol (IPP) 1.1 from the Internet Engineering Task Force (IETF). JPS allows
you to print even on very size-limited platforms such as J2ME; it also supports
standard Java 2D
graphics.

Get developer tips in your inbox

Delivered each Thursday, our free Java newsletter provides insight and hands-on tips you need to unlock the full potential of this programming language.

Automatically sign up today!

The most important features of JPS are:

  • Printer
    Discovery:
    Both the client-
    and server-side applications can programmatically do Printer Discovery and
    find suitable printers that can print the Print Job with user-specified
    attributes. There are a variety of Print Job attributes that you can
    specify, such as the number of sides (single-sided or double-sided);
    chromaticity (color or monochrome); media size (A4, legal, letter, etc.);
    Print Job name (specify a name for any printing job), and so on.
  • Print
    Job Attributes as Objects:
    Implementations of standard IPP attributes
    are included in the JPS API as objects.
  • Print
    Job Attribute Classes:
    Applications
    can extend the attributes included with the JPS API.
  • Service
    Provider Interface (SPI):
    Third parties can plug in their own Print
    Services using the SPIs. Print Service is
    implemented most effectively and efficiently when you use the vendor
    provided SPI.

How to organize printing

Printing with the JPS API involves a three-part process of
discovery, specification, and printing. An optional fourth part involves
notification as a printing task progresses. (All of the classes and interfaces
that I cover in this article are in the javax.print
package or one of its subpackages.)

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 named PrintServiceLookup.
You can use any of these three methods:

  • lookupDefaultPrintService() returns the default print
    service.
  • lookupPrintServices () returns the set of printers that
    support printing a specific document type (such as PNG or HTML) 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. (Later on, you’ll send output to this job.) You can
use the PrintService returned by the lookup to create
the job with its createPrintJob() method:

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

Once you specify the service, you must specify the format
of your print documents. The DocFlavor class is used
to identify the Multipurpose Internet Mail Extensions (MIME) 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.

There are several subclasses of DocFlavor,
and they can be broken up into three subsets of MIME types: byte-oriented,
character-oriented, and service-oriented. Each flavor type supports its own set
of MIME types. These types are defined again as inner classes of DocFlavor subclasses (which are also inner classes, so it’s
an inner class of an inner class).

  • Byte-oriented flavors include GIF,
    JPEG, PDF, PNG, POSTSCRIPT, TEXT_HTML_UTF_8, and others.
  • Character-oriented streams can be
    only one of two formats: TEXT_HTML and TEXT_PLAIN.
  • Service-oriented streams can be PAGEABLE,
    PRINTABLE,
    or RENDERABLE_IMAGE.

For example, here is
how you would configure the flavor in order to print a PNG picture:

DocFlavor flavor = DocFlavor.INPUT_STREAM.PNG;

You can also 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 vs. 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.

Here is an example of how you can print two copies of an
object:

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

You can have a look at the full list of accessible
attributes in the javax.print.attribute package.

The Doc interface provides the data to the print job. The
implementer of the interface is the SimpleDoc class.
With a single constructor, you provide the content as the first parameter, the
flavor as the second parameter, and the attributes as the third parameter. The
content is accepted as Object, thus you have to supplement an appropriate
object type in actual data. If you specify a flavor of DocFlavor.INPUT_STREAM,
then the data would be identified by its InputStream.
If your flavor is DocFlavor.BYTE_ARRAY, then the data
would be a byte array (byte []).

To print a PNG picture from a file, use the following code:

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

You can finally print by using the print()
method of the DocPrintJob object, which I already
retrieved from the PrintService, as shown above:

job. print(doc, pras);

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

For additional information about printing on the J2SE
platform, visit the Sun Developer Network.

Peter V. Mikhalenko is a Sun certified professional who works for Deutsche Bank as a business consultant.