Add support for Buffer and Stream-based TIFF output

This commit is contained in:
Lovell Fuller 2017-05-04 16:40:49 +01:00
parent 19dd6a997f
commit c8e59f08ec
7 changed files with 42 additions and 6 deletions

View File

@ -38,7 +38,7 @@ Returns **[Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe
## toBuffer ## toBuffer
Write output to a Buffer. Write output to a Buffer.
JPEG, PNG, WebP, and RAW output are supported. JPEG, PNG, WebP, TIFF and RAW output are supported.
By default, the format will match the input image, except GIF and SVG input which become PNG output. By default, the format will match the input image, except GIF and SVG input which become PNG output.
`callback`, if present, gets three arguments `(err, data, info)` where: `callback`, if present, gets three arguments `(err, data, info)` where:

View File

@ -10,6 +10,10 @@ Requires libvips v8.5.2.
[#573](https://github.com/lovell/sharp/issues/573) [#573](https://github.com/lovell/sharp/issues/573)
[@strarsis](https://github.com/strarsis) [@strarsis](https://github.com/strarsis)
* Add support for Buffer and Stream-based TIFF output.
[#587](https://github.com/lovell/sharp/issues/587)
[@strarsis](https://github.com/strarsis)
* Expose warnings from libvips via NODE_DEBUG=sharp environment variable. * Expose warnings from libvips via NODE_DEBUG=sharp environment variable.
[#607](https://github.com/lovell/sharp/issues/607) [#607](https://github.com/lovell/sharp/issues/607)
[@puzrin](https://github.com/puzrin) [@puzrin](https://github.com/puzrin)

View File

@ -22,7 +22,7 @@ the installation of any external runtime dependencies.
This module supports reading JPEG, PNG, WebP, TIFF, GIF and SVG images. This module supports reading JPEG, PNG, WebP, TIFF, GIF and SVG images.
Output images can be in JPEG, PNG and WebP formats as well as uncompressed raw pixel data. Output images can be in JPEG, PNG, WebP and TIFF formats as well as uncompressed raw pixel data.
Streams, Buffer objects and the filesystem can be used for input and output. Streams, Buffer objects and the filesystem can be used for input and output.

View File

@ -32,7 +32,7 @@ const debuglog = util.debuglog('sharp');
* *
* Constructor factory to create an instance of `sharp`, to which further methods are chained. * Constructor factory to create an instance of `sharp`, to which further methods are chained.
* *
* JPEG, PNG or WebP format image data can be streamed out from this object. * JPEG, PNG, WebP or TIFF format image data can be streamed out from this object.
* When using Stream based output, derived attributes are available from the `info` event. * When using Stream based output, derived attributes are available from the `info` event.
* *
* Implements the [stream.Duplex](http://nodejs.org/api/stream.html#stream_class_stream_duplex) class. * Implements the [stream.Duplex](http://nodejs.org/api/stream.html#stream_class_stream_duplex) class.

View File

@ -46,7 +46,7 @@ function toFile (fileOut, callback) {
/** /**
* Write output to a Buffer. * Write output to a Buffer.
* JPEG, PNG, WebP, and RAW output are supported. * JPEG, PNG, WebP, TIFF and RAW output are supported.
* By default, the format will match the input image, except GIF and SVG input which become PNG output. * By default, the format will match the input image, except GIF and SVG input which become PNG output.
* *
* `callback`, if present, gets three arguments `(err, data, info)` where: * `callback`, if present, gets three arguments `(err, data, info)` where:

View File

@ -734,7 +734,7 @@ class PipelineWorker : public Nan::AsyncWorker {
baton->width = image.width(); baton->width = image.width();
baton->height = image.height(); baton->height = image.height();
// Output // Output
if (baton->fileOut == "") { if (baton->fileOut.empty()) {
// Buffer output // Buffer output
if (baton->formatOut == "jpeg" || (baton->formatOut == "input" && inputImageType == ImageType::JPEG)) { if (baton->formatOut == "jpeg" || (baton->formatOut == "input" && inputImageType == ImageType::JPEG)) {
// Write JPEG to buffer // Write JPEG to buffer
@ -786,6 +786,24 @@ class PipelineWorker : public Nan::AsyncWorker {
area->free_fn = nullptr; area->free_fn = nullptr;
vips_area_unref(area); vips_area_unref(area);
baton->formatOut = "webp"; baton->formatOut = "webp";
} else if (baton->formatOut == "tiff" || (baton->formatOut == "input" && inputImageType == ImageType::TIFF)) {
// Cast pixel values to float, if required
if (baton->tiffPredictor == VIPS_FOREIGN_TIFF_PREDICTOR_FLOAT) {
image = image.cast(VIPS_FORMAT_FLOAT);
}
// Write TIFF to buffer
VipsArea *area = VIPS_AREA(image.tiffsave_buffer(VImage::option()
->set("strip", !baton->withMetadata)
->set("Q", baton->tiffQuality)
->set("squash", baton->tiffSquash)
->set("compression", baton->tiffCompression)
->set("predictor", baton->tiffPredictor)));
baton->bufferOut = static_cast<char*>(area->data);
baton->bufferOutLength = area->length;
area->free_fn = nullptr;
vips_area_unref(area);
baton->formatOut = "tiff";
baton->channels = std::min(baton->channels, 3);
} else if (baton->formatOut == "raw" || (baton->formatOut == "input" && inputImageType == ImageType::RAW)) { } else if (baton->formatOut == "raw" || (baton->formatOut == "input" && inputImageType == ImageType::RAW)) {
// Write raw, uncompressed image data to buffer // Write raw, uncompressed image data to buffer
if (baton->greyscale || image.interpretation() == VIPS_INTERPRETATION_B_W) { if (baton->greyscale || image.interpretation() == VIPS_INTERPRETATION_B_W) {

View File

@ -837,6 +837,20 @@ describe('Input/output', function () {
}); });
}); });
it('Save TIFF to Buffer', function (done) {
sharp(fixtures.inputTiff)
.resize(320, 240)
.toBuffer(function (err, data, info) {
if (err) throw err;
assert.strictEqual(true, data.length > 0);
assert.strictEqual(data.length, info.size);
assert.strictEqual('tiff', info.format);
assert.strictEqual(320, info.width);
assert.strictEqual(240, info.height);
done();
});
});
it('Invalid WebP quality throws error', function () { it('Invalid WebP quality throws error', function () {
assert.throws(function () { assert.throws(function () {
sharp().webp({ quality: 101 }); sharp().webp({ quality: 101 });
@ -914,7 +928,7 @@ describe('Input/output', function () {
}); });
}); });
it('TIFF deflate compression with hoizontal predictor shrinks test file', function (done) { it('TIFF deflate compression with horizontal predictor shrinks test file', function (done) {
const startSize = fs.statSync(fixtures.inputTiffUncompressed).size; const startSize = fs.statSync(fixtures.inputTiffUncompressed).size;
sharp(fixtures.inputTiffUncompressed) sharp(fixtures.inputTiffUncompressed)
.tiff({ .tiff({