From 8408e99aa38a84be63986ca0210eae106d13cbc2 Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Thu, 20 Apr 2023 10:49:39 +0100 Subject: [PATCH] Ensure trim op works with CMYK input #3636 --- docs/changelog.md | 3 +++ src/operations.cc | 28 +++++++++------------------- test/unit/trim.js | 26 ++++++++++++++++++++++++++ 3 files changed, 38 insertions(+), 19 deletions(-) diff --git a/docs/changelog.md b/docs/changelog.md index 662da39b0..1bf8733b3 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -26,6 +26,9 @@ Requires libvips v8.14.2 * Add support for `modulate` operation when using non-sRGB pipeline colourspace. [#3620](https://github.com/lovell/sharp/issues/3620) +* Ensure `trim` operation works with CMYK images (regression in 0.31.0). + [#3636](https://github.com/lovell/sharp/issues/3636) + ### v0.32.0 - 24th March 2023 * Default to using sequential rather than random access read where possible. diff --git a/src/operations.cc b/src/operations.cc index a3b480a53..e59157ff9 100644 --- a/src/operations.cc +++ b/src/operations.cc @@ -269,30 +269,20 @@ namespace sharp { if (image.width() < 3 && image.height() < 3) { throw VError("Image to trim must be at least 3x3 pixels"); } - - // Scale up 8-bit values to match 16-bit input image - double multiplier = sharp::Is16Bit(image.interpretation()) ? 256.0 : 1.0; - threshold *= multiplier; - - std::vector backgroundAlpha(1); if (background.size() == 0) { // Top-left pixel provides the default background colour if none is given background = image.extract_area(0, 0, 1, 1)(0, 0); - multiplier = 1.0; - } - if (HasAlpha(image) && background.size() == 4) { - // Just discard the alpha because flattening the background colour with - // itself (effectively what find_trim() does) gives the same result - backgroundAlpha[0] = background[3] * multiplier; + } else if (sharp::Is16Bit(image.interpretation())) { + for (size_t i = 0; i < background.size(); i++) { + background[i] *= 256.0; + } + threshold *= 256.0; } - if (image.bands() > 2) { - background = { - background[0] * multiplier, - background[1] * multiplier, - background[2] * multiplier - }; + std::vector backgroundAlpha({ background.back() }); + if (HasAlpha(image)) { + background.pop_back(); } else { - background[0] = background[0] * multiplier; + background.resize(image.bands()); } int left, top, width, height; left = image.find_trim(&top, &width, &height, VImage::option() diff --git a/test/unit/trim.js b/test/unit/trim.js index 1025e6971..8d2c76d44 100644 --- a/test/unit/trim.js +++ b/test/unit/trim.js @@ -153,6 +153,32 @@ describe('Trim borders', function () { assert.strictEqual(trimOffsetLeft, -12); }); + it('Ensure CMYK image can be trimmed', async () => { + const cmyk = await sharp({ + create: { + width: 16, + height: 8, + channels: 3, + background: 'red' + } + }) + .extend({ left: 12, right: 24, background: 'blue' }) + .toColourspace('cmyk') + .jpeg() + .toBuffer(); + + const { info } = await sharp(cmyk) + .trim() + .raw() + .toBuffer({ resolveWithObject: true }); + + const { width, height, trimOffsetTop, trimOffsetLeft } = info; + assert.strictEqual(width, 16); + assert.strictEqual(height, 8); + assert.strictEqual(trimOffsetTop, 0); + assert.strictEqual(trimOffsetLeft, -12); + }); + it('Ensure trim of image with all pixels same is no-op', async () => { const { info } = await sharp({ create: {