Paint Styles in Java2D

Download Report

Transcript Paint Styles in Java2D

Continuing to very powerful
Rendering Model Java2D.
Summary about Java2D API from
previous week
 That API is not considered a part of Swing;
but
it is closely related to Swing &
effectively used to develop sophisticated Swing
applications.
 Consists of a set of classes and interfaces
for advanced 2D line art, text, and image
rendering.
Some classes and interfaces from
package jawa.awt
Graphicd2D Graphics subclass for rendering 2D
shapes, text and images
BasicStroke Defines a basic set of rendering
attributes for outlines of graphics primitives
GradientPaint provides a way to fill and outline 2D
shapes with a linear color gradient
TexturePaint provides a way to fill and outline shapes
with texture images
Paint define how color patterns can be generated for
rendering operations
Shape provides definitions for geometrical objects
Stroke provides methods for obtaining the outline of
a geometrical shape
Some classes and interfaces from
package java.awt.geom
General Path represents a path constructed from
straight lines, quadratic curves and cubic curves
Line2D Represents a line in coordinate space
RectangularShape Base class for geometrical
shapes with rectangular frames. Subclasses
include Arc2D,Ellipse2D, Rectangle2D and
RoundRectangle2D
BufferedImage Describes an Image with a buffer of
colored pixel data composed of a ColorModel and a
Raster
ColorModel Defines methods for translating a
numerical pixel value to color
Some classes and interfaces from
package java.awt.image
Raster is part of a BufferedImage that describes
sample valued in a rectangular array of pixels
Kernel describes 2D array used for filtering
BufferedImages
BufferedImageOp defines methods that perform
operations on BufferedImages
RasterOp describes single-input/single-output
processes performed on Rasters
Defining BufferedImage object
new BufferedImage (int width, int height, int type)
 Gives us an image of the width/height/type
we require, synchronously. That is:
 After the method returns, that image does exist
 We can then get at the data directly
getRGB, setRGB,
Raster object allows more ways of getting at the pixel
data,
get the ColorModel,
………………………………………………
BufferedImage b= new BufferedImage
(10,10,BufferedImage.TYPE_INT_RGB);
//This BufferedImage is 10 pixels wide and 10 pixels height
//From the third image is stored in RGB color sheme.
Graphics2D graph = b.createGraphics();
//To create the pattern, first draw into BufferedImage
//Created a Graphics2D object for drawing on the BufferedImage
graph.setColor (Color.yellow); //draw in yellow
graph.fillRect (0,0,10,10); //draw filled rectangle
……………………………………………………………
/**graph2D is previously created to get Graphics2D by casting g to Graphics2D **/
// Graphics2D= graph2D = (Graphics2D) g;
graph2D.setPaint (new TexturePaint (b, new Rectangle (10,10)));
//set the Paint object to a new TexturePaint object
graphics2D.fill (new RoundRectangle2D.Double
(155,30,75,100,50,50));
//invoked the fill method of Graphics2D to draw a filled objectRoundRectangle2D.Double
TexturePaint class
TexturePaint ( BufferedImage txt, Rectangle2D anchor)
txt the BufferedImage object with the texture used for painting
anchor - the Rectangle2D in user space from the BufferedImage used to
anchor and replicate the texture
 A TexturePaint object uses the image stored in its associated BufferedImage
as the fill texture for a filled-in shape.
 The TexturePaint class provides a way to fill any shape with a texture that is
specified as a BufferedImage.

The size of the BufferedImage object should be small because the
BufferedImage data is copied by the TexturePaint object.
 But, rectangle may be the same size of BufferedImage
 At construction time, the texture is anchored to the upper left corner of a
Rectangle2D that is specified in user space.
 Texture is computed for locations in the device space by conceptually
replicating the specified Rectangle2D infinitely in all directions in user space
and mapping the BufferedImage to each replicated Rectangle2D.
TYPE_INT_RGB
public static final int TYPE_INT_RGB
 Represents an image with 8-bit RGB color components packed into
integer pixels.
 The image has a DirectColorModel without alpha.
TYPE_BYTE_BINARY
public static final int TYPE_BYTE_BINARY
 Represents an opaque byte-packed 1, 2, or 4 bit image.
 The image has an IndexColorModel without alpha.
 When this type is used as the imageType argument to the
BufferedImage constructor that takes an imageType argument but no
ColorModel argument,
 1-bit image is created with an IndexColorModel with two colors in the
default RGB ColorSpace: {0, 0, 0} and {255, 255, 255}.
 Images with 2 or 4 bits per pixel may be constructed via the
BufferedImage constructor that takes a ColorModel argument by
supplying a ColorModel with an appropriate map size.
 Images with 8 bits per pixel should use the image types
TYPE_BYTE_INDEXED or TYPE_BYTE_GRAY depending on their
ColorModel.
What are Alpha Textures?
 An alpha texture is a texture that contains only alpha
channel, transparency, information.
 Typically this is used to "stencil" a piece of geometry to only
leave pieces visible without chewing very large numbers of
polygons.
 Effectively it is a cookie-cutter for geometry.
 Where the alpha texture is completely transparent, we see
nothing.
 Where it is fully opaque, we see whatever underlying
geometry is there - including the material color.
 If we go the multi-texture route, it would also include the
other textures.
 A typical use for alpha textures is for creating 2D text in a
3D world.
Creating an alpha texture
 Dynamically creating one in code or
 Loading one from a file. (When we load from a file,
we get whatever the file format has).
 The main feature of an alpha texture is that it only
contains one piece of information - the alpha
channel.
 This could be expressed in two ways
a full RGBA image with the color channels ignored,
 We use 4 bytes per pixel, and effectively throwing three of
them away,
 a simple grey-scale image with a single channel, which is
interpreted to mean alpha channel information
 We use one byte per pixel.
Creating Source Image
 Firstly we must start by a BufferedImage
we set the type to be a greyscale image (1 byte per channel)
BufferedImage b = new BufferedImage(128, 128,
BufferedImage.TYPE_BYTE_GRAY);
 We can also use the byte-packed format
(TYPE_BYTE_BINARY)
 if we want to save even more memory,
these are really only useful if all we want is transparent/nontransparent, rather than shades of transparency.
 We need to draw to the texture.
We start with the usual fetch of the Graphics context to draw with
Graphics2D g = b.createGraphics();
Creating Source Image (cont’d)
 We have to execute the drawing instructions.
 How we are going to draw to the image?
Clear all the alpha bits or make the image all transparent
and just draw the parts we want to see OR
We need to decide on the colors to use, and this is the
tricky bit.
To create instances of Color that have the Alpha value set
Color CLEAR_COLOR = new Color(0, 0, 0, 0);
Color VISIBLE_COLOR = new Color(0, 0, 0, 1f);
This is not correct
 We are drawing to an image that only has one byte of color
representation.
If we did the above, all we get is a completely clear image.
The drawing routines will just ignore the alpha value completely and
only work from the color value.
Creating Source Image (cont’d)
 This is a greyscale image so we really need to think
in terms of black and white.
 What black and white mean in the context of
transparency?
If something is transparent, we have a (normal) alpha value of
zero.
 If this alpha value is sourced from a black and white image, we
need to have the value that is zero in that image be the
transparent bit
 In the color world, what has a value of zero? Black.
what is the visible bit? White.
 color definitions really need to be this:
Color CLEAR_COLOR = Color.black;
Color VISIBLE_COLOR = Color.white
Creating Source Image (cont’d)
 We are ready to draw away.
 We clear all the image and then draw a box
with a hole in it:
g.setColor (CLEAR_COLOR);
g.fillRect (0, 0, 128, 128);
g.setColor (VISIBLE_COLOR);
g.fillRect (32, 32, 64, 64);
g.setColor (CLEAR_COLOR);
g.fillRect (48, 48, 32, 32);
g.dispose();
Example:
Tiled Images as Fill Patterns
import javax.swing.*;
import java.awt.*;
import java.awt.geom.*;
import java.awt.image.*;
/** An example of using TexturePaint to fill objects with tiled images. Uses
the getBufferedImage method of ImageUtilities to load an Image from a
file and turn that into a BufferedImage **/
public class TiledImages extends JPanel {
private String dir = System.getProperty ("user.dir");
private String imageFile1 = dir + "/images/yourpicture.jpg";
private TexturePaint imagePaint1;
private Rectangle imageRect;
private String imageFile2 = dir + "/images/yourshape.gif";
private TexturePaint imagePaint2;
private int[] xPoints = { 30, 700, 400 };
private int[] yPoints = { 30, 30, 600 };
private Polygon imageTriangle = new Polygon (xPoints, yPoints, 3);
public TiledImages() {
BufferedImage image =
ImageUtilities.getBufferedImage(imageFile1, this);
imageRect = new Rectangle(235, 70, image.getWidth(), image.getHeight());
imagePaint1 = new TexturePaint (image, imageRect);
image = ImageUtilities.getBufferedImage(imageFile2, this);
imagePaint2 = new TexturePaint(image, new Rectangle(0, 0, 32, 32)); }
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D)g;
g2d.setPaint(imagePaint2);
g2d.fill(imageTriangle);
g2d.setPaint(Color.blue);
g2d.setStroke(new BasicStroke(5));
g2d.draw(imageTriangle);
g2d.setPaint(imagePaint1);
g2d.fill(imageRect);
g2d.setPaint(Color.black);
g2d.draw(imageRect); }
public static void main(String[] args) {
WindowUtilities.openInJFrame(new TiledImages(), 750, 650); } }
Stroke Interface
 abstract interface java.awt.Stroke. Defines only one method:
createStrokedShape(Shape p),
which generates a Shape that is the outline of the given Shape parameter.
 This outline can be of various size, shape. The only implementing class
is BasicStroke
 We use Strokes to define line styles for drawing in the Java2D graphics
context.
 To set the stroke attribute of a given Graphics2D we use its setStroke()
method.
BasicStroke:
class java.awt.BasicStroke
 This class implements the Stroke interface and defines a set of rendering
attributes specifying how to render the outline of a Shape.
 These attributes consist of line width, join style, end-cap style, and dash
style:
The line width (often called the pen width) is the thickness measured perpendicular to
its trajectory.
The end-cap style specifies whether round, butt, or square ends are used to render
the ends of line segments: CAP_ROUND, CAP_BUTT, and CAP_SQUARE.
The join style specifies how to render the joints between segments. This can be one
of bevel, miter, or round: JOIN_BEVEL, JOIN_MITER, and JOIN_ROUND.
The dash style defines a pattern of opaque and transparent regions rendered along a
line segment.
ImageUtilities.java
 A class that simplifies a few common
image operations
 Creating a BufferedImage from an image
file, using MediaTracker to wait until an
image or several images are done loading.
import java.awt.*;
import java.awt.image.*;
public class ImageUtilities {
// Create Image from a file, then turn that into a BufferedImage.
public static BufferedImage getBufferedImage(String
imageFile, Component c) {
Image image = c. getToolkit() .getImage (imageFile);
waitForImage(image, c);
BufferedImage bufferedImage = new
BufferedImage(image.getWidth(c), image.getHeight(c),
BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = bufferedImage.createGraphics();
g2d.drawImage(image, 0, 0, c);
return(bufferedImage); }
//Take an Image associated with a file, and wait until it is done loading.
//Just a simple application of MediaTracker.
//If we are loading multiple images, we don't use this consecutive times;
// instead we use the version that takes an array of images.
public static boolean waitForImage(Image image, Component c)
{
MediaTracker tracker = new MediaTracker(c);
tracker.addImage(image, 0);
try { tracker.waitForAll();
} catch(InterruptedException ie) {}
return (!tracker.isErrorAny());
}
//Take some Images associated with files
//wait until they are done loading.
//Just a simple application of MediaTracker.
public static boolean waitForImages (Image[] images,
Component c) {
MediaTracker tracker = new MediaTracker(c);
for (int i=0; i<images.length; i++)
tracker.addImage(images[i], 0);
try {
tracker.waitForAll();
} catch(InterruptedException ie) {}
return(!tracker.isErrorAny());
}
}
public class MediaTracker
 The MediaTracker class is a utility class to track the status
of a number of media objects.
 Media objects could include audio clips as well as images,
though currently only images are supported.
 To use a media tracker, create an instance of MediaTracker
and call its addImage method for each image to be tracked.
 In addition, each image can be assigned a unique identifier.
 This identifier controls the priority order in which the images
are fetched.
 It can also be used to identify unique subsets of the images
that can be waited on independently.
 Images with a lower ID are loaded in preference to those
with a higher ID number.