package com.mindprod.example;
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Composite;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Polygon;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.font.FontRenderContext;
import java.awt.font.LineMetrics;
import java.awt.geom.Area;
import java.awt.geom.Ellipse2D;
import java.awt.image.BufferedImage;
/**
* Draws Pacman on a transparent background eight ways. Teaching tool.
* Various ways of overpainting with transparency. Though DROPCLOTH is best here,
* others may be more suitable in other contexts.
*/
enum Technique
{
DROPCLOTH
{
void technique(
final Graphics2D g2dOfCaller, final Shape body, final Shape mouth, final Shape eye )
{
final Graphics2D g2d = ( Graphics2D ) g2dOfCaller.create();
final Shape currentClip = g2d.getClip();
final Area dropCloth = currentClip == null ? new Area( new Rectangle( 0,
0,
imageWidth,
imageHeight ) )
: new Area( currentClip );
dropCloth.subtract( new Area( mouth ) );
g2d.clip( dropCloth );
g2d.setColor( PACMAN_BODY_COLOR );
g2d.fill( body );
g2d.setColor( EYE_COLOR );
g2d.fill( eye );
}
},
BUFFEREDCOMPOSITE
{
void technique( final Graphics2D g2d, final Shape body, final Shape mouth, final Shape eye )
{
final Rectangle r = g2d.getClipBounds();
final BufferedImage bufferedImage =
new BufferedImage( r.width, r.height, BufferedImage.TYPE_4BYTE_ABGR_PRE );
final Graphics2D g2d2 = bufferedImage.createGraphics();
g2d2.setColor( PACMAN_BODY_COLOR );
g2d2.fill( body );
g2d2.setColor( TRANSPARENT );
Composite was = g2d2.getComposite();
g2d2.setComposite( AlphaComposite.Clear );
g2d2.fill( mouth );
g2d2.setComposite( was );
g2d2.setColor( EYE_COLOR );
g2d2.fill( eye );
g2d.drawImage( bufferedImage, null, 0, 0 );
}
},
COMPOSITE
{
void technique( final Graphics2D g2d, final Shape body, final Shape mouth, final Shape eye )
{
g2d.setColor( PACMAN_BODY_COLOR );
g2d.fill( body );
g2d.setColor( TRANSPARENT );
Composite was = g2d.getComposite();
g2d.setComposite( AlphaComposite.Clear );
g2d.fill( mouth );
g2d.setComposite( was );
g2d.setColor( EYE_COLOR );
g2d.fill( eye );
}
},
BUFFEREDCLEARRECT
{
void technique( final Graphics2D g2d, final Shape body, final Shape mouth, final Shape eye )
{
final Rectangle r = g2d.getClipBounds();
final BufferedImage bufferedImage =
new BufferedImage( r.width, r.height, BufferedImage.TYPE_4BYTE_ABGR_PRE );
final Graphics2D g2d2 = bufferedImage.createGraphics();
g2d2.setColor( PACMAN_BODY_COLOR );
g2d2.fill( body );
g2d2.setBackground( TRANSPARENT );
g2d2.setColor( TRANSPARENT );
final Rectangle rm = mouth.getBounds();
g2d2.clearRect( rm.x, rm.y, rm.width, rm.height );
g2d2.setColor( EYE_COLOR );
g2d2.fill( eye );
g2d.drawImage( bufferedImage, null, 0, 0 );
}
},
CLEARRECT
{
void technique( final Graphics2D g2d, final Shape body, final Shape mouth, final Shape eye )
{
g2d.setColor( PACMAN_BODY_COLOR );
g2d.fill( body );
g2d.setBackground( TRANSPARENT );
g2d.setColor( TRANSPARENT );
final Rectangle r = mouth.getBounds();
g2d.clearRect( r.x, r.y, r.width, r.height );
g2d.setColor( EYE_COLOR );
g2d.fill( eye );
}
},
COPYAREA
{
void technique( final Graphics2D g2d, final Shape body, final Shape mouth, final Shape eye )
{
g2d.setColor( PACMAN_BODY_COLOR );
g2d.fill( body );
g2d.setBackground( TRANSPARENT );
final Rectangle r = mouth.getBounds();
g2d.copyArea( 0, 0, r.width, r.height, r.x, r.y );
g2d.setColor( EYE_COLOR );
g2d.fill( eye );
}
},
FILL
{
void technique( final Graphics2D g2d, final Shape body, final Shape mouth, final Shape eye )
{
g2d.setColor( PACMAN_BODY_COLOR );
g2d.fill( body );
g2d.setColor( TRANSPARENT );
g2d.fill( mouth );
g2d.setColor( EYE_COLOR );
g2d.fill( eye );
}
},
OPAQUE
{
void technique( final Graphics2D g2d, final Shape body, final Shape mouth, final Shape eye )
{
g2d.setColor( Color.BLACK );
g2d.fill( g2d.getClipBounds() );
g2d.setColor( PACMAN_BODY_COLOR );
g2d.fill( body );
g2d.setColor( Color.BLACK );
g2d.fill( mouth );
g2d.setColor( EYE_COLOR );
g2d.fill( eye );
}
};
/**
* colour of Pacman's eye
*/
private static final Color EYE_COLOR = new Color( 0x335edd );
/**
* colour of Pacman's body, orangy yellow
*/
private static final Color PACMAN_BODY_COLOR = new Color( 0xffd700 );
/**
* default transparent background colour for images.
*/
private static final Color TRANSPARENT = new Color( 0x00ffffff, true );
private static int imageHeight;
private static int imageWidth;
/**
* set the size of the images drawn by Technique
*/
static void setSize( Dimension d )
{
Technique.imageWidth = d.width;
Technique.imageHeight = d.height;
}
/**
* Draw a yellow Pacman with a transparent mouth and background and blue eye
*
* @param g2d graphics context
* @param body outline of Paman's body
* @param mouth outline of Pacman's mouth
* @param eye outline of Pacman's eye
*/
abstract void technique( final Graphics2D g2d, final Shape body, final Shape mouth, final Shape eye );
}
/**
* Draws Pacman on a transparent background eight ways. Teaching tool.
*
* @author Roedy Green, Canadian Mind Products
* @version 1.0 2011-01-09 initial version
* @since 2011-01-09
*/
public class Pacman
{
/**
* color to display the connection against
*/
private static final Color MATTE_COLOUR = new Color( 0xe0e0e0 );
/**
* Prepares a set of png files for various connectors.
*
* @param args not used
*/
public static void main( String[] args )
{
JFrame f = new JFrame();
f.setSize( 760, 470 );
Container contentPane = f.getContentPane();
contentPane.setLayout( new FlowLayout() );
contentPane.setBackground( MATTE_COLOUR );
for ( Technique t : Technique.values() )
{
contentPane.add( new PacmanPanel( t ) );
}
f.validate();
f.setVisible( true );
}
}
/**
* Draw a Pacman on a transparent background
*/
class PacmanPanel extends JPanel
{
/**
* radius of the Pacman
*/
private static final int radius = 75;
/**
* transparent background colour .
*/
private static final Color TRANSPARENT = new Color( 0x00ffffff, true );
/**
* font used to label the Pacmen
*/
private static final Font USUAL_FONT = new Font( "Dialog", Font.PLAIN, 18 );
/**
* which technique to use for transparent overpainting.
*/
private final Technique technique;
/**
* Constructor
*
* @param technique which technique to use for transparent painting
*/
PacmanPanel( Technique technique )
{
this.technique = technique;
setBackground( TRANSPARENT );
setOpaque( false );
final Dimension d = new Dimension( radius * 2 + 20, radius * 2 + 40 );
Technique.setSize( d );
this.setMaximumSize( d );
this.setMinimumSize( d );
this.setPreferredSize( d );
}
/**
* Draw string centered on x,y in both x and y directions
*
* @param g2d the graphics context
* @param x location of center of string.
* @param y location of center of string.
* @param text string to display
*/
private static void drawCenteredString( final Graphics2D g2d, final String text, final int x, final int y )
{
final Font font = g2d.getFont();
int width = g2d.getFontMetrics().stringWidth( text );
final FontRenderContext fr = g2d.getFontRenderContext();
final LineMetrics lm = font.getLineMetrics( text, fr );
final int height = ( int ) ( lm.getAscent() * .76 + .5 );
g2d.drawString( text, x - width / 2, y + height / 2 );
}
/**
* draw a Pacman
*
* @param g where to paint
*/
public void paintComponent( Graphics g )
{
super.paintComponent( g );
Graphics2D g2d = ( Graphics2D ) g;
g2d.setFont( USUAL_FONT );
g2d.setRenderingHint( RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON );
g2d.setRenderingHint( RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY );
g2d.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON );
g2d.setBackground( TRANSPARENT );
final Shape body = new Ellipse2D.Double( 0, 0, radius * 2, radius * 2 );
final Shape mouth = new Polygon( new int[] { radius, radius * 2, radius * 2 },
new int[] { radius, radius - 20, radius + 20 },
3 );
final Shape eye = new Ellipse2D.Double( radius + 5, radius / 2 - 5, 25, 15 );
technique.technique( g2d, body, mouth, eye );
g2d.setColor( Color.RED );
drawCenteredString( g2d, technique.toString().toLowerCase(), radius, radius * 2 + 20 );
}
}