13.1 Printing with the Java 1.1 API
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.
Example 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.java
package 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( );
}
}
 |