Drawing Shapes and Text with the Graphics Class
Java has two fundamentally different kinds of Image: those read from external sources such as files or network connections, and off-screen canvases created by drawing within the program.
Two Ways an Image Gets into Memory
Suppose a Java program needs to show a picture. The picture might already exist as a file on the hard disk, or it might not exist at all until the program draws it. In both cases an image ends up in the computer's memory, but the two cases are not the same. Java's image library gives you a single idea, the Image, that sits underneath both situations. Before you write any drawing code, it helps to know which kind of image you are holding, because the kind determines how you can use it.
What do you think happens?
When a program creates an off-screen canvas, does the canvas already contain pixels from a file?
Reveal answer
No, it starts blank and is filled in by the program's drawing code.
The source describes the second kind of Image as one the program creates by drawing to it with a graphics context. Only this kind starts blank and is filled in by your code. The first kind receives its pixels from outside the program.
In this article you will follow one image through two stages. First you will see it as something loaded from outside the program, and then as a surface the program builds for itself. Watch for the moment the image changes from a passive thing you receive into something you actively write on.
Images Read From Outside Versus Canvases Built Inside
The class java.awt.Image represents an image stored in the computer's memory. Java distinguishes two fundamentally different kinds of Image. The first kind is an image read from a source outside the program, such as a file on the computer's hard disk or a network connection. The program does not create the pixels of this image. It receives them from outside.
The second kind is an image created by the program itself, by drawing to it using a graphics context. The source calls this second type an off-screen canvas. Both kinds are images in memory, but only the second kind starts blank and is filled in by your code.
| Question | Image read from outside | Off-screen canvas |
|---|---|---|
| Where do the pixels come from? | A file on disk or a network connection | Drawing done by the program |
| What is its starting state? | Already holds the received pixels | Starts blank |
| Who fills it in? | The outside source supplies the pixels | Your code fills it in |
The two kinds of Image differ in origin and starting state, as described in the source.
What an Off-Screen Canvas Is
An off-screen canvas is a region of memory that can serve as a drawing surface. It is not required to be the visible window.
Notice what this definition does and does not promise. It says the canvas is a region of memory that can serve as a drawing surface. It does not say the canvas is always visible, and it does not say the canvas is the same thing as the window on the screen. Keeping those two ideas apart will make the rest of this article easier to follow.
BufferedImage and the Image Class
An off-screen canvas can be represented by an object of the class BufferedImage. The source says this class is defined in the package java.awt.image, so to use it you refer to that package. BufferedImage is the concrete tool Java provides for the program-built kind of image described above.
The most important relationship is inheritance. BufferedImage is a subclass of Image. Because of this, a BufferedImage is still an Image, so it can be used anywhere the program expects an Image. The source states the practical consequence directly: once you have a BufferedImage, you can copy it into a graphics context g using one of the g.drawImage() methods, just as you would do with any other image.
Tracing Pixels from Drawing Calls to the Screen
Creating a canvas is only half of the story. The canvas becomes useful when something is drawn onto it. The source explains that it is possible to draw to an off-screen image using the same Graphics class used for drawing on the screen. The drawing code therefore looks much like the drawing code you would write for the screen. The difference is the destination: the Graphics object points at the off-screen canvas instead of the visible window.
Once the canvas has content, the source describes a second step. A BufferedImage can be copied into a graphics context g with a g.drawImage() method. This is how a finished off-screen canvas reaches a visible surface. Read the diagram below from left to right as a story. The program issues drawing instructions through a Graphics object. Those instructions change the canvas, which is the piece whose content is being built. Only at the end does the canvas leave the picture: a g.drawImage() call copies it into the destination graphics context g.
- 1The program creates an off-screen canvas, represented by a BufferedImage.
- 2The program issues drawing instructions through a Graphics object that points at the canvas instead of the visible window.
- 3Each drawing instruction changes the content of the canvas in memory.
- 4A
g.drawImage()call copies the finished canvas into the destination graphics context g. - 5The copied result reaches a visible surface.
Mistakes Beginners Make With Off-Screen Canvases
Common mistake Treating the off-screen canvas as the visible window
Why it failsThe source states the canvas is a region of memory that can serve as a drawing surface and is not required to be the visible window.
Do this insteadThink of the canvas as a memory surface. It reaches the screen only through a g.drawImage() copy into a graphics context.
Common mistake Assuming every Image already contains pixels to show
Why it failsAn image read from a file or network source receives its pixels from outside, but a program-built canvas starts blank and is filled in by drawing code.
Do this insteadBefore drawing, identify which kind of Image you hold, because the kind determines what it contains at the start.
Common mistake Expecting a separate drawing API for canvases
Why it failsThe source says the same Graphics class used for drawing on the screen can draw to an off-screen canvas.
Do this insteadReuse the same drawing approach, and change only the destination the Graphics object points at.
Tracing a Canvas Through Its Two Stages
A program creates a BufferedImage canvas, draws a filled shape onto it through a Graphics object, and then calls g.drawImage() to copy the canvas into the destination graphics context g. Describe, in order, what the canvas contains at each stage: right after creation, after drawing, and after the copy. Then state whether the canvas is the same object as the visible window.
Hints
- Recall what the source says about the starting state of a program-built canvas.
- Ask what changes the canvas content, and which step moves it toward the visible surface.
- The source says the canvas is not required to be the visible window.
Key Takeaways
- Java has two kinds of Image: one read from an external source such as a file or network connection, and one created by the program by drawing to it.
- An off-screen canvas is a region of memory that can serve as a drawing surface and is not required to be the visible window.
- BufferedImage, defined in
java.awt.image, is a subclass of Image that represents an off-screen canvas, so it can be used wherever an Image is expected. - Drawing uses the same Graphics class as screen drawing, but the Graphics object points at the canvas; a
g.drawImage()call then copies the finished canvas into a graphics context g to reach a visible surface.