HOME  |    TRAINING  |   FREE TUTORIALS   |   JOBS
Find out more about our new RSS feed.
FREE Tutorial
BEGINNING JAVA 2 - JDK 1.3 VERSION PART 7 - SYNTHESIZING IMAGES

CATEGORY
SEARCH OUR OTHER TUTORIALS

DESCRIPTION

You don't have to read all your images in from files - you can create your own. The most flexible way of doing this involves using a BufferedImage object. This is a subclass of the Image class that has the image data stored in a buffer that you can access. It also supports a variety of ways of storing the pixel data: with or without an alpha channel, different types of color model and with various precisions for color components.
Click here to be kept informed of our new Tutorials.


This free tutorial is a sample from the book Beginning Java 2: 1.3 Version.


The ColorModel class provides a flexible way to define various kinds of color models for use with a BufferedImage object but to understand the basics of how this works we will only use one color model, the default where color components are RGB values, and one buffer type - storing 8 bit RGB color values plus an alpha channel. This type is specified in the BufferedImage class by the constant TYPE_INT_ARGB, which implies an int value is used for each pixel. The value for each pixel stores an alpha component plus the RGB color components as 8 bit bytes. We can create a BufferedImage object of this type with a given width and height with statements such as:

int width = 200;
int height = 300;
BufferedImage image = new BufferedImage(width, height, 
BufferedImage.TYPE_INT_ARGB);

This creates a BufferedImage object that represents an image 200 pixels wide and 300 pixels high. To draw on the image, we need a graphics context, and the createGraphics() method for the BufferedImage object returns a Graphics2D object that relates to the image:

Graphics2D g2D = image.createGraphics();

Operations using the g2D object modify pixels in the BufferedImage object, image. With this object available you now have the full capability to draw on the BufferedImage object - you can draw shapes, images, GeneralPath objects or whatever, and you can set the alpha compositing object for the graphics context as we discussed in the previous section. And you also have all the affine transform capability that comes with a Graphics2D object.

You can retrieve an individual pixel from a BufferedImage object by calling its getRGB() method and supplying the x,y coordinates of the pixel as arguments of type int. The pixel is returned as type int in the TYPE_INT_ARGB format, which consists of four 8-bit values for the alpha and RGB color components packed into the 32-bit word. There is also an overloaded version of getRGB() that returns an array of pixels from a portion of the image data. You can set an individual pixel value by calling the setRGB() method. The first two arguments are the coordinates of the pixel, and the third argument is the value that is to be set, of type int. There is also a version of this method that will set the values of an array of pixels. We won't be going into pixel operations further, but we will venture drawing on a BufferedImage object with a working example.

We will put together an applet that uses a BufferedImage object. The applet will create an animation of the buffered image object that is created against a background of the Wrox logo. This will also demonstrate how you can make part of an image transparent. The applet will be broadly similar to applets we have produced earlier in this chapter; the basic contents of the source file will look like this:

import java.awt.*;
import java.awt.image.*;
import java.awt.geom.*;
import javax.swing.*;

public class ImageDrawDemo extends JApplet
{
// The init() method to initialize everything...

// The start() method to start the animation...
// The stop() method to stop the animation...
// The ImagePanel class defining the panel displaying the animation...

// Data members for the applet...
}

Creating an Image

A sprite is a small graphical image that you can draw over a static image to create an animation. To create the animation effect, you just draw the sprite in different positions and orientations over time, and of course transformations of the coordinate system can be a great help in making this easier. Games often use sprites - they can make the animation take much less processor time because you only need to draw the sprite against a static background. Our interest in using BufferedImage objects means we won't get into the best techniques for minimizing processor time. We will instead concentrate on understanding how we can create and use images internally in a program.

Our BufferedImage object is going to look as shown below.

The image is a square with sides of length spriteSize. Dimensions of other parts of the image are relative to this. There are really only two geometric entities here, a line and a circle, each repeated in different positions and orientations, so if we create a Line2D.Double object for the line, and an Ellipse2D.Double object for the circle, we should be able to draw the whole thing by moving the user coordinate system around and drawing one or other of these two objects.

A true object-oriented approach would define a class representing a sprite, possibly as a subclass of BufferedImage, but since we are exploring the mechanics of using a BufferedImage object, it will suit our purpose better to develop a method, createSprite(), that draws the sprite on a BufferedImage object. The method will just be a member of our applet class so we will add data members to the applet to store any data required. You can plug the data members we will be using into the applet class outline now:

double totalAngle;       // Current angular position of sprite
double spriteAngle;      
// Rotation angle of sprite about its center
ImagePanel imagePanel;     // Panel to display animation

BufferedImage sprite;     // Stores reference to the sprite
int spriteSize = 100;     // Diameter of the sprite
Ellipse2D.Double circle;    // A circle - part of the sprite
Line2D.Double line;      // A line - part of the sprite

// Colors used in sprite
Color[] colors = {Color.red , Color.yellow, Color.green , Color.blue,
Color.cyan, Color.pink , Color.magenta, Color.orange};

java.util.Timer timer;     // Timer for the animation
long interval = 50;      // Time interval msec between repaints

The general use of these members should be clear from the comments. We will see how they are used as we develop the code.

The first thing the createSprite() method needs to do is to create the BufferedImage object, sprite, and we will need a Graphics2D object to use to draw on the sprite image. The code to do this is as follows:

BufferedImage createSprite(int spriteSize)
{
 // Create image with RGB and alpha channel
 BufferedImage sprite = new BufferedImage(spriteSize, spriteSize, 
 BufferedImage.TYPE_INT_ARGB);

 Graphics2D g2D = sprite.createGraphics();  
 // Context for buffered image
 // plus the rest of the method...
}

The sprite object has a width and height of spriteSize, and the image is of the type TYPE_INT_ARGB, so the alpha and color components for each pixel will be stored as a single int value, and the color will be stored as 8 bit red, green and blue components. This means that our sprite image will occupy 40,000 bytes, which is a small indication of how browsing a web page can gobble up memory. This doesn't affect the download time for the page - this memory is allocated in the local machine when the applet is executed. Apart from the contents of the HTML file that is the page, the download time is affected by the size of the .class file for the applet, plus any image or other files that it downloads when it executes.

Creating a Transparent Background

The alpha channel is important in our sprite image because we want the background to be completely transparent - only the sprite object itself should be seen when we draw it, not the whole 100x100 rectangle of the image. We can achieve this quite easily by making the whole sprite image area transparent to start with - that is with an alpha of 0.0f - and then drawing what we want on top of this as opaque with an alpha of 1.0f. Here's the code to make the entire image transparent:

 
// Clear image with transparent alpha by drawing a rectangle
g2D.setComposite(AlphaComposite.getInstance(
AlphaComposite.CLEAR, 0.0f));
Rectangle2D.Double rect = new Rectangle2D.Double(0,0,
spriteSize,spriteSize); 
g2D.fill(rect);

We first set the alpha composite using an AlphaComposite object with the CLEAR rule - this will set the color components to zero, and with an alpha of 0.0f, which will make it transparent. We then fill a rectangle that covers the whole area of the image. We don't need to set a color since with the CLEAR rule the fraction of the foreground and background for each pixel is zero, so neither participates in the resulting pixel. We still have to fill the rectangle though, since this determines the image pixels that are operated on.

At this point we can take a short detour into how you can affect the quality of your images.

Continued...


NEXT PAGE



7 RELATED COURSES AVAILABLE
INTRODUCTION TO JAVA PROGRAMMING
The aims of this Java training courses is to understand the role that Java plays on the Internet; describe the be....
JAVA (V1.2): ADVANCED PROGRAMMING
This course teaches the reader to learn, understand and become familiar with the advanced features of Java progra....
INTRODUCTION TO JAVABEANS
To go from the fundamentals of JavaBeans programming to the threshold of Advanced level. Gaining in depth progr....
C++ PROGRAMMING
Object oriented programming is fast becoming the leading software design methodology, with C++ becoming ever more....
C PROGRAMMING
This course is design to provide non-C programmers with the essential skills and knowledge necessary to allow the....
 
1 RELATED JOBS AVAILABLE
JAVA DEVELOPER MANCHESTER
Computer Futures Solutions are seeking a Senior Java Developer for their Manchester based client. You will be joi....
CONTACT US
Wednesday 7th January 2009  © COPYRIGHT 2009 - VISUALSOFT