Java 2D Graphics public abstract void setPrintable(Printable painter, PageFormat format) Use this method to supply a Printable and an associated PageFormat to the PrinterJob. PrinterJob also knows how to print instances of Printable’s more capable cousin, java.awt.print.Pageable. But don’t be confused Pageable is really just a container for Printable objects anyhow. I’ll talk about the Pageable interface later in this chapter. This method gives a PrinterJob a Pageable object to print: public abstract void setPageable(Pageable document) This method tells this PrinterJob to print the supplied Pageable. Once the PrinterJob knows what it’s supposed to print, you just need to kick off the job: public abstract void print() throws PrinterException This method begins the printer job. This method does not return until the entire job has been queued to the printer in your operating system. There are two methods named print(). The first, in the Printable interface, is a method that renders a single page on a printer. It is called by the Printing API; you will probably never have to call it yourself. The second print() method, in the PrinterJob class, is used to start a printing job. You must call it explicitly to begin the printing process. Eventually, the print() method in PrinterJob will end up calling the print() method in Printable, but you don’t have to worry about exactly how this happens. If you need to stop a print job for any reason, call the cancel() method: public abstract void cancel() This method cancels a print job in progress. You can cancel a job only between the time that print() is called and when it returns. Therefore, if you want to call cancel(), you’ll have to do it from another thread. The job may not be canceled immediately; the documentation merely states that the job will be canceled as soon as possible. Print jobs have a name. This name may allow a user to identify a print job in printing queues displayed by the operating system. You can retrieve the print job’s name or set it as follows: public abstract String getJobName() This method returns the name of this PrinterJob. public abstract void setJobName(String jobName) Use this method to set the name of the print job. A PrinterJob can also supply you with a default PageFormat: public PageFormat defaultPage() This method returns the default PageFormat for this PrinterJob. page 237
Note: If you are looking for good and high quality web space to host and run your application check Lunarwebhost Java Web Hosting services
Java 2D Graphics Use this method to set the paper size and imageable area. Normally, you won’t ever need to call this method from your application. Users choose the paper size from the printing or page setup dialogs. Usually, your application has to deal with the paper size but doesn’t choose it. 13.1.4 The Paper Class The PageFormat class, as you’ve seen, describes a piece of paper and its orientation. PageFormatuses a simpler class, java.awt.print.Paper, to represent the paper itself. If you want to define your own paper sizes, you’ll have to create your own Paper instances. If you just want your users to be able to choose different page sizes, they can use the page setup dialog to do that. (I’ll talk about the page setup dialog later in this chapter.) To programmatically create a Paper object, use the following constructor: public Paper() This constructor creates a default-sized Paper, 8.5″ by 11″. The imageable area is 6.5″ by 9″ with 1″ margins on all sides. To change the imageable area or the size of the paper, use the following methods: public void setSize(double width, double height) This method sets the paper size in units of 1/72 inch. public void setImageableArea(double x, double y, double width, double height) This method sets the imageable origin, width, and height for this Paper. 13.2 Controlling Printing The PrinterJob class is the boss of the printing process. As you’ve seen, you can obtain an instance of PrinterJob with the following factory method: public static PrinterJob getPrinterJob() This method returns a PrinterJob instance. You can use this PrinterJob to show a print dialog and a page setup dialog, and to start and cancel a print job. 13.2.1 PrinterJob Basics There are two essential steps to using a PrinterJob. You have to give it something to print, and you have to tell it to start printing. The “something to print” may be a Printable, as you saw in the examples above: public abstract void setPrintable(Printable painter) This method sets this PrinterJob to print the supplied object. page 236
Note: If you are looking for good and high quality web space to host and run your application check Lunarwebhost Java Web Hosting services
Java 2D Graphics public double getImageableX() public double getImageableY() public double getImageableWidth() public double getImageableHeight() These methods return the origin, width, and height of this PageFormat’s imageable area. These values are also returned in units of 1/72 inch. Let’s modify our original example to take advantage of this new information. The new example draws a rectangle around the imageable area: import java.awt.*; import java.awt.geom.*; import java.awt.print.*; public class OutlineImageableArea { public static void main(String[] args) { PrinterJob pj = PrinterJob.getPrinterJob(); pj.setPrintable(new OutlinePrintable()); if (pj.printDialog()) { try { pj.print(); } catch (PrinterException e) { System.out.println(e); } } } } class OutlinePrintable implements Printable { public int print(Graphics g, PageFormat pf, int pageIndex) { if (pageIndex != 0) return NO_SUCH_PAGE; Graphics2D g2 = (Graphics2D)g; Rectangle2D outline = new Rectangle2D.Double( pf.getImageableX(), pf.getImageableY(), pf.getImageableWidth(), pf.getImageableHeight()); g2.setPaint(Color.black); g2.draw(outline); return PAGE_EXISTS; } } Any rendering that you do outside the imageable area of the page will be clipped. You can set the orientation of a PageFormat with the following method: public void setOrientation(int orientation) throws IllegalArgumentException Use this method to change the orientation of this PageFormat. The orientation parameter should be PORTRAIT, LANDSCAPE, or REVERSE_LANDSCAPE. If you pass any other value, an IllegalArgumentException is thrown. If you want to use a paper size other than the default, you’ll need the following method. The Paper class is discussed in the following section. public void setPaper(Paper paper) page 235
Note: If you are looking for good and high quality web space to host and run your application check Lunarwebhost Java Web Hosting services
Java 2D Graphics landscape orientations look, while Figure 13.3 shows how they appear as they come out of the printer. Figure 13.2. Orientation and imageable area Figure 13.3. Different orientations, as they come out of the printer PageFormat defines three constants that represent orientations: public static int PORTRAIT public static int LANDSCAPE public static int REVERSE_LANDSCAPE You can find out the orientation and size of a PageFormat with the following methods: public int getOrientation() This method returns the paper orientation. The returned value will be one of the orientation constants, either PORTRAIT, LANDSCAPE, or REVERSE_LANDSCAPE. public double getWidth() public double getHeight() These methods return the width and height of the paper, in units of 1/72 inch. A standard 8.5″ by 11″ piece of paper in portrait orientation will have a width and height of 612 and 792, respectively, as returned from these methods. The imageable area is the rectangle on which the printer can print. The following methods return values that describe the imageable area rectangle: page 234
Note: If you are looking for good and high quality web space to host and run your application check Lunarwebhost Java Web Hosting services
Java 2D Graphics Don’t worry about the parts of this example that don’t make sense yet. I’ll cover everything in detail in this chapter. 13.1.2 The Printable Interface Let’s take a closer look at the Printable interface, which contains one method: public int print(Graphics g, PageFormat pf, int pageIndex) throws PrinterException This method is called by the Printing API to render a page on a printer. The Graphicsobject represents the drawing surface of the page. You can cast it to a Graphics2D to take advantage of the 2D API’s features. The PageFormat object describes the size and orientation of the paper. I’ll describe the PageFormat class in detail later. The pageIndexparameter is the number of the page that will be printed. It is zero-based; that is, the first page is 0. It’s possible that this method will be called multiple times to render the same page. Usually this doesn’t affect how you write the method just make sure you’re not expecting only one call to print() per page. If your Printable implementation is able to print the requested page, it should do its rendering and return PAGE_EXISTS, a constant in the Printable interface. If the requested [3] page does not exist, return NO_SUCH_PAGE. [3] You don’t have to declare that the method throws a PrinterException if you don’t plan to throw one yourself. The HelloNursePrintable class, presented above, only prints one page. If any other page index is passed to print(), it returns NO_SUCH_PAGE: public int print(Graphics g, PageFormat pf, int pageIndex) { if (pageIndex != 0) return NO_SUCH_PAGE; Otherwise, HelloNursePrintable goes ahead and renders the page. In this case, it just draws a single string. Having successfully rendered the page, it returns PAGE_EXISTS: Graphics2D g2 = (Graphics2D)g; g2.setFont(new Font(”Serif”, Font.PLAIN, 36)); g2.drawString(”Hello, nurse!”, 144, 144); return PAGE_EXISTS; } You’ve probably noticed that the print() method in the Printable interface looks a lot like a paint() method. If you want to render the same thing on the screen and on a printer, you should take advantage of this similarity. Instead of doing any rendering in the print() method, just call a paint() method from the print() method. You’ll see examples of this later. 13.1.3 The PageFormat Class Instances of java.awt.print.PageFormat describe a sheet of paper and its orientation. The origin of User Space is always placed at the corner of the paper. However, the page’s orientation determines which corner is considered the User Space origin and how the coordinate axes are aligned. Printers, furthermore, usually cannot print right up to the edges of paper. The imageable area is the part of the paper on which the printer can print. Figure 13.2 shows how portrait and page 233
Note: If you are looking for good and high quality web space to host and run your application check Lunarwebhost Tomcat Web Hosting services
Java 2D Graphics Let’s get something on paper right away to illustrate how PrinterJob and Printable work together. Here’s a simple example that displays a print dialog and prints a single page: import java.awt.*; import java.awt.print.*; public class HelloNurse { public static void main(String[] args) { PrinterJob pj = PrinterJob.getPrinterJob(); pj.setPrintable(new HelloNursePrintable()); if (pj.printDialog()) { try { pj.print(); } catch (PrinterException e) { System.out.println(e); } } } } class HelloNursePrintable implements Printable { public int print(Graphics g, PageFormat pf, int pageIndex) { if (pageIndex != 0) return NO_SUCH_PAGE; Graphics2D g2 = (Graphics2D)g; g2.setFont(new Font(”Serif”, Font.PLAIN, 36)); g2.setPaint(Color.black); g2.drawString(”Hello, nurse!”, 144, 144); return PAGE_EXISTS; } } Let’s look at the sequence of events in this small application: 1. First, a PrinterJob is instantiated by calling the getPrinterJob() factory method: PrinterJob pj = PrinterJob.getPrinterJob(); 2. The thing to be printed, HelloNursePrintable, is passed to the PrinterJob’s setPrintable() method: pj.setPrintable(new HelloNursePrintable()); 3. Then the example shows a print dialog: if (pj.printDialog()) { 4. If the user pressed OK in the print dialog, the printDialog() method returns true. In this case, the printing job is started by calling print(): try { pj.print(); } 5. The job is now in the hands of the Printing API. It calls our Hello-NursePrintable’s print() method as appropriate to render the page on the printer. Control is returned to the HelloNurse application once the entire printing job has been sent to the underlying operating system. Since HelloNurse doesn’t have anything else to do, it exits right away. page 232
Note: If you are looking for good and high quality web space to host and run your application check Lunarwebhost Tomcat Web Hosting services
Java 2D Graphics 13.1 How Printing Works The Printing API uses a callback model, which means that the printing system calls your application when it needs something to be drawn. But it’s more complicated than that. The following is a typical sequence of events: 1. The user of your application requests printed output, usually by clicking on a button or choosing a menu item. 2. Your application displays a print dialog box that is appropriate for the underlying operating system. The Windows print dialog is shown in Figure 13.1. From this dialog, users can choose a printer, change the number of copies that will be printed, and fiddle with other options. 3. If the user clicks on the OK button in the print dialog, your application can tell the system to begin a printing job. 4. The system will call back your rendering code at the appropriate time to render your picture on the printer. Figure 13.1. The print dialog in Windows 13.1.1 The Players One class and one interface form the crux of the Printing API: java.awt.print.PrinterJob The PrinterJob class controls the printing process.[2] You can use this class to kick off printing or to cancel a job in progress. This class also includes methods for displaying a print dialog and a page setup dialog. [2] Don’t confuse this with java.awt.PrintJob, which was part of JDK 1.1’s printing solution. java.awt.print.Printable The Printable interface represents something that can be printed. It contains a single method, print(). page 231
Note: If you are looking for good and high quality web space to host and run your application check Lunarwebhost JSP Web Hosting services
Java 2D Graphics in your programming after all, you’re just dealing with a BufferedImage, and you don’t usually care what data format it uses. However, using compatible images may improve the speed of your application. The following methods create compatible BufferedImages: public abstract BufferedImage createCompatibleImage(int width, int height) This method creates a new BufferedImage of the specified width and height. The new image has the same color model and data layout as this device configuration. public abstract BufferedImage createCompatibleImage(int width, int height, int transparency) This method works just like the previous method except the new image supports the specified transparency mode. The transparency parameter should be one of OPAQUE, BITMASK, or TRANSLUCENT as defined in the Transparency interface. Chapter 13. Printing It used to be that making pretty pictures on a computer was nothing unless you could put the results on paper or transparencies. These days, paper is not as important as it used to be, with images and graphics migrating to the Web. Transparencies, which used to be de rigueur for business presentations, are now old-fashioned. Now a laptop computer attached to a video display is the standard equipment for presentations. But don’t give up on paper yet. The paperless society hasn’t arrived, and I’m not going to hold my breath waiting for it. The Java 2 platform offers a clean, compact Printing API. If you’ve been struggling to get JDK 1.0 or JDK 1.1 to produce nice printed output, you’ll be really happy to see the Printing API.[1] The basic concept is very simple: the Printing API can give you a Graphics2D that represents a printer. You can perform the same rendering, regardless of whether the output device is the screen or a printer. Java 2 unleashes the full power of the 2D API is on your printer. Whee! [1] JDK 1.0 didn’t include any printing support, so you may have turned to third-party native code solutions. The classes and interfaces involved in printing are neatly tucked away in the java.awt.printpackage. It’s a small package, easy to understand and easy to use. The secret of this simplicity is that an application can use the same code to render on a screen or on a printer. Printing is simply a matter of obtaining a Graphics2D that corresponds to the printer and rendering away. Aside from rendering, there are two issues that are important in printing: Job control It’s up to your application to start printing and to display printing dialogs. The 2D API can show the standard print and page setup dialogs for you. Pagination Each page consists of some finite printable area. Your application should break its data into page-sized pieces for printing. page 230
Note: If you are looking for good and high quality web space to host and run your application check Lunarwebhost JSP Web Hosting services
Java 2D Graphics Here’s a simple program that displays the color model of the default screen device in its available configurations: import java.awt.*; public class ShowConfigurations { public static void main(String[] args) { GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); GraphicsDevice defaultScreen = ge.getDefaultScreenDevice(); GraphicsConfiguration[] configurations = defaultScreen. getConfigurations(); System.out.println(”Default screen device: ” + defaultScreen.getIDstring()); for (int i = 0; i < configurations.length; i++) { System.out.println(" Configuration " + (i + 1)); System.out.println(" " + configurations[i].getColorModel()); } System.exit(0); } } On my system, this is the output: Default screen device: :0.0 Configuration 1DirectColorModel: rmask=ff0000 gmask=ff00 bmask=ff amask=0 This corresponds to the settings I have chosen on my Windows system. The DirectColorModel reflects my choice of color depth, 24 bits (called "True Color" in the Windows control panel). As you can see from the band masks, Microsoft orders its color bytes in the same way as Java. On a Solaris system, the red and blue are reversed. It doesn't really matter; the 2D API takes care of the details of swapping color bytes when it's necessary. The last type of information about a device configuration has to do with transformations. Remember that the 2D API provides an automatic transformation from User Space to Device Space so that the results of rendering are the same size, regardless of the output device. The methods that return transformations are: public abstract AffineTransform getDefaultTransform() This method returns a transformation that places the origin of User Space at the upper left corner of the device, with the x axis increasing to the right and the y axis increasing downward. public abstract AffineTransform getNormalizingTransform() The transformation returned by this method can be concatenated with the default transformation to make 72 User Space units equal to one inch in the real world. 12.3.2 Creating Images One of the really useful things you can do with a GraphicsConfiguration is to create an image that is compatible with the device configuration. Compatible means that the image has a color model and data layout that is the same as the underlying device configuration. This allows the image to be quickly rendered on the device. Using a compatible image won't make much difference page 229
Note: If you are looking for good and high quality web space to host and run your application check Lunarwebhost JSP Web Hosting services
Java 2D Graphics C:> A graphics device may operate in more than one mode, or configuration. For example, a screen device might have the following possible configurations: 800 x 600 pixels, 4 bits per pixel color 1152 x 864 pixels, 24 bits per pixel color Device configurations are represented by instances of the java.awt.GraphicsConfigurationclass. (I would have called it DeviceConfiguration, but nobody asked me.) The GraphicsDeviceclass has three methods that return information about configurations: public abstract GraphicsConfiguration[] getConfigurations() This method returns an array of all possible configurations for a device. public abstract GraphicsConfiguration getDefaultConfiguration() This method returns the default configuration for a particular device. public GraphicsConfiguration getBestConfiguration(GraphicsConfigTemplate gct) This method is provided for use by the 3D API. It’s not currently useful in 2D. 12.3 Device Configurations A java.awt.GraphicsConfiguration represents a specific setup of a specific graphics device. There are a few interesting things that a Graphics-Configuration can do. 12.3.1 Configuration Information Most of GraphicsConfiguration’s methods return information about the configuration itself: public abstract GraphicsDevice getDevice() This method returns the GraphicsDevice associated with this particular configuration. public abstract ColorModel getColorModel() This method returns the color model used by the device in this configuration. Physical devices are entirely opaque, so the color model returned by this method doesn’t support transparency (alpha values). public abstract ColorModel getColorModel(int transparency) This method is the same as above, but returns a color model that supports the requested transparency mode. (If you’re wondering what a color model is, take a look back at Chapter 11.) The transparency parameter should be one of the constants from the java.awt.Transparency interface either OPAQUE, BITMASK, or TRANSLUCENT. page 228
Note: If you are looking for good and high quality web space to host and run your application check Lunarwebhost JSP Web Hosting services