Commit ec944b92 authored by O'Reilly Media, Inc.'s avatar O'Reilly Media, Inc.

Initial commit

parents
9781565924840
\ No newline at end of file
<HTML>
<BODY>
The code in these example archives may not match the examples in the latest print copy of the book. Please check
<A HREF="http://www.oreilly.com/catalog/java2d/errata/"><B>the posted errata</B></A> for discrepancies between the book and online errata. We
apologize for the inconvenience.
</BODY>
</HTML>
The files in the "examples" subdirectory are the
same as the files contained in the examples.zip
file.
## Example files for the title:
# Java 2D Graphics, by Jonathan Knudsen
[![Java 2D Graphics, by Jonathan Knudsen](http://akamaicovers.oreilly.com/images/9781565924840/cat.gif)](https://www.safaribooksonline.com/library/view/title/1565924843//)
The following applies to example files from material published by O’Reilly Media, Inc. Content from other publishers may include different rules of usage. Please refer to any additional usage rights explained in the actual example files or refer to the publisher’s website.
O'Reilly books are here to help you get your job done. In general, you may use the code in O'Reilly books in your programs and documentation. You do not need to contact us for permission unless you're reproducing a significant portion of the code. For example, writing a program that uses several chunks of code from our books does not require permission. Answering a question by citing our books and quoting example code does not require permission. On the other hand, selling or distributing a CD-ROM of examples from O'Reilly books does require permission. Incorporating a significant amount of example code from our books into your product's documentation does require permission.
We appreciate, but do not require, attribution. An attribution usually includes the title, author, publisher, and ISBN.
If you think your use of code examples falls outside fair use or the permission given here, feel free to contact us at <permissions@oreilly.com>.
Please note that the examples are not production code and have not been carefully testing. They are provided "as-is" and come with no warranty of any kind.
import java.awt.*;
public abstract class AnimationComponent
extends Container
implements Runnable {
private boolean mTrucking = true;
private long[] mPreviousTimes; // milliseconds
private int mPreviousIndex;
private boolean mPreviousFilled;
private double mFrameRate; // frames per second
private Image mImage;
public AnimationComponent() {
mPreviousTimes = new long[128];
mPreviousTimes[0] = System.currentTimeMillis();
mPreviousIndex = 1;
mPreviousFilled = false;
}
public abstract void timeStep();
public void run() {
while (mTrucking) {
render();
timeStep();
calculateFrameRate();
}
}
protected void render() {
Graphics g = getGraphics();
if (g != null) {
Dimension d = getSize();
if (checkImage(d)) {
Graphics imageGraphics = mImage.getGraphics();
// Clear the image background.
imageGraphics.setColor(getBackground());
imageGraphics.fillRect(0, 0, d.width, d.height);
imageGraphics.setColor(getForeground());
// Draw this component offscreen.
paint(imageGraphics);
// Now put the offscreen image on the screen.
g.drawImage(mImage, 0, 0, null);
// Clean up.
imageGraphics.dispose();
}
g.dispose();
}
}
// Offscreen image.
protected boolean checkImage(Dimension d) {
if (d.width == 0 || d.height == 0) return false;
if (mImage == null || mImage.getWidth(null) != d.width
|| mImage.getHeight(null) != d.height) {
mImage = createImage(d.width, d.height);
}
return true;
}
protected void calculateFrameRate() {
// Measure the frame rate
long now = System.currentTimeMillis();
int numberOfFrames = mPreviousTimes.length;
double newRate;
// Use the more stable method if a history is available.
if (mPreviousFilled)
newRate = (double)numberOfFrames /
(double)(now - mPreviousTimes[mPreviousIndex]) *
1000.0;
else
newRate = 1000.0 /
(double)(now - mPreviousTimes[numberOfFrames - 1]);
firePropertyChange("frameRate", mFrameRate, newRate);
mFrameRate = newRate;
// Update the history.
mPreviousTimes[mPreviousIndex] = now;
mPreviousIndex++;
if (mPreviousIndex >= numberOfFrames) {
mPreviousIndex = 0;
mPreviousFilled = true;
}
}
public double getFrameRate() { return mFrameRate; }
// Property change support.
private transient AnimationFrame mRateListener;
public void setRateListener(AnimationFrame af) {
mRateListener = af;
}
protected void firePropertyChange(String name, double oldValue,
double newValue) {
mRateListener.rateChanged(newValue);
}
}
\ No newline at end of file
import java.awt.*;
import java.text.NumberFormat;
public class AnimationFrame
extends ApplicationFrame {
private Label mStatusLabel;
private NumberFormat mFormat;
public AnimationFrame(AnimationComponent ac) {
super("AnimationFrame v1.0");
setLayout(new BorderLayout());
add(ac, BorderLayout.CENTER);
add(mStatusLabel = new Label(), BorderLayout.SOUTH);
// Create a number formatter.
mFormat = NumberFormat.getInstance();
mFormat.setMaximumFractionDigits(1);
// Listen for the frame rate changes.
ac.setRateListener(this);
// Kick off the animation.
Thread t = new Thread(ac);
t.start();
}
public void rateChanged(double frameRate) {
mStatusLabel.setText(mFormat.format(frameRate) + " fps");
}
}
\ No newline at end of file
import java.awt.*;
import java.awt.event.*;
public class Annoyance
extends ApplicationFrame
implements MouseMotionListener {
public static void main(String[] args) {
new Annoyance();
}
private int mX, mY;
public Annoyance() {
super("Annoyance v1.0");
addMouseMotionListener(this);
setVisible(true);
}
public void mouseMoved(MouseEvent me) {
mX = (int)me.getPoint().getX();
mY = (int)me.getPoint().getY();
repaint();
}
public void mouseDragged(MouseEvent me) { mouseMoved(me); }
public void paint(Graphics g) {
int s = 100;
g.setColor(Color.blue);
g.fillRect(mX - s / 2, mY - s / 2, s, s);
}
}
\ No newline at end of file
import java.awt.*;
import java.awt.event.*;
public class ApplicationFrame
extends Frame {
public ApplicationFrame() { this("ApplicationFrame v1.0"); }
public ApplicationFrame(String title) {
super(title);
createUI();
}
protected void createUI() {
setSize(500, 400);
center();
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
dispose();
System.exit(0);
}
});
}
public void center() {
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
Dimension frameSize = getSize();
int x = (screenSize.width - frameSize.width) / 2;
int y = (screenSize.height - frameSize.height) / 2;
setLocation(x, y);
}
}
\ No newline at end of file
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
public class Bandito {
public static void main(String[] args) {
// Create a frame window to hold everything.
ApplicationFrame f = new ApplicationFrame("Bandito v1.0");
// Create a SplitImageComponent with the source image.
String filename = "Ethol with Roses.small.jpg";
SplitImageComponent sic = new SplitImageComponent(filename);
// Create a BandCombineOp.
float[][] matrix = {
{ -1, 0, 0, 255 },
{ 0, 1, 0, 0 },
{ 0, 0, 1, 0 }
};
BandCombineOp op = new BandCombineOp(matrix, null);
// Process the source image raster.
BufferedImage sourceImage = sic.getImage();
Raster source = sourceImage.getRaster();
WritableRaster destination = op.filter(source, null);
// Create a destination image using the processed
// raster and the same color model as the source image.
BufferedImage destinationImage = new BufferedImage(
sourceImage.getColorModel(), destination, false, null);
sic.setSecondImage(destinationImage);
// Set up the frame window.
f.setLayout(new BorderLayout());
f.add(sic, BorderLayout.CENTER);
f.setSize(f.getPreferredSize());
f.center();
f.setVisible(true);
}
}
\ No newline at end of file
import java.awt.*;
public class BidirectionalText {
public static void main(String[] args) {
Frame f = new ApplicationFrame("BidirectionalText v1.0") {
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D)g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
Font font = new Font("Lucida Sans Regular", Font.PLAIN, 32);
g2.setFont(font);
g2.drawString("Please \u062e\u0644\u0639 slowly.", 40, 80);
}
};
f.setVisible(true);
}
}
\ No newline at end of file
import java.awt.*;
import java.awt.print.*;
public class Booker {
public static void main(String[] args) {
PrinterJob pj = PrinterJob.getPrinterJob();
// Create two Printables.
Component c1 = new PatchworkComponent("printable1");
Component c2 = new PatchworkComponent("printable2");
c1.setSize(500, 400);
c2.setSize(500, 400);
BookComponentPrintable printable1 = new BookComponentPrintable(c1);
BookComponentPrintable printable2 = new BookComponentPrintable(c2);
// Create two PageFormats.
PageFormat pageFormat1 = pj.defaultPage();
PageFormat pageFormat2 = (PageFormat)pageFormat1.clone();
pageFormat2.setOrientation(PageFormat.LANDSCAPE);
// Create a Book.
Book book = new Book();
book.append(printable1, pageFormat1);
book.append(printable2, pageFormat2);
// Print the Book.
pj.setPageable(book);
if (pj.printDialog()) {
try { pj.print(); }
catch (PrinterException e) {
System.out.println(e);
}
}
}
}
class BookComponentPrintable
implements Printable {
private Component mComponent;
public BookComponentPrintable(Component c) {
mComponent = c;
}
public int print(Graphics g, PageFormat pageFormat, int pageIndex) {
Graphics2D g2 = (Graphics2D)g;
g2.translate(pageFormat.getImageableX(), pageFormat.getImageableY());
mComponent.paint(g2);
return PAGE_EXISTS;
}
}
\ No newline at end of file
import java.awt.*;
import java.awt.event.*;
import java.awt.font.*;
import java.awt.geom.*;
import java.util.Random;
public class Bouncer
extends AnimationComponent {
public static void main(String[] args) {
final Bouncer bouncer = new Bouncer();
Frame f = new AnimationFrame(bouncer);
f.setFont(new Font("Serif", Font.PLAIN, 12));
Panel controls = new Panel();
controls.add(bouncer.createCheckbox("Anti.", Bouncer.ANTIALIASING));
controls.add(bouncer.createCheckbox("Trans.", Bouncer.TRANSFORM));
controls.add(bouncer.createCheckbox("Gradient", Bouncer.GRADIENT));
controls.add(bouncer.createCheckbox("Outline", Bouncer.OUTLINE));
controls.add(bouncer.createCheckbox("Dotted", Bouncer.DOTTED));
controls.add(bouncer.createCheckbox("Axes", Bouncer.AXES));
controls.add(bouncer.createCheckbox("Clip", Bouncer.CLIP));
f.add(controls, BorderLayout.NORTH);
f.setVisible(true);
}
// Tweakable variables
private boolean mAntialiasing, mGradient, mOutline;
private boolean mTransform, mDotted, mAxes, mClip;
// ...and the constants that represent them. See setSwitch().
public static final int ANTIALIASING = 0;
public static final int GRADIENT = 1;
public static final int OUTLINE = 2;
public static final int TRANSFORM = 3;
public static final int DOTTED = 4;
public static final int AXES = 5;
public static final int CLIP = 6;
private float[] mPoints;
private float[] mDeltas;
private float mTheta;
private int mN;
private Shape mClipShape;
public Bouncer() {
mN = 38;
mPoints = new float[mN];
mDeltas = new float[mN];
Random random = new Random();
for (int i = 0; i < mN; i++) {
mPoints[i] = random.nextFloat() * 500;
mDeltas[i] = random.nextFloat() * 3;
}
// Make sure points are within range.
addComponentListener(new ComponentAdapter() {
public void componentResized(ComponentEvent ce) {
Dimension d = getSize();
for (int i = 0; i < mN; i++) {
int limit = ((i % 2) == 0) ? d.width : d.height;
if (mPoints[i] < 0) mPoints[i] = 0;
else if (mPoints[i] >= limit) mPoints[i] = limit - 1;
}
}
});
}
public void setSwitch(int item, boolean value) {
switch(item) {
case ANTIALIASING: mAntialiasing = value; break;
case GRADIENT: mGradient = value; break;
case OUTLINE: mOutline = value; break;
case TRANSFORM: mTransform = value; break;
case DOTTED: mDotted = value; break;
case AXES: mAxes = value; break;
case CLIP: mClip = value; break;
default: break;
}
}
protected Checkbox createCheckbox(String label, final int item) {
Checkbox check = new Checkbox(label);
check.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent ie) {
setSwitch(item, (ie.getStateChange() == ie.SELECTED));
}
});
return check;
}
public void timeStep() {
Dimension d = getSize();
for (int i = 0; i < mN; i++) {
float value = mPoints[i] + mDeltas[i];
int limit = ((i % 2) == 0) ? d.width : d.height;
if (value < 0 || value > limit) {
mDeltas[i] = -mDeltas[i];
mPoints[i] += mDeltas[i];
}
else mPoints[i] = value;
}
mTheta += Math.PI / 192;
if (mTheta > (2 * Math.PI)) mTheta -= (2 * Math.PI);
}
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D)g;
setAntialiasing(g2);
setClip(g2);
setTransform(g2);
Shape shape = createShape();
setPaint(g2);
// Fill the shape.
g2.fill(shape);
// Maybe draw the outline.
if (mOutline) {
setStroke(g2);
g2.setPaint(Color.blue);
g2.draw(shape);
}
drawAxes(g2);
}
protected void setAntialiasing(Graphics2D g2) {
if (mAntialiasing == false) return;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
}
protected void setClip(Graphics2D g2) {
if (mClip == false) return;
if (mClipShape == null) {
Dimension d = getSize();
FontRenderContext frc = g2.getFontRenderContext();
Font font = new Font("Serif", Font.PLAIN, 144);
String s = "Spoon!";
GlyphVector gv = font.createGlyphVector(frc, s);
Rectangle2D bounds = font.getStringBounds(s, frc);
mClipShape = gv.getOutline((d.width - (float)bounds.getWidth()) / 2,
(d.height + (float)bounds.getHeight()) / 2);
}
g2.clip(mClipShape);
}
protected void setTransform(Graphics2D g2) {
if (mTransform == false) return;
Dimension d = getSize();
g2.rotate(mTheta, d.width / 2, d.height / 2);
}
protected Shape createShape() {
GeneralPath path = new GeneralPath(GeneralPath.WIND_EVEN_ODD,
mPoints.length);
path.moveTo(mPoints[0], mPoints[1]);
for (int i = 2; i < mN; i += 6)
path.curveTo(mPoints[i], mPoints[i + 1],
mPoints[i + 2], mPoints[i + 3],
mPoints[i + 4], mPoints[i + 5]);
path.closePath();
return path;
}
protected void setPaint(Graphics2D g2) {
if (mGradient) {
GradientPaint gp = new GradientPaint(0, 0, Color.yellow,
50, 25, Color.red, true);
g2.setPaint(gp);
}