From 9de8fae6743af00faf41c7cc28b503c3dc41f137 Mon Sep 17 00:00:00 2001 From: Wouter Verweirder Date: Tue, 9 Dec 2014 20:06:31 +0100 Subject: [PATCH 1/5] pass in a raw pixelBuffer to the open command --- examples/open_pixelbuffer.js | 51 +++++++++++++++++++++++++++++++++ lib/defs.js | 2 +- lib/obtain.js | 14 ++++++--- tests/02.operations/001.open.js | 20 +++++++++++++ 4 files changed, 82 insertions(+), 5 deletions(-) create mode 100644 examples/open_pixelbuffer.js diff --git a/examples/open_pixelbuffer.js b/examples/open_pixelbuffer.js new file mode 100644 index 00000000..3e0d6551 --- /dev/null +++ b/examples/open_pixelbuffer.js @@ -0,0 +1,51 @@ +/** + * Example for using LWIP to open a raw pixel buffer + */ + +var path = require('path'), + lwip = require('../'); + +var w = 90; +var h = 90; +var channelSize = w * h; +var size = channelSize * 4; +var redChannelEnd = channelSize * 1; +var greenChannelEnd = channelSize * 2; +var blueChannelEnd = channelSize * 3; +var alphaChannelEnd = channelSize * 4; +var i, x; + +var buffer = new Buffer(size); +for(i = blueChannelEnd; i < alphaChannelEnd; i++) { + buffer[i] = 100; +} +for(var y = 0; y < h; y++) { + for(x = 0; x < 30; x++) { + i = y * w + x; + buffer[i] = 255; + buffer[i + redChannelEnd] = 0; + buffer[i + greenChannelEnd] = 0; + } + for(x = 30; x < 60; x++) { + i = y * w + x; + buffer[i] = 0; + buffer[i + redChannelEnd] = 255; + buffer[i + greenChannelEnd] = 0; + } + for(x = 60; x < 90; x++) { + i = y * w + x; + buffer[i] = 0; + buffer[i + redChannelEnd] = 0; + buffer[i + greenChannelEnd] = 255; + } +} + +lwip.open(buffer, { width: w, height: h, trans: true }, function(err, image) { + if (err) return console.log("err open", err); + image.batch() + .blur(9) + .writeFile('image_from_pixelbuffer.png', function(err){ + if (err) return console.log("err write", err); + console.log('done'); + }); +}); diff --git a/lib/defs.js b/lib/defs.js index 984e7f0d..785f8974 100644 --- a/lib/defs.js +++ b/lib/defs.js @@ -85,7 +85,7 @@ type: '*' }, { name: 'type', - type: 'string', + types: ['string', 'hash'], optional: true }, { name: 'callback', diff --git a/lib/obtain.js b/lib/obtain.js index 476fb168..fc7423df 100644 --- a/lib/obtain.js +++ b/lib/obtain.js @@ -28,10 +28,16 @@ }); }); } else if (source instanceof Buffer) { - var opener = getOpener(type); - opener(source, function(err, pixelsBuf, width, height, channels, trans) { - callback(err, err ? null : new Image(pixelsBuf, width, height, trans)); - }); + if(typeof type === 'object') { + if(type.width && type.height) { + callback(null, new Image(source, type.width, type.height, type.trans)); + } else throw Error("Missing width and height"); + } else { + var opener = getOpener(type); + opener(source, function(err, pixelsBuf, width, height, channels, trans) { + callback(err, err ? null : new Image(pixelsBuf, width, height, trans)); + }); + } } else throw Error("Invalid source"); }); } diff --git a/tests/02.operations/001.open.js b/tests/02.operations/001.open.js index 74af5d62..c9a4909e 100644 --- a/tests/02.operations/001.open.js +++ b/tests/02.operations/001.open.js @@ -188,4 +188,24 @@ describe('lwip.open', function() { }); }); + + describe('raw pixel buffer', function() { + + describe('raw pixel buffer', function(){ + var buffer; + before(function(done) { + buffer = new Buffer(100 * 100 * 4); + done(); + }); + + it('should succeed', function(done) { + lwip.open(buffer, { width: 100, height: 100, trans: true }, function(err, img) { + should(err).not.be.Error; + img.should.be.OK; + done(); + }); + }); + }); + + }); }); From 63060b5db9a81af4acc9cfaf607d377b21cb787e Mon Sep 17 00:00:00 2001 From: Wouter Verweirder Date: Wed, 10 Dec 2014 09:21:22 +0100 Subject: [PATCH 2/5] added checks to raw pixelbuffer size arguments --- lib/obtain.js | 30 +++++++++++++++-- tests/00.argsValidation/001.open.js | 52 +++++++++++++++++++++++++++++ tests/02.operations/001.open.js | 2 +- 3 files changed, 80 insertions(+), 4 deletions(-) diff --git a/lib/obtain.js b/lib/obtain.js index fc7423df..1ddbf00f 100644 --- a/lib/obtain.js +++ b/lib/obtain.js @@ -29,9 +29,33 @@ }); } else if (source instanceof Buffer) { if(typeof type === 'object') { - if(type.width && type.height) { - callback(null, new Image(source, type.width, type.height, type.trans)); - } else throw Error("Missing width and height"); + if(!type.width && !type.height) { + throw Error("Missing width and height"); + } + if(!type.width) { + throw Error("Missing width"); + } + if(!type.height) { + throw Error("Missing height"); + } + if(typeof type.width !== "number") { + throw Error("Width must be numeric"); + } + if(typeof type.height !== "number") { + throw Error("Height must be numeric"); + } + var channelSize = type.width * type.height; + var numChannels = 3; + var size = channelSize * numChannels; + var bufferSize = source.length; + if(size !== bufferSize) { + numChannels++; + size += channelSize; + } + if(size !== bufferSize) { + throw Error("Invalid width or height"); + } + callback(null, new Image(source, type.width, type.height, (numChannels === 4))); } else { var opener = getOpener(type); opener(source, function(err, pixelsBuf, width, height, channels, trans) { diff --git a/tests/00.argsValidation/001.open.js b/tests/00.argsValidation/001.open.js index a5ce9b22..4c10c6da 100644 --- a/tests/00.argsValidation/001.open.js +++ b/tests/00.argsValidation/001.open.js @@ -65,4 +65,56 @@ describe('lwip.open arguments validation', function() { }); + describe('pixelbuffer', function() { + + var buffer; + before(function(done) { + buffer = new Buffer(100 * 100 * 4); + done(); + }); + + describe('without width', function() { + it('should throw an error', function() { + lwip.open.bind(lwip, buffer, { height: 100 }, function() {}).should.throwError(); + }); + }); + + describe('without height', function() { + it('should throw an error', function() { + lwip.open.bind(lwip, buffer, { width: 100 }, function() {}).should.throwError(); + }); + }); + + describe('without width and height', function() { + it('should throw an error', function() { + lwip.open.bind(lwip, buffer, { }, function() {}).should.throwError(); + }); + }); + + describe('with non numeric width', function() { + it('should throw an error', function() { + lwip.open.bind(lwip, buffer, { width: "lorem", height: 100 }, function() {}).should.throwError(); + }); + }); + + describe('with non numeric height', function() { + it('should throw an error', function() { + lwip.open.bind(lwip, buffer, { width: 100, height: "lorem" }, function() {}).should.throwError(); + }); + }); + + describe('with non numeric width and height', function() { + it('should throw an error', function() { + lwip.open.bind(lwip, buffer, { width: "lorem", height: "ipsum" }, function() {}).should.throwError(); + }); + }); + + describe('with incorrect width and height', function() { + it('should throw an error', function() { + lwip.open.bind(lwip, buffer, { width: 123, height: 321 }, function() {}).should.throwError(); + }); + }); + + }); + }); diff --git a/tests/02.operations/001.open.js b/tests/02.operations/001.open.js index c9a4909e..7db6a36f 100644 --- a/tests/02.operations/001.open.js +++ b/tests/02.operations/001.open.js @@ -199,7 +199,7 @@ describe('lwip.open', function() { }); it('should succeed', function(done) { - lwip.open(buffer, { width: 100, height: 100, trans: true }, function(err, img) { + lwip.open(buffer, { width: 100, height: 100 }, function(err, img) { should(err).not.be.Error; img.should.be.OK; done(); From d457592c95df0bbd8c156a9e2ae4fc61a327892d Mon Sep 17 00:00:00 2001 From: Wouter Verweirder Date: Wed, 10 Dec 2014 12:00:32 +0100 Subject: [PATCH 3/5] removed trans option from open_pixelbuffer example --- examples/open_pixelbuffer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/open_pixelbuffer.js b/examples/open_pixelbuffer.js index 3e0d6551..05df95ba 100644 --- a/examples/open_pixelbuffer.js +++ b/examples/open_pixelbuffer.js @@ -40,7 +40,7 @@ for(var y = 0; y < h; y++) { } } -lwip.open(buffer, { width: w, height: h, trans: true }, function(err, image) { +lwip.open(buffer, { width: w, height: h }, function(err, image) { if (err) return console.log("err open", err); image.batch() .blur(9) From 7c3f3c6deb4de89ae3c2abb9d8726ecc83357c7e Mon Sep 17 00:00:00 2001 From: Wouter Verweirder Date: Wed, 10 Dec 2014 16:37:57 +0100 Subject: [PATCH 4/5] dropped check for width AND height, as separate checks are sufficient --- lib/obtain.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/obtain.js b/lib/obtain.js index 1ddbf00f..a983e388 100644 --- a/lib/obtain.js +++ b/lib/obtain.js @@ -29,9 +29,6 @@ }); } else if (source instanceof Buffer) { if(typeof type === 'object') { - if(!type.width && !type.height) { - throw Error("Missing width and height"); - } if(!type.width) { throw Error("Missing width"); } From f13c07cf6c5353a934b831bed318de4d4a181d11 Mon Sep 17 00:00:00 2001 From: Wouter Verweirder Date: Thu, 11 Dec 2014 10:36:26 +0100 Subject: [PATCH 5/5] improved raw buffer type validation - moved part of that validation to custom decree type --- lib/defs.js | 2 +- lib/obtain.js | 26 +++----------- lib/util.js | 11 ++++++ tests/00.argsValidation/001.open.js | 55 ++++++++++++++++++++++++++--- tests/02.operations/001.open.js | 50 +++++++++++++++++++++++++- 5 files changed, 115 insertions(+), 29 deletions(-) diff --git a/lib/defs.js b/lib/defs.js index 785f8974..70614090 100644 --- a/lib/defs.js +++ b/lib/defs.js @@ -85,7 +85,7 @@ type: '*' }, { name: 'type', - types: ['string', 'hash'], + types: ['string', 'raw-buffer-properties'], optional: true }, { name: 'callback', diff --git a/lib/obtain.js b/lib/obtain.js index a983e388..107f8624 100644 --- a/lib/obtain.js +++ b/lib/obtain.js @@ -29,30 +29,12 @@ }); } else if (source instanceof Buffer) { if(typeof type === 'object') { - if(!type.width) { - throw Error("Missing width"); - } - if(!type.height) { - throw Error("Missing height"); - } - if(typeof type.width !== "number") { - throw Error("Width must be numeric"); - } - if(typeof type.height !== "number") { - throw Error("Height must be numeric"); - } var channelSize = type.width * type.height; - var numChannels = 3; - var size = channelSize * numChannels; - var bufferSize = source.length; - if(size !== bufferSize) { - numChannels++; - size += channelSize; - } - if(size !== bufferSize) { - throw Error("Invalid width or height"); + var numChannels = source.length / channelSize; + if (numChannels !== parseInt(numChannels) || numChannels < 1 || numChannels > 4) { + throw Error("Buffer size does not match width and height"); } - callback(null, new Image(source, type.width, type.height, (numChannels === 4))); + callback(null, new Image(source, type.width, type.height, (numChannels % 2 === 0))); } else { var opener = getOpener(type); opener(source, function(err, pixelsBuf, width, height, channels, trans) { diff --git a/lib/util.js b/lib/util.js index 3424e211..56541acc 100644 --- a/lib/util.js +++ b/lib/util.js @@ -8,6 +8,7 @@ decree.register('interpolation', validateInterpolation); decree.register('axes', validateAxes); decree.register('image', validateImage); + decree.register('raw-buffer-properties', validateRawBufferProperties); function undefinedFilter(v) { return v !== undefined; @@ -49,6 +50,16 @@ return true; } + function validateRawBufferProperties(rawBufferProperties) { + if (!(rawBufferProperties.width === parseInt(rawBufferProperties.width) && rawBufferProperties.width > 0)){ + return false; + } + if (!(rawBufferProperties.height === parseInt(rawBufferProperties.height) && rawBufferProperties.height > 0)){ + return false; + } + return true; + } + function normalizeColor(color) { if (typeof color === 'string') { color = defs.colors[color]; diff --git a/tests/00.argsValidation/001.open.js b/tests/00.argsValidation/001.open.js index 4c10c6da..a56e0578 100644 --- a/tests/00.argsValidation/001.open.js +++ b/tests/00.argsValidation/001.open.js @@ -69,19 +69,19 @@ describe('lwip.open arguments validation', function() { var buffer; before(function(done) { - buffer = new Buffer(100 * 100 * 4); + buffer = new Buffer(120 * 120); done(); }); describe('without width', function() { it('should throw an error', function() { - lwip.open.bind(lwip, buffer, { height: 100 }, function() {}).should.throwError(); + lwip.open.bind(lwip, buffer, { height: 120 }, function() {}).should.throwError(); }); }); describe('without height', function() { it('should throw an error', function() { - lwip.open.bind(lwip, buffer, { width: 100 }, function() {}).should.throwError(); + lwip.open.bind(lwip, buffer, { width: 120 }, function() {}).should.throwError(); }); }); @@ -93,13 +93,13 @@ describe('lwip.open arguments validation', function() { describe('with non numeric width', function() { it('should throw an error', function() { - lwip.open.bind(lwip, buffer, { width: "lorem", height: 100 }, function() {}).should.throwError(); + lwip.open.bind(lwip, buffer, { width: "lorem", height: 120 }, function() {}).should.throwError(); }); }); describe('with non numeric height', function() { it('should throw an error', function() { - lwip.open.bind(lwip, buffer, { width: 100, height: "lorem" }, function() {}).should.throwError(); + lwip.open.bind(lwip, buffer, { width: 120, height: "lorem" }, function() {}).should.throwError(); }); }); @@ -109,12 +109,57 @@ describe('lwip.open arguments validation', function() { }); }); + describe('with negative width', function() { + it('should throw an error', function() { + lwip.open.bind(lwip, buffer, { width: -120, height: 120 }, function() {}).should.throwError(); + }); + }); + + describe('with negative height', function() { + it('should throw an error', function() { + lwip.open.bind(lwip, buffer, { width: 120, height: -120 }, function() {}).should.throwError(); + }); + }); + + describe('with negative width and height', function() { + it('should throw an error', function() { + lwip.open.bind(lwip, buffer, { width: -120, height: -120 }, function() {}).should.throwError(); + }); + }); + describe('with incorrect width and height', function() { it('should throw an error', function() { lwip.open.bind(lwip, buffer, { width: 123, height: 321 }, function() {}).should.throwError(); }); }); + describe('with correct width and height for 1 channel', function() { + it('should succeed', function() { + lwip.open.bind(lwip, buffer, { width: 120, height: 120 }, function() {}).should.not.throw(); + }); + }); + + describe('with correct width and height for 2 channels', function() { + var newBuffer = new Buffer(120 * 120 * 2) + it('should succeed', function() { + lwip.open.bind(lwip, newBuffer, { width: 120, height: 120 }, function() {}).should.not.throw(); + }); + }); + + describe('with correct width and height for 3 channels', function() { + var newBuffer = new Buffer(120 * 120 * 3) + it('should succeed', function() { + lwip.open.bind(lwip, newBuffer, { width: 120, height: 120 }, function() {}).should.not.throw(); + }); + }); + + describe('with correct width and height for 4 channels', function() { + var newBuffer = new Buffer(120 * 120 * 4) + it('should succeed', function() { + lwip.open.bind(lwip, newBuffer, { width: 120, height: 120 }, function() {}).should.not.throw(); + }); + }); + }); }); diff --git a/tests/02.operations/001.open.js b/tests/02.operations/001.open.js index 7db6a36f..a28a7d1e 100644 --- a/tests/02.operations/001.open.js +++ b/tests/02.operations/001.open.js @@ -191,7 +191,55 @@ describe('lwip.open', function() { describe('raw pixel buffer', function() { - describe('raw pixel buffer', function(){ + describe('grayscale image', function(){ + var buffer; + before(function(done) { + buffer = new Buffer(100 * 100); + done(); + }); + + it('should succeed', function(done) { + lwip.open(buffer, { width: 100, height: 100 }, function(err, img) { + should(err).not.be.Error; + img.should.be.OK; + done(); + }); + }); + }); + + describe('grayscale image with alpha', function(){ + var buffer; + before(function(done) { + buffer = new Buffer(100 * 100 * 2); + done(); + }); + + it('should succeed', function(done) { + lwip.open(buffer, { width: 100, height: 100 }, function(err, img) { + should(err).not.be.Error; + img.should.be.OK; + done(); + }); + }); + }); + + describe('rgb image', function(){ + var buffer; + before(function(done) { + buffer = new Buffer(100 * 100 * 3); + done(); + }); + + it('should succeed', function(done) { + lwip.open(buffer, { width: 100, height: 100 }, function(err, img) { + should(err).not.be.Error; + img.should.be.OK; + done(); + }); + }); + }); + + describe('rgb image with alpha', function(){ var buffer; before(function(done) { buffer = new Buffer(100 * 100 * 4);