From 0176bd063f406ac13a60d7c682919cd258469c35 Mon Sep 17 00:00:00 2001 From: CBenni Date: Sun, 31 Dec 2017 13:59:14 +0100 Subject: [PATCH] Added gif support --- gifsupport-node/README.txt | 3 - gifsupport-node/gif.js | 3 - gifsupport-node/gif.worker.js | 3 - gifsupport-node/imageex.js | 303 --------------------------------- gifsupport-node/index.html | 20 --- gifsupport-node/index.js | 286 ------------------------------- gifsupport-node/license.txt | 12 -- gifsupport/README.txt | 3 - gifsupport/gif.js | 3 - gifsupport/gif.worker.js | 3 - gifsupport/index.html | 20 --- gifsupport/index.js | 309 ---------------------------------- gifsupport/license.txt | 12 -- imageex.js | 117 +++++++++---- index.js | 27 ++- package.json | 4 +- yarn.lock | 6 +- 17 files changed, 106 insertions(+), 1028 deletions(-) delete mode 100644 gifsupport-node/README.txt delete mode 100644 gifsupport-node/gif.js delete mode 100644 gifsupport-node/gif.worker.js delete mode 100644 gifsupport-node/imageex.js delete mode 100644 gifsupport-node/index.html delete mode 100644 gifsupport-node/index.js delete mode 100644 gifsupport-node/license.txt delete mode 100644 gifsupport/README.txt delete mode 100644 gifsupport/gif.js delete mode 100644 gifsupport/gif.worker.js delete mode 100644 gifsupport/index.html delete mode 100644 gifsupport/index.js delete mode 100644 gifsupport/license.txt diff --git a/gifsupport-node/README.txt b/gifsupport-node/README.txt deleted file mode 100644 index 6aec385..0000000 --- a/gifsupport-node/README.txt +++ /dev/null @@ -1,3 +0,0 @@ -A Pen created at CodePen.io. You can find this one at https://codepen.io/CBenni/pen/YYZKeO. - - \ No newline at end of file diff --git a/gifsupport-node/gif.js b/gifsupport-node/gif.js deleted file mode 100644 index 2e4d204..0000000 --- a/gifsupport-node/gif.js +++ /dev/null @@ -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;o0&&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;iref;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?jref;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?jnumWorkers;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?jref;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=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 diff --git a/gifsupport-node/gif.worker.js b/gifsupport-node/gif.worker.js deleted file mode 100644 index 269624e..0000000 --- a/gifsupport-node/gif.worker.js +++ /dev/null @@ -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=ByteArray.pageSize)this.newPage();this.pages[this.page][this.cursor++]=val};ByteArray.prototype.writeUTFBytes=function(string){for(var l=string.length,i=0;i=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=0&&x1+x=0&&y1+y>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=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>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=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<0){outs.writeByte(a_count);outs.writeBytes(accum,0,a_count);a_count=0}}function MAXCODE(n_bits){return(1<0)cur_accum|=code<=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<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<>betashift;var betagamma=intbias<>3;var radiusbiasshift=6;var radiusbias=1<>3);var i,v;for(i=0;i>=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(jlo){a=radpower[m++];if(jlo){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>intbiasshift-netbiasshift);if(biasdist>betashift;freq[i]-=betafreq;bias[i]+=betafreq<>1;for(j=previouscol+1;j>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=0){if(i=bestd)i=netsize;else{i++;if(dist<0)dist=-dist;a=p[0]-b;if(a<0)a=-a;dist+=a;if(dist=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>radiusbiasshift;if(rad<=1)rad=0;for(i=0;i=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 ({ - 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)) */ diff --git a/gifsupport-node/index.html b/gifsupport-node/index.html deleted file mode 100644 index 3e01af9..0000000 --- a/gifsupport-node/index.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - A Pen by CBenni - - - - - - - - - - - - - - diff --git a/gifsupport-node/index.js b/gifsupport-node/index.js deleted file mode 100644 index 95458fe..0000000 --- a/gifsupport-node/index.js +++ /dev/null @@ -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 \\\\ to flip the template horizontally.\nInvite link: <${invitelink}>`, - beebot: `Available commands: ${commands}.\nUse \\\\ 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!'); -}); diff --git a/gifsupport-node/license.txt b/gifsupport-node/license.txt deleted file mode 100644 index be92a99..0000000 --- a/gifsupport-node/license.txt +++ /dev/null @@ -1,12 +0,0 @@ - - - diff --git a/gifsupport/README.txt b/gifsupport/README.txt deleted file mode 100644 index 6aec385..0000000 --- a/gifsupport/README.txt +++ /dev/null @@ -1,3 +0,0 @@ -A Pen created at CodePen.io. You can find this one at https://codepen.io/CBenni/pen/YYZKeO. - - \ No newline at end of file diff --git a/gifsupport/gif.js b/gifsupport/gif.js deleted file mode 100644 index 2e4d204..0000000 --- a/gifsupport/gif.js +++ /dev/null @@ -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;o0&&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;iref;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?jref;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?jnumWorkers;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?jref;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=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 diff --git a/gifsupport/gif.worker.js b/gifsupport/gif.worker.js deleted file mode 100644 index 269624e..0000000 --- a/gifsupport/gif.worker.js +++ /dev/null @@ -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=ByteArray.pageSize)this.newPage();this.pages[this.page][this.cursor++]=val};ByteArray.prototype.writeUTFBytes=function(string){for(var l=string.length,i=0;i=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=0&&x1+x=0&&y1+y>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=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>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=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<0){outs.writeByte(a_count);outs.writeBytes(accum,0,a_count);a_count=0}}function MAXCODE(n_bits){return(1<0)cur_accum|=code<=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<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<>betashift;var betagamma=intbias<>3;var radiusbiasshift=6;var radiusbias=1<>3);var i,v;for(i=0;i>=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(jlo){a=radpower[m++];if(jlo){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>intbiasshift-netbiasshift);if(biasdist>betashift;freq[i]-=betafreq;bias[i]+=betafreq<>1;for(j=previouscol+1;j>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=0){if(i=bestd)i=netsize;else{i++;if(dist<0)dist=-dist;a=p[0]-b;if(a<0)a=-a;dist+=a;if(dist=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>radiusbiasshift;if(rad<=1)rad=0;for(i=0;i=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 - - - - - A Pen by CBenni - - - - - - - - - - - - - - diff --git a/gifsupport/index.js b/gifsupport/index.js deleted file mode 100644 index 00d888b..0000000 --- a/gifsupport/index.js +++ /dev/null @@ -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)) */ diff --git a/gifsupport/license.txt b/gifsupport/license.txt deleted file mode 100644 index be92a99..0000000 --- a/gifsupport/license.txt +++ /dev/null @@ -1,12 +0,0 @@ - - - diff --git a/imageex.js b/imageex.js index 6785619..e550f96 100644 --- a/imageex.js +++ b/imageex.js @@ -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 => ({ - type: res.headers['content-type'], - data: res.body - })); +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,26 +55,24 @@ 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 = [{ - 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(); - }; - }); + + 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); } decodeFrames(reader) { @@ -148,7 +163,7 @@ class CanvasEx { addFrame(actualDelay, delay) { if ((actualDelay === undefined || actualDelay === null) - && (delay === undefined || delay === null)) throw new Error('Delay has to be set!'); + && (delay === undefined || delay === null)) throw new Error('Delay has to be set!'); const canvas = createCanvas(this.width, this.height); const frame = { actualOffset: this.totalDuration, @@ -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,17 +237,41 @@ class CanvasEx { } 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); + 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(0xfefe01); + 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(); + } 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'); } - gif.finish(); + } + + 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()); + }); + }); } } diff --git a/index.js b/index.js index eeac557..a53df40 100644 --- a/index.js +++ b/index.js @@ -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 ? +}); diff --git a/package.json b/package.json index 63e0a56..a7cae9e 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/yarn.lock b/yarn.lock index a36c9f5..2e42139 100644 --- a/yarn.lock +++ b/yarn.lock @@ -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"