Example 13-1 is a Swing component that displays a fractal image known as a "Julia set," pictured in Figure 13-1. The image is fascinating, and the mathematics interesting, but the real point of the example is the print( ) method, which demonstrates how to print the Julia set using the Java 1.1 API and the Java 1.3 extensions to that API. The print( ) code is straightforward: it sets some default attribute values, then displays a dialog box to the user, to allow him to modify those attributes or cancel the print request. The dialog box returns a PrintJob object. The print( ) method then obtains a Graphics object from the PrintJob. Next, it draws the Julia set to this Graphics object and, finally, calls the Graphics.dispose( ) method to tell the printer that printing is done. These basic steps are repeated in the next two examples as well: when studying the examples of the Java 1.2 and Java 1.4 APIs, look for the code that sets attributes, displays a dialog, and obtains the Graphics object. Figure 13-1. A Julia set printed with the Java 1.1 APIExample 13-1 does not include a main( ) method. To display the component, use the ShowBean program from Chapter 11, and then use the Commands menu to test the print( ) method: java je3.gui.ShowBean je3.print.JuliaSet1 Example 13-1. JuliaSet1.javapackage je3.print; import javax.swing.*; import java.awt.*; import java.awt.image.*; /** * This class is a Swing component that computes and displays a fractal image * known as a "Julia set". The print( ) method demonstrates printing with the * Java 1.1 printing API, and is the main point of the example. The code * that computes the Julia set uses complex numbers, and you don't need to * understand it. **/ public class JuliaSet1 extends JComponent { // These constants are hard-coded for simplicity double x1=-1.5, y1=-1.5, x2=1.5, y2=1.5; // Region of complex plane int width = 400, height = 400; // Mapped to these pixels double cx, cy; // This complex constant defines the set we display BufferedImage image; // The image we compute // We compute values between 0 and 63 for each point in the complex plane. // This array holds the color values for each of those values. static int[ ] colors; static { // Static initializer for the colors[ ] array. colors = new int[64]; for(int i = 0; i < colors.length; i++) { colors[63-i] = (i*4 << 16) + (i*4 << 8) + i*4; // grayscale // (i*4) ^ ((i * 3)<<6) ^ ((i * 7)<<13); // crazy technicolor } } // No-arg constructor with default values for cx, cy. public JuliaSet1( ) { this(-1, 0); } // This constructor specifies the {cx,cy} constant. // For simplicity, the other constants remain hardcoded. public JuliaSet1(double cx, double cy) { this.cx = cx; this.cy = cy; setPreferredSize(new Dimension(width, height)); computeImage( ); } // This method computes a color value for each pixel of the image void computeImage( ) { // Create the image image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); // Now loop through the pixels int i,j; double x, y; double dx = (x2 - x1)/width; double dy = (y2 - y1)/height; for(j = 0, y = y1; j < height; j++, y += dy) { for(i = 0, x = x1; i < width; i++, x += dx) { // For each pixel, call testPoint( ) to determine a value. // Then map that value to a color and set it in the image. // If testPoint( ) returns 0, the point is part of the Julia set // and is displayed in black. If it returns 63, the point is // displayed in white. Values in-between are displayed in // varying shades of gray. image.setRGB(i, j, colors[testPoint(x,y)]); } } } // This is the key method for computing Julia sets. For each point z // in the complex plane, we repeatedly compute z = z*z + c using complex // arithmetic. We stop iterating when the magnitude of z exceeds 2 or // after 64 iterations. We return the number of iterations-1. public int testPoint(double zx, double zy) { for(int i = 0; i < colors.length; i++) { // Compute z = z*z + c; double newx = zx*zx - zy*zy + cx; double newy = 2*zx*zy + cy; zx = newx; zy = newy; // Check magnitude of z and return iteration number if (zx*zx + zy*zy > 4) return i; } return colors.length-1; } // This method overrides JComponent to display the Julia set. // Just scale the image to fit and draw it. public void paintComponent(Graphics g) { g.drawImage(image,0,0,getWidth( ), getHeight( ),this); } // This method demonstrates the Java 1.1 java.awt.PrintJob printing API. // It also demonstrates the JobAttributes and PageAttributes classes // added in Java 1.3. Display the Julia set with ShowBean and use // the Command menu to invoke this print command. public void print( ) { // Create some attributes objects. This is Java 1.3 stuff. // In Java 1.1, we'd use a java.util.Preferences object instead. JobAttributes jattrs = new JobAttributes( ); PageAttributes pattrs = new PageAttributes( ); // Set some example attributes: monochrome, landscape mode pattrs.setColor(PageAttributes.ColorType.MONOCHROME); pattrs.setOrientationRequested( PageAttributes.OrientationRequestedType.LANDSCAPE); // Print to file by default jattrs.setDestination(JobAttributes.DestinationType.FILE); jattrs.setFileName("juliaset.ps"); // Look up the Frame that holds this component Component frame = this; while(!(frame instanceof Frame)) frame = frame.getParent( ); // Get a PrintJob object to print the Julia set with. // The getPrintJob( ) method displays a print dialog and allows the user // to override and modify the default JobAttributes and PageAttributes Toolkit toolkit = this.getToolkit( ); PrintJob job = toolkit.getPrintJob((Frame)frame, "JuliaSet1", jattrs, pattrs); // We get a null PrintJob if the user clicked cancel if (job == null) return; // Get a Graphics object from the PrintJob. // We print simply by drawing to this Graphics object. Graphics g = job.getGraphics( ); // Center the image on the page Dimension pagesize = job.getPageDimension( ); // how big is page? Dimension panesize = this.getSize( ); // how big is image? g.translate((pagesize.width-panesize.width)/2, // center it (pagesize.height-panesize.height)/2); // Draw a box around the Julia set and label it g.drawRect(-1, -1, panesize.width+2, panesize.height+2); g.drawString("Julia Set for c={" + cx + "," + cy + "}", 0, -15); // Set a clipping region g.setClip(0, 0, panesize.width, panesize.height); // Now print the component by calling its paint method this.paint(g); // Finally tell the printer we're done with the page. // No output will be generated if we don't call dispose( ) here. g.dispose( ); } } |