An Introduction to 2-D Graphics
in Java |
Prof. David Bernstein |
Computer Science Department |
bernstdh@jmu.edu |
The (Linear) Color Cube
JComponent
Class:
paint(java.awt.Graphics)
method is called and is passed a rendering engine
JComponent
paint()
methodAn Example
import java.awt.*; import javax.swing.*; /** * A concrete extension of a JComponent that illustrates * the process of obtaining and using a rendering engine * * @author Prof. David Bernstein, James Madison University * @version 1.0 */ public class BoringComponent extends JComponent { /** * Render this BoringComponent * * @param g The rendering engine to use */ public void paint(Graphics g) { Graphics2D g2; // Cast the rendering engine appropriately g2 = (Graphics2D)g; // Put the rendering code here } }
read()
method in the ImageIO
classdrawImage(Image i, int x, int y, null)
method
in the Graphics
classimport java.awt.*; import javax.swing.*; /** * A concrete extension of a JComponent that illustrates * the rendering of sampled static visual content * * @author Prof. David Bernstein, James Madison University * @version 1.0 */ public class ImageComponent extends JComponent { private Image image; /** * Explicit Value Constructor * * @param image The Image to render */ public ImageComponent(Image image) { this.image = image; } /** * Render this ImageCanvas * * @param g The rendering engine to use */ public void paint(Graphics g) { Graphics2D g2; // Cast the rendering engine appropriately g2 = (Graphics2D)g; // Render the image g2.drawImage(image, // The Image to render 0, // The horizontal coordinate 0, // The vertical coordinate null); // An ImageObserver } }
import java.awt.*; import java.io.*; import javax.imageio.*; import javax.swing.*; /** * An example that illustrates the rendering of sampled static visual * content * * @author Prof. David Bernstein, James Madison University * @version 1.0 */ public class ImageComponentDriver implements Runnable { private String name; /** * The entry point of the application. * * @param args The command line arguments (args[0] is the file) */ public static void main(String[] args) throws Exception { String name; if (args.length == 0) name = "firstsnow.gif"; else name = args[0]; SwingUtilities.invokeAndWait(new ImageComponentDriver(name)); } /** * Construtor. * * @param name The name of the file to read */ public ImageComponentDriver(String name) { super(); this.name = name; } /** * The code to run in the event dispatch thread. */ public void run() { try { // Read the Image Image image = ImageIO.read(new File(name)); // Construct the JComponent JComponent component = new ImageComponent(image); // Construct the JFrame and add the JComponent JFrame frame = new JFrame(); frame.setSize(600,400); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); JPanel contentPane = (JPanel)frame.getContentPane(); contentPane.setLayout(new BorderLayout()); contentPane.add(component, BorderLayout.CENTER); frame.setVisible(true); } catch (IOException ioe) { System.out.println("Unable to load image!"); } } }
Shape
Objectsimport java.awt.*; import java.awt.geom.*; import java.util.Random; import javax.swing.*; /** * A JComponent that renders a Rectangle with randomly * generated attributes each time it's paint method is called * * @author Prof. David Bernstein, James Madison University * @version 1.0 */ public class RandomRectangleComponent extends JComponent { private Random generator; /** * Default Constructor */ public RandomRectangleComponent() { super(); generator = new Random(System.currentTimeMillis()); } /** * Paint this Component * * @param g The rendering engine to use */ public void paint(Graphics g) { Graphics2D g2; int height, maxHeight, maxWidth, width, x, y; Rectangle rectangle; g2 = (Graphics2D)g; maxHeight = getHeight(); maxWidth = getWidth(); x = generator.nextInt(maxWidth - 1); y = generator.nextInt(maxHeight - 1); width = generator.nextInt(maxWidth - x - 1); height = generator.nextInt(maxHeight - y - 1); rectangle = new Rectangle(x, y, width, height); g2.draw(rectangle); } }
// Construct a quadratic curve quadraticCurve = new QuadCurve2D.Double( 120.0, 120.0, // End 1 300.0, 180.0, // Control 130.0, 190.0); // End 2
// Construct a cubic curve cubicCurve = new CubicCurve2D.Double( 320.0, 320.0, // End 1 300.0, 180.0, // Control 1 330.0, 370.0, // End 2 360.0, 390.0); // Control 2
// Construct an arc arc = new Arc2D.Double(10.0, 200.0, // Upper Left 150.0, // Width 100.0, // Height 0.0, // Starting Angle 135.0, // Angular Extent Arc2D.PIE); // Type
f and i as two glyphs and as a ligature
The RSB is positive for A and negative for f
Kerning - The Use of Different Bearings for Differnt Glyphs
Line Metrics
import java.awt.*; import java.awt.font.*; import javax.swing.*; /** * A JComponent that displays a GlyphVector * * @author Prof. David Bernstein, James Madison University * @version 1.0 */ public class GlyphComponent extends JComponent { protected Font font; protected String text; /** * Explicit Value Constructor */ public GlyphComponent(String text) { super(); setText(text); // Construct a (logical) font font = new Font("Serif", Font.ITALIC, 100); } /** * Paint this component * * @param g The Graphics context to use */ public void paint(Graphics g) { Graphics2D g2; g2 = (Graphics2D)g; // Set the font g2.setFont(font); // Use antialiasing for text and shapes g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); // Use high-quality rendering g2.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); // Use floating point for font metrics g2.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON); // Render the glyphs if (text != null) paintGlyphs(g2, text); } /** * Render a String */ protected void paintGlyphs(Graphics2D g2, String text) { FontRenderContext frc; GlyphVector glyphs; Shape shape; frc = g2.getFontRenderContext(); glyphs = font.createGlyphVector(frc, text); shape = glyphs.getOutline(0.0f, 100.0f); g2.setColor(Color.BLACK); g2.draw(shape); } /** * Set the text associated with this component */ public void setText(String text) { this.text = text; } }
import java.awt.*; import java.awt.font.*; import java.awt.geom.*; import javax.swing.*; /** * A JComponent that displays a GlyphVector and LineMetrics * * @author Prof. David Bernstein, James Madison University * @version 1.0 */ public class GlyphMetricsComponent extends GlyphComponent { /** * Explicit Value Constructor */ public GlyphMetricsComponent(String text) { super(text); // Construct a (logical) Font font = new Font("Serif", Font.PLAIN, 100); } /** * Render the glyphs and the metrics * * Note: There are better approaches. This method * is used for illustrative purposes only. */ protected void paintGlyphs(Graphics2D g2, String text) { FontRenderContext frc; GlyphVector glyphs; frc = g2.getFontRenderContext(); glyphs = font.createGlyphVector(frc, text); LineMetrics lm; lm = font.getLineMetrics(text, frc); float ascent, descent, height, leading; // Get the various metrics ascent = lm.getAscent(); descent = lm.getDescent(); height = lm.getHeight(); leading = lm.getLeading(); Dimension d; float baseline, pWidth, y; Rectangle2D bounds; Shape shape; d = getSize(); g2.setColor(Color.BLACK); baseline = (float)(d.height)/2.0f; pWidth = (float)(d.width); // Draw the metrics y = baseline - ascent; g2.setColor(Color.BLUE); g2.draw(new Line2D.Float(0.0f, y, pWidth, y)); y = baseline; g2.setColor(Color.WHITE); g2.draw(new Line2D.Float(0.0f, y, pWidth, y)); g2.setColor(Color.RED); y = baseline + descent; g2.draw(new Line2D.Float(0.0f, y, pWidth, y)); if (leading > 0) { y = baseline + descent + leading; g2.setColor(Color.GREEN); g2.draw(new Line2D.Float(0.0f, y, pWidth, y)); } // Get the outline at (0,baseline) shape = glyphs.getOutline(0, baseline); g2.setColor(Color.BLACK); g2.draw(shape); g2.fill(shape); } }
import java.awt.*; import java.awt.font.*; import java.awt.geom.*; import javax.swing.*; /** * A JPanel that displays a GlyphVector centered * * @author Prof. David Bernstein, James Madison University * @version 1.0 */ public class CenteredGlyphComponent extends GlyphComponent { /** * Explicit Value Constructor */ public CenteredGlyphComponent(String text) { super(text); } /** * Render the glyphs centered * * Note: There are better approaches. This method * is used for illustrative purposes only. */ protected void paintGlyphs(Graphics2D g2, String text) { FontRenderContext frc; GlyphVector glyphs; Rectangle2D bounds; Shape shape; frc = g2.getFontRenderContext(); glyphs = font.createGlyphVector(frc, text); g2.setColor(Color.black); // Get the outline at (0,0) shape = glyphs.getOutline(); // Get the bounding box bounds = glyphs.getVisualBounds(); Dimension d; float x, y; d = getSize(); // Center the text x = (float)(d.width/2-bounds.getWidth()/2); y = (float)(d.height/2+bounds.getHeight()/2); // Get the outline when centered shape = glyphs.getOutline(x,y); g2.draw(shape); } }
bodyShape = new Path2D.Float(); bodyShape.moveTo( 20, 50); bodyShape.lineTo( 20, 70); bodyShape.lineTo( 20, 90); bodyShape.lineTo( 10, 90); bodyShape.lineTo( 10,100); bodyShape.lineTo( 80,100); bodyShape.lineTo( 80, 90); bodyShape.lineTo( 40, 90); bodyShape.lineTo( 40, 70); bodyShape.lineTo( 40, 50); bodyShape.closePath();
Stroke Joins
Stroke Caps
import java.awt.*; import java.awt.geom.*; import javax.swing.*; /** * An example of a described static visual content * * @author Prof. David Bernstein, James Madison University * @version 1.0 */ public class BuzzyComponent extends JComponent { private Arc2D.Float helmetShape, visorShape; private BasicStroke stroke; private Color black, gold, gray, purple; private Path2D.Float bodyShape; private QuadCurve2D.Float hairShape; /** * Default Constructor */ public BuzzyComponent() { super(); black = Color.BLACK; gold = new Color(0xc2,0xa1,0x4d); gray = new Color(0xaa,0xaa,0xaa); purple = new Color(0x45,0x00,0x84); stroke = new BasicStroke(); bodyShape = new Path2D.Float(); bodyShape.moveTo( 20, 50); bodyShape.lineTo( 20, 70); bodyShape.lineTo( 20, 90); bodyShape.lineTo( 10, 90); bodyShape.lineTo( 10,100); bodyShape.lineTo( 80,100); bodyShape.lineTo( 80, 90); bodyShape.lineTo( 40, 90); bodyShape.lineTo( 40, 70); bodyShape.lineTo( 40, 50); bodyShape.closePath(); hairShape = new QuadCurve2D.Float(10,2,40,10,30,25); helmetShape = new Arc2D.Float(2,20,70,40,2,360,Arc2D.OPEN); visorShape = new Arc2D.Float(40,25,35,30,315,90,Arc2D.PIE); } /** * Paint this Component * * @param g The rendering engine to use */ public void paint(Graphics g) { Graphics2D g2; g2 = (Graphics2D)g; g2.setStroke(stroke); g2.setColor(purple); g2.fill(bodyShape); g2.setColor(black); g2.draw(bodyShape); g2.setColor(purple); g2.draw(hairShape); g2.setColor(gold); g2.fill(helmetShape); g2.setColor(black); g2.draw(helmetShape); g2.setColor(gray); g2.fill(visorShape); g2.setColor(black); g2.draw(visorShape); } }