[ Team LiB ] Previous Section Next Section

13.5 Advanced Printing with Java 1.4

The Java 1.4 Printing API is substantially more complex than the Java 1.1 and Java 1.2 APIs. It is a command-line utility that can:

  • List available printers capable of handling specific printing requests (color printing, collation, stapling, etc.)

  • Query the status of a particular named printer

  • Spool text or image files directly to a printer

  • Convert GIF, JPEG, and PNG image files to PostScript files

Example 13-5 demonstrates some of these advanced features. The example does not create a GUI, and, unlike the other examples in this chapter, it prints without using a Graphics object. The code is well-commented and straightforward; the example is long only because it demonstrates several different features of the Java 1.4 API.

Example 13-5. Print.java
package je3.print;
import javax.print.*;
import javax.print.event.*;
import javax.print.attribute.*;
import javax.print.attribute.standard.*;
import java.io.*;

 * This utility program demonstrates the javax.print API and allows you to 
 * list available printers, query a named printer, print text and image files
 * to a printer, and print to PostScript files.
 * Usage:
 * java Print -i inputfile [-q] [-p printer] [-ps outputfile] [attributes]
public class Print {
    public static void main(String[  ] args) throws IOException {
        // These are values we'll set from the command-line arguments
        boolean query = false;
        String printerName = null;
        String inputFileName = null;
        String outputFileName = null;
        String outputFileType = null;
        PrintRequestAttributeSet attributes =
            new HashPrintRequestAttributeSet( );

        // Loop through the arguments
        for(int i = 0; i < args.length; i++) {
            if (args[i].equals("-q")) query = true; // Is this a query?
            else if (args[i].equals("-p"))          // Specific printer name
                printerName = args[++i];
            else if (args[i].equals("-i"))          // The file to print
                inputFileName = args[++i];
            else if (args[i].equals("-ps")) {       // Print it to this file
                // Sun's Java 1.4 implementation only supports PostScript
                // output.  Other implementations might offer PDF, for example.
                outputFileName = args[++i];
                outputFileType = "application/postscript";
            // The rest of the arguments represent common printing attributes
            else if (args[i].equals("-color"))      // Request a color printer
            else if (args[i].equals("-landscape"))  // Request landscape mode
            else if (args[i].equals("-letter"))     // US Letter-size paper
            else if (args[i].equals("-a4"))         // European A4 paper
            else if (args[i].equals("-staple"))     // Request stapling
            else if (args[i].equals("-collate"))    // Collate multiple copies
            else if (args[i].equals("-duplex"))     // Request 2-sided
            else if (args[i].equals("-2"))          // 2 pages to a sheet 
                attributes.add(new NumberUp(2));
            else if (args[i].equals("-copies"))     // how many copies
                attributes.add(new Copies(Integer.parseInt(args[++i])));
            else {
                System.out.println("Unknown argument: " + args[i]);

        if (query) {
            // If the -q argument was specified, but no printer was named,
            // then list all available printers that can support the attributes
            if (printerName == null) queryServices(attributes);
            // Otherwise, look for a named printer that can support the
            // attributes and print its status
            else queryPrinter(printerName, attributes);
        else if (outputFileName != null)
            // If this is not a query and we have a filename, print to a file
            printToFile(outputFileName, outputFileType,
                        inputFileName, attributes);
            // Otherwise, print to the named printer, or to the default 
            // printer otherwise.
            print(printerName, inputFileName, attributes);

        // The main( ) method ends here, but there may be a printing thread
        // operating in the background.  So the program may not terminate
        // until printing completes.  

    // List names of all PrintServices that can support the attributes
    public static void queryServices(PrintRequestAttributeSet attributes) {
        // Find all services that can support the specified attributes
        PrintService[  ] services =
            PrintServiceLookup.lookupPrintServices(null, attributes);
        // Loop through available services
        for(int i = 0; i < services.length; i++) {
            // Print service name
            System.out.print(services[i].getName( ));

            // Then query and print the document types it can print
            DocFlavor[  ] flavors = services[i].getSupportedDocFlavors( );
            for(int j = 0; j < flavors.length; j++) {
                // Filter out DocFlavors that have a representation class other
                // than java.io.InputStream.  
                String repclass = flavors[j].getRepresentationClassName( );
                if (!repclass.equals("java.io.InputStream"))continue;
                System.out.println("\t" + flavors[j].getMimeType( ));

    // List details about the named printer
    public static void queryPrinter(String printerName,
                                    PrintRequestAttributeSet attributes)
        // Find the named printer
        PrintService service = getNamedPrinter(printerName, attributes);
        if (service == null) {
            System.out.println(printerName + ": no such printer capable of " +
                               "handling the specified attributes");

        // Print status and other information about the printer
        System.out.println(printerName + " status:");
        Attribute[  ] attrs = service.getAttributes( ).toArray( );
        for(int i = 0; i < attrs.length; i++) 
            System.out.println("\t" + attrs[i].getName( ) + ": " + attrs[i]);


    // Print the contents of the named file to the named printer (or to a 
    // default printer if printerName is null) requesting the specified 
    // attributes.
    public static void print(String printerName, String filename,
                             PrintRequestAttributeSet attributes)
        throws IOException
        // Look for a printer that can support the attributes
        PrintService service = getNamedPrinter(printerName, attributes);
        if (service == null) {
            System.out.println("Can't find a printer " +
                               "with specified attributes");
        // Print the file to that printer.  See method definition below
        printToService(service, filename, attributes);
        // Let the user know where to pick up their printout
        System.out.println("Printed " + filename + " to " + service.getName( ));

    // Print to an output file instead of a printer
    public static void printToFile(String outputFileName,
                                   String outputFileType,
                                   String inputFileName, 
                                   PrintRequestAttributeSet attributes)
        throws IOException

        // Determine whether the system can print to the specified type, and
        // get a factory object if so.
        // The name of this static method is way too long!
        StreamPrintServiceFactory[  ] factories = StreamPrintServiceFactory.
            lookupStreamPrintServiceFactories(null, outputFileType);

        // Error message if we can't print to the specified output type
        if (factories.length == 0) {
            System.out.println("Unable to print files of type: " +
        // Open the output file
        FileOutputStream out = new FileOutputStream(outputFileName);
        // Get a PrintService object to print to that file
        StreamPrintService service = factories[0].getPrintService(out);
        // Print using the method below
        printToService(service, inputFileName, attributes);
        // And remember to close the output file
        out.close( );

    // Print the contents of the named file to the specified PrintService,
    // requesting the specified attributes.
    // This is shared code used by print( ) and printToFile( ) above.
    public static void printToService(PrintService service, String filename, 
                                      PrintRequestAttributeSet attributes)
        throws IOException
        // Figure out what type of file we're printing
        DocFlavor flavor = getFlavorFromFilename(filename);
        // Open the file
        InputStream in = new FileInputStream(filename);
        // Create a Doc object to print from the file and flavor.
        Doc doc = new SimpleDoc(in, flavor, null);
        // Create a print job from the service
        DocPrintJob job = service.createPrintJob( );

        // Monitor the print job with a listener
        job.addPrintJobListener(new PrintJobAdapter( ) {
                public void printJobCompleted(PrintJobEvent e) {
                    System.out.println("Print job complete");
                public void printDataTransferCompleted(PrintJobEvent e) {
                    System.out.println("Document transfered to printer");
                public void printJobRequiresAttention(PrintJobEvent e) {
                    System.out.println("Print job requires attention");
                    System.out.println("Check printer: out of paper?");
                public void printJobFailed(PrintJobEvent e) {
                    System.out.println("Print job failed");

        // Now print the document, catching errors
        try {
            job.print(doc, attributes);
        catch(PrintException e) {

    // A utility method to look up printers that can support the specified
    // attributes and return the one that matches the specified name.
    public static PrintService getNamedPrinter(String name,
                                               PrintRequestAttributeSet attrs)
        PrintService[  ] services = 
            PrintServiceLookup.lookupPrintServices(null, attrs);
        if (services.length > 0) {
            if (name == null) return services[0];
            else {
                for(int i = 0; i < services.length; i++) {
                    if (services[i].getName( ).equals(name)) return services[i];
        return null;

    // A utility method to return a DocFlavor object matching the 
    // extension of the filename.
    public static DocFlavor getFlavorFromFilename(String filename) {
        String extension = filename.substring(filename.lastIndexOf('.')+1);
        extension = extension.toLowerCase( );
        if (extension.equals("gif"))
            return DocFlavor.INPUT_STREAM.GIF;
        else if (extension.equals("jpeg"))
            return DocFlavor.INPUT_STREAM.JPEG;
        else if (extension.equals("jpg"))
            return DocFlavor.INPUT_STREAM.JPEG;
        else if (extension.equals("png"))
            return DocFlavor.INPUT_STREAM.PNG;
        else if (extension.equals("ps"))
            return DocFlavor.INPUT_STREAM.POSTSCRIPT;
        else if (extension.equals("txt"))
            return DocFlavor.INPUT_STREAM.TEXT_PLAIN_HOST;
        // Fallback: try to determine flavor from file content
        else return DocFlavor.INPUT_STREAM.AUTOSENSE;
    [ Team LiB ] Previous Section Next Section