Java Easy Programming Guide
Java Easy Programming Guide
Home•
Features•
Submit an article○
Presentations and Articles○
JavaPolis 2004 Online○
JavaZone 2005○
Announcements○
Newsletters○
Forums•
Overview○
Help & FAQ○
Posting guidelines○
Recent postings○
Popular discussions○
Who's online○
Blogs•
Popular blogs○
Start your free blog○
Recent blog entries○
JL Network•
Javalobby.org○
Javacrawl.com○
JDocs.com○
JRoller.com○
JUGCentral.com○
MyJavaServer.com○
Friends & Partners○
Members Only•
Control Panel○
Subscriptions○
Downloads○
Benefits○
Special Offers○
About JL•
Our story○
Sites & Services○
In the News○
Privacy policy○
Contact us○
Advertising info○
FAQ○
finishing out his senior year in high school, and has aspirations of
Spotlight Features
Contents
Basic Image Theory and Operations-
Images in Java-
Loading an Image-
Saving Images-
Flipping an Image-
Rotating an Image-
Resizing an Image-
Splitting Images-
Sprite Animation-
Images are the staple of any graphical application, whether on the web or on the desk,
images are everywhere. Having the ability to control and manipulate these images is a
crucial skill that is absolutely necessary for any graphical artist, designer, or Game
Engineer. This article will get you, the aspiring artist, professional designer, or amateur
hobbyist, the foundations to be able to manipulate any image to your will. The end result
will be twofold, you will have a nice Image Utility class for use in any of your Projects (I
found it was most useful for 2d gaming), and you will have a small, but powerful
application that can perform most common, and many not so common operations on.
jpg's, .png's, .gif's, and bmp image files. This article assumes only that you have basic
Java programming ability; of course a little prior Image experience would help. Know that
!I wont bog you down with trigonometric details. So, enough talking lets get coding
Images in Java
basic model for controlling an image, but the real meat of the Java Image is
thejava.awt.image.BufferedImage. A BufferedImage is an accessible buffer of image
data, essentially pixels, and their RGB colors. The BufferedImage provides a powerful way
to manipulate the Image data. A BufferedImage object is made up of two parts
.a ColorModel object and a Raster object
The ColorModel object provides methods that translate an image's pixel data into color
that stores the sample values and a SampleModel that describes how to locate a given
sample value in a DataBuffer. Basically, the Raster holds two things, a DataBuffer,
which contains the raw image data and a SampleModel, which describes how the data is
Loading an Image
Probably the most common and most used image operation is loading an image. Loading
an image is fairly straight forward, and there are many ways to do it, so I will show you
.one of the simplest and quickest ways, using the javax.imageio.ImageIO class
Basically what we want to do is load all the bytes from some image file, into
a BufferedImage so that we can display it. This can be accomplished through the use
.of ImageIO
?view plaincopy to clipboardprint
} (public static BufferedImage loadImage(String ref.1
;BufferedImage bimg = null .2
} try .3
.4
;((bimg = ImageIO.read(new File(ref .5
} (catch (Exception e { .6
;()e.printStackTrace .7
{ .8
;return bimg .9
{ .10
of an image to a BufferedImage. Once you have the BufferedImage, you can do many
things with it. Of course loading an image is nearly completely useless unless you can
This is where the fun starts. To draw an Image, we need a surface to draw on; the
Abstract Windowing Toolkit and Swing supply this. For a more detailed tutorial on those
subjects, look up the java documentation at java.net. Every top-level container in Swing
and AWT such as aJPanel, JFrame, or Canvas, has its own Graphics object.
This Graphics object allows us to draw on its parent surface (a JPanel, JFrame,
Canvas, or Image) with such calls asGraphics.drawLine(int x1, int y1, int
x2, int y2); or Graphics.drawImage(Image img, int x, int y,
ImageObserver ob); The Graphics2D object, is a more powerful child of
the Graphicsobject, it adds more methods which allow for drawing BufferedImages. Here
.is an example of how to load and draw a BufferedImage onto the screen
the JFrame that is passed in to our liking, and get the frames Graphics object. Note that
we have to set the frame visible before we ask for the Graphics object. Then we use the
graphics to draw the image at position (0, 0). Very simple, and very incomplete, you will
notice that if you resize the screen, the image will disappear. To remedy this problem, we
need to create a sub-class of JPanel that will facilitate showing images that will display no
the supplied coordinates. Wrapping our images in this Panel will allow Swing and AWT to
:handle all rendering. Here is the previous example, except now using theJImagePanel
This change makes a world of difference, as now the resizing, buffering, and other
complicated stuff is handled internally, now all we have to worry about is manipulating
.images
There are a few ways to create your own Image, all fairly simple. The most obvious way
:would be to simply create a new BufferedImage object. Like this
?view plaincopy to clipboardprint
BufferedImage img = new BufferedImage(100, 100, BufferedImage.TYPE_3BYT .1
;(E_BGR
But to be able to draw into this image, you first need to create
:the Graphics
?view plaincopy to clipboardprint
BufferedImage img = new BufferedImage(100, 100, BufferedImage.TYPE_3BYT .1
;(E_BGR
;()img.createGraphics.2
Now we have a surface to draw on, so, as an example, Ill draw a road on a yellow
;background
?view plaincopy to clipboardprint
} public class ImageMaker.1
.2
} ()public static BufferedImage createImage .3
BufferedImage img = new BufferedImage(100, 100, BufferedImage.TYPE_I .4
;(NT_RGB
;()img.createGraphics .5
;()Graphics2D g = (Graphics2D)img.getGraphics .6
;(g.setColor(Color.YELLOW .7
;(g.fillRect(0, 0, 100, 100 .8
.9
} (++for(int i = 1; i < 49; i .10
;((g.setColor(new Color(5*i, 5*i, 4+1*2+i*3 .11
;(g.fillRect(2*i, 2*i, 3*i, 3*1 .12
{ .13
;return img .14
{ .15
.16
} (public static void main(String[] args .17
;("JFrame frame = new JFrame("Image Maker .18
} ()frame.addWindowListener(new WindowAdapter .19
} (public void windowClosing(WindowEvent event .20
;(System.exit(0 .21
{ .22
;({ .23
;(frame.setBounds(0, 0, 200, 200 .24
;(JImagePanel panel = new JImagePanel(createImage(), 50, 45 .25
;(frame.add(panel .26
;(frame.setVisible(true .27
{ .28
.29
{.30
This creates a BufferedImage, creates its graphics, then sets the background to yellow,
lastly, using clever manipulation of a for loop, the program makes a rough drawing of a
road. This method returns an image that is promptly displayed our custom JImagePanel.
Note that I addedWindowAdapter to the JFrame so that it will actually destroy the JVM
This is a small example of how you can make your own images. You can also use
the Graphics2Dmethods to display a string in a particular font, draw ovals, predefined
Saving Images
Saving an image to a file is a fairly simple operation, basically, all that needs to happen is
.for bytes in memory to be written to a file. Below is the old way of saving a JPEG
?view plaincopy to clipboardprint
} (public static void saveOldWay(String ref, BufferedImage img.1
;BufferedOutputStream out .2
} try .3
;((out = new BufferedOutputStream(new FileOutputStream(ref .4
;(JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out .5
;(JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam(img .6
;int quality = 5 .7
;((quality = Math.max(0, Math.min(quality, 100 .8
;(param.setQuality((float) quality / 100.0f, false .9
;(encoder.setJPEGEncodeParam(param .10
;(encoder.encode(img .11
;()out.close .12
} (catch (Exception e { .13
;()e.printStackTrace .14
{ .15
{ .16
This saves your BufferedImage img to a JPEG file with a path specified by the String
refBasically, it encodes your image data into the JPEG format, sets the image quality,
then saves it to a file. This archaic way of saving an image has many faults though,
three forms of the write method, which writes your image data to a file in JPEG or PNG,
:We can wrap our ImageUtil around one of these write methods, like this
?view plaincopy to clipboardprint
**/.1
Saves a BufferedImage to the given file, pathname must not have any * .2
periods "." in it except for the one before the format, i.e. C:/images/fooimage. * .3
png
param img@ * .4
param saveFile@ * .5
/* .6
} (public static void saveImage(BufferedImage img, String ref.7
} try .8
;"String format = (ref.endsWith(".png")) ? "png" : "jpg .9
;((ImageIO.write(img, format, new File(ref .10
} (catch (IOException e { .11
;()e.printStackTrace .12
{ .13
{.14
Making an Image Translucent
or see through. If you have any experience with Photoshop, Gimp or other Imaging
programs, this means modifying an Images alpha, or applying an Alpha layer on top of the
The Graphics2D object, which is a part of every image, and top level container (such as
setPaint(Paint paint), all of these affect how the Graphics2D draws the image. For
this part of the tutorial, we will mainly be concerned with setComposite(Composite
comp). Composites let us modify things like the transparency of an image, which is what
we are interested in. Most of the time we only want the AlphaComposite on the Image, not
on the entire Container. So we'll add another method to ourImageUtil class that will load
an Image and set a certain amount of alpha on the image only, leaving the container
This block of code first loads your our image, and then creates
another BufferedImage to draw into that allows translucency. Then, right after it gets
the Graphics2D object of the image, it sets the composite to an AlphaComposite, with
the alpha level set to whatever the user specifies. The amount of alpha can be any float
value from 0.0 to 1.0. Next it draws the loaded image, into the translucency capable
image, and disposes of unsued resources. Using our JImagePanel we draw the image
A useful function of many imaging programs such as GIMP is its ability to make only one
color of an Image transparent; this is called applying a mask. To do this, GIMP evaluates
each pixel of an image, and tests if it is the user specified masking color, if it is it sets that
:pixel's RGB value to nothing, and it's alpha to 0.0. Here is the Java implementation
?view plaincopy to clipboardprint
} (public static BufferedImage makeColorTransparent(String ref, Color color.1
;(BufferedImage image = loadImage(ref .2
BufferedImage dimg = new BufferedImage(image.getWidth(), image.getHei .3
;(ght(), BufferedImage.TYPE_INT_ARGB
This will load the image, and also sets up a destination image for drawing into. The next
Alpha. It then draws the Image onto the screen, and disposes of the Graphics2D to clear
up system resources. Next, it cycles through all the pixels in the image, using the for
loops, and compares the color of the pixel to the mask color. If the pixels color matches
the mask color, that pixels color is replaced by an alpha RGB value. Lastly, the destination
Here is what the output will be, when we wrap the manipulated image inside
:our JImagePanel
As you can see, all the white pixels on the image on the left were replaced with pixels of
Flipping an Image
compared to the reflection of yourself in a lake, flipping horizontally is kind of like looking
into a mirror. To do a flip, we use drawImage(Image img, int dx1, int dy1, int
dx2, int dy2, int sx1, int sy1, int sx2, int sy2, ImageObserver
observer); of Graphics2D object. This method lets us draw part of an image into an
image, or scale an image etc. The method takes an image, and a set of coordinates of the
destination rectangle, it also takes a set of coordinates for the source rectangle of the
image you supply. These source coordinates can be manipulated for varying results, as I
For flipping an image horizontally, we give the source rectangle coordinates starting from
.the top right, and ending at the bottom left like this
?view plaincopy to clipboardprint
drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int s.1
;(x2, int sy2, ImageObserver observer
.2
g.drawImage(<i>The Source Image</i>, 0, 0, <i>image width</i>, <i>imag .3
;(e height</i>, <i>image width</i>, 0, 0, <i>image height</i>, null
<b><i>as opposed to the unflipped way</i></b> .4
.5
g.drawImage(<i>The Source Image</i>, 0, 0, <i>image width</i>, <i>imag .6
;(e height</i>, 0, 0, <i>image width</i>, <i>image height</i>, null
.7
:Putting it all together, you would flip an image horizontally like this
?view plaincopy to clipboardprint
} (public static BufferedImage horizontalflip(BufferedImage img.1
;()int w = img.getWidth .2
;()int h = img.getHeight .3
;(()BufferedImage dimg = new BufferedImage(w, h, img.getType .4
;()Graphics2D g = dimg.createGraphics .5
;(g.drawImage(img, 0, 0, w, h, w, 0, 0, h, null .6
;()g.dispose .7
;return dimg .8
{ .9
:Here is what the output would be with the manipulated image inside our JImagePanel
To flip an image vertically, you just change the source rectangle coordinates around some
:more
?view plaincopy to clipboardprint
} (public static BufferedImage verticalflip(BufferedImage img.1
;()int w = img.getWidth .2
;()int h = img.getHeight .3
BufferedImage dimg = dimg = new BufferedImage(w, h, img.getColorModel .4
;(()().getTransparency
;()Graphics2D g = dimg.createGraphics .5
;(g.drawImage(img, 0, 0, w, h, 0, h, w, 0, null .6
;()g.dispose .7
;return dimg .8
{ .9
:Here is what the output would be if this was wrapped inside an application
Fig. 9. Regular Duke Fig. 10. Flipped Duke
Rotating an Image
and image processing, thankfully we dont need to know any of that, as Sun provides us a
method inside of the Graphics2D object that does all that complicated stuff for us, aptly
.(namedrotate(double theta, double x, double y
This method, besides doing usual initialization, turns the supplied angle (in degrees) to
.radians. It also ensures that the image stays in the middle of the destination image
.Here is a sample of the output if wrapped in an application and rotation set at 45 degrees
Fig. 11. Regular Duke Fig. 12. Rotated Duke
Resizing an Image
For resizing an image, we again refer to the Graphics2D object, resizing an image is a
very simple operation, just like in rotating an image, all math is taken care of by
.the Graphics2Dobject
Note that we set rendering hints to balance speed and quality, unfortunately an
:explanation ofRenderingHints is beyond the scope of this article
newHeight, int renderHints). Do NOT use this to resize, it is slow and unwieldy, for
.detailed reasons check out this article by Chris Campbell
Splitting Images
Now to have some fun, and whats more fun than Mario! Our goal for this part of the
Splitting an image is fairly simple, and very useful. What we want to do is split the image
into rows and columns, and draw each mini image into it's own BufferedImage, all of
these smaller images will be kept inside a BufferedImage array. Keeping the images in an
array will allow for easy access when we want to animate the sprites. Here is how you
This block of code first figures out the width and height of the mini images, using the
columns and rows variables. Next it initializes the BufferedImage array, then starts two
loops, one for columns, one for rows. Next it initializes each image in the array, and draws
into them their respective mini image using the w and h variables as a helper to figure out
.the exact coordinates of each rectangle. Lastly, it returns the BufferedImage array
Now that we can get all the images, we need to figure out how to animate them, so keep
:reading
Sprite Animation
Now lets make use of our new found skill. Being able to split up Images is only half of the
challenge, now we need to be able to make mario seem like he's moving, we can achieve
this by alternating different images that correspond to one part of his movement. This is
called animation, to make it easier we will make a new class called AnimatedSprite. This
class will serve many purposes, it will hold hold onto the split up image, the frame
.numbers, the location, and anything else that comes to our whimsy
For animation to work correctly we need to make sure some things happen right. First we
need a way to remember the animation frames, this can be solved by putting the index of
each frame for a particular animation inside an int array. Then, we can put that int array
inside of a HashMap. The HashMap will allow us to get the int array by giving it a "key", or
a name, this name in our case will be the animation name, for example "walk". Heres how
Along with a way to store the frames, we will also need coordinates for rendering help, as
well as multiple variables for keeping track of the current animation state, here are the
:variables needed
?view plaincopy to clipboardprint
**/.1
The current 'state' or animation that the sprite is in, ie. "walk", "run", or "stan * .2
"d
/* .3
;private String currentAnim.4
**/.5
The current frame being rendered, it's not the number of the frame, its the ind * .6
[]ex for the Image
as in it's this number "frameset[currentframe] = 1;" not this number "framese * .7
";t[0] = currentframe
/* .8
;private int currentFrame.9
**/.10
The current set of frames being used * .11
/* .12
;private int[] currentFrameSet.13
The most important method of the class is the draw(Graphics2D g) method, this
method will eraser the previous image, and draw the current frame, as well as preparing
Another thing about animation is that there are multiple ways of cycleing through the
frames, one way, is to loop through the frames and then go back to the first. The second
way is to loop through the frames and then go backwards through them again, for
example, if the frame indexes were {15,16,17,18} they would be cycled through like this
"15,16,17,18,17,16,15.... etc.". Using one or the other depends on your animation, for our
.LOOP_BEGINNING respectively
Summary
The previous tips have hopefully given you a strong foothold in the quagmire that is java
Images, and possibly a handhold on games and Animation. Hopefully you have found
these tricks useful. In the next installment we will look at more advanced image operations
!such as compositing and paint strokes. Until next time, happy coding
Refferences
Ecksteinhttp://java.sun.com/developer/technicalArticles/GUI/java2d/java2dpart2.html
media.html