Working with Images and Resources in Java
Images are copied to a destination using g.drawImage() methods defined in the Graphics class.
Where Can an Image Go?
Suppose your program already has an image. The next question is where that image can go. In Java, an image can be copied onto two kinds of destination: the screen itself, or an off-screen canvas that exists only in memory. Both destinations are reached through the same tool, the set of drawing methods defined in the Graphics class. Once you see that the image is the source and a graphics context is the route to the destination, most of this topic falls into place.
This article approaches the topic from the destination side. First we look at how an image gets copied through a Graphics object. Then we look at how an off-screen canvas can be prepared in advance. Finally we follow a small piece of drawing from start to finish so you can track what changes at each step.
What do you think happens?
If you create a new BufferedImage and draw into it, does anything appear on the screen yet?
Reveal answer
No, nothing is displayed until the image is copied onto a visible surface.
The source states that creating a BufferedImage does not display anything until it is copied onto a visible surface. A BufferedImage is an off-screen canvas, so drawing into it keeps the result in the program's memory.
Two Destinations, One Drawing Tool
An Image of either type can be copied onto the screen or onto an off-screen canvas by using methods defined in the Graphics class. The most common place to do this is inside the paintComponent() method of a JComponent. The Graphics object that Java passes to paintComponent() is the handle you use for drawing. In that case you do not create the destination yourself. You draw through the Graphics object you were given.
The destination of an image copy is determined by which Graphics object is used. If the Graphics object refers to the screen, the pixels land on the screen. If it refers to an off-screen canvas, the pixels land on that canvas and stay in memory.
The diagram shows the central structure. The image is the thing being copied, the g.drawImage() call performs the copy, and the Graphics object decides where the result lands. The same call works in both cases. What differs is whether the result is visible to a user the moment it is drawn, and whether the drawing persists in the program for later use.
Reading the g.drawImage() Call
The source introduces the copying operation with two names. g is the Graphics object passed into paintComponent(), and img is a variable of type Image. The copy itself is written as a call to one of the g.drawImage() methods. Notice that the call names the Graphics object first. That is how the destination is chosen: whatever surface g refers to receives the pixels.
- g: the Graphics object that determines the destination surface
drawImage: the Graphics method that copies an image- img: the Image being copied
- ...: remaining arguments, which this excerpt does not describe
Tracing One Draw Call Step by Step
Here is a short scenario you can trace on paper. Assume a component's paintComponent() method has been called by Java, so a Graphics object g is available, and an Image named img was loaded earlier. Work through the steps in order and keep track of which object is being used at each point.
Copying a loaded image inside paintComponent()
A component's paintComponent() receives a Graphics object g. An Image named img was loaded earlier. Trace which surface receives the pixels when g.drawImage(img, ...) runs.
- 1Java calls paintComponent()
Java passes a Graphics object g into the method. You did not create this destination yourself.
- 2Identify the source
img is the Image variable. It is the thing being copied, and it may come from a file or be a BufferedImage, since both share the type Image.
- 3Identify the destination
The call names g first. Whatever surface g refers to receives the pixels. Here g was given to you by Java, so the destination is the visible component.
- 4Perform the copy
The
g.drawImage()call copies img onto the surface g refers to. The image now appears on the component.
The pixels of img are copied onto the surface referred to by g, which in this scenario is the visible component.
The BufferedImage as an Off-Screen Canvas
Copying images is only half of the picture. The source also describes creating images by drawing to an off-screen canvas. The canvas is represented by an object of the class BufferedImage, which is defined in the package java.awt.image. Because it is an off-screen canvas, drawing into it does not put anything on the screen by itself. The result is a picture held in the program, ready to be used later.
Drawing Off-Screen, Then Copying to the Screen
Put the two halves together and the full path becomes clear. First you draw into the BufferedImage through its own Graphics object, which changes the canvas contents in memory. Later, you copy that canvas onto a visible surface by calling g.drawImage() with the screen's Graphics object. Nothing is visible during the first stage. The copy in the second stage is what makes the result appear.
Preparing a canvas and displaying it later
A program creates a BufferedImage, draws a shape into it, and later copies it to the component. Track what is visible after each stage.
- 1Create the BufferedImage
The constructor produces an off-screen canvas. Creating it does not display anything.
- 2Draw into the canvas
Drawing through the canvas's Graphics object changes the BufferedImage's contents. The screen is still unchanged.
- 3Copy during paintComponent()
The call
g.drawImage(canvas, ...)uses the component's Graphics g as the destination. The copied pixels now appear on the visible surface.
The drawing was prepared off-screen and became visible only when it was copied with the screen's Graphics object.
Common Mistakes With Images and Destinations
Common mistake Assuming a BufferedImage appears on screen as soon as it is drawn into
Why it failsA BufferedImage is an off-screen canvas. Drawing into it changes the image in memory, but nothing is displayed until it is copied onto a visible surface.
Do this insteadCopy the canvas onto the screen with g.drawImage() using the screen's Graphics object.
Common mistake Treating a BufferedImage as a different kind of object from other images
Why it failsBufferedImage is a subclass of Image, so it is copied the same way as other images.
Do this insteadUse the same g.drawImage() copying approach for file-loaded images and BufferedImage canvases.
Common mistake Thinking the destination is chosen by the image
Why it failsThe destination is determined by which Graphics object is used in the call, not by the image.
Do this insteadCheck which Graphics object g refers to. It decides whether the pixels land on the screen or on an off-screen canvas.
Common mistake Creating a canvas and expecting its parameter list to be documented here, when the source excerpt does not describe it
Practice Tracing the Destination
A program creates a BufferedImage named canvas and draws a circle into it. Then, inside paintComponent(), it calls g.drawImage(canvas, ...). Explain in your own words what happens at each stage, and state which Graphics object decides where the circle appears.
Hints
- Ask first whether the circle exists on screen before the
drawImage()call. - Look at the object named first in the
drawImage()call. - Recall that a BufferedImage is a subclass of Image.
Sketch the data flow for a program that draws a text label into a BufferedImage and then copies that image onto the screen in two separate paint calls. Mark which stage changes only memory and which stage makes the result visible.
Hints
- Separate the drawing into the canvas from the copying onto the screen.
- Only the copy to a visible surface makes the result appear to the user.
Key Takeaways
- An image is copied onto a destination with
g.drawImage()methods defined in the Graphics class, and the Graphics object named in the call determines the destination. - The screen and an off-screen canvas are both reached through the same copy operation; the difference is visibility and persistence.
- A BufferedImage is an off-screen canvas defined in
java.awt.imageand is a subclass of Image, so it is copied the same way as other images. - Drawing into a BufferedImage does not display anything by itself; the result becomes visible only when it is copied onto a visible surface.