Test for broken images -- works in Safari

Posted by mde [ Sun, 30 Sep 2007 19:06:00 GMT ]

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.