Simon Eliasson
Simon Eliasson

Reputation: 1295

Painting an Image object on a BufferedImage for later use

I need some help with painting an Image object upon/inside/on a BufferedImage and then painting that BufferedImage on a JPanel.

I've prepared a small program to illustrate my problem. Just a frame with a panel accompanied by an ImageLoader.

The image is placed in the same folder as the code. The sten Image is painted successfully when just painted, but not when I try painting it with the BufferedImage, which you'll notice if you try to run the program. just create the Test object and the constructor does the rest.

Thanks in advance!

My code:

public class Test extends JFrame{

static class ImageLoader {
    public static Image loadImage(String name){
        Image img = null;
        img = Toolkit.getDefaultToolkit().getImage(ImageLoader.class.getResource(name));
        return img;
    }
}

class Panel extends JPanel{

    Image sten;
    BufferedImage bf = new BufferedImage(500,500,BufferedImage.TYPE_INT_RGB);

    public Panel(Image sten){
        super();
        this.sten = sten;
        initBF();
    } 

    private void initBF(){
        Graphics2D g = (Graphics2D) bf.createGraphics();
        g.drawImage(sten, 0,0,this);
    }

    public void paintComponent (Graphics g)
    {
        g.drawImage(bf, 100,100,null);
        g.drawImage(sten, 0,0,null);
        repaint();
    } 
}


public Test(){
    setSize(new Dimension(500, 500));
    setEnabled(true);
    this.setBounds(50, 150, 500, 500);
    setVisible(true);

    Image sten = ImageLoader.loadImage("sten.png");;

    Panel panel = new Panel(sten);
    panel.setBackground(Color.GREEN);
    panel.setSize(500, 500);
    this.add(panel);

    setDefaultCloseOperation(EXIT_ON_CLOSE);

    panel.paintComponent(this.getGraphics());
}

}

Upvotes: 0

Views: 455

Answers (2)

Reimeus
Reimeus

Reputation: 159774

The problem is that Toolkit.getDefaultToolkit().getImage loads images asychronously so will not be loaded when paintComponent is invoked. Use a MediaTracker to block until the image has been loaded:

public Image loadImage(String name) {
   Image img = null;
   MediaTracker tracker = new MediaTracker(myPanel); // pass the panel from ctor
   img = Toolkit.getDefaultToolkit().getImage(ImageLoader.class.getResource(name));
   tracker.addImage(img, 0);
   try {
      tracker.waitForID(0);
   } catch (InterruptedException e) {
      e.printStackTrace();
   }

   return img;
}

or far simpler:

img = ImageIO.read(ImageLoader.class.getResource(name)));

This will eliminate the need to use MediaTracker.

Some notes:

  • Don't call paintComponent directly, request repaints by invoking repaint.
  • Don't use getGraphics for custom painting - this uses a transient Graphics reference.
  • When using a custom Graphics reference, make sure to call Graphics#dispose when finished using the reference.

Upvotes: 1

leonbloy
leonbloy

Reputation: 75906

In addition of Reimeus' aswer, notice that Toolkit.getDefaultToolkit().getImage() is non-blocking, it loads images asynchronously, so at the point when you call g.drawImage(sten, 0,0,this); sten will probably not still actually be loaded (see the doc of the method). See also this (false) bug report.

Upvotes: 1

Related Questions