// Logo2D.java - Demos Many 2D graphics effects. Note this // Applet requires a Java 2 (version 1.4 or higher) JVM to run. // This shows a fancy Java2D, internationalized logo. // A special feature of this logo is the use of random numbers // to control the appearence of the text. // // (C) 2003 by Wayne Pollock, Tampa FL USA. All Rights Reserved. /* <APPLET CODE="Logo2D" HEIGHT="250" WIDTH="400"> </APPLET> */ import java.applet.*; import java.awt.*; import java.awt.font.*; // For fancy text effects import java.awt.geom.*; // Shapes to draw and fill import java.util.Random; // New random number generator class public class Logo2D extends Applet { long seed; // value for random number generator. String logo, motto; public void init () { seed = new Random().nextLong(); setBackground( Color.pink ); logo = "Miracle Widgets"; motto = "It's a Miracle if it works well"; } public void paint( Graphics gr ) { Graphics2D g = (Graphics2D) gr; Random rng = new Random( seed ); // create random number generator. // Set the Font to something big: Font mottoFont = new Font( "Serif", Font.BOLD, 18 ); Font logoFont = new Font( "Monospaced", Font.BOLD, 24 ); FontMetrics fm; int hpos; // The left edge for drawing text int ypos = 145; // The baseline for drawing motto text // Draw simple text, centered: g.setFont( mottoFont ); fm = g.getFontMetrics(); hpos = ( getWidth() - fm.stringWidth(motto) ) / 2; g.drawString( motto, hpos, ypos ); ypos -= (fm.getHeight() + 5); // Place the logo above motto. // Draw "fun" text. First convert a String into an array // of "glyphs" which are Font-specific Shapes. Then before // drawing any letter shape, apply some random transformations: // Save original transformation and Paint: AffineTransform originalTransform = g.getTransform(); Paint originalPaint = g.getPaint(); // Set initial drawing position for logo: g.setFont( logoFont ); fm = g.getFontMetrics(); hpos = ( getWidth() - fm.stringWidth(logo) ) / 2; g.translate( hpos, ypos ); // Create a GlyphVector (list of Shapes of letters): FontRenderContext frc = g.getFontRenderContext(); GlyphVector gv = logoFont.createGlyphVector( frc, logo ); // Create a Transform to "jiggle" each letter shape a bit // by small random scale, rotate, or shear transformations: for ( int i = 0; i < gv.getNumGlyphs(); ++i ) { // Create the transform to use to jiggle the letter: AffineTransform at = new AffineTransform(); // Move ("translate") to position to draw the letter: Point2D pos = gv.getGlyphPosition( i ); at.translate( pos.getX(), pos.getY() ); // Jiggle the letter: switch ( rng.nextInt(4) ) { case 0: // Apply a rotate transformation by +/- 10..20 degrees: int sign = ( rng.nextInt( 2 ) == 0 ? -1 : 1 ); double angle = sign * (rng.nextDouble()/2.0 + 0.5) * Math.PI / 9.0; at.rotate( angle ); break; case 1: // Apply a scale traqnsformation: // Stretch/shrink letter by +/- 50%: double factor = (50 + rng.nextInt(100 + 1) ) / 100.0; at.scale( factor, factor ); break; case 2: // Apply a 25%..50% shear transformation in Y dimension only: at.shear( ( 5 + rng.nextInt(6) ) / 20.0, 0.0 ); break; default: // Don't transform (do nothing): break; } // Set a random color to draw with: Color [] colors = { Color.red, Color.orange.darker(), Color.blue, Color.green.darker(), Color.darkGray, Color.magenta, Color.black }; g.setPaint( colors[ rng.nextInt( colors.length ) ] ); // Draw the glyph: (The letter Shape is defined with (0,0) local to // upper left of the glyphVector. As we have already used a translate // transform (so as to apply the other transforms), if we just draw // the Shapes they will all stack up on each other. The Shapes must // be translated back to the correct positions. This could be done // later using the Shape but Java 1.4 includes the method below, // which allows use to easily reverse the original translation. // (Prior to Java 1.4 each Shape in a GlyphVector had it's own // (0,0) coordinate, so you would just use gv.getGlyphOutline(i).) Shape letterShape = gv.getGlyphOutline( i, (float) -pos.getX(), (float) -pos.getY() ); letterShape = at.createTransformedShape( letterShape ); g.fill( letterShape ); } // Restore original graphic context: g.setTransform( originalTransform ); g.setPaint( originalPaint ); // Draw a box using dashed lines and default Paint: float [] dashList = { 5, // First a dash of 5 pixels 3, // then a 3 pixel gap 2, // then a 2 pixel dash 3 // a final 3 pixel gap before repeating }; BasicStroke dashes = new BasicStroke( 2, // Line thickness BasicStroke.CAP_ROUND, // Line end style BasicStroke.JOIN_ROUND, // Line joint style 1, // Mitre join limit (joint extension) dashList, // array of dash lengths 0 // Starting point of dashes ); g.setStroke( dashes ); g.draw( new Rectangle(75, 70, 250, 95) ); // Draw a box using a thick diagonal rainbow line: GradientPaint rainbow = new GradientPaint( 0, 0, Color.yellow, // Starting point and Color 20, 20, Color.blue, // Ending point and Color true // Cycle through colors repeatedly ); g.setPaint ( rainbow ); g.setStroke( new BasicStroke(10) ); // a 10 pel thick line g.draw( new RoundRectangle2D.Double(30, 45, 340, 145, 5, 5) ); } }
Send comments and questions to
pollock@acm.org. |