 | Level: Introductory John Zukowski (jaz@zukowski.net)JZ Ventures, Inc.
01 Mar 2002 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. 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:
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:
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

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
About the author
Rate this page
|  |