Graphics Rendering

Chapter describes the ImaneN presentation of rendering shapes, text, and images.

10.1 Introduction

ImageN provides classes that support drawing operations beyond the Graphics2D class. Three different types of graphics rendering are offered: simple 2D graphics, renderable graphics, and tiled image graphics. These are described in more detail in the sections that follow.

Figure 10-1 Simple Text and Line Added to an Image

10.1.1 Simple 2D Graphics

The Graphics2D class extends the even simpler Graphics class to provide more control over geometry, coordinate transformations, color management, and text layout. Graphics2D is the fundamental class for rendering two-dimensional shapes, text and images. Graphics2D supports geometric rendering by providing a mechanism for rendering virtually any geometric shape, draw styled lines of any width, and fill geometric shapes with virtually any texture.

The BufferedImage.createGraphics method creates a Graphics2D object, which can then be used to draw into this BufferedImage.

Geometric shapes are provided through implementations of the Shape interface, such as Polygon, Rectangle, CubicCurve2D, and QuadCurve2D. Fill and pen styles are provided through implementations of the Paint and Stroke interfaces. For example, the Paint interface supports Color, GradientPaint, and TexturePaint. The Stroke interface supports BasicStroke, which defines a set of attributes for the outlines of graphics primitives.

Text is added to graphics using the Font class, which represents character fonts. A Font is defined by a collections of Glyphs, which in turn are defined by individual Shapes. Since text is represented by glyphs, text strings can also be stroked and filled like other geometric objects.

10.1.2 Renderable Graphics

The RenderableGraphics class is an implementation of Graphics2D with RenderableImage semantics. This means that content may be drawn into the image using the Graphics2D interface and later be turned into RenderedImages with different resolutions and characteristics.

The RenderableGraphics class allows you to store a sequence of drawing commands and "replay" them at an arbitrary output resolution. By serializing an instance of RenderableGraphics, you create a kind of metafile for storing the graphical content.

The methods in the RenderableGraphics class override the methods in the java.awt.Graphics and java.awt.Graphics2D classes. This means that you can use the methods in RenderableGraphics to set your fonts and colors, to create the graphics shapes and text, define a clipping path, and so on.

The only method unique to RenderableGraphics is the createRendering method, which creates a RenderedImage that represents a rendering of the image using a given RenderContext. This is the most general way to obtain a rendering of a RenderableImage.

10.2 A Review of Graphics Rendering

To render a graphic object, you set up the Graphics2D context and pass the graphic object to one of the Graphics2D rendering methods. Before rendering the graphic object, you first need to set certain state attributes that define how the Graphics2D context displays the graphics. For example, you specify:

  • The stroke width
  • How strokes are joined
  • A clipping path to limit the area that is rendered
  • Define colors and patterns to fill shapes with

Graphics2D defines several methods that add or change attributes in the graphics context. Most of these methods take an object that represents a particular attribute, such as a Paint or Stroke object.

10.2.1 Overview of the Rendering Process

When a graphic object is rendered, the geometry, image, and attribute information are combined to calculate which pixel values must be changed on the display.

The rendering process for a Shape is described into the following four steps:

Rendering text is similar to rendering a Shape, since the text is rendered as glyphs and each glyph is a Shape. However, you still must specify what Font to use for the text and get the appropriate glyphs from the Font before rendering. The attributes are described in more detail in the following sections.

10.2.2 Stroke Attributes

The Graphics2D Stroke attribute defines the characteristics of strokes. The BasicStroke object is used to define the stroke attributes for a Graphics2D context. BasicStroke defines characteristics such as line width, endcap style, segment join style, and pattern (solid or dashing). To change the Stroke attribute in the Graphics2D context, you call the setStroke method. Line Width

The line width is specified in points (there are 72 points to the inch). To set the stroke width, create a BasicStroke object with the desired width and call setStroke. The following example sets the stroke width to 12 points.

wideStroke = new BasicStroke(12.0);
g2.setStroke(wideStroke); Endcap Style

Table 10-1 lists the endcap style attributes.

Table 10-1 Endcap Styles

Appearance Attribute Description
CAP_BUTT Ends unclosed subpaths with no added decoration.
CAP_ROUND Ends unclosed subpaths with a round end cap radius equal to half the pen width.
CAP_SQUARED Ends unclosed subpaths with a square projection that extends beyond the end of the segment to a distance equal to half the line width.

To set the endcap style, create a BasicStroke object with the desired attribute. The following example sets the stroke width to 12 points and endcap style is set to CAP_ROUND.

wideStroke = new BasicStroke(12.0, BasicStroke.CAP_ROUND);
g2.setStroke(roundStroke); Join Style

Table 10-2 lists the join style attributes. These attributes affect the appearance of line junctions.

Table 10-2 Join Styles

Appearance Attribute Description
JOIN_BEVEL Joins path segments by connecting the outer corners of their wide outlines with a straight segment.
JOIN_ROUND Joins path segments by rounding off the corner at a radius of half the line width.
JOIN_MITER Joins path segments by extending their outside edges until they meet.

To set the join style, create a BasicStroke object with the desired attribute. The following example sets the stroke width to 12 points, an endcap style of CAP_ROUND, and a join style of JOIN_ROUND.

wideStroke = new BasicStroke(12.0, BasicStroke.CAP_ROUND,
g2.setStroke(roundStroke); Stroke Style

The stroke style is defined by two parameters:

  • dash - an array that represents the dashing pattern. Alternating elements in the array represent the dash size and the size of the space between dashes. Element 0 represents the first dash, element 1 represents the first space.

  • dash_phase - an offset that defines where the dashing pattern starts.

Listing 10-1 shows a code sample in which two different dashing patterns are created. In the first pattern, the size of the dashes and the space between them is constant. The second pattern uses a six-element array to define the dashing pattern. The two dash patterns are shown in Figure 10-2.

Listing 10-1 Example Stroke Styles

// Define the first dashed line.
float dash1[] = {10.0f};
BasicStroke bs = new BasicStroke(5.0f, BasicStroke.CAP_BUTT,
                     BasicStroke.JOIN_MITER, 10.0f, dash1, 0.0f);

Line2D line = new Line2D.Float(20.0f, 10.0f, 100.0f, 10.0f);

// Define the second dashed line.
float[] dash2 = {6.0f, 4.0f, 2.0f, 4.0f, 2.0f, 4.0f};
bs = new BasicStroke(5.0f, BasicStroke.CAP_BUTT,
                     BasicStroke.JOIN_MITER, 10.0f, dash2, 0.0f);

Figure 10-2 Example Stroke Styles Fill Styles

The Paint attribute in the Graphics2D context defines the fill color or pattern used when text and Shapes are rendered.

Filling a Shape with a Gradient

The GradientPaint class allows a shape to be filled with a gradient of one color to another. When creating a GradientPaint object, you specify a beginning position and color, and an ending position and color. The fill color changes proportionally from one color to the other along the line connecting the two positions, as shown in Figure 10-3.

In all three stars, the gradient line extends from point P1 to point P2. In the middle star, all of the points along the gradient line extending to the left of P1 take the beginning color and the points to the right of P2 take the ending color.

Figure 10-3 Filling a Shape with a Gradient

To fill a shape with a gradient of one color to another:

Listing 10-2 shows sample code in which a rectangle is filled with a blue-green gradient.

Listing 10-2 Example Filling a Rectangle with a Gradient

GradientPaint gp = new GradientPaint(50.0f, 50.0f,,
                                     50.0f, 250.0f,;
g2.fillRect(50, 50, 200, 200);
Filling a Shape with a Texture

The TexturePaint class allows you to fill a shape with a repeating pattern. When you create a TexturePaint, you specify a BufferedImage to use as the pattern. You also pass the constructor a rectangle to define the repetition frequency of the pattern.

To fill a shape with a texture:

Listing 10-3 shows sample code in which a shape is filled with texture.

Listing 10-3 Example Filling a Shape with Texture

// Create a buffered image texture patch of size 5 X 5.
BufferedImage bi = new BufferedImage(5, 5,
Graphics2D big bi.createGraphics();

// Render into the BufferedImage graphics to create the texture.
big.fillRect(0, 0, 5, 5);
big.fillOval(0, 0, 5, 5);

// Create a texture paint from the buffered image.
Rectangle r = new Rectangle(0, 0, 5, 5);
TexturePaint tp = new
    TexturePaint(bi, r, TexturePaint.NEAREST_NEIGHBOR);

// Add the texture paint to the graphics context.

// Create and render a rectangle filled with the texture.
g2.fillRect(0, 0, 200, 200);

10.2.3 Rendering Graphics Primitives

The Graphics2D class provides methods for creating Shapes and Text, and for rendering Images. Table 10-3 lists these methods.

Table 10-3 Graphics Primitives Methods

Method Description
_ draw Strokes the outline of a Shape using the Stroke and Paint settings of the current Graphics2D context.
fill Fills the interior of a Shape using the Paint settings of the Graphics2D context.
drawString Renders the specified text string using the Paint setting of the Graphics2D context.
drawImage Renders the specified Image.
drawRenderableImage Renders the specified RenderableImage.
drawRenderedImage Renders the specified RenderedImage. Drawing a Shape

The Graphics2D.draw method is used to render the outline of any Shape. The Graphics2D class also inherits draw methods from the Graphics class, such as drawLine, drawRect, drawRoundRect, drawOval, drawArc, drawPolyline, drawPolygon, and draw3DRect.

When a Shape is drawn, its path is stroked with the Stroke object in the Graphics2D context. (See Section 10.2.2, "Stroke Attributes," for more information.) By setting an appropriate BasicStroke object in the Graphics2D context, you can draw lines of any width or pattern. The BasicStroke object also defines the line's endcap and join attributes.

To render a Shape's outline:

Listing 10-4 shows a code example in which a GeneralPath object is used to define a star and a BasicStroke object is added to the Graphics2D context to define the star's line width and join attributes.

Listing 10-4 Example Drawing a Shape

public void paint(Graphics g) {
   Graphics2D g2 = (Graphics2D) g;

   // Create and set the stroke.
   g2.setStroke(new BasicStroke(4.0f));

   // Create a star using a general path object.
   GeneralPath p new GeneralPath(GeneralPath.NON_ZERO);
   p.moveTo(- 100.0f, - 25.0f);
   p.lineTo(+ 100.0f, - 25.0f);
   p.lineTo(- 50.0f, + 100.0f);
   p.lineTo(+ 0.0f, - 100.0f);
   p.lineTo(+ 50.0f, + 100.0f);

   // Translate the origin towards the center of the canvas.
   g2.translate(100.0f, 100.0f);

   // Render the star's path.
} Filling a Shape

The Graphics2D.fill method is used to fill any Shape. When a Shape is filled, the area within its path is rendered with the Paint object in the Graphics2D context: a Color, TexturePaint, or GradientPaint.

The Graphics2D class also inherits fill methods from the Graphics class, such as fillRect, fill3DRect, fillRoundRect, FillOval, fillArc, fillPolygon, and clearRect.

To fill a Shape:

Listing 10-5 shows a code example in which the setColor method is called to define a green fill for a Rectangle2D.

Listing 10-5 Example Filling a Shape

Public void paint(Graphics g) {
   Graphics2D g2 = (Graphics2D) g;

   Rectangle2D r2 = new Rectangle2D.float(25, 25, 150, 150);

} Rendering Text

The entire subject of fonts and text layout is too extensive to try to describe here. In this section, we'll give a brief overview of the Graphics2D.drawString method, which is used to render a text string.

There are two basic variations on the drawString method. Two methods takes a String for an argument and two methods take an AttributedCharacterIterator. If the argument is a String, the current Font in the Graphics2D context is used to convert the characters in the String into a set of glyphs with whatever basic layout and shaping algorithms the font implements. If the argument is an AttributedCharacterIterator, the iterator is asked to convert itself to a TextLayout using its embedded font attributes. The TextLayout implements more sophisticated glyph layout algorithms that perform Unicode I-directional layout adjustments automatically for multiple fonts of differing writing directions.

A third method used to render text is the Graphics2D.drawGlyphVector method, which takes a GlyphVector as an argument. The GlyphVector object contains the appropriate font-specific glyph codes with explicit coordinates for the position of each glyph.

The character outlines are filled with the Paint object in the Graphics2D context.

10.3 Graphics2D Example

Listing 10-6 shows a code sample for a Graphics2D example.

Listing 10-6 Graphics2D Example

// Read a RenderedImage and convert it to a BufferedImage.
imagePath = new String("./images/sample.jpg");
Image ai = loadAWTImage(imagePath, this);
RenderedImage ri = JAI.create("awtimage", ai);
BufferedImage bi = getBufferedImage(ri);
RenderedImage targetImage = null;
targetImage = new BufferedImage(bi.getWidth(),

// Create a Graphics2D object to draw into the BufferedImage.
Graphics2D g2d = targetImage.createGraphics();

10.4 Adding Graphics and Text to an Image

The java.awt.Graphics2D class enables you to draw lines, geometric shapes, images, and text. These objects can then be "painted" over a TiledImage.