• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 360
  • Last Modified:

BufferedImage looks incomplete

Hi!

please read this to the end, to understand my problem!

I'm using ptolemy's plot-package to generate 2D-dataplots.
(downloadable at http://devnull.at/?EOO73 )
what I do:
I create an instance of Plot ('Plot p = new Plot();'), and fill data into it (points, title, names of axes, legend ...)
then I do:

    p.validate();
    p.repaint();
//    try{ Thread.sleep(10);}catch (Exception e){};
    BufferedImage image = p.exportImage();
    image.flush();

If I run this, 9 out of 10 times the image is not complete (sometimes the title is missing, sometimes the points ...).
BUT: If I uncomment the sleep line, the image looks correct 20 out of 21 times. The sleep is only 10ms!!

What's going on - any hint???
witty
0
witty
Asked:
witty
  • 10
  • 8
  • 3
  • +1
1 Solution
 
objectsCommented:
The actual painting is handled in the asynchronously by another thread and may not have completed.
0
 
objectsCommented:
I can't find any mention of the exportImage() method?
0
 
wittyAuthor Commented:
thanks object:

here you can find the exportImage()-method of PlotBox: http://devnull.at/?IZ2LQ (there is a little version-jam on this website!)
Plot is a direct subclass of PlotBox!

Is it possible to wait for all threads are finished???

What would you recommend?

thanks
witty
0
Cloud Class® Course: CompTIA Cloud+

The CompTIA Cloud+ Basic training course will teach you about cloud concepts and models, data storage, networking, and network infrastructure.

 
wittyAuthor Commented:
also to mention:

I tried
p.paintImmediately(p.getBounds());
before exportImage()

but without a result!!!

paintImmediately(Rectangle r) is a method of class javax.swing.JComponent ( http://devnull.at/?GVSU6 )

I also found this article on (a)synchronous paint:
http://devnull.at/?IW6AJ (look for "Synchronous Painting")

so, how to do synchronous painting???
witty
0
 
objectsCommented:
Maybe they don't wait for the image to complete being painted. Try using MediaTracker to wait for the image to complete loading when it is returned:

BufferedImage image = p.exportImage();
mt.addImage(image, 0);
mt.waitForID(0);

// image should be loaded now


If this doesn't help then their may be a bug in the plot code and would suggests asking the author(s) about it.
0
 
wittyAuthor Commented:
thanks again!

the mt did'nt change anything either :-( !!

I think the problem is AFTER repaint() and BEFORE exportImage(). The sleep inbetween returns almost ever the correct image!!!

I thought, this line should do it (is p.getBounds() ok to get the correct Rectangle?)
p.paintImmediately(p.getBounds());

thanks
witty
0
 
objectsCommented:
It's strange, cause I would expect that the exportImage() method would be passing the image graphics context to paint().

paint(image.getGraphics());
0
 
heyhey_Commented:
why don't you e-mail the authors of the package ?
0
 
wittyAuthor Commented:
you don't know, what I have done three times in the last two weeks!!!

... and I think I have found a solution! it's a java-thing!!!
0
 
wittyAuthor Commented:
yes - I have made it!!!

the point is: no one is generating server-side images with java!!!
I have found a way to control the repaint() (so I know when it has finished!!!)

thanks to all of you!!!

I won't delete ths quiestion - perhaps someone has a better solution :-)
0
 
heyhey_Commented:
> the point is: no one is generating server-side images with java!!!

I have generated Images from servlets without any problem ?

>I have found a way to control the repaint() (so I know when it has finished!!!)

how do you 'control' repaint() ?
0
 
objectsCommented:
> no one is generating server-side images with java!!!

Yes they are :)
And what has this got to do with the problem?

> I have found a way to control the repaint()
> (so I know when it has finished!!!)

I would think the repaint() has nothing to do with it, it is involved with painting to the screen not to an offscreen image.
0
 
wittyAuthor Commented:
if you want to write a component to an image, you have to call repaint() at least once (explicitly or by calling another method).
but:
YOU CAN NEVER be sure, whether repaint() has finished, or is still "scheduled" (and this is exactly the problem!). in an application it doesn't matter whether you "see" the repaint()-result now or in 5ms - when you write the component to an image, it does matter at what time you write the image (this can occur before the repaint() has finished - so the image would leak of the last paintings!)

this problem primarily arises with (very) fast machines (I have a dual processor machine (AMD Athlon(TM) MP 2100+))!

some javasources (which are in use for online websites) were mailed to me, where images are created for servlets. on slower machines (as my AMD Athlon(TM) XP 1800+) this code is no problem, but my dual-processor-machine is too fast for this code! so I had to find a solution, to be sure, the repaint() has finished, the moment I create my image!

witty
0
 
objectsCommented:
> if you want to write a component to an image, you have
> to call repaint()

Why??? All repaint() does is queue a paint request to paint the component to the *screen*.

To write a component to an image, you simply call:

component.paint(image.getGraphics());
0
 
heyhey_Commented:
I agree with objects
0
 
wittyAuthor Commented:
if I edit a component and do a paint straight afterwards - then the last edit won't be visible (on the fast machine)!

as said: everything works fine on an ordinary machine!

witty
0
 
objectsCommented:
Can you post the method that is creating and saving the image.
0
 
objectsCommented:
Here is the exportImage code that draws the image by simply passing the image cgraphics context to _drawPlot, which is the same method called by paintComponent().

public synchronized BufferedImage exportImage(
    BufferedImage bufferedImage,
    Rectangle rectangle,
    RenderingHints hints,
    boolean transparent) {
  Graphics2D graphics = bufferedImage.createGraphics();
  graphics.addRenderingHints(_defaultImageRenderingHints());
  if ( !transparent ) {
     graphics.setColor(Color.white);     // set the background color
     graphics.fill(rectangle);
  }
  _drawPlot(graphics, false , rectangle);
  return bufferedImage;
}
0
 
objectsCommented:
> when you write the component to an image, it does matter
> at what time you write the image (this can occur before
> the repaint() has finished - so the image would leak of
> the last paintings!)

That's partly true, though the painting of the component and the image are in a way seperate. They are just performed by the same code. So what actually appears on the screen is not used to produce the image. And calling repaint() has no effect on the image, it only affects painting to the screen.
To ensure that the painting of the image is complete can be achieved using MediaTracker as I mentioned above.
0
 
wittyAuthor Commented:
here is the code:
--cut--
Plot p = new Plot();
boolean first = true;
for(int a = -1 ; a <= 100 ;a++){
  p.addPoint(0, a, a*a, !first);
  first = false;
}
p.addLegend(0, "Legend 0");
p.setTitle("T I T L E");
p.setXLabel("XLabel");
p.setYLabel("YLabel");
java.awt.image.BufferedImage image = p.exportImage();
--cut--
then the  image is encoded into a jpg, png ...

if I look at this image, something is ever missing - title, axes, legend, datapoints ...

if I create subclass "class MyPlot extends Plot" and overwrite the exportImage()-method with my code, everything works fine when using MyPlot instead of Plot (and the same code as above!!!)!!!

what I do in my exportImage():
* create a ComponentListener and add it to p
* start a thread X (X waits on the ComponentEvent componentShown())
* p.setVisible(false)
* p.setVisible(true) -> the componentShown()-method is triggered and this method notifies X)
* X.join()

because setVisible() calls repaint(), and the repaint() isn't done immediatly, I have to wait till the thread has finished (join()) and this happens because the thread is notified by the ComponentListener

witty
0
 
objectsCommented:
java.awt.image.BufferedImage image = p.exportImage();

// You need to use use MediaTracker here to wait until
// image is complete before encoding.

--cut--  // What happens in here??

then the  image is encoded into a jpg, png ...
0
 
girionisCommented:
No comment has been added lately, so it's time to clean up this TA.
I will leave a recommendation in the Cleanup topic area that this
question is:

- points to objects

Please leave any comments here within the
next seven days.

PLEASE DO NOT ACCEPT THIS COMMENT AS AN ANSWER !

girionis
Cleanup Volunteer
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

Free Tool: Port Scanner

Check which ports are open to the outside world. Helps make sure that your firewall rules are working as intended.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

  • 10
  • 8
  • 3
  • +1
Tackle projects and never again get stuck behind a technical roadblock.
Join Now