Animated Gif Tearing?

Got a bit of a problem, trying to play an animated gif in Java2D even though I am using double buffering the animated gif is still tearing every few frames (as if it were only partially drawn).


        
        protected Image	gifImage;

	protected Image	offscreen;
	
	protected Thread	animationThread;

	
	public void start() {
		
                               animationThread = new Thread() {
					public void run() {
						while(loaderThread != null) {
							repaint();
							MyApplet.this.sleep(100);
						}
						animationThread = null;
					}
				};
				animationThread.start();
	}
	
	
	...

	public final void update(Graphics g) {
		paint(g);
	}
	
	public void paint(Graphics g) {
		
		// create offscreen if missing
		if (offscreen == null) {
			offscreen = createImage(getWidth(), getHeight());
		}

		// draw everything onto an image before drawing to avoid flicker
		Graphics og = offscreen.getGraphics();
		
		// set background color
		og.setColor(Color.black);
		og.fillRect(0, 0, getWidth(), getHeight());

		// get logo position so its in the middle of applet
		int x = (getWidth() - gifImage.getWidth(this)) / 2;
		int y = (getHeight() - gifImage.getHeight(this)) / 2;
		
		// draw animated gif
		og.drawImage(gifImage, x, y, null);
			
		og.dispose();

		// finally draw it all
		g.drawImage(offscreen, 0, 0, null);
	}	


it doesn’t happen every frame but after random interval.

anyone got any idea’s or fixes for this?

In this ancient thread it seems like a Java2D bug, and there is code to grab frames from the GIF and roll your own animator.

Hope this helps ::slight_smile:

Ah thx.

I was hoping to avoid rolling my own animation and timer from gif frames since code size is a limit in this case and would like it to remain as small and simple as possible.

Anyway I’ll have a further look but I did notice that this seems to be some sort of Toolkit timer issue and the tearing is due to the gif image getting drawn as it switches frames. If I use an ImageObserver without using another thread to call repaint, e.g.

og.drawImage(gifImage, x, y, this);

then the problem disappears and I get smooth tear free animation, however if I use two gifs both with their own ImageObservers then I get some tearing, probably due to one gif calling repaint while the other gif is changing frames.

Not sure where the timer is that updates the gif animation but finding that might be a good place to start.

as its for the appletloader is it out of the question to load an array of images?

People could pass the name of the image, plus a (optional)count to the applet with a defaul value as 1.
if you want to keep coding to a minimum.

so people can still pass the gif, as it is currently implemented. without changing any html script.

but if they dont like the flicker, they can take the time to import a list of jpg’s. and add the extra paramater.

It might help to put each GIF in its own Component. They will have independent Toolkit-triggered repaints.

How to integrate that into your current project, plus using transparant GIFs on heavyweight components, is left as an exercise for the reader :wink:

Seriously, it’s probably easier to roll your own.

http://www.permadi.com/tutorial/javaImgObserverAndAnimGif/
this explains how the listener handles the gif flags.

at the start of the paint method, set something like “painting = true;”

at the end set it to false;
and in the imageUpdate method
do something like:


if (!painting) super.imageUpdate();

or possible override the image update method to do nothing, because all it seems to do is call repaint, but you set the appletlaoder to force repaint every 100ms anyway.

I find result is pretty good using old way of ImageObserver

class MayApplet implements ImageObserver
....
....
public void paint(Graphics g)
{
 this.checkBackGraphics(); //create/resize backGraphics/backImage if needed
 this.backGraphics.drawImage(this.myGif,0,0,this);
 g.drawImage(this.backImage,0,0);
}
...
...
public void imageUpdate(Image img,....,int flag)
{
 if(flag&ImageObserver.FRAMEBITS ) //new animated gif image ready ?
 {
  this.paint(this.getGraphics()); //direct painting ( may be replaced by this.redraw() )
 }
 return true; //return true to recevice further call to imageUpdate and continue animation of the gif
}

oh great, thx ppl, will test this out.

ok brilliant, this method does fix the issue. plus only uses a minimal amount of code.

thx.

I tried this on the applet loader and it seems to work fine
all you need to add is:


public boolean imageUpdate( Image i, int flags, int x, int y, int w, int h)  {
	return true;
}

yup its already fixed and patch is applied.

But yeh Applet does implement ImageObserver.