the best solution… don’t use MediaTracker!
simply use toolkit.createImage (or getImage)
then, to begin the loading,
toolkit.checkImage (passing in an image observer)
followed by a synchronized wait,
which gets woken by the image observer when the image is loaded completely.
Alternatively, forget about all that crap, and just use ImageIO.
(followed by copying the unaccelerated image into a blank acceleratable image)
If you still want to use toolkit.createImage, perhaps this image loader i wrote a while ago will be helpful.
(be warned, it isn’t bulletproof - having said that, it includes a fix relating to Image.createScaledinstance())
It doesn’t have any facility for handling images that ABORT or ERROR during loading.
import java.awt.*;
import java.awt.image.*;
public class ImageLoader implements ImageObserver
{
//THIS CLASS IS NOT THREAD SAFE
final Toolkit toolkit;
final GraphicsConfiguration gc;
final boolean debug;
public ImageLoader(Toolkit toolkit, GraphicsConfiguration gc)
{
this(toolkit,gc,false);
}
public ImageLoader(Toolkit toolkit, GraphicsConfiguration gc, boolean debug)
{
this.toolkit = toolkit;
this.gc = gc;
this.debug = debug;
}
public Image[] loadImages(String[] s, int transparency)
{
Image[] imagesToLoad = new Image[s.length];
for(int i = 0; i < imagesToLoad.length; i++)
{
imagesToLoad[i] = loadImage(s[i], transparency);
}
return imagesToLoad;
}
// a duplicate of the image is made, because some methods
// when called using an Image obtained directly from a file (i.e. the Images ImageProducer is a file)
// are very buggy (i.e. Image.getScaledInstance();)
public Image loadImage(String s, int transparency)
{
if(debug) System.out.print("loadImage " + s + " ");
//1st, fully load the source image
Image sourceImage = prepareImage(toolkit.createImage(getClass().getResource(s)));
//then, create a replica, that will have its ImageObserver as a memoryImage (rather than a file)
BufferedImage returnImage = gc.createCompatibleImage(sourceImage.getWidth(null),sourceImage.getHeight(null), transparency);
//now, copy the sourceImage into the memoryImage
Graphics2D g2d = returnImage.createGraphics();
g2d.setComposite(AlphaComposite.Src);
g2d.drawImage(sourceImage,0,0,null);
g2d.dispose();
//and return the memoryImage (the original image source is lost)
return returnImage;
}
//prepares an [] of precreated Images
// blocks until all images are loaded (or ERRORed)
// each image is 'prepared' sequencially, so only 1
// image loading thread should be active at any 1 time
// im not sure if this is better or worse than loading all images simultaneously
// though, looking at the way MediaTracker does it - i think its better
public Image[] prepareImages(Image[] imagesToLoad)
{
for(int i = 0; i < imagesToLoad.length; i++)
{
prepareImage(imagesToLoad[i],-1,-1);
}
return imagesToLoad;
}
//prepares a single image (blocks until it is fully loaded
public Image prepareImage(Image image)
{
return prepareImage(image, -1,-1);
}
volatile boolean loaded = false;
public synchronized Image prepareImage(Image image, int width, int height)
{
if(debug) System.out.print("prepareImage " + width + "," + height + " ");
loaded = false;
//prepare image doesn't always do the loading asynchronously!!
if(!toolkit.prepareImage(image,width,height,this) && !loaded)
{
//if(debug) System.out.print("async load");
try
{
this.wait();
}
catch(InterruptedException e){}
}
if(!loaded) System.out.println("ERROR: Failed to load image " + image);
return image;
}
public synchronized boolean imageUpdate(Image img, int flags, int x, int y, int w, int h)
{
if((flags & ImageObserver.ALLBITS) == ImageObserver.ALLBITS)
{
if(debug) System.out.println(generateDebugData("Complete",x,y,w,h,flags));
loaded = true;
this.notifyAll();
return false;
}
if((flags & ImageObserver.FRAMEBITS) == ImageObserver.FRAMEBITS)
{
if(debug) System.out.println(generateDebugData("Framebits",x,y,w,h,flags));
loaded = true;
this.notifyAll();
return false;
}
if((flags & ImageObserver.ERROR) == ImageObserver.ERROR)
{
if(debug) System.out.println(generateDebugData("Error",x,y,w,h,flags));
this.notifyAll();
return false;
}
if((flags & ImageObserver.ABORT) == ImageObserver.ABORT)
{
if(debug) System.out.println(generateDebugData("Abort",x,y,w,h,flags));
this.notifyAll();
return false;
}
if(debug) System.out.print(".");
return true;
}
private String generateDebugData(String flagString, int x, int y, int w, int h, int flags)
{
StringBuffer sb = new StringBuffer();
sb.append(flagString).append(" x=").append(x)
.append(" y=").append(y)
.append(" width=").append(w)
.append(" height=").append(h)
.append(" flags=").append(flags);
return sb.toString();
}
}