From 397ee492d922e2bc9c871ae964bfe440f582ce07 Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Thu, 18 Apr 2024 11:05:04 +0100 Subject: [PATCH] Ensure extend op is sequential for multi-page TIFF #4069 --- docs/changelog.md | 3 +++ src/pipeline.cc | 1 + test/unit/extend.js | 47 +++++++++++++++++++++++++++++++-------------- 3 files changed, 37 insertions(+), 14 deletions(-) diff --git a/docs/changelog.md b/docs/changelog.md index 5361e5126..d3e63c8ae 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -18,6 +18,9 @@ Requires libvips v8.15.2 * Expose `bilinear` resizing kernel (and interpolator). [#4061](https://github.com/lovell/sharp/issues/4061) +* Ensure `extend` operation stays sequential for multi-page TIFF (regression in 0.32.0). + [#4069](https://github.com/lovell/sharp/issues/4069) + ### v0.33.3 - 23rd March 2024 * Upgrade to libvips v8.15.2 for upstream bug fixes. diff --git a/src/pipeline.cc b/src/pipeline.cc index a9c68f123..c80988cd2 100644 --- a/src/pipeline.cc +++ b/src/pipeline.cc @@ -566,6 +566,7 @@ class PipelineWorker : public Napi::AsyncWorker { std::vector background; std::tie(image, background) = sharp::ApplyAlpha(image, baton->extendBackground, shouldPremultiplyAlpha); + image = sharp::StaySequential(image, baton->input->access, nPages > 1); image = nPages > 1 ? sharp::EmbedMultiPage(image, baton->extendLeft, baton->extendTop, baton->width, baton->height, diff --git a/test/unit/extend.js b/test/unit/extend.js index 4d57ba977..3ddbd0e14 100644 --- a/test/unit/extend.js +++ b/test/unit/extend.js @@ -73,20 +73,6 @@ describe('Extend', function () { }); }); - it('extend top with mirroring uses ordered read', async () => { - const data = await sharp(fixtures.inputJpg) - .extend({ - extendWith: 'mirror', - top: 1 - }) - .png({ compressionLevel: 0 }) - .toBuffer(); - - const { width, height } = await sharp(data).metadata(); - assert.strictEqual(2725, width); - assert.strictEqual(2226, height); - }); - it(`extend sides unequally with RGBA (${extendWith})`, function (done) { sharp(fixtures.inputPngWithTransparency16bit) .resize(120) @@ -127,6 +113,39 @@ describe('Extend', function () { }); }); + it('extend top with mirroring uses ordered read', async () => { + const data = await sharp(fixtures.inputJpg) + .extend({ + extendWith: 'mirror', + top: 1 + }) + .png({ compressionLevel: 0 }) + .toBuffer(); + + const { width, height } = await sharp(data).metadata(); + assert.strictEqual(2725, width); + assert.strictEqual(2226, height); + }); + + it('multi-page extend uses ordered read', async () => { + const multiPageTiff = await sharp(fixtures.inputGifAnimated, { animated: true }) + .resize({ width: 8, height: 48 }) + .tiff() + .toBuffer(); + + const data = await sharp(multiPageTiff, { pages: -1 }) + .extend({ + background: 'red', + top: 1 + }) + .png({ compressionLevel: 0 }) + .toBuffer(); + + const { width, height } = await sharp(data).metadata(); + assert.strictEqual(8, width); + assert.strictEqual(1470, height); + }); + it('missing parameter fails', function () { assert.throws(function () { sharp().extend();