Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Socket
Sign inDemoInstall

gifencoder

Package Overview
Dependencies
Maintainers
1
Versions
12
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

gifencoder - npm Package Compare versions

Comparing version 0.1.0 to 0.2.0

test/fixtures/frame0.png

63

lib/GIFEncoder.js

@@ -11,3 +11,3 @@ /*

var Readable = require('stream').Readable;
var stream = require('stream');
var NeuQuant = require('./TypedNeuQuant.js');

@@ -67,18 +67,55 @@ var LZWEncoder = require('./LZWEncoder.js');

this.readStream = null;
this.started = false; // started encoding
this.readStreams = [];
this.out = new ByteArray();
}
GIFEncoder.prototype.createReadStream = function () {
if (this.readStream !== null) return this.readStream;
this.readStream = new Readable();
this.readStream._read = function () {};
return this.readStream;
GIFEncoder.prototype.createReadStream = function (rs) {
if (!rs) {
rs = new stream.Readable();
rs._read = function () {};
}
this.readStreams.push(rs);
return rs;
};
GIFEncoder.prototype.createWriteStream = function (options) {
var self = this;
if (options) {
Object.keys(options).forEach(function (option) {
var fn = 'set' + option[0].toUpperCase() + option.substr(1);
if (~['setDelay', 'setFrameRate', 'setDispose', 'setRepeat',
'setTransparent', 'setQuality'].indexOf(fn)) {
self[fn].call(self, options[option]);
}
});
}
var ws = new stream.Duplex({ objectMode: true });
ws._read = function () {};
this.createReadStream(ws);
var self = this;
ws._write = function (data, enc, next) {
if (!self.started) self.start();
self.addFrame(data);
next();
};
var end = ws.end;
ws.end = function () {
end.apply(ws, [].slice.call(arguments));
self.finish();
};
return ws;
};
GIFEncoder.prototype.emit = function() {
if (this.readStream === null) return;
var self = this;
if (this.readStreams.length === 0) return;
if (this.out.cursor < this.out.data.length) {
this.readStream.push(new Buffer(this.out.data.slice(this.out.cursor, this.out.data.length)));
this.readStreams.forEach(function (rs) {
rs.push(new Buffer(self.out.data.slice(self.out.cursor, self.out.data.length)));
});
}

@@ -89,5 +126,8 @@ this.out.cursor = this.out.data.length;

GIFEncoder.prototype.end = function() {
if (this.readStream === null) return;
if (this.readStreams.length === null) return;
this.emit();
this.readStream.push(null);
this.readStreams.forEach(function (rs) {
rs.push(null);
});
this.readStreams = [];
};

@@ -206,2 +246,3 @@

this.out.writeUTFBytes("GIF89a");
this.started = true;
this.emit();

@@ -208,0 +249,0 @@ };

7

package.json
{
"name": "gifencoder",
"version": "0.1.0",
"version": "0.2.0",
"description": "Streaming server-side animated (and non-animated) gif generation for node.js",

@@ -42,4 +42,7 @@ "main": "index.js",

"canvas": "~1.1.0",
"concat-stream": "~1.0.1"
"concat-stream": "~1.0.1",
"png-js": "~0.1.1",
"after": "~0.8.1",
"range": "0.0.2"
}
}

@@ -65,3 +65,3 @@ # gifencoder

## Streaming API
## Streaming API - Reads

@@ -105,1 +105,17 @@ You can also use a streaming API to receive data:

```
## Streaming API - Writes
You can also stream writes of pixel data (or canvas contexts) to the encoder:
``` js
var GIFEncoder = require('gifencoder');
var encoder = new GIFEncoder(854, 480);
var bitMapStream = makeMyBitMaps(); // read stream that creates RGBA 1-dimensional bitmaps
bitMapStream
.pipe(encoder.createWriteStream({ repeat: -1, delay: 500, quality: 10 }))
.pipe(fs.createWriteStream('myanimated.gif'));
```
NB: The chunks that get emitted by your read stream must either by a 1-dimensional bitmap of RGBA
data (either an array or Buffer), or a canvas 2D `context`.

@@ -6,7 +6,23 @@ var expect = require('expect.js'),

concat = require('concat-stream'),
stream = require('stream'),
png = require('png-js'),
after = require('after'),
range = require('range'),
GIFEncoder = require('..');
function getData(ctx, width, height) {
return ctx.getImageData(0, 0, width || ctx.canvas.width, height || ctx.canvas.height).data;
}
function fixtures(file) {
return path.join(__dirname, 'fixtures', file);
}
function root(file) {
return path.join(__dirname, '..', file);
}
describe('GIFEncoder', function() {
it('should be able to Generate a PNG', function(done) {
var buf = fs.readFileSync(path.join(__dirname, 'fixtures', 'in.png'));
var buf = fs.readFileSync(fixtures('in.png'));
var img = new Canvas.Image();

@@ -37,3 +53,3 @@ img.src = buf;

var out = encoder.stream().getData();
var expected = fs.readFileSync(path.join(__dirname, 'fixtures', 'out.gif'));
var expected = fs.readFileSync(fixtures('out.gif'));

@@ -45,4 +61,4 @@ expect(out).to.eql(expected);

it('should expose a streaming interface', function(done) {
var buf = fs.readFileSync(path.join(__dirname, 'fixtures', 'in.png'));
it('should expose a read streaming interface', function(done) {
var buf = fs.readFileSync(fixtures('in.png'));
var img = new Canvas.Image();

@@ -56,3 +72,3 @@ img.src = buf;

encoder.createReadStream().pipe(concat(function (data) {
var expected = fs.readFileSync(path.join(__dirname, 'fixtures', 'out.gif'));
var expected = fs.readFileSync(fixtures('out.gif'));
expect(data).to.eql(expected);

@@ -80,2 +96,204 @@ done();

});
it('should expose a write streaming interface', function(done) {
var buf = fs.readFileSync(fixtures('in.png'));
var img = new Canvas.Image();
img.src = buf;
var canvas = new Canvas(img.width, img.height);
var ctx = canvas.getContext('2d');
var encoder = new GIFEncoder(img.width, img.height);
encoder.createReadStream().pipe(concat(function (data) {
var expected = fs.readFileSync(fixtures('out.gif'));
expect(data).to.eql(expected);
done();
}));
encoder.setRepeat(-1);
encoder.setDelay(500);
encoder.setQuality(10);
var ws = encoder.createWriteStream();
ctx.drawImage(img, 0, 0);
ws.write(ctx);
ctx.fillStyle = '#ff0000';
ctx.fillRect(0, 0, img.width, img.height);
ws.write(ctx);
ctx.fillStyle = '#0000ff';
ctx.fillRect(0, 0, img.width, img.height);
ws.write(ctx);
ws.end();
});
it('should be able to pipe with bitmaps', function(done) {
var rs = new stream.Readable({ objectMode: true });
var frames = [];
rs._read = function () {
if (frames.length) {
rs.push(frames.shift());
} else {
rs.push(null);
}
};
var buf = fs.readFileSync(fixtures('in.png'));
var img = new Canvas.Image();
img.src = buf;
var canvas = new Canvas(img.width, img.height);
var ctx = canvas.getContext('2d');
var encoder = new GIFEncoder(img.width, img.height);
encoder.createReadStream().pipe(concat(function (data) {
var expected = fs.readFileSync(fixtures('out.gif'));
expect(data).to.eql(expected);
done();
}));
encoder.setRepeat(-1);
encoder.setDelay(500);
encoder.setQuality(10);
var ws = encoder.createWriteStream();
ctx.drawImage(img, 0, 0);
frames.push(getData(ctx));
ctx.fillStyle = '#ff0000';
ctx.fillRect(0, 0, img.width, img.height);
frames.push(getData(ctx));
ctx.fillStyle = '#0000ff';
ctx.fillRect(0, 0, img.width, img.height);
frames.push(getData(ctx));
rs.pipe(ws);
});
it('should pipe with png file bitmaps', function(done) {
function createReadStream() {
var rs = new stream.Readable({ objectMode: true });
rs._read = function () { };
var n = 3;
var next = after(n, finish);
var frames = [];
range(0, n).forEach(function (i) {
png.decode(fixtures('frame' + i + '.png'), function (pixels) {
frames[i] = pixels;
next();
});
});
function finish() {
(function next() {
if (frames.length) {
rs.push(frames.shift());
setImmediate(next);
} else {
rs.push(null);
}
})();
}
return rs;
}
var encoder = new GIFEncoder(854, 480);
encoder.createReadStream().pipe(concat(function (data) {
var expected = fs.readFileSync(fixtures('out.gif'));
expect(data).to.eql(expected);
done();
}));
encoder.setRepeat(-1);
encoder.setDelay(500);
encoder.setQuality(10);
var ws = encoder.createWriteStream();
createReadStream().pipe(ws);
});
it('should pipe with write options', function(done) {
function createReadStream() {
var rs = new stream.Readable({ objectMode: true });
rs._read = function () { };
var n = 3;
var next = after(n, finish);
var frames = [];
range(0, n).forEach(function (i) {
png.decode(fixtures('frame' + i + '.png'), function (pixels) {
frames[i] = pixels;
next();
});
});
function finish() {
(function next() {
if (frames.length) {
rs.push(frames.shift());
setImmediate(next);
} else {
rs.push(null);
}
})();
}
return rs;
}
var encoder = new GIFEncoder(854, 480);
encoder.createReadStream().pipe(concat(function (data) {
var expected = fs.readFileSync(fixtures('out.gif'));
expect(data).to.eql(expected);
done();
}));
var ws = encoder.createWriteStream({ repeat: -1, delay: 500, quality: 10 });
createReadStream().pipe(ws);
});
it('should pipe a through stream', function(done) {
function createReadStream() {
var rs = new stream.Readable({ objectMode: true });
rs._read = function () { };
var n = 3;
var next = after(n, finish);
var frames = [];
range(0, n).forEach(function (i) {
png.decode(fixtures('frame' + i + '.png'), function (pixels) {
frames[i] = pixels;
next();
});
});
function finish() {
(function next() {
if (frames.length) {
rs.push(frames.shift());
setImmediate(next);
} else {
rs.push(null);
}
})();
}
return rs;
}
var encoder = new GIFEncoder(854, 480);
createReadStream()
.pipe(encoder.createWriteStream({ repeat: -1, delay: 500, quality: 10 }))
.pipe(concat(function (data) {
var expected = fs.readFileSync(fixtures('out.gif'));
expect(data).to.eql(expected);
done();
}));
});
});
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc