JuliaSet3.java Source code

Java tutorial

Introduction

Here is the source code for JuliaSet3.java

Source

/*
 * Copyright (c) 2004 David Flanagan.  All rights reserved.
 * This code is from the book Java Examples in a Nutshell, 3nd Edition.
 * It is provided AS-IS, WITHOUT ANY WARRANTY either expressed or implied.
 * You may study, use, and modify it for any non-commercial purpose,
 * including teaching and use in open-source projects.
 * You may distribute it non-commercially as long as you retain this notice.
 * For a commercial use license, or to purchase the book, 
 * please visit http://www.davidflanagan.com/javaexamples3.
 */
//package je3.print;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.JobAttributes;
import java.awt.PageAttributes;
import java.awt.PrintJob;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.awt.print.PageFormat;
import java.awt.print.Printable;
import java.awt.print.PrinterException;
import java.awt.print.PrinterJob;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

import javax.print.Doc;
import javax.print.DocFlavor;
import javax.print.DocPrintJob;
import javax.print.PrintException;
import javax.print.PrintService;
import javax.print.PrintServiceLookup;
import javax.print.ServiceUI;
import javax.print.SimpleDoc;
import javax.print.StreamPrintService;
import javax.print.StreamPrintServiceFactory;
import javax.print.attribute.HashPrintRequestAttributeSet;
import javax.print.attribute.PrintRequestAttributeSet;
import javax.print.attribute.standard.Chromaticity;
import javax.print.attribute.standard.OrientationRequested;
import javax.print.event.PrintJobAdapter;
import javax.print.event.PrintJobEvent;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;

/**
 * This class extends JuliaSet2 and its print() and save() methods demonstrate
 * the Java 1.4 printing API.
 */
public class JuliaSet3 extends JuliaSet2 {
    public JuliaSet3() {
        super(-.7, -.25);
    }

    // This method overrides JuliaSet2.print() and demonstrates the javax.print
    // printing API.
    public void print() {
        // Get a list of all printers that can handle Printable objects.
        DocFlavor flavor = DocFlavor.SERVICE_FORMATTED.PRINTABLE;
        PrintService[] services = PrintServiceLookup.lookupPrintServices(flavor, null);

        // Set some define printing attributes
        PrintRequestAttributeSet printAttributes = new HashPrintRequestAttributeSet();
        printAttributes.add(OrientationRequested.LANDSCAPE); // landscape mode
        printAttributes.add(Chromaticity.MONOCHROME); // print in mono

        // Display a dialog that allows the user to select one of the
        // available printers and to edit the default attributes
        PrintService service = ServiceUI.printDialog(null, 100, 100, services, null, null, printAttributes);

        // If the user canceled, don't do anything
        if (service == null)
            return;

        // Now call a method defined below to finish the printing
        printToService(service, printAttributes);
    }

    // This method is like print() above but prints to a PostScript file
    // instead of printing to a printer.
    public void save() throws IOException {
        // Find a factory object for printing Printable objects to PostScript.
        DocFlavor flavor = DocFlavor.SERVICE_FORMATTED.PRINTABLE;
        String format = "application/postscript";
        StreamPrintServiceFactory factory = StreamPrintServiceFactory.lookupStreamPrintServiceFactories(flavor,
                format)[0];

        // Ask the user to select a file and open the selected file
        JFileChooser chooser = new JFileChooser();
        if (chooser.showSaveDialog(this) != JFileChooser.APPROVE_OPTION)
            return;
        File f = chooser.getSelectedFile();
        FileOutputStream out = new FileOutputStream(f);

        // Obtain a PrintService that prints to that file
        StreamPrintService service = factory.getPrintService(out);

        // Do the printing with the method below
        printToService(service, null);

        // And close the output file.
        out.close();
    }

    // Print the Julia set to the sepecifed PrintService using the specified
    // attributes.
    public void printToService(PrintService service, PrintRequestAttributeSet printAttributes) {
        // Wrap ourselves in the PrintableComponent class defined by JuliaSet2.
        String title = "Julia set for c={" + cx + "," + cy + "}";
        Printable printable = new PrintableComponent(this, title);

        // Now create a Doc that encapsulate the Printable object and its type
        DocFlavor flavor = DocFlavor.SERVICE_FORMATTED.PRINTABLE;
        Doc doc = new SimpleDoc(printable, flavor, null);

        // Java 1.1 uses PrintJob.
        // Java 1.2 uses PrinterJob.
        // Java 1.4 uses DocPrintJob. Create one from the service
        DocPrintJob job = service.createPrintJob();

        // Set up a dialog box to monitor printing status
        final JOptionPane pane = new JOptionPane("Printing...", JOptionPane.PLAIN_MESSAGE);
        JDialog dialog = pane.createDialog(this, "Print Status");
        // This listener object updates the dialog as the status changes
        job.addPrintJobListener(new PrintJobAdapter() {
            public void printJobCompleted(PrintJobEvent e) {
                pane.setMessage("Printing complete.");
            }

            public void printDataTransferCompleted(PrintJobEvent e) {
                pane.setMessage("Document transfered to printer.");
            }

            public void printJobRequiresAttention(PrintJobEvent e) {
                pane.setMessage("Check printer: out of paper?");
            }

            public void printJobFailed(PrintJobEvent e) {
                pane.setMessage("Print job failed");
            }
        });

        // Show the dialog, non-modal.
        dialog.setModal(false);
        dialog.show();

        // Now print the Doc to the DocPrintJob
        try {
            job.print(doc, printAttributes);
        } catch (PrintException e) {
            // Display any errors to the dialog box
            pane.setMessage(e.toString());
        }
    }
}

class JuliaSet2 extends JuliaSet1 {
    public JuliaSet2() {
        this(.4, .4);
    } // Display a different set by default

    public JuliaSet2(double cx, double cy) {
        super(cx, cy);
    }

    // This method demonstrates the Java 1.2 printing API.
    // Test it using the ShowBean program.
    public void print() {
        // Java 1.1 used java.awt.PrintJob.
        // In Java 1.2 we use java.awt.print.PrinterJob
        PrinterJob job = PrinterJob.getPrinterJob();

        // Alter the default page settings to request landscape mode
        PageFormat page = job.defaultPage();
        page.setOrientation(PageFormat.LANDSCAPE); // landscape by default

        // Tell the PrinterJob what Printable object we want to print.
        // PrintableComponent is defined as an inner class below
        String title = "Julia set for c={" + cx + "," + cy + "}";
        Printable printable = new PrintableComponent(this, title);
        job.setPrintable(printable, page);

        // Call the printDialog() method to give the user a chance to alter
        // the printing attributes or to cancel the printing request.
        if (job.printDialog()) {
            // If we get here, then the user did not cancel the print job
            // So start printing, displaying a dialog for errors.
            try {
                job.print();
            } catch (PrinterException e) {
                JOptionPane.showMessageDialog(this, e.toString(), "PrinterException", JOptionPane.ERROR_MESSAGE);
            }
        }
    }

    // This inner class implements the Printable interface for an AWT component
    public static class PrintableComponent implements Printable {
        Component c;

        String title;

        public PrintableComponent(Component c, String title) {
            this.c = c;
            this.title = title;
        }

        // This method should print the specified page number to the specified
        // Graphics object, abiding by the specified page format.
        // The printing system will call this method repeatedly to print all
        // pages of the print job. If pagenum is greater than the last page,
        // it should return NO_SUCH_PAGE to indicate that it is done. The
        // printing system may call this method multiple times per page.
        public int print(Graphics g, PageFormat format, int pagenum) {
            // This implemenation is always a single page
            if (pagenum > 0)
                return Printable.NO_SUCH_PAGE;

            // The Java 1.2 printing API passes us a Graphics object, but we
            // can always cast it to a Graphics2D object
            Graphics2D g2 = (Graphics2D) g;

            // Translate to accomodate the requested top and left margins.
            g2.translate(format.getImageableX(), format.getImageableY());

            // Figure out how big the drawing is, and how big the page
            // (excluding margins) is
            Dimension size = c.getSize(); // component size
            double pageWidth = format.getImageableWidth(); // Page width
            double pageHeight = format.getImageableHeight(); // Page height

            // If the component is too wide or tall for the page, scale it down
            if (size.width > pageWidth) {
                double factor = pageWidth / size.width; // How much to scale
                g2.scale(factor, factor); // Adjust coordinate system
                pageWidth /= factor; // Adjust page size up
                pageHeight /= factor;
            }
            if (size.height > pageHeight) { // Do the same thing for height
                double factor = pageHeight / size.height;
                g2.scale(factor, factor);
                pageWidth /= factor;
                pageHeight /= factor;
            }

            // Now we know the component will fit on the page. Center it by
            // translating as necessary.
            g2.translate((pageWidth - size.width) / 2, (pageHeight - size.height) / 2);

            // Draw a line around the outside of the drawing area and label it
            g2.drawRect(-1, -1, size.width + 2, size.height + 2);
            g2.drawString(title, 0, -15);

            // Set a clipping region so the component can't draw outside of
            // its won bounds.
            g2.setClip(0, 0, size.width, size.height);

            // Finally, print the component by calling its paint() method.
            // This prints the background, border, and children as well.
            // For swing components, if you don't want the background, border,
            // and children, then call printComponent() instead.
            c.paint(g);

            // Tell the PrinterJob that the page number was valid
            return Printable.PAGE_EXISTS;
        }
    }
}

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();
    }
}