FileDocCategorySizeDatePackage
CompositeEffects.javaAPI DocExample6191Sat Jan 24 10:44:36 GMT 2004je3.graphics

CompositeEffects.java

/*
 * 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.graphics;
import java.awt.*;
import java.awt.geom.*;
import java.awt.image.*;

public class CompositeEffects implements GraphicsExample {
    Image cover;  // The image we'll be displaying, and its size
    static final int COVERWIDTH = 127, COVERHEIGHT = 190;

    /** This constructor loads the cover image */
    public CompositeEffects() {
	java.net.URL imageurl = this.getClass().getResource("cover.gif");
	cover = new javax.swing.ImageIcon(imageurl).getImage();
    }

    // These are basic GraphicsExample methods
    public String getName() {return "Composite Effects";} 
    public int getWidth() { return 6*COVERWIDTH + 70; } 
    public int getHeight() { return COVERHEIGHT + 35; }

    /** Draw the example */
    public void draw(Graphics2D g, Component c) {
	// fill the background 
	g.setPaint(new Color(175, 175, 175));
	g.fillRect(0, 0, getWidth(), getHeight());

	// Set text attributes
	g.setColor(Color.black);
	g.setFont(new Font("SansSerif", Font.BOLD, 12));

	// Draw the unmodified image
	g.translate(10, 10);
	g.drawImage(cover, 0, 0, c);
	g.drawString("SRC_OVER", 0, COVERHEIGHT+15);

	// Draw the cover again, using AlphaComposite to make the opaque
	// colors of the image 50% translucent
	g.translate(COVERWIDTH+10, 0);
	g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
						  0.5f));
	g.drawImage(cover, 0, 0, c);

	// Restore the pre-defined default Composite for the screen, so
	// opaque colors stay opaque.
	g.setComposite(AlphaComposite.SrcOver);
	// Label the effect
	g.drawString("SRC_OVER, 50%", 0, COVERHEIGHT+15);

	// Now get an offscreen image to work with.  In order to achieve
	// certain compositing effects, the drawing surface must support
	// transparency. Onscreen drawing surfaces cannot, so we have to do the
	// compositing in an offscreen image that is specially created to have
	// an "alpha channel", then copy the final result to the screen.
	BufferedImage offscreen =
	    new BufferedImage(COVERWIDTH, COVERHEIGHT,
			      BufferedImage.TYPE_INT_ARGB);
	
	// First, fill the image with a color gradient background that varies
	// left-to-right from opaque to transparent yellow
	Graphics2D osg = offscreen.createGraphics();
	osg.setPaint(new GradientPaint(0, 0, Color.yellow,
				       COVERWIDTH, 0,
				       new Color(255, 255, 0, 0))); 
	osg.fillRect(0,0, COVERWIDTH, COVERHEIGHT);

	// Now copy the cover image on top of this, but use the DstOver rule
	// which draws it "underneath" the existing pixels, and allows the
	// image to show depending on the transparency of those pixels.
	osg.setComposite(AlphaComposite.DstOver);
	osg.drawImage(cover, 0, 0, c);
	
	// And display this composited image on the screen.  Note that the
	// image is opaque and that none of the screen background shows through
	g.translate(COVERWIDTH+10, 0);
	g.drawImage(offscreen, 0, 0, c);
	g.drawString("DST_OVER", 0, COVERHEIGHT+15);

	// Now start over and do a new effect with the off-screen image.
	// First, fill the offscreen image with a new color gradient.  We
	// don't care about the colors themselves; we just want the
	// translucency of the background to vary.  We use opaque black to
	// transparent black. Note that since we've already used this offscreen
	// image, we set the composite to Src, so we can fill the image and
	// ignore anything that is already there.
	osg.setComposite(AlphaComposite.Src); 
	osg.setPaint(new GradientPaint(0, 0, Color.black,
				       COVERWIDTH, COVERHEIGHT,
				       new Color(0, 0, 0, 0))); 
	osg.fillRect(0,0, COVERWIDTH, COVERHEIGHT);
	
	// Now set the compositing type to SrcIn, so colors come from the 
	// source, but translucency comes from the destination
	osg.setComposite(AlphaComposite.SrcIn);
	
	// Draw our loaded image into the off-screen image, compositing it.
	osg.drawImage(cover, 0, 0, c);
	
	// And then copy our off-screen image to the screen.  Note that the
	// image is translucent and some of the background shows through.
	g.translate(COVERWIDTH+10, 0);
	g.drawImage(offscreen, 0, 0, c);
	g.drawString("SRC_IN", 0, COVERHEIGHT+15);
	
	// If we do the same thing but use SrcOut, then the resulting image 
	// will have the inverted translucency values of the destination
	osg.setComposite(AlphaComposite.Src); 
	osg.setPaint(new GradientPaint(0, 0, Color.black,
				       COVERWIDTH, COVERHEIGHT,
				       new Color(0, 0, 0, 0))); 
	osg.fillRect(0,0, COVERWIDTH, COVERHEIGHT);
	osg.setComposite(AlphaComposite.SrcOut);
	osg.drawImage(cover, 0, 0, c);
	g.translate(COVERWIDTH+10, 0);
	g.drawImage(offscreen, 0, 0, c);
	g.drawString("SRC_OUT", 0, COVERHEIGHT+15);

	// Here's a cool effect; it has nothing to do with compositing, but
	// uses an arbitrary shape to clip the image.  It uses Area to combine
	// shapes into more complicated ones.
	g.translate(COVERWIDTH+10, 0);
	Shape savedClip = g.getClip();  // Save current clipping region
	// Create a shape to use as the new clipping region.  
	// Begin with an ellipse
	Area clip = new Area(new Ellipse2D.Float(0,0,COVERWIDTH,COVERHEIGHT));
	// Intersect with a rectangle, truncating the ellipse.
	clip.intersect(new Area(new Rectangle(5,5,
					      COVERWIDTH-10,COVERHEIGHT-10)));
	// Then subtract an ellipse from the bottom of the truncated ellipse.
	clip.subtract(new Area(new Ellipse2D.Float(COVERWIDTH/2-40,
						   COVERHEIGHT-20, 80, 40)));
	// Use the resulting shape as the new clipping region
	g.clip(clip);
	// Then draw the image through this clipping region
	g.drawImage(cover, 0, 0, c);
	// Restore the old clipping region so we can label the effect
	g.setClip(savedClip);
	g.drawString("Clipping", 0, COVERHEIGHT+15);
    }
}