Concepts / Working with Images and Resources in Java

Working with Images and Resources in Java

Images are copied to a destination using g.drawImage() methods defined in the Graphics class.

  • Programming

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?

  • Yes, the drawing appears on screen immediately

  • No, nothing is displayed until the image is copied onto a visible surface

Reveal answer
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.

Definition

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.

Image imgthe source being copiedg.drawImage()same copy operationGraphics for screendestination is the screenVisible on screenuser sees it at onceGraphics for canvasdestination is aBufferedImageStored in programkept for later usecopied byvia gvia gdisplayedpersists
How does the destination Graphics object differ when drawing directly to the screen versus to an off-screen image, and what is visible to the user in each case?

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.

java
Notes on the code
  • 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.

Worked example

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.

  1. 1
    Java calls paintComponent()

    Java passes a Graphics object g into the method. You did not create this destination yourself.

  2. 2
    Identify 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.

  3. 3
    Identify 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.

  4. 4
    Perform the copy

    The g.drawImage() call copies img onto the surface g refers to. The image now appears on the component.

Result

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.

BufferedImageoff-screen canvas, subclassof ImageImagecommon typeCanvas contentschanged by drawingGraphics for canvasused to draw onto thecanvasis a subclass ofdraws ontoholds
How does a BufferedImage relate to its Graphics object, and how does drawing onto that Graphics object change the image's contents?

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.

Draw onto canvasvia canvas GraphicsBufferedImageholds pixels in programg.drawImage()copy using screen GraphicsVisible screenuser sees the resultchangesis the sourcecopies onto
In what order do pixels move: which buffer is drawn to first, and when does the copy onto the visible screen happen?
Worked example

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.

  1. 1
    Create the BufferedImage

    The constructor produces an off-screen canvas. Creating it does not display anything.

  2. 2
    Draw into the canvas

    Drawing through the canvas's Graphics object changes the BufferedImage's contents. The screen is still unchanged.

  3. 3
    Copy 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.

Result

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 fails

    A 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 instead

    Copy 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 fails

    BufferedImage is a subclass of Image, so it is copied the same way as other images.

    Do this instead

    Use 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 fails

    The destination is determined by which Graphics object is used in the call, not by the image.

    Do this instead

    Check 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

EASY

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.
MEDIUM

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.image and 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.