Test for broken images -- works in Safari

2007-09-30 22:06:00

I've been doing a bit of work recently on the Windmill project for OSAF -- it's pretty usable already, and we're just now approaching the 0.2 release.

One of the pieces I added awhile back was an assert to check for broken images. After doing a bunch of poking around online, the one piece that seemed to elude everyone doing this kind of check was something that works in Safari 2. We plan to support Safari in Windmill, so I did a bit more research and hammered out something that seems to work reliably.

The crux of the problem with Safari is that it doesn't support the complete attribute -- at least not for images loaded normally in markup. Interestingly though, it does support it for script-created images -- which opens to the door to this hack.

Here's the code:

function assertImageLoaded(img) {
  var complete = img.complete;
  var ret = null; // Return value
  // Workaround for Safari -- it only supports the
  // complete attrib on script-created images
  if (typeof complete == 'undefined') {
    var test = new Image();
    // If the original image was successfully loaded,
    // src for new one should be pulled from cache
    test.src = img.src;
    complete = test.complete;
  // Check the complete attrib. Use strict equality
  // check -- don't want undefined, null, etc.
  // --------------------------
  // False -- Img failed to load in IE/Safari, or is
  // still trying to load in FF
  if (complete === false) {
    ret = false;
  // True, but image has no size -- image failed to
  // load in FF
  else if (complete === true &&
    img.naturalWidth == 0) {
    ret = false;
  // Otherwise all we can do is assume image loaded
  else {
    ret = true;
  return ret;

The hack for Safari depends on the normal caching behavior of the browser.

When you do the check, the complete attribute for the original image will be undefined -- but when you create a new Image with JavaScript, and set its src to the src of the original, it grabs the image from cache, and the complete attribute for the script-created image is immediately set to true.

This assumes of course that Safari is pulling images from cache after the first hit, but that should be the default behavior, and in the vast majority of cases that's what you want. If you're using this code, and you get a bunch of false hits for broken images in Safari, you'll want to take a look at how both your browser and server are configured for caching.


mde (2007-10-22)
Dougal: Could you give some specifics about the cases where it doesn't work? If you can point me to a test case, I'll be happy to take a look at it. With the slow-loading images -- it sounds like it's doing exactly what it should do: tell you what images haven't loaded when you run the test. That's why the function is called "assertImageLoaded."

mde (2007-10-15)
TTop, the blog entry you've linked describes a bug that only happens if you actually append the script-created image to the document tree. The code above doesn't actually append the image to the doc -- it's just a dummy Image that gets thrown away after setting its 'src', and testing the 'complete' attribute. E-mail me if you have further questions about how it works, or have some edge case that's giving you fits.

TTop (2007-10-14)

Unfortunately, this doesn’t work for all cases. I’m trying to solve this exact problem with Safari, but I can’t use “new Image()” due to yet another Safari image bug:


Dougal (2007-10-22)

Unfortunately this does not work in all cases. It also detects slow loading images as broken.



This is the blog for Matthew Eernisse. I currently work at Yammer as a developer, working mostly with JavaScript. All opinions expressed here are my own, not my employer's.


Previous posts

All previous posts ยป

This blog is a GeddyJS application.