Skip to content

Commit

Permalink
omggif matte and transparency closes #120
Browse files Browse the repository at this point in the history
  • Loading branch information
forresto committed May 13, 2013
1 parent 45a18af commit 0589e69
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 30 deletions.
54 changes: 36 additions & 18 deletions libs/omggif/omggif-worker.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,32 @@
/* message should be object with frames (array of pixel data objects), delay (ms delay per frame), matte, transparent ([r,g,b]) */

/* listen for messages back that will be either {type:"progress", data:percent done} or {type:"gif", data:binary gif data} */

importScripts('omggif.js', 'NeuQuant.js');

var rgba2rgb = function (data) {
var rgba2rgb = function (data, matte, transparent) {
var pixels = [];
var count = 0;
var len = data.length;
for ( var i=0; i<len; i+=4 ) {
pixels[count++] = data[i];
pixels[count++] = data[i+1];
pixels[count++] = data[i+2];
var r = data[i];
var g = data[i+1];
var b = data[i+2];
var a = data[i+3];
if (transparent && a===0) {
// Use transparent color
r = transparent[0];
g = transparent[1];
b = transparent[2];
} else if (matte && a<255) {
// Use matte with "over" blend mode
r = ( (r*a + (matte[0] * (255-a))) / 255 ) |0;
g = ( (g*a + (matte[1] * (255-a))) / 255 ) |0;
b = ( (b*a + (matte[2] * (255-a))) / 255 ) |0;
}
pixels[count++] = r;
pixels[count++] = g;
pixels[count++] = b;
}
return pixels;
}
Expand All @@ -27,6 +46,9 @@ self.onmessage = function(event) {
var framesLength = frames.length;
var delay = event.data.delay / 10;

var matte = event.data.matte ? event.data.matte : [255,255,255];
var transparent = event.data.transparent ? event.data.transparent : false;

var startTime = Date.now();

var buffer = new Uint8Array( frames[0].width * frames[0].height * framesLength * 5 );
Expand All @@ -37,7 +59,7 @@ self.onmessage = function(event) {
var data = frame.data;

// Make palette with NeuQuant.js
var nqInPixels = rgba2rgb(data);
var nqInPixels = rgba2rgb(data, matte, transparent);
var len = nqInPixels.length;
var nPix = len / 3;
var map = [];
Expand All @@ -52,19 +74,15 @@ self.onmessage = function(event) {
// usedEntry[index] = true;
map[j] = index;
}
// var colorDepth = 8;
// var palSize = 7;
// get closest match to transparent color if specified
// if (transparent != null) {
// transIndex = findClosest(transparent);
// }

// force palette to be power of 2
// var powof2 = 1;
// while ( powof2 < palette.length ) powof2 <<= 1;
// palette.length = powof2;

gif.addFrame( 0, 0, frame.width, frame.height, new Uint8Array( map ), { palette: new Uint32Array( palette ), delay: delay } );

var options = { palette: new Uint32Array( palette ), delay: delay };

if (transparent) {
options.transparent = nq.map(transparent[0], transparent[1], transparent[2]);
options.disposal = 2; // Clear between frames
}

gif.addFrame( 0, 0, frame.width, frame.height, new Uint8Array( map ), options );
}

// Add all frames
Expand Down
18 changes: 6 additions & 12 deletions src/nodes/variable-animation.js
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,8 @@ $(function(){
}
});
},
_matte: [255, 255, 255],
_transparent: [0, 255, 0],
makeGif: function(){
// Spawn worker
this.$(".status").text("Setting up GIF...");
Expand Down Expand Up @@ -263,28 +265,20 @@ $(function(){
self.$(".status").text("GIF encoding error :-(");
}, false);

// Make canvas for matte
var keyCanvas = document.createElement("canvas");
keyCanvas.width = this._animation.width;
keyCanvas.height = this._animation.height;
keyContext = keyCanvas.getContext('2d');
keyContext.fillStyle = "#FFFFFF";

// Send image data
var frames = [];
for (var i = 0; i<this._animation.length; i++) {
// White background
keyContext.fillRect(0, 0, keyCanvas.width, keyCanvas.height);
keyContext.drawImage(this._animation.frames[i], 0, 0);
var imageData = keyContext.getImageData(0, 0, keyCanvas.width, keyCanvas.height);
var imageData = this._animation.frames[i].getContext('2d').getImageData(0, 0, this._animation.width, this._animation.height);
frames[i] = imageData;
if (this._pingpong && i>0 && i<this._animation.length-1) {
frames[this._animation.length * 2 - 2 - i] = imageData;
}
}
gifWorker.postMessage({
frames: frames,
delay: this._ms
delay: this._ms,
matte: this._matte,
transparent: this._transparent
});

},
Expand Down

0 comments on commit 0589e69

Please sign in to comment.