Added gif support

This commit is contained in:
CBenni 2017-12-31 13:59:14 +01:00
parent 3ad870d990
commit 0176bd063f
17 changed files with 106 additions and 1028 deletions

View file

@ -1,3 +0,0 @@
A Pen created at CodePen.io. You can find this one at https://codepen.io/CBenni/pen/YYZKeO.

View file

@ -1,3 +0,0 @@
// gif.js 0.2.0 - https://github.com/jnordberg/gif.js
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.GIF=f()}})(function(){var define,module,exports;return function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s}({1:[function(require,module,exports){function EventEmitter(){this._events=this._events||{};this._maxListeners=this._maxListeners||undefined}module.exports=EventEmitter;EventEmitter.EventEmitter=EventEmitter;EventEmitter.prototype._events=undefined;EventEmitter.prototype._maxListeners=undefined;EventEmitter.defaultMaxListeners=10;EventEmitter.prototype.setMaxListeners=function(n){if(!isNumber(n)||n<0||isNaN(n))throw TypeError("n must be a positive number");this._maxListeners=n;return this};EventEmitter.prototype.emit=function(type){var er,handler,len,args,i,listeners;if(!this._events)this._events={};if(type==="error"){if(!this._events.error||isObject(this._events.error)&&!this._events.error.length){er=arguments[1];if(er instanceof Error){throw er}else{var err=new Error('Uncaught, unspecified "error" event. ('+er+")");err.context=er;throw err}}}handler=this._events[type];if(isUndefined(handler))return false;if(isFunction(handler)){switch(arguments.length){case 1:handler.call(this);break;case 2:handler.call(this,arguments[1]);break;case 3:handler.call(this,arguments[1],arguments[2]);break;default:args=Array.prototype.slice.call(arguments,1);handler.apply(this,args)}}else if(isObject(handler)){args=Array.prototype.slice.call(arguments,1);listeners=handler.slice();len=listeners.length;for(i=0;i<len;i++)listeners[i].apply(this,args)}return true};EventEmitter.prototype.addListener=function(type,listener){var m;if(!isFunction(listener))throw TypeError("listener must be a function");if(!this._events)this._events={};if(this._events.newListener)this.emit("newListener",type,isFunction(listener.listener)?listener.listener:listener);if(!this._events[type])this._events[type]=listener;else if(isObject(this._events[type]))this._events[type].push(listener);else this._events[type]=[this._events[type],listener];if(isObject(this._events[type])&&!this._events[type].warned){if(!isUndefined(this._maxListeners)){m=this._maxListeners}else{m=EventEmitter.defaultMaxListeners}if(m&&m>0&&this._events[type].length>m){this._events[type].warned=true;console.error("(node) warning: possible EventEmitter memory "+"leak detected. %d listeners added. "+"Use emitter.setMaxListeners() to increase limit.",this._events[type].length);if(typeof console.trace==="function"){console.trace()}}}return this};EventEmitter.prototype.on=EventEmitter.prototype.addListener;EventEmitter.prototype.once=function(type,listener){if(!isFunction(listener))throw TypeError("listener must be a function");var fired=false;function g(){this.removeListener(type,g);if(!fired){fired=true;listener.apply(this,arguments)}}g.listener=listener;this.on(type,g);return this};EventEmitter.prototype.removeListener=function(type,listener){var list,position,length,i;if(!isFunction(listener))throw TypeError("listener must be a function");if(!this._events||!this._events[type])return this;list=this._events[type];length=list.length;position=-1;if(list===listener||isFunction(list.listener)&&list.listener===listener){delete this._events[type];if(this._events.removeListener)this.emit("removeListener",type,listener)}else if(isObject(list)){for(i=length;i-- >0;){if(list[i]===listener||list[i].listener&&list[i].listener===listener){position=i;break}}if(position<0)return this;if(list.length===1){list.length=0;delete this._events[type]}else{list.splice(position,1)}if(this._events.removeListener)this.emit("removeListener",type,listener)}return this};EventEmitter.prototype.removeAllListeners=function(type){var key,listeners;if(!this._events)return this;if(!this._events.removeListener){if(arguments.length===0)this._events={};else if(this._events[type])delete this._events[type];return this}if(arguments.length===0){for(key in this._events){if(key==="removeListener")continue;this.removeAllListeners(key)}this.removeAllListeners("removeListener");this._events={};return this}listeners=this._events[type];if(isFunction(listeners)){this.removeListener(type,listeners)}else if(listeners){while(listeners.length)this.removeListener(type,listeners[listeners.length-1])}delete this._events[type];return this};EventEmitter.prototype.listeners=function(type){var ret;if(!this._events||!this._events[type])ret=[];else if(isFunction(this._events[type]))ret=[this._events[type]];else ret=this._events[type].slice();return ret};EventEmitter.prototype.listenerCount=function(type){if(this._events){var evlistener=this._events[type];if(isFunction(evlistener))return 1;else if(evlistener)return evlistener.length}return 0};EventEmitter.listenerCount=function(emitter,type){return emitter.listenerCount(type)};function isFunction(arg){return typeof arg==="function"}function isNumber(arg){return typeof arg==="number"}function isObject(arg){return typeof arg==="object"&&arg!==null}function isUndefined(arg){return arg===void 0}},{}],2:[function(require,module,exports){var UA,browser,mode,platform,ua;ua=navigator.userAgent.toLowerCase();platform=navigator.platform.toLowerCase();UA=ua.match(/(opera|ie|firefox|chrome|version)[\s\/:]([\w\d\.]+)?.*?(safari|version[\s\/:]([\w\d\.]+)|$)/)||[null,"unknown",0];mode=UA[1]==="ie"&&document.documentMode;browser={name:UA[1]==="version"?UA[3]:UA[1],version:mode||parseFloat(UA[1]==="opera"&&UA[4]?UA[4]:UA[2]),platform:{name:ua.match(/ip(?:ad|od|hone)/)?"ios":(ua.match(/(?:webos|android)/)||platform.match(/mac|win|linux/)||["other"])[0]}};browser[browser.name]=true;browser[browser.name+parseInt(browser.version,10)]=true;browser.platform[browser.platform.name]=true;module.exports=browser},{}],3:[function(require,module,exports){var EventEmitter,GIF,browser,extend=function(child,parent){for(var key in parent){if(hasProp.call(parent,key))child[key]=parent[key]}function ctor(){this.constructor=child}ctor.prototype=parent.prototype;child.prototype=new ctor;child.__super__=parent.prototype;return child},hasProp={}.hasOwnProperty,indexOf=[].indexOf||function(item){for(var i=0,l=this.length;i<l;i++){if(i in this&&this[i]===item)return i}return-1},slice=[].slice;EventEmitter=require("events").EventEmitter;browser=require("./browser.coffee");GIF=function(superClass){var defaults,frameDefaults;extend(GIF,superClass);defaults={workerScript:"gif.worker.js",workers:2,repeat:0,background:"#fff",quality:10,width:null,height:null,transparent:null,debug:false,dither:false};frameDefaults={delay:500,copy:false};function GIF(options){var base,key,value;this.running=false;this.options={};this.frames=[];this.freeWorkers=[];this.activeWorkers=[];this.setOptions(options);for(key in defaults){value=defaults[key];if((base=this.options)[key]==null){base[key]=value}}}GIF.prototype.setOption=function(key,value){this.options[key]=value;if(this._canvas!=null&&(key==="width"||key==="height")){return this._canvas[key]=value}};GIF.prototype.setOptions=function(options){var key,results,value;results=[];for(key in options){if(!hasProp.call(options,key))continue;value=options[key];results.push(this.setOption(key,value))}return results};GIF.prototype.addFrame=function(image,options){var frame,key;if(options==null){options={}}frame={};frame.transparent=this.options.transparent;for(key in frameDefaults){frame[key]=options[key]||frameDefaults[key]}if(this.options.width==null){this.setOption("width",image.width)}if(this.options.height==null){this.setOption("height",image.height)}if(typeof ImageData!=="undefined"&&ImageData!==null&&image instanceof ImageData){frame.data=image.data}else if(typeof CanvasRenderingContext2D!=="undefined"&&CanvasRenderingContext2D!==null&&image instanceof CanvasRenderingContext2D||typeof WebGLRenderingContext!=="undefined"&&WebGLRenderingContext!==null&&image instanceof WebGLRenderingContext){if(options.copy){frame.data=this.getContextData(image)}else{frame.context=image}}else if(image.childNodes!=null){if(options.copy){frame.data=this.getImageData(image)}else{frame.image=image}}else{throw new Error("Invalid image")}return this.frames.push(frame)};GIF.prototype.render=function(){var i,j,numWorkers,ref;if(this.running){throw new Error("Already running")}if(this.options.width==null||this.options.height==null){throw new Error("Width and height must be set prior to rendering")}this.running=true;this.nextFrame=0;this.finishedFrames=0;this.imageParts=function(){var j,ref,results;results=[];for(i=j=0,ref=this.frames.length;0<=ref?j<ref:j>ref;i=0<=ref?++j:--j){results.push(null)}return results}.call(this);numWorkers=this.spawnWorkers();if(this.options.globalPalette===true){this.renderNextFrame()}else{for(i=j=0,ref=numWorkers;0<=ref?j<ref:j>ref;i=0<=ref?++j:--j){this.renderNextFrame()}}this.emit("start");return this.emit("progress",0)};GIF.prototype.abort=function(){var worker;while(true){worker=this.activeWorkers.shift();if(worker==null){break}this.log("killing active worker");worker.terminate()}this.running=false;return this.emit("abort")};GIF.prototype.spawnWorkers=function(){var j,numWorkers,ref,results;numWorkers=Math.min(this.options.workers,this.frames.length);(function(){results=[];for(var j=ref=this.freeWorkers.length;ref<=numWorkers?j<numWorkers:j>numWorkers;ref<=numWorkers?j++:j--){results.push(j)}return results}).apply(this).forEach(function(_this){return function(i){var worker;_this.log("spawning worker "+i);worker=new Worker(_this.options.workerScript);worker.onmessage=function(event){_this.activeWorkers.splice(_this.activeWorkers.indexOf(worker),1);_this.freeWorkers.push(worker);return _this.frameFinished(event.data)};return _this.freeWorkers.push(worker)}}(this));return numWorkers};GIF.prototype.frameFinished=function(frame){var i,j,ref;this.log("frame "+frame.index+" finished - "+this.activeWorkers.length+" active");this.finishedFrames++;this.emit("progress",this.finishedFrames/this.frames.length);this.imageParts[frame.index]=frame;if(this.options.globalPalette===true){this.options.globalPalette=frame.globalPalette;this.log("global palette analyzed");if(this.frames.length>2){for(i=j=1,ref=this.freeWorkers.length;1<=ref?j<ref:j>ref;i=1<=ref?++j:--j){this.renderNextFrame()}}}if(indexOf.call(this.imageParts,null)>=0){return this.renderNextFrame()}else{return this.finishRendering()}};GIF.prototype.finishRendering=function(){var data,frame,i,image,j,k,l,len,len1,len2,len3,offset,page,ref,ref1,ref2;len=0;ref=this.imageParts;for(j=0,len1=ref.length;j<len1;j++){frame=ref[j];len+=(frame.data.length-1)*frame.pageSize+frame.cursor}len+=frame.pageSize-frame.cursor;this.log("rendering finished - filesize "+Math.round(len/1e3)+"kb");data=new Uint8Array(len);offset=0;ref1=this.imageParts;for(k=0,len2=ref1.length;k<len2;k++){frame=ref1[k];ref2=frame.data;for(i=l=0,len3=ref2.length;l<len3;i=++l){page=ref2[i];data.set(page,offset);if(i===frame.data.length-1){offset+=frame.cursor}else{offset+=frame.pageSize}}}image=new Blob([data],{type:"image/gif"});return this.emit("finished",image,data)};GIF.prototype.renderNextFrame=function(){var frame,task,worker;if(this.freeWorkers.length===0){throw new Error("No free workers")}if(this.nextFrame>=this.frames.length){return}frame=this.frames[this.nextFrame++];worker=this.freeWorkers.shift();task=this.getTask(frame);this.log("starting frame "+(task.index+1)+" of "+this.frames.length);this.activeWorkers.push(worker);return worker.postMessage(task)};GIF.prototype.getContextData=function(ctx){return ctx.getImageData(0,0,this.options.width,this.options.height).data};GIF.prototype.getImageData=function(image){var ctx;if(this._canvas==null){this._canvas=document.createElement("canvas");this._canvas.width=this.options.width;this._canvas.height=this.options.height}ctx=this._canvas.getContext("2d");ctx.setFill=this.options.background;ctx.fillRect(0,0,this.options.width,this.options.height);ctx.drawImage(image,0,0);return this.getContextData(ctx)};GIF.prototype.getTask=function(frame){var index,task;index=this.frames.indexOf(frame);task={index:index,last:index===this.frames.length-1,delay:frame.delay,transparent:frame.transparent,width:this.options.width,height:this.options.height,quality:this.options.quality,dither:this.options.dither,globalPalette:this.options.globalPalette,repeat:this.options.repeat,canTransfer:browser.name==="chrome"};if(frame.data!=null){task.data=frame.data}else if(frame.context!=null){task.data=this.getContextData(frame.context)}else if(frame.image!=null){task.data=this.getImageData(frame.image)}else{throw new Error("Invalid frame")}return task};GIF.prototype.log=function(){var args;args=1<=arguments.length?slice.call(arguments,0):[];if(!this.options.debug){return}return console.log.apply(console,args)};return GIF}(EventEmitter);module.exports=GIF},{"./browser.coffee":2,events:1}]},{},[3])(3)});
//# sourceMappingURL=gif.js.map

View file

@ -1,3 +0,0 @@
// gif.worker.js 0.2.0 - https://github.com/jnordberg/gif.js
(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){var NeuQuant=require("./TypedNeuQuant.js");var LZWEncoder=require("./LZWEncoder.js");function ByteArray(){this.page=-1;this.pages=[];this.newPage()}ByteArray.pageSize=4096;ByteArray.charMap={};for(var i=0;i<256;i++)ByteArray.charMap[i]=String.fromCharCode(i);ByteArray.prototype.newPage=function(){this.pages[++this.page]=new Uint8Array(ByteArray.pageSize);this.cursor=0};ByteArray.prototype.getData=function(){var rv="";for(var p=0;p<this.pages.length;p++){for(var i=0;i<ByteArray.pageSize;i++){rv+=ByteArray.charMap[this.pages[p][i]]}}return rv};ByteArray.prototype.writeByte=function(val){if(this.cursor>=ByteArray.pageSize)this.newPage();this.pages[this.page][this.cursor++]=val};ByteArray.prototype.writeUTFBytes=function(string){for(var l=string.length,i=0;i<l;i++)this.writeByte(string.charCodeAt(i))};ByteArray.prototype.writeBytes=function(array,offset,length){for(var l=length||array.length,i=offset||0;i<l;i++)this.writeByte(array[i])};function GIFEncoder(width,height){this.width=~~width;this.height=~~height;this.transparent=null;this.transIndex=0;this.repeat=-1;this.delay=0;this.image=null;this.pixels=null;this.indexedPixels=null;this.colorDepth=null;this.colorTab=null;this.neuQuant=null;this.usedEntry=new Array;this.palSize=7;this.dispose=-1;this.firstFrame=true;this.sample=10;this.dither=false;this.globalPalette=false;this.out=new ByteArray}GIFEncoder.prototype.setDelay=function(milliseconds){this.delay=Math.round(milliseconds/10)};GIFEncoder.prototype.setFrameRate=function(fps){this.delay=Math.round(100/fps)};GIFEncoder.prototype.setDispose=function(disposalCode){if(disposalCode>=0)this.dispose=disposalCode};GIFEncoder.prototype.setRepeat=function(repeat){this.repeat=repeat};GIFEncoder.prototype.setTransparent=function(color){this.transparent=color};GIFEncoder.prototype.addFrame=function(imageData){this.image=imageData;this.colorTab=this.globalPalette&&this.globalPalette.slice?this.globalPalette:null;this.getImagePixels();this.analyzePixels();if(this.globalPalette===true)this.globalPalette=this.colorTab;if(this.firstFrame){this.writeLSD();this.writePalette();if(this.repeat>=0){this.writeNetscapeExt()}}this.writeGraphicCtrlExt();this.writeImageDesc();if(!this.firstFrame&&!this.globalPalette)this.writePalette();this.writePixels();this.firstFrame=false};GIFEncoder.prototype.finish=function(){this.out.writeByte(59)};GIFEncoder.prototype.setQuality=function(quality){if(quality<1)quality=1;this.sample=quality};GIFEncoder.prototype.setDither=function(dither){if(dither===true)dither="FloydSteinberg";this.dither=dither};GIFEncoder.prototype.setGlobalPalette=function(palette){this.globalPalette=palette};GIFEncoder.prototype.getGlobalPalette=function(){return this.globalPalette&&this.globalPalette.slice&&this.globalPalette.slice(0)||this.globalPalette};GIFEncoder.prototype.writeHeader=function(){this.out.writeUTFBytes("GIF89a")};GIFEncoder.prototype.analyzePixels=function(){if(!this.colorTab){this.neuQuant=new NeuQuant(this.pixels,this.sample);this.neuQuant.buildColormap();this.colorTab=this.neuQuant.getColormap()}if(this.dither){this.ditherPixels(this.dither.replace("-serpentine",""),this.dither.match(/-serpentine/)!==null)}else{this.indexPixels()}this.pixels=null;this.colorDepth=8;this.palSize=7;if(this.transparent!==null){this.transIndex=this.findClosest(this.transparent,true)}};GIFEncoder.prototype.indexPixels=function(imgq){var nPix=this.pixels.length/3;this.indexedPixels=new Uint8Array(nPix);var k=0;for(var j=0;j<nPix;j++){var index=this.findClosestRGB(this.pixels[k++]&255,this.pixels[k++]&255,this.pixels[k++]&255);this.usedEntry[index]=true;this.indexedPixels[j]=index}};GIFEncoder.prototype.ditherPixels=function(kernel,serpentine){var kernels={FalseFloydSteinberg:[[3/8,1,0],[3/8,0,1],[2/8,1,1]],FloydSteinberg:[[7/16,1,0],[3/16,-1,1],[5/16,0,1],[1/16,1,1]],Stucki:[[8/42,1,0],[4/42,2,0],[2/42,-2,1],[4/42,-1,1],[8/42,0,1],[4/42,1,1],[2/42,2,1],[1/42,-2,2],[2/42,-1,2],[4/42,0,2],[2/42,1,2],[1/42,2,2]],Atkinson:[[1/8,1,0],[1/8,2,0],[1/8,-1,1],[1/8,0,1],[1/8,1,1],[1/8,0,2]]};if(!kernel||!kernels[kernel]){throw"Unknown dithering kernel: "+kernel}var ds=kernels[kernel];var index=0,height=this.height,width=this.width,data=this.pixels;var direction=serpentine?-1:1;this.indexedPixels=new Uint8Array(this.pixels.length/3);for(var y=0;y<height;y++){if(serpentine)direction=direction*-1;for(var x=direction==1?0:width-1,xend=direction==1?width:0;x!==xend;x+=direction){index=y*width+x;var idx=index*3;var r1=data[idx];var g1=data[idx+1];var b1=data[idx+2];idx=this.findClosestRGB(r1,g1,b1);this.usedEntry[idx]=true;this.indexedPixels[index]=idx;idx*=3;var r2=this.colorTab[idx];var g2=this.colorTab[idx+1];var b2=this.colorTab[idx+2];var er=r1-r2;var eg=g1-g2;var eb=b1-b2;for(var i=direction==1?0:ds.length-1,end=direction==1?ds.length:0;i!==end;i+=direction){var x1=ds[i][1];var y1=ds[i][2];if(x1+x>=0&&x1+x<width&&y1+y>=0&&y1+y<height){var d=ds[i][0];idx=index+x1+y1*width;idx*=3;data[idx]=Math.max(0,Math.min(255,data[idx]+er*d));data[idx+1]=Math.max(0,Math.min(255,data[idx+1]+eg*d));data[idx+2]=Math.max(0,Math.min(255,data[idx+2]+eb*d))}}}}};GIFEncoder.prototype.findClosest=function(c,used){return this.findClosestRGB((c&16711680)>>16,(c&65280)>>8,c&255,used)};GIFEncoder.prototype.findClosestRGB=function(r,g,b,used){if(this.colorTab===null)return-1;if(this.neuQuant&&!used){return this.neuQuant.lookupRGB(r,g,b)}var c=b|g<<8|r<<16;var minpos=0;var dmin=256*256*256;var len=this.colorTab.length;for(var i=0,index=0;i<len;index++){var dr=r-(this.colorTab[i++]&255);var dg=g-(this.colorTab[i++]&255);var db=b-(this.colorTab[i++]&255);var d=dr*dr+dg*dg+db*db;if((!used||this.usedEntry[index])&&d<dmin){dmin=d;minpos=index}}return minpos};GIFEncoder.prototype.getImagePixels=function(){var w=this.width;var h=this.height;this.pixels=new Uint8Array(w*h*3);var data=this.image;var srcPos=0;var count=0;for(var i=0;i<h;i++){for(var j=0;j<w;j++){this.pixels[count++]=data[srcPos++];this.pixels[count++]=data[srcPos++];this.pixels[count++]=data[srcPos++];srcPos++}}};GIFEncoder.prototype.writeGraphicCtrlExt=function(){this.out.writeByte(33);this.out.writeByte(249);this.out.writeByte(4);var transp,disp;if(this.transparent===null){transp=0;disp=0}else{transp=1;disp=2}if(this.dispose>=0){disp=dispose&7}disp<<=2;this.out.writeByte(0|disp|0|transp);this.writeShort(this.delay);this.out.writeByte(this.transIndex);this.out.writeByte(0)};GIFEncoder.prototype.writeImageDesc=function(){this.out.writeByte(44);this.writeShort(0);this.writeShort(0);this.writeShort(this.width);this.writeShort(this.height);if(this.firstFrame||this.globalPalette){this.out.writeByte(0)}else{this.out.writeByte(128|0|0|0|this.palSize)}};GIFEncoder.prototype.writeLSD=function(){this.writeShort(this.width);this.writeShort(this.height);this.out.writeByte(128|112|0|this.palSize);this.out.writeByte(0);this.out.writeByte(0)};GIFEncoder.prototype.writeNetscapeExt=function(){this.out.writeByte(33);this.out.writeByte(255);this.out.writeByte(11);this.out.writeUTFBytes("NETSCAPE2.0");this.out.writeByte(3);this.out.writeByte(1);this.writeShort(this.repeat);this.out.writeByte(0)};GIFEncoder.prototype.writePalette=function(){this.out.writeBytes(this.colorTab);var n=3*256-this.colorTab.length;for(var i=0;i<n;i++)this.out.writeByte(0)};GIFEncoder.prototype.writeShort=function(pValue){this.out.writeByte(pValue&255);this.out.writeByte(pValue>>8&255)};GIFEncoder.prototype.writePixels=function(){var enc=new LZWEncoder(this.width,this.height,this.indexedPixels,this.colorDepth);enc.encode(this.out)};GIFEncoder.prototype.stream=function(){return this.out};module.exports=GIFEncoder},{"./LZWEncoder.js":2,"./TypedNeuQuant.js":3}],2:[function(require,module,exports){var EOF=-1;var BITS=12;var HSIZE=5003;var masks=[0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535];function LZWEncoder(width,height,pixels,colorDepth){var initCodeSize=Math.max(2,colorDepth);var accum=new Uint8Array(256);var htab=new Int32Array(HSIZE);var codetab=new Int32Array(HSIZE);var cur_accum,cur_bits=0;var a_count;var free_ent=0;var maxcode;var clear_flg=false;var g_init_bits,ClearCode,EOFCode;function char_out(c,outs){accum[a_count++]=c;if(a_count>=254)flush_char(outs)}function cl_block(outs){cl_hash(HSIZE);free_ent=ClearCode+2;clear_flg=true;output(ClearCode,outs)}function cl_hash(hsize){for(var i=0;i<hsize;++i)htab[i]=-1}function compress(init_bits,outs){var fcode,c,i,ent,disp,hsize_reg,hshift;g_init_bits=init_bits;clear_flg=false;n_bits=g_init_bits;maxcode=MAXCODE(n_bits);ClearCode=1<<init_bits-1;EOFCode=ClearCode+1;free_ent=ClearCode+2;a_count=0;ent=nextPixel();hshift=0;for(fcode=HSIZE;fcode<65536;fcode*=2)++hshift;hshift=8-hshift;hsize_reg=HSIZE;cl_hash(hsize_reg);output(ClearCode,outs);outer_loop:while((c=nextPixel())!=EOF){fcode=(c<<BITS)+ent;i=c<<hshift^ent;if(htab[i]===fcode){ent=codetab[i];continue}else if(htab[i]>=0){disp=hsize_reg-i;if(i===0)disp=1;do{if((i-=disp)<0)i+=hsize_reg;if(htab[i]===fcode){ent=codetab[i];continue outer_loop}}while(htab[i]>=0)}output(ent,outs);ent=c;if(free_ent<1<<BITS){codetab[i]=free_ent++;htab[i]=fcode}else{cl_block(outs)}}output(ent,outs);output(EOFCode,outs)}function encode(outs){outs.writeByte(initCodeSize);remaining=width*height;curPixel=0;compress(initCodeSize+1,outs);outs.writeByte(0)}function flush_char(outs){if(a_count>0){outs.writeByte(a_count);outs.writeBytes(accum,0,a_count);a_count=0}}function MAXCODE(n_bits){return(1<<n_bits)-1}function nextPixel(){if(remaining===0)return EOF;--remaining;var pix=pixels[curPixel++];return pix&255}function output(code,outs){cur_accum&=masks[cur_bits];if(cur_bits>0)cur_accum|=code<<cur_bits;else cur_accum=code;cur_bits+=n_bits;while(cur_bits>=8){char_out(cur_accum&255,outs);cur_accum>>=8;cur_bits-=8}if(free_ent>maxcode||clear_flg){if(clear_flg){maxcode=MAXCODE(n_bits=g_init_bits);clear_flg=false}else{++n_bits;if(n_bits==BITS)maxcode=1<<BITS;else maxcode=MAXCODE(n_bits)}}if(code==EOFCode){while(cur_bits>0){char_out(cur_accum&255,outs);cur_accum>>=8;cur_bits-=8}flush_char(outs)}}this.encode=encode}module.exports=LZWEncoder},{}],3:[function(require,module,exports){var ncycles=100;var netsize=256;var maxnetpos=netsize-1;var netbiasshift=4;var intbiasshift=16;var intbias=1<<intbiasshift;var gammashift=10;var gamma=1<<gammashift;var betashift=10;var beta=intbias>>betashift;var betagamma=intbias<<gammashift-betashift;var initrad=netsize>>3;var radiusbiasshift=6;var radiusbias=1<<radiusbiasshift;var initradius=initrad*radiusbias;var radiusdec=30;var alphabiasshift=10;var initalpha=1<<alphabiasshift;var alphadec;var radbiasshift=8;var radbias=1<<radbiasshift;var alpharadbshift=alphabiasshift+radbiasshift;var alpharadbias=1<<alpharadbshift;var prime1=499;var prime2=491;var prime3=487;var prime4=503;var minpicturebytes=3*prime4;function NeuQuant(pixels,samplefac){var network;var netindex;var bias;var freq;var radpower;function init(){network=[];netindex=new Int32Array(256);bias=new Int32Array(netsize);freq=new Int32Array(netsize);radpower=new Int32Array(netsize>>3);var i,v;for(i=0;i<netsize;i++){v=(i<<netbiasshift+8)/netsize;network[i]=new Float64Array([v,v,v,0]);freq[i]=intbias/netsize;bias[i]=0}}function unbiasnet(){for(var i=0;i<netsize;i++){network[i][0]>>=netbiasshift;network[i][1]>>=netbiasshift;network[i][2]>>=netbiasshift;network[i][3]=i}}function altersingle(alpha,i,b,g,r){network[i][0]-=alpha*(network[i][0]-b)/initalpha;network[i][1]-=alpha*(network[i][1]-g)/initalpha;network[i][2]-=alpha*(network[i][2]-r)/initalpha}function alterneigh(radius,i,b,g,r){var lo=Math.abs(i-radius);var hi=Math.min(i+radius,netsize);var j=i+1;var k=i-1;var m=1;var p,a;while(j<hi||k>lo){a=radpower[m++];if(j<hi){p=network[j++];p[0]-=a*(p[0]-b)/alpharadbias;p[1]-=a*(p[1]-g)/alpharadbias;p[2]-=a*(p[2]-r)/alpharadbias}if(k>lo){p=network[k--];p[0]-=a*(p[0]-b)/alpharadbias;p[1]-=a*(p[1]-g)/alpharadbias;p[2]-=a*(p[2]-r)/alpharadbias}}}function contest(b,g,r){var bestd=~(1<<31);var bestbiasd=bestd;var bestpos=-1;var bestbiaspos=bestpos;var i,n,dist,biasdist,betafreq;for(i=0;i<netsize;i++){n=network[i];dist=Math.abs(n[0]-b)+Math.abs(n[1]-g)+Math.abs(n[2]-r);if(dist<bestd){bestd=dist;bestpos=i}biasdist=dist-(bias[i]>>intbiasshift-netbiasshift);if(biasdist<bestbiasd){bestbiasd=biasdist;bestbiaspos=i}betafreq=freq[i]>>betashift;freq[i]-=betafreq;bias[i]+=betafreq<<gammashift}freq[bestpos]+=beta;bias[bestpos]-=betagamma;return bestbiaspos}function inxbuild(){var i,j,p,q,smallpos,smallval,previouscol=0,startpos=0;for(i=0;i<netsize;i++){p=network[i];smallpos=i;smallval=p[1];for(j=i+1;j<netsize;j++){q=network[j];if(q[1]<smallval){smallpos=j;smallval=q[1]}}q=network[smallpos];if(i!=smallpos){j=q[0];q[0]=p[0];p[0]=j;j=q[1];q[1]=p[1];p[1]=j;j=q[2];q[2]=p[2];p[2]=j;j=q[3];q[3]=p[3];p[3]=j}if(smallval!=previouscol){netindex[previouscol]=startpos+i>>1;for(j=previouscol+1;j<smallval;j++)netindex[j]=i;previouscol=smallval;startpos=i}}netindex[previouscol]=startpos+maxnetpos>>1;for(j=previouscol+1;j<256;j++)netindex[j]=maxnetpos}function inxsearch(b,g,r){var a,p,dist;var bestd=1e3;var best=-1;var i=netindex[g];var j=i-1;while(i<netsize||j>=0){if(i<netsize){p=network[i];dist=p[1]-g;if(dist>=bestd)i=netsize;else{i++;if(dist<0)dist=-dist;a=p[0]-b;if(a<0)a=-a;dist+=a;if(dist<bestd){a=p[2]-r;if(a<0)a=-a;dist+=a;if(dist<bestd){bestd=dist;best=p[3]}}}}if(j>=0){p=network[j];dist=g-p[1];if(dist>=bestd)j=-1;else{j--;if(dist<0)dist=-dist;a=p[0]-b;if(a<0)a=-a;dist+=a;if(dist<bestd){a=p[2]-r;if(a<0)a=-a;dist+=a;if(dist<bestd){bestd=dist;best=p[3]}}}}}return best}function learn(){var i;var lengthcount=pixels.length;var alphadec=30+(samplefac-1)/3;var samplepixels=lengthcount/(3*samplefac);var delta=~~(samplepixels/ncycles);var alpha=initalpha;var radius=initradius;var rad=radius>>radiusbiasshift;if(rad<=1)rad=0;for(i=0;i<rad;i++)radpower[i]=alpha*((rad*rad-i*i)*radbias/(rad*rad));var step;if(lengthcount<minpicturebytes){samplefac=1;step=3}else if(lengthcount%prime1!==0){step=3*prime1}else if(lengthcount%prime2!==0){step=3*prime2}else if(lengthcount%prime3!==0){step=3*prime3}else{step=3*prime4}var b,g,r,j;var pix=0;i=0;while(i<samplepixels){b=(pixels[pix]&255)<<netbiasshift;g=(pixels[pix+1]&255)<<netbiasshift;r=(pixels[pix+2]&255)<<netbiasshift;j=contest(b,g,r);altersingle(alpha,j,b,g,r);if(rad!==0)alterneigh(rad,j,b,g,r);pix+=step;if(pix>=lengthcount)pix-=lengthcount;i++;if(delta===0)delta=1;if(i%delta===0){alpha-=alpha/alphadec;radius-=radius/radiusdec;rad=radius>>radiusbiasshift;if(rad<=1)rad=0;for(j=0;j<rad;j++)radpower[j]=alpha*((rad*rad-j*j)*radbias/(rad*rad))}}}function buildColormap(){init();learn();unbiasnet();inxbuild()}this.buildColormap=buildColormap;function getColormap(){var map=[];var index=[];for(var i=0;i<netsize;i++)index[network[i][3]]=i;var k=0;for(var l=0;l<netsize;l++){var j=index[l];map[k++]=network[j][0];map[k++]=network[j][1];map[k++]=network[j][2]}return map}this.getColormap=getColormap;this.lookupRGB=inxsearch}module.exports=NeuQuant},{}],4:[function(require,module,exports){var GIFEncoder,renderFrame;GIFEncoder=require("./GIFEncoder.js");renderFrame=function(frame){var encoder,page,stream,transfer;encoder=new GIFEncoder(frame.width,frame.height);if(frame.index===0){encoder.writeHeader()}else{encoder.firstFrame=false}encoder.setTransparent(frame.transparent);encoder.setRepeat(frame.repeat);encoder.setDelay(frame.delay);encoder.setQuality(frame.quality);encoder.setDither(frame.dither);encoder.setGlobalPalette(frame.globalPalette);encoder.addFrame(frame.data);if(frame.last){encoder.finish()}if(frame.globalPalette===true){frame.globalPalette=encoder.getGlobalPalette()}stream=encoder.stream();frame.data=stream.pages;frame.cursor=stream.cursor;frame.pageSize=stream.constructor.pageSize;if(frame.canTransfer){transfer=function(){var i,len,ref,results;ref=frame.data;results=[];for(i=0,len=ref.length;i<len;i++){page=ref[i];results.push(page.buffer)}return results}();return self.postMessage(frame,transfer)}else{return self.postMessage(frame)}};self.onmessage=function(event){return renderFrame(event.data)}},{"./GIFEncoder.js":1}]},{},[4]);
//# sourceMappingURL=gif.worker.js.map

View file

@ -1,303 +0,0 @@
const _ = require('lodash');
const got = require('got');
const Canvas = require('canvas');
const { GifReader } = require('omggif');
const GifEncoder = require('gifencoder');
const Image = { Canvas };
function loadFromUrl(url) {
return got(url, { encoding: null }).then(res => ({
type: res.headers['content-type'],
data: res.body
}));
}
function createCanvas(width, height) {
const canvas = new Canvas(width, height);
return canvas;
}
class ImageEx {
constructor(url) {
this.url = url;
this.loaded = loadFromUrl(url).then(result => {
this.type = result.type;
this.data = result.data;
if (this.type === 'image/gif') {
this.initGif();
} else {
this.initStatic();
}
return this;
});
}
initGif() {
const reader = new GifReader(new Uint8Array(this.data));
this.width = reader.width;
this.height = reader.height;
this.frames = this.decodeFrames(reader);
this.renderAllFrames();
}
initStatic() {
const img = new Image();
img.src = this.data;
return new Promise(resolve => {
img.onload = () => {
this.width = img.width;
this.height = img.height;
this.frames = [{
actualOffset: 0,
actualDelay: Infinity,
delay: Infinity
}];
this.spriteSheet = createCanvas(this.width, this.height);
const spriteSheetCtx = this.spriteSheet.getContext('2d');
spriteSheetCtx.drawImage(img, 0, 0);
resolve();
};
});
}
decodeFrames(reader) {
const frames = [];
let offset = 0;
for (let i = 0; i < reader.numFrames(); ++i) {
const frameInfo = reader.frameInfo(i);
frameInfo.pixels = new Uint8ClampedArray(reader.width * reader.height * 4);
reader.decodeAndBlitFrameRGBA(i, frameInfo.pixels);
frameInfo.buffer = this.createBufferCanvas(frameInfo, this.width, this.height);
frameInfo.actualOffset = offset;
frameInfo.actualDelay = Math.max(frameInfo.delay * 10, 20);
offset += frameInfo.actualDelay;
frames.push(frameInfo);
}
this.totalDuration = offset;
return frames;
}
renderAllFrames() {
let disposeFrame = null;
const canvas = createCanvas(this.width, this.height);
const ctx = canvas.getContext('2d');
let saved;
this.spriteSheet = createCanvas(this.width * this.frames.length, this.height);
const spriteSheetCtx = this.spriteSheet.getContext('2d');
for (let i = 0; i < this.frames.length; ++i) {
const frame = this.frames[i];
if (typeof disposeFrame === 'function') disposeFrame();
switch (frame.disposal) {
case 2:
disposeFrame = () => ctx.clearRect(0, 0, canvas.width, canvas.height);
break;
case 3:
saved = ctx.getImageData(0, 0, canvas.width, canvas.height);
disposeFrame = () => ctx.putImageData(saved, 0, 0); // eslint-disable-line no-loop-func
break;
default:
this.disposeFrame = null;
}
// draw current frame
ctx.drawImage(frame.buffer, frame.x, frame.y);
// draw the frame onto the sprite sheet
spriteSheetCtx.drawImage(canvas, this.width * i, 0);
}
}
createBufferCanvas(frame, width, height) {
const canvas = createCanvas(frame.width, frame.height);
const ctx = canvas.getContext('2d');
const imageData = ctx.createImageData(width, height);
imageData.data.set(frame.pixels);
ctx.putImageData(imageData, -frame.x, -frame.y);
return canvas;
}
drawFrame(ctx, frameNum, x, y, args = {}) {
const sx = frameNum * this.width + (args.sx || 0);
const sy = args.sy || 0;
const swidth = Math.min(args.swidth || this.width, this.width) - (args.sx || 0);
const sheight = args.sheight || this.height;
console.log(`Drawing frame ${frameNum} at`);
console.log('sx', sx);
console.log('sy', sy);
console.log('sw', swidth);
console.log('sh', sheight);
console.log('x', x);
console.log('y', y);
console.log('w', args.width);
console.log('h', args.height);
ctx.drawImage(this.spriteSheet, sx, sy, swidth, sheight, x, y, args.width || swidth, args.height || sheight);
// ctx.drawImage(this.spriteSheet, 0, 0, 112, 112, 0, 0, 112, 112)
}
}
class CanvasEx {
constructor(width, height) {
this.width = width;
this.height = height;
this.frames = [];
this.totalDuration = Infinity;
}
addFrame(actualDelay, delay) {
if ((actualDelay === undefined || actualDelay === null)
&& (delay === undefined || delay === null)) throw new Error('Delay has to be set!');
const canvas = createCanvas(this.width, this.height);
const frame = {
actualOffset: this.totalDuration,
delay: delay || Math.max(Math.round(actualDelay / 10), 2),
actualDelay: actualDelay || Math.max(delay * 10, 20),
canvas,
ctx: canvas.getContext('2d')
};
this.totalDuration += delay;
this.frames.push(frame);
}
drawImage(img, x, y, args = {}) {
console.log('Drawing image ', img);
console.log('At ', x, y, args);
if (img.frames && img.frames.length > 1) {
if (this.frames.length > 1) throw new Error('Cannot render animations onto animated canvases!');
this.totalDuration = img.totalDuration;
// we are drawing an animated image onto a static one.
// for each frame in the image, create a frame on this one, cloning the original picture (if any),
// render the original on each frame, and draw the frame on top.
for (let i = this.frames.length; i < img.frames.length; ++i) {
const frame = img.frames[i];
// console.log(`Adding frame ${i}:`, frame);
this.addFrame(null, frame.delay);
if (this.frames.length > 0) {
this.frames[i].ctx.drawImage(this.frames[0].canvas, 0, 0);
}
}
for (let i = 0; i < img.frames.length; ++i) {
// console.log(`Drawing frame ${i}:`, img.frames[i]);
// draw the i-th source frame to the i-th target frame
img.drawFrame(this.frames[i].ctx, i, x, y, args);
}
console.log('Done drawing animated image, CanvasEx is now', this);
} else {
// we are drawing a static image on top of a (possibly animated) image.
// for each frame, just draw, nothing fancy.
if (img.frames) {
// the image cant have more than one frame, and if it has 0, we dont need to do anything at all
if (img.frames.length === 1) {
for (let i = 0; i < this.frames.length; ++i) {
img.drawFrame(this.frames[i].ctx, 0, x, y, args);
}
}
} else {
for (let i = 0; i < this.frames.length; ++i) {
this.drawImage(this.frames[i].ctx, img, x, y, args);
}
}
console.log('Done drawing static image, CanvasEx is now', this);
}
}
drawFrame(ctx, frameNum, x, y, args = {}) {
// console.log(`Drawing frame ${frameNum} of`, this)
// ctx.drawImage(this.frames[frameNum].canvas, x, y);
this.drawImage(ctx, this.frames[frameNum].canvas, x, y, args);
}
_drawImage(ctx, img, x, y, args = {}) {
if (args.transform) {
ctx.save();
_.each(args.transform, (value, property) => {
ctx[property](...value);
});
}
if (args.sx !== undefined || args.sy !== undefined || args.swidth !== undefined || args.sheight !== undefined) {
ctx.drawImage(img, args.sx, args.sy, args.swidth, args.sheight, x, y, args.width, args.height);
} else {
ctx.drawImage(img, x, y, args.width, args.height);
}
if (args.transform) {
ctx.restore();
}
}
export(outStream) {
const gif = new GifEncoder(this.width, this.height);
gif.createReadStream().pipe(outStream);
gif.setTransparent(0);
gif.setRepeat(0);
gif.start();
for (let i = 0; i < this.frames.length; ++i) {
const frame = this.frames[i];
gif.setDelay(frame.delay);
gif.addFrame(frame.ctx);
}
gif.finish();
}
}
module.exports = {
CanvasEx,
ImageEx
};
/*
// const img = new ImageEx("https://cors-anywhere.herokuapp.com/https://cdn.betterttv.net/emote/554da1a289d53f2d12781907/3x");
const img = new ImageEx('https://cors-anywhere.herokuapp.com/https://cdn.discordapp.com/emojis/393563453824040983.gif');
const _canvas = document.getElementById('c');
const _ctx = _canvas.getContext('2d');
const img2 = new ImageEx('https://rawgit.com/CBenni/beebot/master/resources/SnowGlobe.png');
const _cnv = new CanvasEx(128, 128);
img.loaded.then(() => {
_cnv.drawImage(img, 0, 0);
// img.drawFrame(_ctx, 0, 0, 0)
return img2.loaded;
}).then(() => {
_cnv.drawImage(img2, 0, 0, { width: 128, height: 128 });
}).then(() => {
console.log('Drawing CanvasEx to screen', _cnv);
_cnv.drawFrame(_ctx, 0, 0, 0);
console.log('Starting gif render');
const GifEncoder = new GIF({
workers: 2,
quality: 10,
transparent: 'rgba(0,0,0,0)'
});
for (let i = 0; i < _cnv.frames.length; ++i) {
const frame = _cnv.frames[i];
console.log(`Rendering frame ${i}`);
GifEncoder.addFrame(frame.canvas, { delay: frame.delay });
}
GifEncoder.on('finished', blob => {
console.log('Done rendering!', URL.createObjectURL(blob));
document.getElementById('i').src = URL.createObjectURL(blob);
});
GifEncoder.render();
});
let curFrm = 0;
setInterval(() => {
_ctx.clearRect(0, 0, 200, 200);
_cnv.drawFrame(_ctx, curFrm++ % _cnv.frames.length, 0, 0);
}, 100);
/* img2.loaded.then(() => {
_ctx.drawImage(img2.spriteSheet, 0, 100)
})
img.loaded.then(()=>_ctx.drawImage(img.spriteSheet,0,0)) */

View file

@ -1,20 +0,0 @@
<!DOCTYPE html>
<html lang="en" >
<head>
<meta charset="UTF-8">
<title>A Pen by CBenni</title>
</head>
<body>
<canvas height=256 width=2560 style="border: 1px solid black;" id="c"></canvas>
<img id="i">
<script src='https://rawgit.com/deanm/omggif/master/omggif.js'></script>
<script src='gif.js'></script>
<script src="index.js"></script>
</body>
</html>

View file

@ -1,286 +0,0 @@
const _ = require('lodash');
const express = require('express');
const { ImageEx, CanvasEx } = require('./imageex');
const request = require('request');
const Discord = require('discord.js');
const Canvas = require('canvas');
const { ImageEx, CanvasEx } = require("./imageex");
const twemoji = require('./twemoji');
const app = express();
const config = require('./config.default.json');
try {
_.extend(config, require('./config'));
} catch (err) {
console.log('No config.json found!');
}
const cache = {};
function all(x, c) {
_.isArray(x) ? _.each(x, c) : c(x);
}
templates = config.templates;
for (templateName in templates) {
const data = templates[templateName];
all(data, template => {
template.image = new Image();
template.image.src = template.src;
});
}
// drawing: we keep the image fixed in its default position and draw the template on top/below it
// calculates the x or y position of the template to be drawn
// size = width or height of the template/image
// anchor = the corresponding anchor config
function calculatePosition(scale, anchor, imageSize) {
return imageSize * anchor.position / 100 - anchor.offset * scale;
}
function render(template, img, size, flipH) {
let imgWidth = img.width;
let imgHeight = img.height;
if (size && size.height) {
imgHeight = size.height;
if (!size.width) imgWidth = imgWidth * size.height / img.height;
}
if (size && size.width) {
imgWidth = size.width;
if (!size.height) imgHeight = imgHeight * size.width / img.width;
}
const xScale = imgWidth / template.anchor.x.size;
const yScale = imgHeight / template.anchor.y.size;
const templateScale = Math.max(0, Math.min(10, Math.max(xScale || 0, yScale || 0)));
console.log('templateScale', templateScale);
let templateOffsetX = calculatePosition(templateScale, template.anchor.x, imgWidth);
let templateOffsetY = calculatePosition(templateScale, template.anchor.y, imgHeight);
let imageOffsetX = 0;
let imageOffsetY = 0;
let resultingWidth = imgWidth; // start with the image boundaries as defined by the image
let resultingHeight = imgHeight;
if (templateOffsetX < 0) {
resultingWidth -= templateOffsetX;
imageOffsetX = -templateOffsetX;
templateOffsetX = 0;
}
if (templateOffsetY < 0) {
resultingHeight -= templateOffsetY;
imageOffsetY = -templateOffsetY;
templateOffsetY = 0;
}
if (templateOffsetX + template.image.width * templateScale > resultingWidth) {
resultingWidth = templateOffsetX + template.image.width * templateScale;
}
if (templateOffsetY + template.image.height * templateScale > resultingHeight) {
resultingHeight = templateOffsetY + template.image.height * templateScale;
}
const toDraw = [{
z: 1,
image: img,
x: flipH ? resultingWidth - imageOffsetX - imgWidth : imageOffsetX,
y: imageOffsetY,
h: imgHeight,
w: imgWidth,
name: 'image'
}, {
z: template.z || 0,
image: template.image,
x: templateOffsetX,
y: templateOffsetY,
h: template.image.height * templateScale,
w: template.image.width * templateScale,
name: `template ${template.src}`,
flipH
}].sort((u, v) => u.z > v.z);
const canvas = new Canvas(resultingWidth, resultingHeight);
const ctx = canvas.getContext('2d');
for (let i = 0; i < toDraw.length; ++i) {
const subject = toDraw[i];
console.log(`Drawing ${subject.name}${subject.flipH ? ' (flipped)' : ''}`);
try {
if (subject.flipH) {
ctx.save();
ctx.translate(resultingWidth, 0);
ctx.scale(-1, 1);
}
ctx.drawImage(subject.image, subject.x, subject.y, subject.w, subject.h);
if (subject.flipH) {
ctx.restore();
}
} catch (err) {
console.error(err);
throw new Error(JSON.stringify({ status: 400, error: 'Invalid template' }));
}
}
// return the image and cache it
return (canvas);
}
app.get('/:templateName/', async (req, res) => {
if (!templates[req.params.templateName]) return res.status(404).end();
try {
const canvas = render(templates[req.params.templateName], await loadImage(req.query.url));
console.log(canvas);
res.setHeader('Content-Type', 'image/png');
return canvas.pngStream().pipe(res);
} catch (err) {
console.log(err);
return res.status(400).end(err.message);
}
});
app.listen(3002, () => {
console.log('Beebot app listening on port 3002!');
});
// Discord stuff
const client = new Discord.Client({
autoReconnect: true
});
// manage roles permission is required
const invitelink = `https://discordapp.com/oauth2/authorize?client_id=${
config.discord.client_id}&scope=bot&permissions=0`;
const authlink = `https://discordapp.com/oauth2/authorize?client_id=${
config.discord.client_id}&scope=email`;
console.log(`Bot invite link: ${invitelink}`);
client.login(config.discord.token).catch(error => {
if (error) {
console.error("Couldn't login: ", error.toString());
}
});
function findEmoji(str) {
const discordEmote = /<:(\w+):(\d+)>/g.exec(str);
if (discordEmote) {
return {
name: discordEmote[1],
id: discordEmote[2],
url: `https://cdn.discordapp.com/emojis/${discordEmote[2]}.png`
};
}
let unicodeEmoji;
twemoji.parse(str, (name, emoji) => {
if (unicodeEmoji) return false;
unicodeEmoji = {
name,
id: name,
url: `${emoji.base + emoji.size}/${name}${emoji.ext}`
};
return false;
});
return unicodeEmoji;
}
function loadImage(url) {
return new Promise((resolve, reject) => {
console.log(`Getting ${url}`);
if (url) {
request.get({ url, encoding: null }, (e, r, data) => {
if (e) {
return reject({ status: (r && r.statusCode || 500), error: e });
}
const img = new Image();
img.src = data;
resolve(img);
});
}
});
}
function reverseString(str) {
return str.split('').reverse().join('');
}
const commands = Object.keys(templates).map(x => `/${x}`).join(', ');
const otherCommands = {
invite: `Invite link: <${invitelink}>`,
help: `Available commands: ${commands}.\nUse \\\\<command> to flip the template horizontally.\nInvite link: <${invitelink}>`,
beebot: `Available commands: ${commands}.\nUse \\\\<command> to flip the template horizontally.\nInvite link: <${invitelink}>`
};
client.on('message', async message => {
console.log(`[${message.guild.name} - ${message.channel.name}] ${message.author.username}#${message.author.discriminator}: ${message.cleanContent}`);
let commandParsed = /^([\/\\])(\w+)\b/.exec(message.cleanContent);
if (commandParsed) {
const [, direction, command] = commandParsed;
if (otherCommands[command]) {
const text = otherCommands[command];
message.channel.send(direction === '\\' ? reverseString(text) : text);
return;
}
}
const messageSplit = message.cleanContent.split(' ');
const emoji = findEmoji(message.cleanContent);
let result = null;
let count = 0;
try {
if (emoji) {
let name = emoji.name;
for (let i = 0; i < messageSplit.length && count < 4; ++i) {
commandParsed = /^([\/\\])(\w+)\b/.exec(messageSplit[i]);
if (commandParsed) {
const [, direction, command] = commandParsed;
console.log('Got command ', direction, command, direction === '\\' ? 'flipped' : 'not flipped');
if (templates[command]) {
count++;
name += command;
if (result === null) result = await loadImage(emoji.url);
const templateData = templates[command];
all(templateData, template => {
result = render(template, result, null, direction === '\\');
});
}
} else if (i === 0) return;
}
if (result) {
const messageOptions = {
files: [
{ attachment: result.toBuffer(), name: `${name}.png` }
]
};
message.channel.send('', messageOptions);
}
}
} catch (err) {
console.error(err);
}
});
app.get('/', (req, res) => {
const img = new ImageEx(req.query.url || 'https://cdn.discordapp.com/emojis/393563453824040983.gif');
img.loaded.then(() => {
res.setHeader('Content-Type', 'image/gif');
const canvas = new CanvasEx(img.width, img.height);
canvas.drawImage(img, 0, 0);
canvas.export(res);
});
});
app.listen(3002, () => {
console.log('Beebot app listening on port 3002!');
});

View file

@ -1,12 +0,0 @@
<!--
Copyright (c) 2017 by CBenni (https://codepen.io/CBenni/pen/YYZKeO)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-->

View file

@ -1,3 +0,0 @@
A Pen created at CodePen.io. You can find this one at https://codepen.io/CBenni/pen/YYZKeO.

View file

@ -1,3 +0,0 @@
// gif.js 0.2.0 - https://github.com/jnordberg/gif.js
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.GIF=f()}})(function(){var define,module,exports;return function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s}({1:[function(require,module,exports){function EventEmitter(){this._events=this._events||{};this._maxListeners=this._maxListeners||undefined}module.exports=EventEmitter;EventEmitter.EventEmitter=EventEmitter;EventEmitter.prototype._events=undefined;EventEmitter.prototype._maxListeners=undefined;EventEmitter.defaultMaxListeners=10;EventEmitter.prototype.setMaxListeners=function(n){if(!isNumber(n)||n<0||isNaN(n))throw TypeError("n must be a positive number");this._maxListeners=n;return this};EventEmitter.prototype.emit=function(type){var er,handler,len,args,i,listeners;if(!this._events)this._events={};if(type==="error"){if(!this._events.error||isObject(this._events.error)&&!this._events.error.length){er=arguments[1];if(er instanceof Error){throw er}else{var err=new Error('Uncaught, unspecified "error" event. ('+er+")");err.context=er;throw err}}}handler=this._events[type];if(isUndefined(handler))return false;if(isFunction(handler)){switch(arguments.length){case 1:handler.call(this);break;case 2:handler.call(this,arguments[1]);break;case 3:handler.call(this,arguments[1],arguments[2]);break;default:args=Array.prototype.slice.call(arguments,1);handler.apply(this,args)}}else if(isObject(handler)){args=Array.prototype.slice.call(arguments,1);listeners=handler.slice();len=listeners.length;for(i=0;i<len;i++)listeners[i].apply(this,args)}return true};EventEmitter.prototype.addListener=function(type,listener){var m;if(!isFunction(listener))throw TypeError("listener must be a function");if(!this._events)this._events={};if(this._events.newListener)this.emit("newListener",type,isFunction(listener.listener)?listener.listener:listener);if(!this._events[type])this._events[type]=listener;else if(isObject(this._events[type]))this._events[type].push(listener);else this._events[type]=[this._events[type],listener];if(isObject(this._events[type])&&!this._events[type].warned){if(!isUndefined(this._maxListeners)){m=this._maxListeners}else{m=EventEmitter.defaultMaxListeners}if(m&&m>0&&this._events[type].length>m){this._events[type].warned=true;console.error("(node) warning: possible EventEmitter memory "+"leak detected. %d listeners added. "+"Use emitter.setMaxListeners() to increase limit.",this._events[type].length);if(typeof console.trace==="function"){console.trace()}}}return this};EventEmitter.prototype.on=EventEmitter.prototype.addListener;EventEmitter.prototype.once=function(type,listener){if(!isFunction(listener))throw TypeError("listener must be a function");var fired=false;function g(){this.removeListener(type,g);if(!fired){fired=true;listener.apply(this,arguments)}}g.listener=listener;this.on(type,g);return this};EventEmitter.prototype.removeListener=function(type,listener){var list,position,length,i;if(!isFunction(listener))throw TypeError("listener must be a function");if(!this._events||!this._events[type])return this;list=this._events[type];length=list.length;position=-1;if(list===listener||isFunction(list.listener)&&list.listener===listener){delete this._events[type];if(this._events.removeListener)this.emit("removeListener",type,listener)}else if(isObject(list)){for(i=length;i-- >0;){if(list[i]===listener||list[i].listener&&list[i].listener===listener){position=i;break}}if(position<0)return this;if(list.length===1){list.length=0;delete this._events[type]}else{list.splice(position,1)}if(this._events.removeListener)this.emit("removeListener",type,listener)}return this};EventEmitter.prototype.removeAllListeners=function(type){var key,listeners;if(!this._events)return this;if(!this._events.removeListener){if(arguments.length===0)this._events={};else if(this._events[type])delete this._events[type];return this}if(arguments.length===0){for(key in this._events){if(key==="removeListener")continue;this.removeAllListeners(key)}this.removeAllListeners("removeListener");this._events={};return this}listeners=this._events[type];if(isFunction(listeners)){this.removeListener(type,listeners)}else if(listeners){while(listeners.length)this.removeListener(type,listeners[listeners.length-1])}delete this._events[type];return this};EventEmitter.prototype.listeners=function(type){var ret;if(!this._events||!this._events[type])ret=[];else if(isFunction(this._events[type]))ret=[this._events[type]];else ret=this._events[type].slice();return ret};EventEmitter.prototype.listenerCount=function(type){if(this._events){var evlistener=this._events[type];if(isFunction(evlistener))return 1;else if(evlistener)return evlistener.length}return 0};EventEmitter.listenerCount=function(emitter,type){return emitter.listenerCount(type)};function isFunction(arg){return typeof arg==="function"}function isNumber(arg){return typeof arg==="number"}function isObject(arg){return typeof arg==="object"&&arg!==null}function isUndefined(arg){return arg===void 0}},{}],2:[function(require,module,exports){var UA,browser,mode,platform,ua;ua=navigator.userAgent.toLowerCase();platform=navigator.platform.toLowerCase();UA=ua.match(/(opera|ie|firefox|chrome|version)[\s\/:]([\w\d\.]+)?.*?(safari|version[\s\/:]([\w\d\.]+)|$)/)||[null,"unknown",0];mode=UA[1]==="ie"&&document.documentMode;browser={name:UA[1]==="version"?UA[3]:UA[1],version:mode||parseFloat(UA[1]==="opera"&&UA[4]?UA[4]:UA[2]),platform:{name:ua.match(/ip(?:ad|od|hone)/)?"ios":(ua.match(/(?:webos|android)/)||platform.match(/mac|win|linux/)||["other"])[0]}};browser[browser.name]=true;browser[browser.name+parseInt(browser.version,10)]=true;browser.platform[browser.platform.name]=true;module.exports=browser},{}],3:[function(require,module,exports){var EventEmitter,GIF,browser,extend=function(child,parent){for(var key in parent){if(hasProp.call(parent,key))child[key]=parent[key]}function ctor(){this.constructor=child}ctor.prototype=parent.prototype;child.prototype=new ctor;child.__super__=parent.prototype;return child},hasProp={}.hasOwnProperty,indexOf=[].indexOf||function(item){for(var i=0,l=this.length;i<l;i++){if(i in this&&this[i]===item)return i}return-1},slice=[].slice;EventEmitter=require("events").EventEmitter;browser=require("./browser.coffee");GIF=function(superClass){var defaults,frameDefaults;extend(GIF,superClass);defaults={workerScript:"gif.worker.js",workers:2,repeat:0,background:"#fff",quality:10,width:null,height:null,transparent:null,debug:false,dither:false};frameDefaults={delay:500,copy:false};function GIF(options){var base,key,value;this.running=false;this.options={};this.frames=[];this.freeWorkers=[];this.activeWorkers=[];this.setOptions(options);for(key in defaults){value=defaults[key];if((base=this.options)[key]==null){base[key]=value}}}GIF.prototype.setOption=function(key,value){this.options[key]=value;if(this._canvas!=null&&(key==="width"||key==="height")){return this._canvas[key]=value}};GIF.prototype.setOptions=function(options){var key,results,value;results=[];for(key in options){if(!hasProp.call(options,key))continue;value=options[key];results.push(this.setOption(key,value))}return results};GIF.prototype.addFrame=function(image,options){var frame,key;if(options==null){options={}}frame={};frame.transparent=this.options.transparent;for(key in frameDefaults){frame[key]=options[key]||frameDefaults[key]}if(this.options.width==null){this.setOption("width",image.width)}if(this.options.height==null){this.setOption("height",image.height)}if(typeof ImageData!=="undefined"&&ImageData!==null&&image instanceof ImageData){frame.data=image.data}else if(typeof CanvasRenderingContext2D!=="undefined"&&CanvasRenderingContext2D!==null&&image instanceof CanvasRenderingContext2D||typeof WebGLRenderingContext!=="undefined"&&WebGLRenderingContext!==null&&image instanceof WebGLRenderingContext){if(options.copy){frame.data=this.getContextData(image)}else{frame.context=image}}else if(image.childNodes!=null){if(options.copy){frame.data=this.getImageData(image)}else{frame.image=image}}else{throw new Error("Invalid image")}return this.frames.push(frame)};GIF.prototype.render=function(){var i,j,numWorkers,ref;if(this.running){throw new Error("Already running")}if(this.options.width==null||this.options.height==null){throw new Error("Width and height must be set prior to rendering")}this.running=true;this.nextFrame=0;this.finishedFrames=0;this.imageParts=function(){var j,ref,results;results=[];for(i=j=0,ref=this.frames.length;0<=ref?j<ref:j>ref;i=0<=ref?++j:--j){results.push(null)}return results}.call(this);numWorkers=this.spawnWorkers();if(this.options.globalPalette===true){this.renderNextFrame()}else{for(i=j=0,ref=numWorkers;0<=ref?j<ref:j>ref;i=0<=ref?++j:--j){this.renderNextFrame()}}this.emit("start");return this.emit("progress",0)};GIF.prototype.abort=function(){var worker;while(true){worker=this.activeWorkers.shift();if(worker==null){break}this.log("killing active worker");worker.terminate()}this.running=false;return this.emit("abort")};GIF.prototype.spawnWorkers=function(){var j,numWorkers,ref,results;numWorkers=Math.min(this.options.workers,this.frames.length);(function(){results=[];for(var j=ref=this.freeWorkers.length;ref<=numWorkers?j<numWorkers:j>numWorkers;ref<=numWorkers?j++:j--){results.push(j)}return results}).apply(this).forEach(function(_this){return function(i){var worker;_this.log("spawning worker "+i);worker=new Worker(_this.options.workerScript);worker.onmessage=function(event){_this.activeWorkers.splice(_this.activeWorkers.indexOf(worker),1);_this.freeWorkers.push(worker);return _this.frameFinished(event.data)};return _this.freeWorkers.push(worker)}}(this));return numWorkers};GIF.prototype.frameFinished=function(frame){var i,j,ref;this.log("frame "+frame.index+" finished - "+this.activeWorkers.length+" active");this.finishedFrames++;this.emit("progress",this.finishedFrames/this.frames.length);this.imageParts[frame.index]=frame;if(this.options.globalPalette===true){this.options.globalPalette=frame.globalPalette;this.log("global palette analyzed");if(this.frames.length>2){for(i=j=1,ref=this.freeWorkers.length;1<=ref?j<ref:j>ref;i=1<=ref?++j:--j){this.renderNextFrame()}}}if(indexOf.call(this.imageParts,null)>=0){return this.renderNextFrame()}else{return this.finishRendering()}};GIF.prototype.finishRendering=function(){var data,frame,i,image,j,k,l,len,len1,len2,len3,offset,page,ref,ref1,ref2;len=0;ref=this.imageParts;for(j=0,len1=ref.length;j<len1;j++){frame=ref[j];len+=(frame.data.length-1)*frame.pageSize+frame.cursor}len+=frame.pageSize-frame.cursor;this.log("rendering finished - filesize "+Math.round(len/1e3)+"kb");data=new Uint8Array(len);offset=0;ref1=this.imageParts;for(k=0,len2=ref1.length;k<len2;k++){frame=ref1[k];ref2=frame.data;for(i=l=0,len3=ref2.length;l<len3;i=++l){page=ref2[i];data.set(page,offset);if(i===frame.data.length-1){offset+=frame.cursor}else{offset+=frame.pageSize}}}image=new Blob([data],{type:"image/gif"});return this.emit("finished",image,data)};GIF.prototype.renderNextFrame=function(){var frame,task,worker;if(this.freeWorkers.length===0){throw new Error("No free workers")}if(this.nextFrame>=this.frames.length){return}frame=this.frames[this.nextFrame++];worker=this.freeWorkers.shift();task=this.getTask(frame);this.log("starting frame "+(task.index+1)+" of "+this.frames.length);this.activeWorkers.push(worker);return worker.postMessage(task)};GIF.prototype.getContextData=function(ctx){return ctx.getImageData(0,0,this.options.width,this.options.height).data};GIF.prototype.getImageData=function(image){var ctx;if(this._canvas==null){this._canvas=document.createElement("canvas");this._canvas.width=this.options.width;this._canvas.height=this.options.height}ctx=this._canvas.getContext("2d");ctx.setFill=this.options.background;ctx.fillRect(0,0,this.options.width,this.options.height);ctx.drawImage(image,0,0);return this.getContextData(ctx)};GIF.prototype.getTask=function(frame){var index,task;index=this.frames.indexOf(frame);task={index:index,last:index===this.frames.length-1,delay:frame.delay,transparent:frame.transparent,width:this.options.width,height:this.options.height,quality:this.options.quality,dither:this.options.dither,globalPalette:this.options.globalPalette,repeat:this.options.repeat,canTransfer:browser.name==="chrome"};if(frame.data!=null){task.data=frame.data}else if(frame.context!=null){task.data=this.getContextData(frame.context)}else if(frame.image!=null){task.data=this.getImageData(frame.image)}else{throw new Error("Invalid frame")}return task};GIF.prototype.log=function(){var args;args=1<=arguments.length?slice.call(arguments,0):[];if(!this.options.debug){return}return console.log.apply(console,args)};return GIF}(EventEmitter);module.exports=GIF},{"./browser.coffee":2,events:1}]},{},[3])(3)});
//# sourceMappingURL=gif.js.map

View file

@ -1,3 +0,0 @@
// gif.worker.js 0.2.0 - https://github.com/jnordberg/gif.js
(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){var NeuQuant=require("./TypedNeuQuant.js");var LZWEncoder=require("./LZWEncoder.js");function ByteArray(){this.page=-1;this.pages=[];this.newPage()}ByteArray.pageSize=4096;ByteArray.charMap={};for(var i=0;i<256;i++)ByteArray.charMap[i]=String.fromCharCode(i);ByteArray.prototype.newPage=function(){this.pages[++this.page]=new Uint8Array(ByteArray.pageSize);this.cursor=0};ByteArray.prototype.getData=function(){var rv="";for(var p=0;p<this.pages.length;p++){for(var i=0;i<ByteArray.pageSize;i++){rv+=ByteArray.charMap[this.pages[p][i]]}}return rv};ByteArray.prototype.writeByte=function(val){if(this.cursor>=ByteArray.pageSize)this.newPage();this.pages[this.page][this.cursor++]=val};ByteArray.prototype.writeUTFBytes=function(string){for(var l=string.length,i=0;i<l;i++)this.writeByte(string.charCodeAt(i))};ByteArray.prototype.writeBytes=function(array,offset,length){for(var l=length||array.length,i=offset||0;i<l;i++)this.writeByte(array[i])};function GIFEncoder(width,height){this.width=~~width;this.height=~~height;this.transparent=null;this.transIndex=0;this.repeat=-1;this.delay=0;this.image=null;this.pixels=null;this.indexedPixels=null;this.colorDepth=null;this.colorTab=null;this.neuQuant=null;this.usedEntry=new Array;this.palSize=7;this.dispose=-1;this.firstFrame=true;this.sample=10;this.dither=false;this.globalPalette=false;this.out=new ByteArray}GIFEncoder.prototype.setDelay=function(milliseconds){this.delay=Math.round(milliseconds/10)};GIFEncoder.prototype.setFrameRate=function(fps){this.delay=Math.round(100/fps)};GIFEncoder.prototype.setDispose=function(disposalCode){if(disposalCode>=0)this.dispose=disposalCode};GIFEncoder.prototype.setRepeat=function(repeat){this.repeat=repeat};GIFEncoder.prototype.setTransparent=function(color){this.transparent=color};GIFEncoder.prototype.addFrame=function(imageData){this.image=imageData;this.colorTab=this.globalPalette&&this.globalPalette.slice?this.globalPalette:null;this.getImagePixels();this.analyzePixels();if(this.globalPalette===true)this.globalPalette=this.colorTab;if(this.firstFrame){this.writeLSD();this.writePalette();if(this.repeat>=0){this.writeNetscapeExt()}}this.writeGraphicCtrlExt();this.writeImageDesc();if(!this.firstFrame&&!this.globalPalette)this.writePalette();this.writePixels();this.firstFrame=false};GIFEncoder.prototype.finish=function(){this.out.writeByte(59)};GIFEncoder.prototype.setQuality=function(quality){if(quality<1)quality=1;this.sample=quality};GIFEncoder.prototype.setDither=function(dither){if(dither===true)dither="FloydSteinberg";this.dither=dither};GIFEncoder.prototype.setGlobalPalette=function(palette){this.globalPalette=palette};GIFEncoder.prototype.getGlobalPalette=function(){return this.globalPalette&&this.globalPalette.slice&&this.globalPalette.slice(0)||this.globalPalette};GIFEncoder.prototype.writeHeader=function(){this.out.writeUTFBytes("GIF89a")};GIFEncoder.prototype.analyzePixels=function(){if(!this.colorTab){this.neuQuant=new NeuQuant(this.pixels,this.sample);this.neuQuant.buildColormap();this.colorTab=this.neuQuant.getColormap()}if(this.dither){this.ditherPixels(this.dither.replace("-serpentine",""),this.dither.match(/-serpentine/)!==null)}else{this.indexPixels()}this.pixels=null;this.colorDepth=8;this.palSize=7;if(this.transparent!==null){this.transIndex=this.findClosest(this.transparent,true)}};GIFEncoder.prototype.indexPixels=function(imgq){var nPix=this.pixels.length/3;this.indexedPixels=new Uint8Array(nPix);var k=0;for(var j=0;j<nPix;j++){var index=this.findClosestRGB(this.pixels[k++]&255,this.pixels[k++]&255,this.pixels[k++]&255);this.usedEntry[index]=true;this.indexedPixels[j]=index}};GIFEncoder.prototype.ditherPixels=function(kernel,serpentine){var kernels={FalseFloydSteinberg:[[3/8,1,0],[3/8,0,1],[2/8,1,1]],FloydSteinberg:[[7/16,1,0],[3/16,-1,1],[5/16,0,1],[1/16,1,1]],Stucki:[[8/42,1,0],[4/42,2,0],[2/42,-2,1],[4/42,-1,1],[8/42,0,1],[4/42,1,1],[2/42,2,1],[1/42,-2,2],[2/42,-1,2],[4/42,0,2],[2/42,1,2],[1/42,2,2]],Atkinson:[[1/8,1,0],[1/8,2,0],[1/8,-1,1],[1/8,0,1],[1/8,1,1],[1/8,0,2]]};if(!kernel||!kernels[kernel]){throw"Unknown dithering kernel: "+kernel}var ds=kernels[kernel];var index=0,height=this.height,width=this.width,data=this.pixels;var direction=serpentine?-1:1;this.indexedPixels=new Uint8Array(this.pixels.length/3);for(var y=0;y<height;y++){if(serpentine)direction=direction*-1;for(var x=direction==1?0:width-1,xend=direction==1?width:0;x!==xend;x+=direction){index=y*width+x;var idx=index*3;var r1=data[idx];var g1=data[idx+1];var b1=data[idx+2];idx=this.findClosestRGB(r1,g1,b1);this.usedEntry[idx]=true;this.indexedPixels[index]=idx;idx*=3;var r2=this.colorTab[idx];var g2=this.colorTab[idx+1];var b2=this.colorTab[idx+2];var er=r1-r2;var eg=g1-g2;var eb=b1-b2;for(var i=direction==1?0:ds.length-1,end=direction==1?ds.length:0;i!==end;i+=direction){var x1=ds[i][1];var y1=ds[i][2];if(x1+x>=0&&x1+x<width&&y1+y>=0&&y1+y<height){var d=ds[i][0];idx=index+x1+y1*width;idx*=3;data[idx]=Math.max(0,Math.min(255,data[idx]+er*d));data[idx+1]=Math.max(0,Math.min(255,data[idx+1]+eg*d));data[idx+2]=Math.max(0,Math.min(255,data[idx+2]+eb*d))}}}}};GIFEncoder.prototype.findClosest=function(c,used){return this.findClosestRGB((c&16711680)>>16,(c&65280)>>8,c&255,used)};GIFEncoder.prototype.findClosestRGB=function(r,g,b,used){if(this.colorTab===null)return-1;if(this.neuQuant&&!used){return this.neuQuant.lookupRGB(r,g,b)}var c=b|g<<8|r<<16;var minpos=0;var dmin=256*256*256;var len=this.colorTab.length;for(var i=0,index=0;i<len;index++){var dr=r-(this.colorTab[i++]&255);var dg=g-(this.colorTab[i++]&255);var db=b-(this.colorTab[i++]&255);var d=dr*dr+dg*dg+db*db;if((!used||this.usedEntry[index])&&d<dmin){dmin=d;minpos=index}}return minpos};GIFEncoder.prototype.getImagePixels=function(){var w=this.width;var h=this.height;this.pixels=new Uint8Array(w*h*3);var data=this.image;var srcPos=0;var count=0;for(var i=0;i<h;i++){for(var j=0;j<w;j++){this.pixels[count++]=data[srcPos++];this.pixels[count++]=data[srcPos++];this.pixels[count++]=data[srcPos++];srcPos++}}};GIFEncoder.prototype.writeGraphicCtrlExt=function(){this.out.writeByte(33);this.out.writeByte(249);this.out.writeByte(4);var transp,disp;if(this.transparent===null){transp=0;disp=0}else{transp=1;disp=2}if(this.dispose>=0){disp=dispose&7}disp<<=2;this.out.writeByte(0|disp|0|transp);this.writeShort(this.delay);this.out.writeByte(this.transIndex);this.out.writeByte(0)};GIFEncoder.prototype.writeImageDesc=function(){this.out.writeByte(44);this.writeShort(0);this.writeShort(0);this.writeShort(this.width);this.writeShort(this.height);if(this.firstFrame||this.globalPalette){this.out.writeByte(0)}else{this.out.writeByte(128|0|0|0|this.palSize)}};GIFEncoder.prototype.writeLSD=function(){this.writeShort(this.width);this.writeShort(this.height);this.out.writeByte(128|112|0|this.palSize);this.out.writeByte(0);this.out.writeByte(0)};GIFEncoder.prototype.writeNetscapeExt=function(){this.out.writeByte(33);this.out.writeByte(255);this.out.writeByte(11);this.out.writeUTFBytes("NETSCAPE2.0");this.out.writeByte(3);this.out.writeByte(1);this.writeShort(this.repeat);this.out.writeByte(0)};GIFEncoder.prototype.writePalette=function(){this.out.writeBytes(this.colorTab);var n=3*256-this.colorTab.length;for(var i=0;i<n;i++)this.out.writeByte(0)};GIFEncoder.prototype.writeShort=function(pValue){this.out.writeByte(pValue&255);this.out.writeByte(pValue>>8&255)};GIFEncoder.prototype.writePixels=function(){var enc=new LZWEncoder(this.width,this.height,this.indexedPixels,this.colorDepth);enc.encode(this.out)};GIFEncoder.prototype.stream=function(){return this.out};module.exports=GIFEncoder},{"./LZWEncoder.js":2,"./TypedNeuQuant.js":3}],2:[function(require,module,exports){var EOF=-1;var BITS=12;var HSIZE=5003;var masks=[0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535];function LZWEncoder(width,height,pixels,colorDepth){var initCodeSize=Math.max(2,colorDepth);var accum=new Uint8Array(256);var htab=new Int32Array(HSIZE);var codetab=new Int32Array(HSIZE);var cur_accum,cur_bits=0;var a_count;var free_ent=0;var maxcode;var clear_flg=false;var g_init_bits,ClearCode,EOFCode;function char_out(c,outs){accum[a_count++]=c;if(a_count>=254)flush_char(outs)}function cl_block(outs){cl_hash(HSIZE);free_ent=ClearCode+2;clear_flg=true;output(ClearCode,outs)}function cl_hash(hsize){for(var i=0;i<hsize;++i)htab[i]=-1}function compress(init_bits,outs){var fcode,c,i,ent,disp,hsize_reg,hshift;g_init_bits=init_bits;clear_flg=false;n_bits=g_init_bits;maxcode=MAXCODE(n_bits);ClearCode=1<<init_bits-1;EOFCode=ClearCode+1;free_ent=ClearCode+2;a_count=0;ent=nextPixel();hshift=0;for(fcode=HSIZE;fcode<65536;fcode*=2)++hshift;hshift=8-hshift;hsize_reg=HSIZE;cl_hash(hsize_reg);output(ClearCode,outs);outer_loop:while((c=nextPixel())!=EOF){fcode=(c<<BITS)+ent;i=c<<hshift^ent;if(htab[i]===fcode){ent=codetab[i];continue}else if(htab[i]>=0){disp=hsize_reg-i;if(i===0)disp=1;do{if((i-=disp)<0)i+=hsize_reg;if(htab[i]===fcode){ent=codetab[i];continue outer_loop}}while(htab[i]>=0)}output(ent,outs);ent=c;if(free_ent<1<<BITS){codetab[i]=free_ent++;htab[i]=fcode}else{cl_block(outs)}}output(ent,outs);output(EOFCode,outs)}function encode(outs){outs.writeByte(initCodeSize);remaining=width*height;curPixel=0;compress(initCodeSize+1,outs);outs.writeByte(0)}function flush_char(outs){if(a_count>0){outs.writeByte(a_count);outs.writeBytes(accum,0,a_count);a_count=0}}function MAXCODE(n_bits){return(1<<n_bits)-1}function nextPixel(){if(remaining===0)return EOF;--remaining;var pix=pixels[curPixel++];return pix&255}function output(code,outs){cur_accum&=masks[cur_bits];if(cur_bits>0)cur_accum|=code<<cur_bits;else cur_accum=code;cur_bits+=n_bits;while(cur_bits>=8){char_out(cur_accum&255,outs);cur_accum>>=8;cur_bits-=8}if(free_ent>maxcode||clear_flg){if(clear_flg){maxcode=MAXCODE(n_bits=g_init_bits);clear_flg=false}else{++n_bits;if(n_bits==BITS)maxcode=1<<BITS;else maxcode=MAXCODE(n_bits)}}if(code==EOFCode){while(cur_bits>0){char_out(cur_accum&255,outs);cur_accum>>=8;cur_bits-=8}flush_char(outs)}}this.encode=encode}module.exports=LZWEncoder},{}],3:[function(require,module,exports){var ncycles=100;var netsize=256;var maxnetpos=netsize-1;var netbiasshift=4;var intbiasshift=16;var intbias=1<<intbiasshift;var gammashift=10;var gamma=1<<gammashift;var betashift=10;var beta=intbias>>betashift;var betagamma=intbias<<gammashift-betashift;var initrad=netsize>>3;var radiusbiasshift=6;var radiusbias=1<<radiusbiasshift;var initradius=initrad*radiusbias;var radiusdec=30;var alphabiasshift=10;var initalpha=1<<alphabiasshift;var alphadec;var radbiasshift=8;var radbias=1<<radbiasshift;var alpharadbshift=alphabiasshift+radbiasshift;var alpharadbias=1<<alpharadbshift;var prime1=499;var prime2=491;var prime3=487;var prime4=503;var minpicturebytes=3*prime4;function NeuQuant(pixels,samplefac){var network;var netindex;var bias;var freq;var radpower;function init(){network=[];netindex=new Int32Array(256);bias=new Int32Array(netsize);freq=new Int32Array(netsize);radpower=new Int32Array(netsize>>3);var i,v;for(i=0;i<netsize;i++){v=(i<<netbiasshift+8)/netsize;network[i]=new Float64Array([v,v,v,0]);freq[i]=intbias/netsize;bias[i]=0}}function unbiasnet(){for(var i=0;i<netsize;i++){network[i][0]>>=netbiasshift;network[i][1]>>=netbiasshift;network[i][2]>>=netbiasshift;network[i][3]=i}}function altersingle(alpha,i,b,g,r){network[i][0]-=alpha*(network[i][0]-b)/initalpha;network[i][1]-=alpha*(network[i][1]-g)/initalpha;network[i][2]-=alpha*(network[i][2]-r)/initalpha}function alterneigh(radius,i,b,g,r){var lo=Math.abs(i-radius);var hi=Math.min(i+radius,netsize);var j=i+1;var k=i-1;var m=1;var p,a;while(j<hi||k>lo){a=radpower[m++];if(j<hi){p=network[j++];p[0]-=a*(p[0]-b)/alpharadbias;p[1]-=a*(p[1]-g)/alpharadbias;p[2]-=a*(p[2]-r)/alpharadbias}if(k>lo){p=network[k--];p[0]-=a*(p[0]-b)/alpharadbias;p[1]-=a*(p[1]-g)/alpharadbias;p[2]-=a*(p[2]-r)/alpharadbias}}}function contest(b,g,r){var bestd=~(1<<31);var bestbiasd=bestd;var bestpos=-1;var bestbiaspos=bestpos;var i,n,dist,biasdist,betafreq;for(i=0;i<netsize;i++){n=network[i];dist=Math.abs(n[0]-b)+Math.abs(n[1]-g)+Math.abs(n[2]-r);if(dist<bestd){bestd=dist;bestpos=i}biasdist=dist-(bias[i]>>intbiasshift-netbiasshift);if(biasdist<bestbiasd){bestbiasd=biasdist;bestbiaspos=i}betafreq=freq[i]>>betashift;freq[i]-=betafreq;bias[i]+=betafreq<<gammashift}freq[bestpos]+=beta;bias[bestpos]-=betagamma;return bestbiaspos}function inxbuild(){var i,j,p,q,smallpos,smallval,previouscol=0,startpos=0;for(i=0;i<netsize;i++){p=network[i];smallpos=i;smallval=p[1];for(j=i+1;j<netsize;j++){q=network[j];if(q[1]<smallval){smallpos=j;smallval=q[1]}}q=network[smallpos];if(i!=smallpos){j=q[0];q[0]=p[0];p[0]=j;j=q[1];q[1]=p[1];p[1]=j;j=q[2];q[2]=p[2];p[2]=j;j=q[3];q[3]=p[3];p[3]=j}if(smallval!=previouscol){netindex[previouscol]=startpos+i>>1;for(j=previouscol+1;j<smallval;j++)netindex[j]=i;previouscol=smallval;startpos=i}}netindex[previouscol]=startpos+maxnetpos>>1;for(j=previouscol+1;j<256;j++)netindex[j]=maxnetpos}function inxsearch(b,g,r){var a,p,dist;var bestd=1e3;var best=-1;var i=netindex[g];var j=i-1;while(i<netsize||j>=0){if(i<netsize){p=network[i];dist=p[1]-g;if(dist>=bestd)i=netsize;else{i++;if(dist<0)dist=-dist;a=p[0]-b;if(a<0)a=-a;dist+=a;if(dist<bestd){a=p[2]-r;if(a<0)a=-a;dist+=a;if(dist<bestd){bestd=dist;best=p[3]}}}}if(j>=0){p=network[j];dist=g-p[1];if(dist>=bestd)j=-1;else{j--;if(dist<0)dist=-dist;a=p[0]-b;if(a<0)a=-a;dist+=a;if(dist<bestd){a=p[2]-r;if(a<0)a=-a;dist+=a;if(dist<bestd){bestd=dist;best=p[3]}}}}}return best}function learn(){var i;var lengthcount=pixels.length;var alphadec=30+(samplefac-1)/3;var samplepixels=lengthcount/(3*samplefac);var delta=~~(samplepixels/ncycles);var alpha=initalpha;var radius=initradius;var rad=radius>>radiusbiasshift;if(rad<=1)rad=0;for(i=0;i<rad;i++)radpower[i]=alpha*((rad*rad-i*i)*radbias/(rad*rad));var step;if(lengthcount<minpicturebytes){samplefac=1;step=3}else if(lengthcount%prime1!==0){step=3*prime1}else if(lengthcount%prime2!==0){step=3*prime2}else if(lengthcount%prime3!==0){step=3*prime3}else{step=3*prime4}var b,g,r,j;var pix=0;i=0;while(i<samplepixels){b=(pixels[pix]&255)<<netbiasshift;g=(pixels[pix+1]&255)<<netbiasshift;r=(pixels[pix+2]&255)<<netbiasshift;j=contest(b,g,r);altersingle(alpha,j,b,g,r);if(rad!==0)alterneigh(rad,j,b,g,r);pix+=step;if(pix>=lengthcount)pix-=lengthcount;i++;if(delta===0)delta=1;if(i%delta===0){alpha-=alpha/alphadec;radius-=radius/radiusdec;rad=radius>>radiusbiasshift;if(rad<=1)rad=0;for(j=0;j<rad;j++)radpower[j]=alpha*((rad*rad-j*j)*radbias/(rad*rad))}}}function buildColormap(){init();learn();unbiasnet();inxbuild()}this.buildColormap=buildColormap;function getColormap(){var map=[];var index=[];for(var i=0;i<netsize;i++)index[network[i][3]]=i;var k=0;for(var l=0;l<netsize;l++){var j=index[l];map[k++]=network[j][0];map[k++]=network[j][1];map[k++]=network[j][2]}return map}this.getColormap=getColormap;this.lookupRGB=inxsearch}module.exports=NeuQuant},{}],4:[function(require,module,exports){var GIFEncoder,renderFrame;GIFEncoder=require("./GIFEncoder.js");renderFrame=function(frame){var encoder,page,stream,transfer;encoder=new GIFEncoder(frame.width,frame.height);if(frame.index===0){encoder.writeHeader()}else{encoder.firstFrame=false}encoder.setTransparent(frame.transparent);encoder.setRepeat(frame.repeat);encoder.setDelay(frame.delay);encoder.setQuality(frame.quality);encoder.setDither(frame.dither);encoder.setGlobalPalette(frame.globalPalette);encoder.addFrame(frame.data);if(frame.last){encoder.finish()}if(frame.globalPalette===true){frame.globalPalette=encoder.getGlobalPalette()}stream=encoder.stream();frame.data=stream.pages;frame.cursor=stream.cursor;frame.pageSize=stream.constructor.pageSize;if(frame.canTransfer){transfer=function(){var i,len,ref,results;ref=frame.data;results=[];for(i=0,len=ref.length;i<len;i++){page=ref[i];results.push(page.buffer)}return results}();return self.postMessage(frame,transfer)}else{return self.postMessage(frame)}};self.onmessage=function(event){return renderFrame(event.data)}},{"./GIFEncoder.js":1}]},{},[4]);
//# sourceMappingURL=gif.worker.js.map

View file

@ -1,20 +0,0 @@
<!DOCTYPE html>
<html lang="en" >
<head>
<meta charset="UTF-8">
<title>A Pen by CBenni</title>
</head>
<body>
<canvas height=256 width=2560 style="border: 1px solid black;" id="c"></canvas>
<img id="i">
<script src='https://rawgit.com/deanm/omggif/master/omggif.js'></script>
<script src='gif.js'></script>
<script src="index.js"></script>
</body>
</html>

View file

@ -1,309 +0,0 @@
function loadFromUrl(url) {
return new Promise(((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.responseType = 'arraybuffer';
xhr.onload = function () {
if (this.status >= 200 && this.status < 300) {
resolve({
type: xhr.getResponseHeader('Content-Type'),
data: xhr.response
});
} else {
reject({
status: this.status,
statusText: xhr.statusText
});
}
};
xhr.onerror = function () {
reject({
status: this.status,
statusText: xhr.statusText
});
};
xhr.send();
}));
}
function _arrayBufferToBase64(buffer) {
let binary = '';
const bytes = new Uint8Array(buffer);
const len = bytes.byteLength;
for (let i = 0; i < len; i++) {
binary += String.fromCharCode(bytes[i]);
}
return window.btoa(binary);
}
function createCanvas(width, height) {
const canvas = document.createElement('canvas');
canvas.width = width;
canvas.height = height;
return canvas;
}
class ImageEx {
constructor(url) {
this.url = url;
this.loaded = loadFromUrl(url).then(result => {
this.type = result.type;
this.data = result.data;
if (this.type === 'image/gif') {
return this.initGif();
}
return this.initStatic();
});
}
initGif() {
const reader = new GifReader(new Uint8Array(this.data));
this.width = reader.width;
this.height = reader.height;
this.frames = this.decodeFrames(reader);
this.renderAllFrames();
}
initStatic() {
// todo: in node, we wanna use this.data
const img = new Image();
const arrayBufferView = new Uint8Array(this.data);
const blob = new Blob([arrayBufferView], { type: this.type });
const urlCreator = window.URL || window.webkitURL;
const imageUrl = urlCreator.createObjectURL(blob);
img.src = imageUrl;
return new Promise(resolve => {
img.onload = () => {
this.width = img.width;
this.height = img.height;
this.frames = [{
actualOffset: 0,
actualDelay: Infinity,
delay: Infinity
}];
this.spriteSheet = createCanvas(this.width, this.height);
const spriteSheetCtx = this.spriteSheet.getContext('2d');
spriteSheetCtx.drawImage(img, 0, 0);
resolve();
};
});
}
decodeFrames(reader) {
const frames = [];
let offset = 0;
for (let i = 0; i < reader.numFrames(); ++i) {
const frameInfo = reader.frameInfo(i);
frameInfo.pixels = new Uint8ClampedArray(reader.width * reader.height * 4);
reader.decodeAndBlitFrameRGBA(i, frameInfo.pixels);
frameInfo.buffer = this.createBufferCanvas(frameInfo, this.width, this.height);
frameInfo.actualOffset = offset;
frameInfo.actualDelay = Math.max(frameInfo.delay * 10, 20);
offset += frameInfo.actualDelay;
frames.push(frameInfo);
}
this.totalDuration = offset;
return frames;
}
renderAllFrames() {
let disposeFrame = null;
const canvas = createCanvas(this.width, this.height);
const ctx = canvas.getContext('2d');
let saved;
this.spriteSheet = createCanvas(this.width * this.frames.length, this.height);
const spriteSheetCtx = this.spriteSheet.getContext('2d');
for (let i = 0; i < this.frames.length; ++i) {
const frame = this.frames[i];
if (typeof disposeFrame === 'function') disposeFrame();
switch (frame.disposal) {
case 2:
disposeFrame = () => ctx.clearRect(0, 0, canvas.width, canvas.height);
break;
case 3:
saved = ctx.getImageData(0, 0, canvas.width, canvas.height);
disposeFrame = () => ctx.putImageData(saved, 0, 0);
break;
default:
this.disposeFrame = null;
}
// draw current frame
ctx.drawImage(frame.buffer, frame.x, frame.y);
// draw the frame onto the sprite sheet
spriteSheetCtx.drawImage(canvas, this.width * i, 0);
}
}
createBufferCanvas(frame, width, height) {
const canvas = createCanvas(frame.width, frame.height);
const ctx = canvas.getContext('2d');
const imageData = ctx.createImageData(width, height);
imageData.data.set(frame.pixels);
ctx.putImageData(imageData, -frame.x, -frame.y);
return canvas;
}
drawFrame(ctx, frameNum, x, y, args = {}) {
console.log('this', this);
const sx = frameNum * this.width + (args.sx || 0);
const sy = args.sy || 0;
const swidth = Math.min(args.swidth || this.width, this.width) - (args.sx || 0);
const sheight = args.sheight || this.height;
console.log(`Drawing frame ${frameNum} at`);
console.log('sx', sx);
console.log('sy', sy);
console.log('sw', swidth);
console.log('sh', sheight);
console.log('x', x);
console.log('y', y);
console.log('w', args.width);
console.log('h', args.height);
ctx.drawImage(this.spriteSheet, sx, sy, swidth, sheight, x, y, args.width || swidth, args.height || sheight);
// ctx.drawImage(this.spriteSheet, 0, 0, 112, 112, 0, 0, 112, 112)
}
}
class CanvasEx {
constructor(width, height) {
this.width = width;
this.height = height;
this.frames = [];
this.totalDuration = Infinity;
}
addFrame(actualDelay, delay) {
if ((actualDelay === undefined || actualDelay === null)
&& (delay === undefined || delay === null)) throw new Error('Delay has to be set!');
const canvas = createCanvas(this.width, this.height);
const frame = {
actualOffset: this.totalDuration,
delay: delay || Math.max(Math.round(actualDelay / 10), 2),
actualDelay: actualDelay || Math.max(delay * 10, 20),
canvas,
ctx: canvas.getContext('2d')
};
this.totalDuration += delay;
this.frames.push(frame);
}
drawImage(img, x, y, args = {}) {
let {
sx, sy, swidth, sheight, width, height, beginAt = 0, endAt = Infinity
} = args;
console.log('Drawing image ', img);
console.log('At ', x, y, args);
beginAt = Math.max(0, beginAt);
endAt = Math.min(Math.max(img.totalDuration || 0, this.totalDuration), endAt);
if (img.frames && img.frames.length > 1) {
if (this.frames.length > 1) throw new Error('Cannot render animations onto animated canvases!');
this.totalDuration = img.totalDuration;
// we are drawing an animated image onto a static one.
// for each frame in the image, create a frame on this one, cloning the original picture (if any),
// render the original on each frame, and draw the frame on top.
for (let i = this.frames.length; i < img.frames.length; ++i) {
const frame = img.frames[i];
console.log(`Adding frame ${i}:`, frame);
this.addFrame(null, frame.delay);
if (this.frames.length > 0) {
this.frames[i].ctx.drawImage(this.frames[0].canvas, 0, 0);
}
}
for (let i = 0; i < img.frames.length; ++i) {
console.log(`Drawing frame ${i}:`, img.frames[i]);
// draw the i-th source frame to the i-th target frame
img.drawFrame(this.frames[i].ctx, i, x, y, args);
}
console.log('Done drawing animated image, CanvasEx is now', this);
} else {
// we are drawing a static image on top of a (possibly animated) image.
// for each frame, just draw, nothing fancy.
if (img.frames) {
// the image cant have more than one frame, and if it has 0, we dont need to do anything at all
if (img.frames.length === 1) {
for (let i = 0; i < this.frames.length; ++i) {
img.drawFrame(this.frames[i].ctx, 0, x, y, args);
}
}
} else {
for (let i = 0; i < this.frames.length; ++i) {
this.drawImage(this.frames[i].ctx, img, x, y, args);
}
}
console.log('Done drawing static image, CanvasEx is now', this);
}
}
drawFrame(ctx, frameNum, x, y, args = {}) {
// console.log(`Drawing frame ${frameNum} of`, this)
ctx.drawImage(this.frames[frameNum].canvas, x, y);
// this.drawImage(ctx, this.frames[frameNum].canvas, x,y,args);
}
_drawImage(ctx, img, x, y, args = {}) {
if (args.sx !== undefined || args.sy !== undefined || args.swidth !== undefined || args.sheight !== undefined) {
ctx.drawImage(img, args.sx, args.sy, args.swidth, args.sheight, x, y, args.width, args.height);
} else {
ctx.drawImage(img, x, y, args.width, args.height);
}
}
}
// const img = new ImageEx("https://cors-anywhere.herokuapp.com/https://cdn.betterttv.net/emote/554da1a289d53f2d12781907/3x");
const img = new ImageEx('https://cors-anywhere.herokuapp.com/https://cdn.discordapp.com/emojis/393563453824040983.gif');
const _canvas = document.getElementById('c');
const _ctx = _canvas.getContext('2d');
const img2 = new ImageEx('https://rawgit.com/CBenni/beebot/master/resources/SnowGlobe.png');
const _cnv = new CanvasEx(128, 128);
img.loaded.then(() => {
_cnv.drawImage(img, 0, 0);
// img.drawFrame(_ctx, 0, 0, 0)
return img2.loaded;
}).then(() => {
_cnv.drawImage(img2, 0, 0, { width: 128, height: 128 });
}).then(() => {
console.log('Drawing CanvasEx to screen', _cnv);
_cnv.drawFrame(_ctx, 0, 0, 0);
console.log('Starting gif render');
const GifEncoder = new GIF({
workers: 2,
quality: 10,
transparent: 'rgba(0,0,0,0)'
});
for (let i = 0; i < _cnv.frames.length; ++i) {
const frame = _cnv.frames[i];
console.log(`Rendering frame ${i}`);
GifEncoder.addFrame(frame.canvas, { delay: frame.delay });
}
GifEncoder.on('finished', blob => {
console.log('Done rendering!', URL.createObjectURL(blob));
document.getElementById('i').src = URL.createObjectURL(blob);
});
GifEncoder.render();
});
let curFrm = 0;
setInterval(() => {
_ctx.clearRect(0, 0, 200, 200);
_cnv.drawFrame(_ctx, curFrm++ % _cnv.frames.length, 0, 0);
}, 100);
/* img2.loaded.then(() => {
_ctx.drawImage(img2.spriteSheet, 0, 100)
})
img.loaded.then(()=>_ctx.drawImage(img.spriteSheet,0,0)) */

View file

@ -1,12 +0,0 @@
<!--
Copyright (c) 2017 by CBenni (https://codepen.io/CBenni/pen/YYZKeO)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-->

View file

@ -1,15 +1,29 @@
const fs = require('fs');
const got = require('got');
const Canvas = require('canvas');
const streamBuffers = require('stream-buffers');
const mime = require('mime-types');
const { GifReader } = require('omggif');
const GifEncoder = require('gifencoder');
const Image = { Canvas };
const { Image } = Canvas;
function loadFromUrl(url) {
return got(url, { encoding: null }).then(res => ({
function loadFromUri(uri) {
if (uri.startsWith('http')) {
return got(uri, { encoding: null }).then(res => ({
type: res.headers['content-type'],
data: res.body
}));
}
return new Promise((resolve, reject) => {
fs.readFile(uri, (err, data) => {
if (err) reject(err);
resolve({
type: mime.lookup(uri),
data
});
});
});
}
function createCanvas(width, height) {
@ -18,15 +32,18 @@ function createCanvas(width, height) {
}
class ImageEx {
constructor(url) {
this.url = url;
this.loaded = loadFromUrl(url).then(result => {
constructor(uri) {
this.uri = uri;
this.loaded = loadFromUri(uri).then(result => {
this.type = result.type;
this.data = result.data;
if (this.type === 'image/gif') {
return this.initGif();
console.log(uri, 'loaded');
this.initGif();
} else {
this.initStatic();
}
return this.initStatic();
return this;
});
}
@ -38,13 +55,14 @@ class ImageEx {
this.frames = this.decodeFrames(reader);
this.renderAllFrames();
return this;
}
initStatic() {
const img = new Image();
img.src = this.data;
return new Promise(resolve => {
img.onload = () => {
this.width = img.width;
this.height = img.height;
this.frames = [{
@ -55,9 +73,6 @@ class ImageEx {
this.spriteSheet = createCanvas(this.width, this.height);
const spriteSheetCtx = this.spriteSheet.getContext('2d');
spriteSheetCtx.drawImage(img, 0, 0);
resolve();
};
});
}
decodeFrames(reader) {
@ -190,6 +205,10 @@ class CanvasEx {
if (img.frames) {
// the image cant have more than one frame, and if it has 0, we dont need to do anything at all
if (img.frames.length === 1) {
// if theres no frames at all, add one
if (this.frames.length === 0) {
this.addFrame(Infinity);
}
for (let i = 0; i < this.frames.length; ++i) {
img.drawFrame(this.frames[i].ctx, 0, x, y, args);
}
@ -218,9 +237,11 @@ class CanvasEx {
}
export(outStream) {
if (this.frames.length > 1) {
if (outStream.setHeader) outStream.setHeader('Content-Type', 'image/gif');
const gif = new GifEncoder(this.width, this.height);
gif.createReadStream().pipe(outStream);
gif.setTransparent(0);
// gif.setTransparent(0xfefe01);
gif.setRepeat(0);
gif.start();
for (let i = 0; i < this.frames.length; ++i) {
@ -229,6 +250,28 @@ class CanvasEx {
gif.addFrame(frame.ctx);
}
gif.finish();
} else if (this.frames.length === 1) {
if (outStream.setHeader) outStream.setHeader('Content-Type', 'image/png');
const stream = this.frames[0].canvas.pngStream();
stream.pipe(outStream);
} else {
throw new Error('No image data to be exported');
}
}
toBuffer() {
const buf = new streamBuffers.WritableStreamBuffer({
initialSize: this.height * this.width * 4 * this.frames.length,
incrementAmount: this.height * this.width * 4
});
this.export(buf);
return new Promise(resolve => {
buf.on('finish', () => {
console.log('Render completed (1)');
resolve(buf.getContents());
});
});
}
}

View file

@ -110,7 +110,7 @@ function render(template, img, size, flipH) {
transform.translate = [resultingWidth, 0];
transform.scale = [-1, 1];
}
canvas.drawImage(subject.image, subject.x, subject.y, { transform });
canvas.drawImage(subject.image, subject.x, subject.y, { width: subject.w, height: subject.h, transform });
} catch (err) {
console.error(err);
throw new Error(JSON.stringify({ status: 400, error: 'Invalid template' }));
@ -127,8 +127,7 @@ app.get('/:templateName/', async (req, res) => {
const img = new ImageEx(req.query.url);
const canvas = render(templates[req.params.templateName], await img.loaded);
console.log(canvas);
res.setHeader('Content-Type', 'image/png');
return canvas.pngStream().pipe(res);
return canvas.export(res);
} catch (err) {
console.log(err);
return res.status(400).end(err.message);
@ -160,12 +159,14 @@ client.login(config.discord.token).catch(error => {
});
function findEmoji(str) {
const discordEmote = /<:(\w+):(\d+)>/g.exec(str);
const discordEmote = /<(a?):(\w+):(\d+)>/g.exec(str);
if (discordEmote) {
const ext = discordEmote[1] === 'a' ? 'gif' : 'png';
return {
name: discordEmote[1],
id: discordEmote[2],
url: `https://cdn.discordapp.com/emojis/${discordEmote[2]}.png`
name: discordEmote[2],
id: discordEmote[3],
url: `https://cdn.discordapp.com/emojis/${discordEmote[3]}.${ext}`,
ext
};
}
@ -234,15 +235,23 @@ client.on('message', async message => {
} else if (i === 0) return;
}
if (result) {
const attachment = await result.toBuffer();
console.log('Render completed, data:', attachment);
const messageOptions = {
files: [
{ attachment: result.toBuffer(), name: `${name}.png` }
{ attachment, name: `${name}.${emoji.ext}` }
]
};
message.channel.send('', messageOptions);
await message.channel.send('', messageOptions);
}
}
} catch (err) {
console.error(err);
}
});
process.on('uncaughtException', exception => {
console.log(exception); // to see your exception details in the console
// if you are on production, maybe you can send the exception details to your
// email as well ?
});

View file

@ -17,8 +17,10 @@
"gifencoder": "^1.1.0",
"got": "^8.0.1",
"lodash": "^4.17.4",
"mime-types": "^2.1.17",
"omggif": "^1.0.9",
"request": "^2.81.0"
"request": "^2.81.0",
"stream-buffers": "^3.0.1"
},
"devDependencies": {
"eslint": "^4.14.0",

View file

@ -1081,7 +1081,7 @@ mime-db@~1.30.0:
version "1.30.0"
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.30.0.tgz#74c643da2dd9d6a45399963465b26d5ca7d71f01"
mime-types@^2.1.12, mime-types@~2.1.15, mime-types@~2.1.16, mime-types@~2.1.17:
mime-types@^2.1.12, mime-types@^2.1.17, mime-types@~2.1.15, mime-types@~2.1.16, mime-types@~2.1.17:
version "2.1.17"
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.17.tgz#09d7a393f03e995a79f8af857b70a9e0ab16557a"
dependencies:
@ -1580,6 +1580,10 @@ sshpk@^1.7.0:
version "1.3.1"
resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e"
stream-buffers@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/stream-buffers/-/stream-buffers-3.0.1.tgz#68a38c5faadeded79ff79988d368e3fb1325ef06"
strict-uri-encode@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713"