BufferedImage

M

Martijn Mulder

I try to load an image into a BufferdImage instance in the constructor
of my class. It does not work. However, if I load the image in the
paint() method, all goes well. How can I fix this?

The code below should compile readily and illustrate the problem. The file
"Dog.jpg" is a file I have on my system. The second line in the constructor
does not do the job. But the same line in the paint()-method (commented out),
makes the picture appear on the screen.

Is there a better way to load an image into a BufferedImage instance?



/*
DisplayImage.java
Load an image into a BufferedImage and display it to the screen
*/

//class DisplayImage
public class DisplayImage extends javax.swing.JFrame
{

//data member image
java.awt.Image image;

//data member displayimage
java.awt.image.BufferedImage displayimage=new
java.awt.image.BufferedImage(377,233,
java.awt.image.BufferedImage.TYPE_INT_ARGB);

//data member graphics2d
java.awt.Graphics2D graphics2d=displayimage.createGraphics();

//constructor
DisplayImage()
{
image=java.awt.Toolkit.getDefaultToolkit().getImage("Dog.jpg");
graphics2d.drawImage(image,0,0,this);
}

//paint
public void paint(java.awt.Graphics a)
{
java.awt.Graphics2D b=(java.awt.Graphics2D)a;
// graphics2d.drawImage(image,0,0,this);//uncommenting this makes it work
b.drawImage(displayimage,0,0,this);
}

static void main(String[]a)
{
DisplayImage displayimage=new DisplayImage();
displayimage.setSize(377,233);
displayimage.show();
}
}
 
T

Thomas Weidenfeller

Martijn said:
I try to load an image into a BufferdImage instance in the constructor
of my class. It does not work.

Wrong, loading works. But then you do the wrong thing with it.
//data member graphics2d
java.awt.Graphics2D graphics2d=displayimage.createGraphics();

This is the Graphics context of the Image itself.
graphics2d.drawImage(image,0,0,this);

Here you draw the image on itself by using its own Graphics context.

Please note, however, that changing to the "right" Graphics context will
not work. There is no right Graphics context the moment you try to
paint. The idea of painting ("pushing" graphics onto a component)
outside of the paint[Component]() method is basically flawed.

Q3.4 of the comp.lang.java.gui FAQ basically applies to your problem.
The TCS article about painting in AWT and Swing is also a good read.

/Thomas
 
J

John McGrath

This is the Graphics context of the Image itself.


Here you draw the image on itself by using its own Graphics context.

Actually, the "graphics2d" graphics context is associated with the
BufferedImage "displayimage", so this draws the image referred to by
"image" onto the BufferedImage "displayImage".

I do see a number of other problems, though:

1) Nothing is done to ensure that the image has completely loaded before
it is drawn onto the BufferedImage. A MediaTracker can do this.

2) It overrides the paint() method. With Swing components, the
paintComponent() method should be overridden instead.

3) It does not call the superclass paint() (or paintComponent()) from the
overridden method.

4) It paints on a JFrame, but that will be covered by the content pane.

5) The class organization is *really* bad. The code that creates and
loads the BufferedImage is spread across multiple initializers and the
class constructor, and temporary variables are declared at the class
level. This should be done in a separate method.

6) The comments are brain-dead. If you don't have anything useful to say
in a comment, don't say anything.
 
M

Martijn Mulder

//data member graphics2d
Actually, the "graphics2d" graphics context is associated with the
BufferedImage "displayimage", so this draws the image referred to by
"image" onto the BufferedImage "displayImage".

I do see a number of other problems, though:

1) Nothing is done to ensure that the image has completely loaded before
it is drawn onto the BufferedImage. A MediaTracker can do this.

2) It overrides the paint() method. With Swing components, the
paintComponent() method should be overridden instead.

3) It does not call the superclass paint() (or paintComponent()) from the
overridden method.

4) It paints on a JFrame, but that will be covered by the content pane.

5) The class organization is *really* bad. The code that creates and
loads the BufferedImage is spread across multiple initializers and the
class constructor, and temporary variables are declared at the class
level. This should be done in a separate method.

6) The comments are brain-dead. If you don't have anything useful to say
in a comment, don't say anything.

Wow. Thank you, I guess. I'll try to implement your suggestions and see if it
works
then.
 
M

Martijn Mulder

"John McGrath"
I do see a number of other problems, though:
<snip>

I tried to heed your advice, but... nope :-(



/*
ImageBuffer.java. Load an instance of BufferedImage with a file from
disk before paintComponent() is called. This shouldn't be difficult at
all. Do I have the wrong books? A blind spot?
*/

//class ImageBuffer. Extend JComponent and draw a BufferedImage on it
public class ImageBuffer extends javax.swing.JComponent
{

//data member bufferedimage. Java2 image, is to hold "Dog.jpg"
java.awt.image.BufferedImage bufferedimage=new
java.awt.image.BufferedImage(233,377,
java.awt.image.BufferedImage.TYPE_INT_ARGB);

//constructor. Load image and copy it to bufferedimage
ImageBuffer(String a)
{
java.awt.Image image=java.awt.Toolkit.getDefaultToolkit().getImage(a);
new java.awt.MediaTracker(this).addImage(image,0);
bufferedimage.createGraphics().drawImage(image,0,0,this);
}

//paintComponent. Draw the pre-stored bufferedimage on the screen
public void paintComponent(java.awt.Graphics a)
{
java.awt.Graphics2D b=(java.awt.Graphics2D)a;
super.paintComponent(b);
b.drawImage(bufferedimage,0,0,this);
}

//main. Create a JFrame, load an ImageBuffer on it and show(). "Dog.jpg" is a
local file
static void main(String[]a)
{
javax.swing.JFrame jframe=new javax.swing.JFrame("ImageBuffer");
jframe.getContentPane().add(new ImageBuffer("Dog.jpg"));
jframe.setSize(233,377);
jframe.show();
}
}
 
M

Martijn Mulder

Fixed!

//class ImageBuffer. Extend JComponent and draw a BufferedImage on it
public class ImageBuffer extends javax.swing.JComponent
{


//data member bufferedimage. Java2 image, is to hold "Dog.jpg"
java.awt.image.BufferedImage bufferedimage=new
java.awt.image.BufferedImage(233,377,
java.awt.image.BufferedImage.TYPE_INT_ARGB);


//constructor. Load image and copy it to bufferedimage
ImageBuffer(String a)
{
java.awt.Image image=java.awt.Toolkit.getDefaultToolkit().getImage(a);
java.awt.MediaTracker mediatracker=new java.awt.MediaTracker(this);
mediatracker.addImage(image,0);
try
{
mediatracker.waitForID(0);
}
catch(java.lang.InterruptedException interruptedexception)
{
System.out.println("Image loading interrupted");
}
if(mediatracker.isErrorID(0))
{
System.out.println("Error loading image");
}
bufferedimage.createGraphics().drawImage(image,0,0,this);
}


//paintComponent. Draw the pre-stored bufferedimage on the screen
public void paintComponent(java.awt.Graphics a)
{
java.awt.Graphics2D b=(java.awt.Graphics2D)a;
b.drawImage(bufferedimage,0,0,this);
super.paintComponent(b);
}


//main. Create a JFrame, load an ImageBuffer on it and show()
static void main(String[]a)
{
javax.swing.JFrame jframe=new javax.swing.JFrame("ImageBuffer");
jframe.getContentPane().add(new ImageBuffer("Dog.jpg"));
jframe.setSize(233,377);
jframe.show();
}
}
 
J

John McGrath

I tried to heed your advice, but... nope :-(

Check the docs for MediaTracker.
static void main(String[]a)

This should be declared *public*.
javax.swing.JFrame jframe=new javax.swing.JFrame("ImageBuffer");

It would be nice to add this line:

jframe.setDefaultCloseOperation( javax.swing.JFrame.EXIT_ON_CLOSE );
 
T

Thomas Weidenfeller

John said:
Actually, the "graphics2d" graphics context is associated with the
BufferedImage "displayimage", so this draws the image referred to by
"image" onto the BufferedImage "displayImage".

Ah yes, I didn't see that in the mess of code.
1) Nothing is done to ensure that the image has completely loaded before
it is drawn onto the BufferedImage. A MediaTracker can do this.

That is a good idea yes. Sun is inconclusive if Toolkit.getImage() works
asynchronously, and better save than sorry.

/Thomas
 
J

John McGrath

Ah yes, I didn't see that in the mess of code.

I had to read through it several times to be sure. This is an excellent
example of the havoc that can be caused by poorly structured code. :eek:)
Sun is inconclusive if Toolkit.getImage() works asynchronously,
and better save than sorry.

My experience has been that Toolkit.getImage() *always* loads the image in
the background. In fact, it just creates the Image object and does not
start loading the image data until some of the Image methods are called to
retrieve the data.

The JavaDocs for getImage() do not say much about this, but I did find the
following in a JDC article:

To load an image in an application, pass the filename or URL to the
getImage() method, which returns a reference to an Image object that
is loaded later.

http://java.sun.com/developer/onlineTraining/new2java/supplements/2004/jan0
4.html
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,754
Messages
2,569,527
Members
44,999
Latest member
MakersCBDGummiesReview

Latest Threads

Top