Sunday, May 19, 2024
 Popular · Latest · Hot · Upcoming
185
rated 0 times [  190] [ 5]  / answers: 1 / hits: 23151  / 12 Years ago, mon, august 13, 2012, 12:00:00

(Pre-emptive strike: If you're tempted to mark this as a duplicate, note that other questions seem to ask why am I getting this error? I know why I'm getting this error; I want to know how I can detect the error in my JavaScript code. It only appears in the Firebug console and, of course, is obvious to the user when the image is loaded.)



I am using picturefill for responsive images. I have a callback that is fired for the load event on the images. So the callback runs every time someone resizes the browser window such that a different image is loaded via picturefill.



Inside the callback, I'm converting the image data to a dataURL via canvas so that I can cache the image data in localStorage so its available to the user even when they are offline.



Note the part about offline. That's why I cannot rely on the browser cache. And the HTML5 offline application cache doesn't meet my needs because the images are responsive. (See Application Cache is a Douchebag for the explanation of the incompatibility of responsive images with HTML offline application cache.)



On Firefox 14.0.1 on a Mac, the load image will fire if I resize the browser to something really big and then resize it back down to something small again before the large image has a chance to fully load. It ends up reporting Image corrupt or truncated in the Firebug console, but doesn't throw an exception or trigger an error event. No indication anything is wrong in the code. Just in the Firebug console. Meanwhile, it stores a truncated image in localStorage.



How can I reliably and efficiently detect this problem within JavaScript so that I don't cache that image?



Here's how I loop through the picturefill divs to find img tags that have been inserted by picturefill:



    var errorLogger = function () {
window.console.log('Error loading image.');
this.removeEventListener('load', cacheImage, false);
};

for( var i = 0, il = ps.length; i < il; i++ ){
if( ps[ i ].getAttribute( data-picture ) !== null ){

image = ps[ i ].getElementsByTagName( img )[0];
if (image) {
if ((imageSrc = image.getAttribute(src)) !== null) {
if (imageSrc.substr(0,5) !== data:) {
image.addEventListener(load, cacheImage, false);
image.addEventListener('error', errorLogger, false);
}
}
}
}
}


And here's what the cacheImage() callback looks like:



var cacheImage = function () {
var canvas,
ctx,
imageSrc;

imageSrc = this.getAttribute(src);

if ((pf_index.hasOwnProperty('pf_s_' + imageSrc)) ||
(imageSrc.substr(0,5) === data:) ||
(imageSrc === null) || (imageSrc.length === 0)) {
return;
}

canvas = w.document.createElement(canvas);
canvas.width = this.width;
canvas.height = this.height;

ctx = canvas.getContext(2d);
ctx.drawImage(this, 0, 0);
try {
dataUri = canvas.toDataURL();
} catch (e) {
// TODO: Improve error handling here. For now, if canvas.toDataURL()
// throws an exception, don't cache the image and move on.
return;
}

// Do not cache if the resulting cache item will take more than 128Kb.
if (dataUri.length > 131072) {
return;
}

pf_index[pf_s_+imageSrc] = 1;

try {
localStorage.setItem(pf_s_+imageSrc, dataUri);
localStorage.setItem(pf_index, JSON.stringify(pf_index));
} catch (e) {
// Caching failed. Remove item from index object so next cached item
// doesn't wrongly indicate this item was successfully cached.
delete pf_index[pf_s_+imageSrc];
}
};


Lastly, here is the full text of what I am seeing in Firebug with the URL changed to protect the guilty:




Image corrupt or truncated: http://www.example.com/pf/external/imgs/extralarge.png



More From » firefox

 Answers
12

It appears that when changing the src attribute of the img tag, Firefox fires a load event. This is contrary to the HTML5 specification, which says that if the src attribute is changed, then any other fetch already in progress should be ended (which Firefox does), and no events should be sent. The load event should be sent only if the fetch was completed successfully. So I'd say that the fact that you get a load event is a Firefox bug.



However, the image should know if it is fully available or not, you could try to use the complete attribute:



if (this.complete === false) {
return;
}


Unfortunately, Firefox has this.complete set to true instead, so that's not an option either.



The best option may be to create a new <img> element each time you wish to change the src attribute.


[#83678] Saturday, August 11, 2012, 12 Years  [reply] [flag answer]
Only authorized users can answer the question. Please sign in first, or register a free account.
makenatiffanic

Total Points: 412
Total Questions: 106
Total Answers: 90

Location: Marshall Islands
Member since Tue, Sep 21, 2021
3 Years ago
;