Skip to content

Instantly share code, notes, and snippets.

@geta6
Created April 17, 2014 12:38
Show Gist options
  • Save geta6/10980131 to your computer and use it in GitHub Desktop.
Save geta6/10980131 to your computer and use it in GitHub Desktop.
extends x-gif
<html>
<head>
</head>
<body>
<input type='file' id='file' name='file' multiple>
<script>
var Reader = function (arrayBuffer) {
this.data = new Uint8Array(arrayBuffer);
this.index = 0;
}
Reader.prototype.finished = function () {
return this.index >= this.data.length;
}
Reader.prototype.readByte = function () {
return this.data[this.index++];
};
Reader.prototype.peekByte = function () {
return this.data[this.index];
};
Reader.prototype.skipBytes = function (n) {
this.index += n;
};
Reader.prototype.peekBit = function (i) {
return !!(this.peekByte() & (1 << 8 - i));
};
Reader.prototype.readAscii = function (n) {
var s = '';
for (var i = 0; i < n; i++) {
s += String.fromCharCode(this.readByte());
}
return s;
};
Reader.prototype.isNext = function (array) {
for (var i = 0; i < array.length; i++) {
if (array[i] !== this.data[this.index + i]) return false;
}
return true;
};
var Exploder = function (file, cb) {
this.file = file;
this.doneCallback = cb;
if (file instanceof ArrayBuffer) {
this.explode(file);
} else {
this.loadAndExplode();
}
};
Exploder.prototype.loadAndExplode = function () {
var loader = new XMLHttpRequest(),
exploder = this.explode.bind(this);
loader.open('GET', this.file, true);
loader.responseType = 'arraybuffer';
loader.onload = function () {
exploder(this.response);
};
loader.send();
}
Exploder.prototype.explode = function (buffer) {
var frames = [],
reader = new Reader(buffer);
if (reader.readAscii(6) != 'GIF89a') {
return;
}
reader.skipBytes(4);
if (reader.peekBit(1)) {
var colorTableSize = reader.readByte() & 0x07;
reader.skipBytes(2);
reader.skipBytes(3 * Math.pow(2, colorTableSize + 1));
}
var gifHeader = buffer.slice(0, reader.index);
var spinning = true, expectingImage = false;
while (spinning) {
if (reader.isNext([0x21, 0xFF])) {
reader.skipBytes(2 + reader.readByte());
if (reader.isNext([0x03, 0x01])) {
reader.skipBytes(5)
} else {
while (!(reader.readByte() === 0 && reader.peekByte() === 0));
reader.skipBytes(1);
}
} else if (reader.isNext([0x21, 0xFE])) {
reader.skipBytes(2);
while (!reader.isNext([0x00])) {
reader.skipBytes(reader.readByte());
}
reader.skipBytes(1);
} else if (reader.isNext([0x2c])) {
if (!expectingImage) {
frames.push({ index: reader.index, delay: 0 });
}
expectingImage = false;
reader.skipBytes(9);
if (reader.peekBit(1)) {
var colorTableSize = reader.readByte() & 0x07;
reader.skipBytes(2);
reader.skipBytes(3 * Math.pow(2, colorTableSize + 1));
} else {
reader.skipBytes(1);
}
reader.skipBytes(1);
while (!reader.isNext([0x00])) {
var blockSize = reader.readByte();
reader.skipBytes(blockSize);
}
reader.skipBytes(1);
} else if (reader.isNext([0x21, 0xF9, 0x04])) {
var index = reader.index;
reader.skipBytes(3);
var disposalMethod = reader.readByte() >> 2;
var delay = reader.readByte() + reader.readByte() * 256;
frames.push({ index: index, delay: delay, disposal: disposalMethod });
reader.skipBytes(2);
expectingImage = true;
} else {
var maybeTheEnd = reader.index;
while (!reader.finished() && !reader.isNext([0x21, 0xF9, 0x04])) {
reader.readByte();
}
if (reader.finished()) {
reader.index = maybeTheEnd;
spinning = false;
}
}
}
var endOfFrames = reader.index;
var gifFooter = buffer.slice(-1);
for (var i = 0; i < frames.length; i++) {
var frame = frames[i];
var nextIndex = (i < frames.length - 1) ? frames[i + 1].index : endOfFrames;
frame.blob = new Blob([ gifHeader, buffer.slice(frame.index, nextIndex), gifFooter ], {type: 'image/gif'});
frame.url = URL.createObjectURL(frame.blob);
}
this.doneCallback(frames);
}
document.getElementById('file').addEventListener('change', function (event) {
var files = event.target.files;
for (var i = 0, f; f = files[i]; i++) {
(function (f){
var reader = new FileReader();
reader.onload = function (event) {
var buffer = event.target.result;
new Exploder(buffer, function (frames) {
console.log(frames);
alert(frames.length);
});
};
reader.readAsArrayBuffer(f);
}(f));
}
}, false);
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment