diff options
Diffstat (limited to 'js/vendor/gif-encode/client.js')
| -rw-r--r-- | js/vendor/gif-encode/client.js | 260 |
1 files changed, 260 insertions, 0 deletions
diff --git a/js/vendor/gif-encode/client.js b/js/vendor/gif-encode/client.js new file mode 100644 index 0000000..a6c09ec --- /dev/null +++ b/js/vendor/gif-encode/client.js @@ -0,0 +1,260 @@ +// 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 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(){ + canvases = []; + contexts = []; + frames = []; + delays = []; + width = 0; + height = 0; + neuquant = null; + colortab = null; + base.quantized = false + } + var resetFrames = this.resetFrames = function(){ + canvases = []; + contexts = []; + frames = []; + delays = []; + width = 0; + height = 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 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('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) { + nq = nq || neuquant + ct = ct || colortab + + started = Date.now(); + + 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("doneSending") + // ui.doneEncodingPicture(); + } + sendWork(); + } + + function receiveEncode(e){ + var frame_index = e.data["frame_index"]; + var frame_data = e.data["frame_data"]; + + frames[frame_index] = frame_data; + 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; + } + +} |
