summaryrefslogtreecommitdiff
path: root/js/gif-encode/client.js
diff options
context:
space:
mode:
authorJulie Lala <jules@okfoc.us>2013-12-18 21:32:42 -0500
committerJulie Lala <jules@okfoc.us>2013-12-18 21:32:42 -0500
commit5ef224e2a9b37d4b5b283d5bf5ebd4f5d0ec226b (patch)
treebf47e4b5447dc01c31dd718de0de8a75bc060ad4 /js/gif-encode/client.js
initial commit...
Diffstat (limited to 'js/gif-encode/client.js')
-rw-r--r--js/gif-encode/client.js279
1 files changed, 279 insertions, 0 deletions
diff --git a/js/gif-encode/client.js b/js/gif-encode/client.js
new file mode 100644
index 0000000..271cbb0
--- /dev/null
+++ b/js/gif-encode/client.js
@@ -0,0 +1,279 @@
+// Total frames to record
+var FRAMES_PER_GIF = 36;
+
+// Frames per second to read from the video
+var FPS = 12;
+
+// Per-frame delay in milliseconds
+var DELAY = Math.floor( 1000 / FPS );
+
+// Number of WebWorkers to create
+var WORKERS = 4;
+
+// Number of frames to use to build the gif palette (takes longest)
+var FRAMES_TO_QUANTIZE = 4;
+
+// Upload these gifs when finished??
+var DO_UPLOAD = true;
+
+function GifEncoder(){
+ var base = this;
+ this.working = false;
+ var canvases = [];
+ var contexts = [];
+ var frames = [];
+ var delays = [];
+ var width = 0;
+ var height = 0;
+ var frames_done = 0;
+
+ var initted = Date.now();
+ var started = Date.now();
+ var tube = base.tube = new Tube ()
+
+ var workers = new Factory ();
+
+ var width, height;
+ var neuquant, colortab;
+
+ workers.hire("message", receiveMessage);
+ workers.hire("quantize", receiveQuantize);
+ workers.hire("encode", receiveEncode);
+
+ var reset = this.reset = function(){
+ resetFrames()
+ neuquant = null;
+ colortab = null;
+ base.quantized = false
+ }
+ var resetFrames = this.resetFrames = function(){
+ canvases = [];
+ contexts = [];
+ frames = [];
+ delays = [];
+ width = 0;
+ height = 0;
+ frames_done = 0;
+ }
+
+ this.on = function(){
+ base.tube.on.apply(base.tube, arguments)
+ };
+
+ this.off = function(){
+ base.tube.off.apply(base.tube, arguments)
+ };
+
+ var addFrame = this.addFrame = function(canvas, delay) {
+ var ctx = canvas.getContext('2d');
+ canvases.push(canvas);
+ contexts.push(ctx);
+ delays.push(delay);
+
+ if (canvases.length == 1) {
+ width = canvas.width;
+ height = canvas.height;
+ }
+ }
+
+ var addFrames = this.addFrames = function(canvas_array, delay){
+ for (var i = 0; i < canvas_array.length; i++) {
+ var canvas = canvas_array[i]
+ var ctx = canvas.getContext('2d');
+ canvases.push(canvas);
+ contexts.push(ctx);
+ delays.push(delay);
+ }
+
+ if (canvases.length == canvas_array.length) {
+ width = canvas_array[0].width;
+ height = canvas_array[0].height;
+ }
+ }
+
+ var copyFrame = this.copyFrame = function(canvas, delay) {
+ var newCanvas = document.createElement("canvas");
+ var ctx = newCanvas.getContext('2d');
+
+ ctx.drawImage(canvas, 0, 0, canvas.width, canvas.height);
+
+ canvases.push(newCanvas);
+ contexts.push(ctx);
+ delays.push(delay);
+
+ if (canvases.length == 1) {
+ width = canvas.width;
+ height = canvas.height;
+ }
+ }
+
+ function Factory () {
+ var base = this;
+ var w = 0; // which worker to work next
+ var ww = [];
+ base.init = function(){
+ for (var i = 0; i < WORKERS; i++) {
+ var worker = new Worker('js/vendor/gif-encode/worker.js');
+ worker.onmessage = base.receiveWork;
+ ww.push(worker);
+ }
+ }
+ var tasks = {};
+ base.hire = function(task, cb){
+ tasks[task] = cb;
+ }
+ base.work = function(job){
+ ww[++w % ww.length].postMessage(job);
+ }
+ base.receiveWork = function(e){
+ e.data.task in tasks && tasks[e.data.task](e);
+ }
+ base.init();
+ }
+
+ function receiveMessage(e){
+ console.log("[WORKER]", e.data.message);
+ }
+
+ var neuquant, colortab;
+ var quantize = this.quantize = function () {
+ initted = Date.now();
+ started = Date.now();
+ var spritedata = spriteSheet(FRAMES_TO_QUANTIZE);
+
+ workers.work({
+ task: 'quantize',
+ imageData: spritedata
+ });
+ }
+
+ function receiveQuantize(e) {
+ console.log(Date.now() - started, "quantization done");
+ neuquant = e.data.neuquant;
+ colortab = e.data.colortab;
+ base.quantized = true
+ base.tube("quantized")
+ }
+
+ var encode = this.encode = function (nq, ct) {
+ if (! canvases.length) {
+ throw Error ("No frames to encode")
+ }
+ nq = nq || neuquant
+ ct = ct || colortab
+
+ started = Date.now();
+ frames_done = 0;
+
+ console.log('working .... ');
+ var i = 0;
+
+ function sendWork () {
+ if (i == canvases.length) return doneSending();
+
+ var ctx = contexts[i];
+ var imdata = ctx.getImageData(0, 0, width, height).data;
+ var delay = delays[i];
+
+ workers.work({
+ task: 'encode',
+ frame_index: i,
+ frame_length: contexts.length-1,
+ height: height,
+ width: width,
+ delay: delay,
+ imageData: imdata,
+ neuquant: neuquant,
+ colortab: colortab
+ });
+
+ i++;
+ setTimeout(sendWork, 16);
+ }
+ function doneSending(){
+ base.tube("done_sending")
+ }
+ sendWork();
+ }
+
+ function receiveEncode(e){
+ var frame_index = e.data["frame_index"];
+ var frame_data = e.data["frame_data"];
+
+ frames[frame_index] = frame_data;
+
+ base.tube("encoded-frame", frames.length, canvases.length)
+ for (var j = 0; j < canvases.length; j++) {
+ if (frames[j] == null) {
+ return;
+ }
+ }
+ console.log("FINISHED " + canvases.length);
+ var binary_gif = frames.join('');
+ var base64_gif = window.btoa(binary_gif);
+ var data_url = 'data:image/gif;base64,'+base64_gif;
+
+ base.working = false;
+
+ // photo.setAttribute('src', data_url);
+ // ui.doneEncodingPicture();
+ base.tube("rendered", binary_gif)
+ base.tube("rendered-url", data_url)
+// if (DO_UPLOAD) upload( base64_gif );
+
+ console.log((Date.now() - started), "processed frames");
+ console.log((Date.now() - initted), "done");
+ }
+
+// function upload (base64_gif) {
+// $("#working").html("UPLOADING")
+//
+// console.log("starting upload")
+// var params = {
+// url: base64_gif
+// }
+// $.ajax({
+// 'url': "/photos.json",
+// 'type': 'post',
+// 'data': csrf(params),
+// 'success': function(data){
+//
+// // $("#share").data("href", "/photos/" + data.hash)
+// // $("#share, #make-another").fadeIn(400);
+// console.log(data);
+// console.log((Date.now() - started), "uploaded");
+// // $("#photo").attr("src", data.url);
+// // window.location.href = "/photos/" + data.hash
+// localStorage.setItem('hash', data.hash)
+// window.location.href = "/"
+// // data.hash
+// }
+// });
+// console.log("ok");
+// }
+
+ function spriteSheet (frameCount) {
+ var start = Date.now();
+ frameCount = Math.min(contexts.length, frameCount);
+ var sprites = document.createElement("canvas");
+ var spriteContext = sprites.getContext('2d');
+ sprites.width = width;
+ sprites.height = height * frameCount;
+ var spritedata = spriteContext.getImageData(0, 0, sprites.width, sprites.height)
+ var spritedatadata = spritedata.data
+ var j = 0;
+ var ctxz = sample(contexts, 4);
+ while (frameCount--) {
+ var ctx = ctxz[frameCount];
+ var imdata = ctx.getImageData(0, 0, width, height).data;
+ for (var n = 0; n < imdata.length; j++, n++) {
+ spritedatadata[j] = imdata[n];
+ }
+ }
+ // spriteContext.putImageData(spritedata, 0, 0, 0, 0, sprites.width, sprites.height);
+ // upload( sprites.toDataURL("image/png").split(",")[1]
+ console.log(Date.now() - start, "built spritesheet");
+ return spritedata;
+ }
+
+}