From a2314c4aa0db25fd2f812df439e3d5e8de8757c7 Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Sat, 15 Feb 2020 11:46:13 +0000 Subject: [PATCH] Ensure RGBA LZW TIFF info.channel count #2064 --- docs/changelog.md | 3 +++ src/pipeline.cc | 4 ++-- test/unit/tiff.js | 37 +++++++++++++++++++++++++++++++++++++ 3 files changed, 42 insertions(+), 2 deletions(-) diff --git a/docs/changelog.md b/docs/changelog.md index 297b4b27..73e1fc78 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -9,6 +9,9 @@ Requires libvips v8.9.0. * Prevent use of sequentialRead for EXIF-based rotate operation. [#2042](https://github.com/lovell/sharp/issues/2042) +* Ensure RGBA LZW TIFF returns correct channel count. + [#2064](https://github.com/lovell/sharp/issues/2064) + ### v0.24.0 - 16th January 2020 * Drop support for Node.js 8. diff --git a/src/pipeline.cc b/src/pipeline.cc index 5c38beae..c6c22a98 100644 --- a/src/pipeline.cc +++ b/src/pipeline.cc @@ -764,6 +764,7 @@ class PipelineWorker : public Nan::AsyncWorker { // Write TIFF to buffer if (baton->tiffCompression == VIPS_FOREIGN_TIFF_COMPRESSION_JPEG) { sharp::AssertImageTypeDimensions(image, ImageType::JPEG); + baton->channels = std::min(baton->channels, 3); } // Cast pixel values to float, if required if (baton->tiffPredictor == VIPS_FOREIGN_TIFF_PREDICTOR_FLOAT) { @@ -786,7 +787,6 @@ class PipelineWorker : public Nan::AsyncWorker { area->free_fn = nullptr; vips_area_unref(area); baton->formatOut = "tiff"; - baton->channels = std::min(baton->channels, 3); } else if (baton->formatOut == "heif" || (baton->formatOut == "input" && inputImageType == ImageType::HEIF)) { // Write HEIF to buffer VipsArea *area = VIPS_AREA(image.heifsave_buffer(VImage::option() @@ -887,6 +887,7 @@ class PipelineWorker : public Nan::AsyncWorker { // Write TIFF to file if (baton->tiffCompression == VIPS_FOREIGN_TIFF_COMPRESSION_JPEG) { sharp::AssertImageTypeDimensions(image, ImageType::JPEG); + baton->channels = std::min(baton->channels, 3); } image.tiffsave(const_cast(baton->fileOut.data()), VImage::option() ->set("strip", !baton->withMetadata) @@ -901,7 +902,6 @@ class PipelineWorker : public Nan::AsyncWorker { ->set("xres", baton->tiffXres) ->set("yres", baton->tiffYres)); baton->formatOut = "tiff"; - baton->channels = std::min(baton->channels, 3); } else if (baton->formatOut == "heif" || (mightMatchInput && isHeif) || (willMatchInput && inputImageType == ImageType::HEIF)) { // Write HEIF to file diff --git a/test/unit/tiff.js b/test/unit/tiff.js index a5bf0208..5c11eb6a 100644 --- a/test/unit/tiff.js +++ b/test/unit/tiff.js @@ -208,11 +208,48 @@ describe('TIFF', function () { .toFile(fixtures.outputTiff, (err, info) => { if (err) throw err; assert.strictEqual('tiff', info.format); + assert.strictEqual(3, info.channels); assert(info.size < startSize); rimraf(fixtures.outputTiff, done); }); }); + it('TIFF LZW RGBA toFile', () => + sharp({ + create: { + width: 1, + height: 1, + channels: 4, + background: 'red' + } + }) + .tiff({ + compression: 'lzw' + }) + .toFile(fixtures.outputTiff) + .then(info => { + assert.strictEqual(4, info.channels); + }) + ); + + it('TIFF LZW RGBA toBuffer', () => + sharp({ + create: { + width: 1, + height: 1, + channels: 4, + background: 'red' + } + }) + .tiff({ + compression: 'lzw' + }) + .toBuffer({ resolveWithObject: true }) + .then(({ info }) => { + assert.strictEqual(4, info.channels); + }) + ); + it('TIFF ccittfax4 compression shrinks b-w test file', function (done) { const startSize = fs.statSync(fixtures.inputTiff).size; sharp(fixtures.inputTiff)