Printing Help for Java Developers

Market Development Engineering
SMCC, Sun Microsystems, Inc.

Executive Summary

End users expect to be able to print to printers attached to local machines or to the network itself. The applets and applications they use may run in concert with a browser or directly on top of an operating system itself. There may be server code somewhere on the network that these apps/applets use (especially thin clients). In all cases, users expect to be able to print from their desktop to any printers on their network.

The Java environment must meet this need by providing a rich set of printing interfaces and functionality, including:

  • APIs to create and dispatch print jobs
  • Standard GUI components to present to the user when they wish to print
  • SPIs(Service Provider Interfaces) to create drivers for new printers

Java Printing Circa 1997: JDK 1.1

The original JDK 1.0 release did not provide any printing support.  The release of the 1.1 version of the Java Developer's Kit in 1997 provided Java developers with a basic framework for printing from applications. JDK 1.1 Core contains facilities for "platform printing": using a printer that is accessible to the client platform. Note that this does not necessarily require that the printer be connected physically to the client machine, but rather that the Java client uses facilities provided by the platform operating system to use a printer. Also note that some Java platforms may have no printer accessible, directly or indirectly.

To print, a client initiates a print job by obtaining a new instance of PrintJob. The PrintJob class will create for you an instance of a concrete subclass of Graphics, which implements all the usual rendering calls for text, graphics, and images. This subclass differs from the normal Graphics subclasses in that rendering is done not on the screen, but on a printer. In practice, the subclass either builds a document file, such as PostScript, and ships it to a printer, or it passes the responsibility on to the operating system, e.g., on Windows 95, the implementation exploits the ability of the underlying window system to divert rendering calls to a printer. You indicate the end of each page by calling dispose() on the Graphics subclass, and obtain a new graphics instance from PrintJob for the next page.

Java Printing 1998: SDK 1.2 Printing Support

The SDK 1.2 advanced the state of printing with the Java platform: the java.awt.print package can print all Java 2D graphics or Java AWT graphics, and the interface is extensible enough to allow for the addition of powerful new printing features in the future. 

The Java printing system uses a callback model in which the printing system controls when pages are printed; the application provides information about the document to be printed, and the printing system asks the application to render each page as it needs them. 

While untraditional, the callback model fits better with the existing AWT component painting model.  The printing system might request that a particular page be rendered more than once or request that pages be rendered out of order. The application must be able to generate the proper page image, no matter which page the printing system requests. In this respect, the printing system is similar to the window toolkit, which can request components to repaint at any time, in any order.

The callback printing model is also more flexible than traditional application-driven printing models and supports printing on a wider range of systems and printers. For example, if a printer stacks output pages in reverse order, the printing system can ask the application to generate pages in reverse order so that the final stack is in proper reading order.

Kestrel 1.1 Printing Enhancements

For the SDK, version 1.3, the 1.1 (AWT) Java Printing API included two new classes: JobAttributes and PageAttributes . The JobAttributes class controls the properties of a print job, such as destination and number of copies. The PageAttributes class controls the attributes of a printed page, such as paper size, orientation, and print quality. These new classes are used by the new method getPrintJob(Frame, String, JobAttributes, PageAttributes) in java.awt.Toolkit . This method returns a PrintJob object, which encapsulates the information associated with a printing request.

The JobAttributes and PageAttributes classes provide an application with the ability to store particular attributes as instances of these classes, which can be applied to different printing jobs. With the JobAttributes class, you can specify a cross-platform dialog, which was not available in previous versions of the SDK.

A New, Unified Printing Model: the Java Print Service

The proposed Unified Printing Model will allow printing on all platforms requiring a Java Print API, including platforms requiring a small footprint, such as a J2ME profile, but will still support the current Java 2 Print API, which allows printing of all Java 2D graphics.  This unified Java Print API uses the extendable, industry-standard attribute set specified in the Internet Printing Protocol (IPP) 1.1 from the IETF.  The Unified Printing Model also builds on previously-released printing features, such as the ability to specify a cross-platform dialog.

Through a Service Provider Interface, the Java Print Service will enable third parties to install their own print services, such as a JINI print service, which could print different formats, including Postscript, PDF, and SVG, with a specified attribute set, as defined by the IPP. 

The Java 2D printing API, introduced in the SDK 1.2, will be integrated with the Java Print Service.  As a result, applications that print 2D graphics will be able to :

  • Discover and select printers capable of printing 2D Graphics.
  • Plug in third-party print services by using the Service Provider model.
  • Print in different formats using the JPS DocFlavor and StreamPrinter2D API.

New Java Print Service API

The proposed JPS API will be the package javax.print .  Please note that this API is still being developed through the Java Community Process and is subject to change.  The main proposed JPS classes are:

  • Doc: Specifies the interface for the print data.
  • DocPrintJob: Initiates printing on the Doc with the specified attributes
  • DocFlavor: Specifies the format for the print data
  • PrintService: Describes a printers capabilities and creates a DocPrintJob
  • PrintServiceLookup: Finds printers capable of printing the specified flavor and supporting the specified attribute set.  Third parties can implement this class to plug in their own print services through a Service Provider Interface.

        
// PrintDoc is an implementation of Doc
        Doc psDoc = new PrintDoc("file.ps");
        // Gets the format of the document
        DocFlavor psFlavor = psDoc.getDocFlavor();
        // Creates a new attribute set
        PrintRequestAttributeSet aset = new HashPrintRequestAttributeSet();
        // Prints 5 copies
        aset.add(new Copies(5));
        // Specifies the size of the medium
        aset.add(MediaSize.A4);
        // Prints two-sided
        aset.add(Sides.DUPLEX);
        // Staples the pages
        aset.add( FinishingsBinding STAPLE);
        /* Locates printers that can print the specified document format
         * with the specified attribute set
         */
        PrintService[] services = 
        PrintServiceLookup.lookupPrintServices(psFlavor, aset);
        if (services != null && services.length > 0) {
           DocPrintJob job = services[0].createPrintJob();
           try {
              job.print(psDoc, aset);
           }
        } catch (PrintException pe) {
        }

New Java 2D Printing API

The proposed Java 2D printing API will be added to the java.awt.print package.  Please note that this API is still being developed and is subject to change.  The main proposed Java 2D printing classes are:

  • StreamPrinter2D: Represents a stream printer
  • StreamPrintRenderer2D: Generates stream-printer output from 2D graphics

StreamPrinter2D DocFlavor javax.print DocFlavor PrintServiceLookup javax.print


 
DocFlavor psFlavor = 
           new DocFlavor("application/postscript", "java.io.OutputStream");
        StreamPrinter2D[] streamPrinter[] =
           PrinterServiceLookup.lookupStreamPrinters(psFlavor);
        if(streamPrinter != null && streamPrinter.length > 0) {
           StreamPrinter2D sprinter = streamPrinter[0];
           try {
              FileOutputStream fos = new FileOutputStream("out.ps");
              PrinterJob pjob =
                 PrinterJob.getPrinterJob(sprinter, fos);
              pjob.setPageable(this);
              pjob.print();
              fos.close();
           } catch (IOException e) {
           } catch (PrinterException e) {
           }
        }

Conclusions

Users who print with the Java platform should find that many of their needs and the goals we have set in the beginning of this paper either have already been met by previous SDK releases or will be met by the new Unified Printing API.  To review, we said that the Java environment must provide a rich set of printing functionality, including:

  • APIs to create and dispatch print jobs
  • Standard GUI components to present to the user when they wish to print
  • SPIs(Service Provider Interfaces) to create drivers for new printers

The standard GUI component, or print dialog, was available in the JDK 1.1.  With the SDK 1.3, users can specify a cross-platform print dialog.  When the SDK 1.4 is available, users will still be able to specify a cross-platform print dialog, but they will also be able to discover and select a printer from their application code, whereas before they could only select a printer with  the print dialog.

The third goal is met by the Unified Printing API, which allows third parties to plug in print services through a Service Provider Interface.  In addition to print services, third parties can add their own attribute sets because the attributes included with JPS are first-class objects, which can be extended, and are based on the industry-standard attribute names specified in the IPP 1.1.