Add 'clone' method to snapshot an instance

Cloned instances share a common input
Allows multiple output Streams to use a single input Stream
This commit is contained in:
Lovell Fuller 2015-06-23 13:24:32 +01:00
parent 1091be374e
commit 86490bedfb
4 changed files with 93 additions and 1 deletions

View File

@ -163,6 +163,15 @@ var pipeline = sharp()
readableStream.pipe(pipeline); readableStream.pipe(pipeline);
``` ```
```javascript
var pipeline = sharp().rotate();
pipeline.clone().resize(800, 600).pipe(firstWritableStream);
pipeline.clone().extract(20, 20, 100, 100).pipe(secondWritableStream);
readableStream.pipe(pipeline);
// firstWritableStream receives auto-rotated, resized readableStream
// secondWritableStream receives auto-rotated, extracted region of readableStream
```
```javascript ```javascript
sharp('input.png') sharp('input.png')
.rotate(180) .rotate(180)
@ -347,6 +356,14 @@ Do not process input images where the number of pixels (width * height) exceeds
`pixels` is the integral Number of pixels, with a value between 1 and the default 268402689 (0x3FFF * 0x3FFF). `pixels` is the integral Number of pixels, with a value between 1 and the default 268402689 (0x3FFF * 0x3FFF).
#### clone()
Takes a "snapshot" of the instance, returning a new instance.
Cloned instances inherit the input of their parent instance.
This allows multiple output Streams
and therefore multiple processing pipelines
to share a single input Stream.
### Image transformation options ### Image transformation options
#### resize(width, [height]) #### resize(width, [height])

View File

@ -760,6 +760,24 @@ Sharp.prototype.metadata = function(callback) {
} }
}; };
/*
Clone new instance using existing options.
Cloned instances share the same input.
*/
Sharp.prototype.clone = function() {
// Clone existing options
var clone = new Sharp();
util._extend(clone.options, this.options);
clone.streamIn = false;
// Pass 'finish' event to clone for Stream-based input
this.on('finish', function() {
// Clone inherits input data
clone.options.bufferIn = this.options.bufferIn;
clone.emit('finish');
});
return clone;
};
/* /*
Get and set cache memory and item limits Get and set cache memory and item limits
*/ */

View File

@ -1222,7 +1222,6 @@ NAN_METHOD(pipeline) {
baton->bufferInLength = node::Buffer::Length(buffer); baton->bufferInLength = node::Buffer::Length(buffer);
baton->bufferIn = new char[baton->bufferInLength]; baton->bufferIn = new char[baton->bufferInLength];
memcpy(baton->bufferIn, node::Buffer::Data(buffer), baton->bufferInLength); memcpy(baton->bufferIn, node::Buffer::Data(buffer), baton->bufferInLength);
options->Set(NanNew<String>("bufferIn"), NanNull());
} }
// ICC profile to use when input CMYK image has no embedded profile // ICC profile to use when input CMYK image has no embedded profile
baton->iccProfilePath = *String::Utf8Value(options->Get(NanNew<String>("iccProfilePath"))->ToString()); baton->iccProfilePath = *String::Utf8Value(options->Get(NanNew<String>("iccProfilePath"))->ToString());

58
test/unit/clone.js Executable file
View File

@ -0,0 +1,58 @@
'use strict';
var fs = require('fs');
var assert = require('assert');
var sharp = require('../../index');
var fixtures = require('../fixtures');
sharp.cache(0);
describe('Clone', function() {
it('Read from Stream and write to multiple Streams', function(done) {
var finishEventsExpected = 2;
// Output stream 1
var output1 = fixtures.path('output.multi-stream.1.jpg');
var writable1 = fs.createWriteStream(output1);
writable1.on('finish', function() {
sharp(output1).toBuffer(function(err, data, info) {
if (err) throw err;
assert.strictEqual(true, data.length > 0);
assert.strictEqual(data.length, info.size);
assert.strictEqual('jpeg', info.format);
assert.strictEqual(320, info.width);
assert.strictEqual(240, info.height);
fs.unlinkSync(output1);
finishEventsExpected--;
if (finishEventsExpected === 0) {
done();
}
});
});
// Output stream 2
var output2 = fixtures.path('output.multi-stream.2.jpg');
var writable2 = fs.createWriteStream(output2);
writable2.on('finish', function() {
sharp(output2).toBuffer(function(err, data, info) {
if (err) throw err;
assert.strictEqual(true, data.length > 0);
assert.strictEqual(data.length, info.size);
assert.strictEqual('jpeg', info.format);
assert.strictEqual(100, info.width);
assert.strictEqual(122, info.height);
fs.unlinkSync(output2);
finishEventsExpected--;
if (finishEventsExpected === 0) {
done();
}
});
});
// Create parent instance
var rotator = sharp().rotate(90);
// Cloned instances with differing dimensions
rotator.clone().resize(320, 240).pipe(writable1);
rotator.clone().resize(100).pipe(writable2);
// Go
fs.createReadStream(fixtures.inputJpg).pipe(rotator);
});
});