Skip to content

Commit

Permalink
Concat Stream-based input in single operation for ~+3% perf and less GC
Browse files Browse the repository at this point in the history
  • Loading branch information
lovell committed May 24, 2016
1 parent 8a3b660 commit 331926d
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 14 deletions.
6 changes: 6 additions & 0 deletions docs/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@

Requires libvips v8.3.1

#### v0.15.1 - TBD

* Concat Stream-based input in single operation for ~+3% perf and less GC.
[#429](https://github.com/lovell/sharp/issues/429)
[@papandreou](https://github.com/papandreou)

#### v0.15.0 - 21<sup>st</sup> May 2016

* Use libvips' new Lanczos 3 kernel as default for image reduction.
Expand Down
34 changes: 20 additions & 14 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ var Sharp = function(input, options) {
stream.Duplex.call(this);
this.options = {
// input options
bufferIn: null,
bufferIn: [],
streamIn: false,
sequentialRead: false,
limitInputPixels: maximum.pixels,
Expand Down Expand Up @@ -217,18 +217,8 @@ Sharp.prototype._inputOptions = function(options) {
Sharp.prototype._write = function(chunk, encoding, callback) {
/*jslint unused: false */
if (this.options.streamIn) {
if (typeof chunk === 'object' && chunk instanceof Buffer) {
if (this.options.bufferIn instanceof Buffer) {
// Append to existing Buffer
this.options.bufferIn = Buffer.concat(
[this.options.bufferIn, chunk],
this.options.bufferIn.length + chunk.length
);
} else {
// Create new Buffer
this.options.bufferIn = new Buffer(chunk.length);
chunk.copy(this.options.bufferIn);
}
if (isBuffer(chunk)) {
this.options.bufferIn.push(chunk);
callback();
} else {
callback(new Error('Non-Buffer data on Writable Stream'));
Expand All @@ -238,6 +228,15 @@ Sharp.prototype._write = function(chunk, encoding, callback) {
}
};

/*
Flattens the array of chunks in bufferIn
*/
Sharp.prototype._flattenBufferIn = function() {
if (Array.isArray(this.options.bufferIn)) {
this.options.bufferIn = Buffer.concat(this.options.bufferIn);
}
};

// Weighting to apply to image crop
module.exports.gravity = {
center: 0,
Expand Down Expand Up @@ -882,6 +881,7 @@ Sharp.prototype._pipeline = function(callback) {
if (this.options.streamIn) {
// output=file/buffer, input=stream
this.on('finish', function() {
that._flattenBufferIn();
sharp.pipeline(that.options, callback);
});
} else {
Expand All @@ -894,6 +894,7 @@ Sharp.prototype._pipeline = function(callback) {
if (this.options.streamIn) {
// output=stream, input=stream
this.on('finish', function() {
that._flattenBufferIn();
sharp.pipeline(that.options, function(err, data, info) {
if (err) {
that.emit('error', err);
Expand Down Expand Up @@ -923,6 +924,7 @@ Sharp.prototype._pipeline = function(callback) {
// output=promise, input=stream
return new BluebirdPromise(function(resolve, reject) {
that.on('finish', function() {
that._flattenBufferIn();
sharp.pipeline(that.options, function(err, data) {
if (err) {
reject(err);
Expand Down Expand Up @@ -956,6 +958,7 @@ Sharp.prototype.metadata = function(callback) {
if (typeof callback === 'function') {
if (this.options.streamIn) {
this.on('finish', function() {
that._flattenBufferIn();
sharp.metadata(that.options, callback);
});
} else {
Expand All @@ -966,6 +969,7 @@ Sharp.prototype.metadata = function(callback) {
if (this.options.streamIn) {
return new BluebirdPromise(function(resolve, reject) {
that.on('finish', function() {
that._flattenBufferIn();
sharp.metadata(that.options, function(err, metadata) {
if (err) {
reject(err);
Expand Down Expand Up @@ -994,13 +998,15 @@ Sharp.prototype.metadata = function(callback) {
Cloned instances share the same input.
*/
Sharp.prototype.clone = function() {
var that = this;
// Clone existing options
var clone = new Sharp();
util._extend(clone.options, this.options);
// Pass 'finish' event to clone for Stream-based input
this.on('finish', function() {
// Clone inherits input data
clone.options.bufferIn = this.options.bufferIn;
that._flattenBufferIn();
clone.options.bufferIn = that.options.bufferIn;
clone.emit('finish');
});
return clone;
Expand Down

0 comments on commit 331926d

Please sign in to comment.