Partial Image Drawing
The Graphics class provides the methods that copy an image onto the screen or an off-screen canvas, most commonly from inside paintComponent() of a JComponent.
Predicting a Simple Image Call
Start with the simplest statement for drawing an image in Java: drawImage(img, x, y, this), called with a Graphics object named g. Read it as a request. It asks for the image named img to be placed at the position x and y, using the Graphics object g. The call does not return a new image and does not ask for a size. It only asks for the image to be placed.
What do you think happens?
Before reading on, decide what determines where the image lands and how big it appears. Write down your guess.
Reveal answer
The x and y values determine where the image is placed, and the image is drawn at its own size because the basic call does not specify a size.
The basic form of the call carries only a position. The rest of this article tests guesses like this one: each variant of drawImage() is a change to the same call, so reading one call carefully makes the others easier to read.
Where Image Copying Happens
An image in a Java program is not drawn by the image itself. It is copied onto a drawing surface by a method that belongs to the Graphics class. That surface is usually the screen, though it can also be an off-screen canvas. In practice this copying most often happens inside the paintComponent() method of a JComponent.
The control flow works like this. The paintComponent() method is the caller. It hands its Graphics object to the drawing statement, and the Graphics object performs the copying onto whatever surface it is attached to. Your code controls the call, while the copying itself is carried out through the Graphics object.
paintComponentreceives the Graphics object g as a parameter- g.drawImage is the call that copies the image onto the component's drawing surface
- this refers to the
JComponentthat contains the drawing code
Parameters of the Basic Call
Each piece of the basic call has its own job. The first parameter, g, is the Graphics object that does the drawing. The second, img, is the image being drawn. The x and y values give the position at which the image is placed. The final argument, this, is the image observer.
The image observer deserves attention because beginners often treat it as optional decoration. The source describes the image observer as required when an image is drawn, and it is passed as the final parameter of drawImage(). In the examples in the source, this is used as the observer, which is the JComponent that contains the drawing code. The same final argument appears in every form of the method discussed here.
Scaling With Width and Height
One variant of drawImage() scales the image as it is drawn, so that it fills a width and height you specify. The form inserts two size values after the position values, which gives the pattern drawImage(img, x, y, width, height, this). Compare this with the basic call. The position is still set by x and y. What has changed is that the image is no longer drawn at whatever size it has. Its drawn size is set by width and height.
What do you think happens?
If you call g.drawImage(img, 10, 20, 200, 100, this) instead of g.drawImage(img, 10, 20, this), does the image move?
Reveal answer
No, it keeps the same position and only its drawn size changes.
Scaling changes only the size at which the image is placed. The position is still defined by x and y, so the upper-left placement point stays where you put it, and the image grows or shrinks from that starting location. Position and size are separate arguments that answer separate questions.
The first call places the image at (10, 20) at its original size. The second call places it at the same point, stretched or shrunk to 200 by 100.- The x and y values are identical in both calls
- Only the two size values differ, so only the drawn size changes
Eight Coordinates: Source and Destination
The most detailed variant of drawImage() takes eight coordinates instead of a position and size. It is written as a set of destination coordinates, followed by a set of source coordinates, and then the observer. The destination pair of corners describes where on the drawing surface the result goes. The source pair of corners describes which rectangle of the original image is taken.
- Destination corners (0,0) and (150,150) define the place and size on the surface
- Source corners (40,40) and (140,140) select a 100 by 100 region of the original image
- The 100 by 100 region is stretched to fill the 150 by 150 destination
Cropping and placing part of an image
An image is 300 pixels wide and 300 pixels tall. You want to draw only its central 100 by 100 region, placed at the top left corner of the component and enlarged to 200 by 200.
- 1Identify the source rectangle
The central 100 by 100 region runs from (100, 100) to (200, 200) in the original image, so the source corners are sx1 = 100, sy1 = 100, sx2 = 200, sy2 = 200.
- 2Identify the destination rectangle
The top left placement is (0, 0) and the enlarged size is 200 by 200, so the destination corners are dx1 = 0, dy1 = 0, dx2 = 200, dy2 = 200.
- 3Assemble the call
Destination coordinates come first, then source coordinates, then the observer:
g.drawImage(img, 0, 0, 200, 200, 100, 100, 200, 200, this). - 4Check the independence
The source region is 100 by 100 and the destination is 200 by 200. The two rectangles do not have to match, so the region is enlarged as it is placed.
Only the central 100 by 100 part of the original image appears, enlarged to fill 200 by 200 at the top left of the drawing surface.
Where Unexpected Results Come From
When a drawn image is not what you expected, the cause is usually one argument in one call. Read each entry below as a question to ask about your own code: at which argument did my expectation and the call stop agreeing?
Common mistake Expecting the position values to change the image size
What it looks likeChanging x and y from 10, 20 to 50, 60 and expecting the picture to get bigger
Why it failsPosition and size are separate arguments. x and y only set where the image is placed.
Do this insteadChange width and height to change the drawn size, and change x and y to move the image.
Common mistake Assuming the source rectangle must match the destination rectangle
What it looks likeTaking a 100 by 100 source region and expecting it to appear at 100 by 100 on the surface
Why it failsThe destination rectangle is not required to match the source rectangle, so the region is stretched or shrunk to fit.
Do this insteadCheck both rectangles separately, and compute the destination size you actually want.
Common mistake Reversing the coordinate order in the eight-argument form
What it looks likeWriting the source corners before the destination corners
Why it failsThe eight-coordinate form takes the destination pair first, then the source pair, then the observer.
Do this insteadWrite destination coordinates first, source coordinates second, and this last.
Common mistake Dropping the image observer
What it looks likeWriting g.drawImage(img, 10, 20) without the final argument
Why it failsThe source describes the image observer as required when an image is drawn.
Do this insteadAlways pass this, or the JComponent that contains the drawing code, as the final argument.
Practice Reading Drawing Calls
Given g.drawImage(img, 5, 5, 300, 120, 0, 0, 150, 60, this), state which pixels of the original image are taken, what rectangle they fill on the drawing surface, and whether the image is stretched or shrunk. Then explain what changes if you keep the same source corners but change the destination corners to 5, 5, 150, 60.
Hints
- The source corners 0, 0, 150, 60 describe a rectangle inside the original image, not on the surface.
- Compare the width and height of the source rectangle with the destination rectangle.
- Changing only the destination corners changes where and how large the result is, but not which pixels are taken.
Key Takeaways
- The basic
drawImage(img, x, y, this)call places an image at a position using the Graphics object g, and the final argument is the image observer, which is required. - Adding width and height after the position scales the image to that size; the position is still set by x and y, so position and size answer separate questions.
- The eight-coordinate form takes destination corners, then source corners, then the observer; the source rectangle selects a portion of the original image, and the destination rectangle sets where and how large it is drawn.
- When a result looks wrong, check the source rectangle first, then the destination rectangle, then the scaling that connects them.