-
-
Save lakenen/3012623 to your computer and use it in GitHub Desktop.
function isAnimatedGif(src, cb) { | |
var request = new XMLHttpRequest(); | |
request.open('GET', src, true); | |
request.responseType = 'arraybuffer'; | |
request.addEventListener('load', function () { | |
var arr = new Uint8Array(request.response), | |
i, len, length = arr.length, frames = 0; | |
// make sure it's a gif (GIF8) | |
if (arr[0] !== 0x47 || arr[1] !== 0x49 || | |
arr[2] !== 0x46 || arr[3] !== 0x38) | |
{ | |
cb(false); | |
return; | |
} | |
//ported from php http://www.php.net/manual/en/function.imagecreatefromgif.php#104473 | |
//an animated gif contains multiple "frames", with each frame having a | |
//header made up of: | |
// * a static 4-byte sequence (\x00\x21\xF9\x04) | |
// * 4 variable bytes | |
// * a static 2-byte sequence (\x00\x2C) (some variants may use \x00\x21 ?) | |
// We read through the file til we reach the end of the file, or we've found | |
// at least 2 frame headers | |
for (i=0, len = length - 9; i < len, frames < 2; ++i) { | |
if (arr[i] === 0x00 && arr[i+1] === 0x21 && | |
arr[i+2] === 0xF9 && arr[i+3] === 0x04 && | |
arr[i+8] === 0x00 && | |
(arr[i+9] === 0x2C || arr[i+9] === 0x21)) | |
{ | |
frames++; | |
} | |
} | |
// if frame count > 1, it's animated | |
cb(frames > 1); | |
}); | |
request.send(); | |
} |
looks like it's never satisfying the for conditions if the GIF is not animated.
can't understand why
It is because multiple comma-separated conditions in a for loop like this
for (i=0, len = length - 9; i < len, frames < 2; ++i)
will evaluate both checks, but use only the last one for determining whether to run the loop again. So unless more than one frame is found, i will just grow and frames < 2 never satisfy.
In this case, better to use || (or have an inner loop)
N.B. the img.replace(/\x00\x21\xF9\x04\x00[\x2c\x21]/g
solution suffers the same problem as the original code here -- if the ECB isn't 4 bytes this regex won't find the frame (see the wikipedia article examples).
great rubust solution from @marckubischta ! thanks for that.
anyone able to come up with detecting animation for webp image format?
Smaller solution (inside xhr callback):
var img = request.response;
if (!/^GIF8[79]a/) { cb(false); } else {
var frames = 0;
img.replace(/\x00\x21\xF9\x04\x00[\x2c\x21]/g, function(){ frames++ });
cb(frames>1);
}
In addition, this only works if the domain origin of the image is the same as the page you are loading the script from.