Link to home
Start Free TrialLog in
Avatar of witty
witty

asked on

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
Avatar of Mick Barry
Mick Barry
Flag of Australia image

The actual painting is handled in the asynchronously by another thread and may not have completed.
I can't find any mention of the exportImage() method?
Avatar of witty
witty

ASKER

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
Avatar of witty

ASKER

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
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.
Avatar of witty

ASKER

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
It's strange, cause I would expect that the exportImage() method would be passing the image graphics context to paint().

paint(image.getGraphics());
why don't you e-mail the authors of the package ?
Avatar of witty

ASKER

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!!!
Avatar of witty

ASKER

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 :-)
> 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() ?
> 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.
Avatar of witty

ASKER

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
> 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());
I agree with objects
Avatar of witty

ASKER

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
Can you post the method that is creating and saving the image.
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;
}
> 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.
Avatar of witty

ASKER

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
ASKER CERTIFIED SOLUTION
Avatar of Mick Barry
Mick Barry
Flag of Australia image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
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