From fe2b298a2f724ec4b2b148c6a3b8ba0c3f08f783 Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Fri, 15 Dec 2023 12:13:57 +0000 Subject: [PATCH] Emit warning for invalid ICC profile #3895 --- docs/changelog.md | 3 +++ src/pipeline.cc | 14 +++++++++----- test/fixtures/invalid-illuminant.icc | Bin 0 -> 672 bytes test/unit/metadata.js | 18 ++++++++++++++++++ 4 files changed, 30 insertions(+), 5 deletions(-) create mode 100644 test/fixtures/invalid-illuminant.icc diff --git a/docs/changelog.md b/docs/changelog.md index 352336b7d..9c1c80e8a 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -9,6 +9,9 @@ Requires libvips v8.15.0 * Add support for Yarn Plug'n'Play filesystem layout. [#3888](https://github.com/lovell/sharp/issues/3888) +* Emit warning when attempting to use invalid ICC profiles. + [#3895](https://github.com/lovell/sharp/issues/3895) + ### v0.33.0 - 29th November 2023 * Drop support for Node.js 14 and 16, now requires Node.js >= 18.17.0 diff --git a/src/pipeline.cc b/src/pipeline.cc index 5a8fc8476..198a7364c 100644 --- a/src/pipeline.cc +++ b/src/pipeline.cc @@ -794,11 +794,15 @@ class PipelineWorker : public Napi::AsyncWorker { // Apply output ICC profile if (!baton->withIccProfile.empty()) { - image = image.icc_transform(const_cast(baton->withIccProfile.data()), VImage::option() - ->set("input_profile", processingProfile) - ->set("embedded", TRUE) - ->set("depth", sharp::Is16Bit(image.interpretation()) ? 16 : 8) - ->set("intent", VIPS_INTENT_PERCEPTUAL)); + try { + image = image.icc_transform(const_cast(baton->withIccProfile.data()), VImage::option() + ->set("input_profile", processingProfile) + ->set("embedded", TRUE) + ->set("depth", sharp::Is16Bit(image.interpretation()) ? 16 : 8) + ->set("intent", VIPS_INTENT_PERCEPTUAL)); + } catch(...) { + sharp::VipsWarningCallback(nullptr, G_LOG_LEVEL_WARNING, "Invalid profile", nullptr); + } } else if (baton->keepMetadata & VIPS_FOREIGN_KEEP_ICC) { image = sharp::SetProfile(image, inputProfile); } diff --git a/test/fixtures/invalid-illuminant.icc b/test/fixtures/invalid-illuminant.icc new file mode 100644 index 0000000000000000000000000000000000000000..8ad73be2531c491950a45f1cea51ed9d2a950b61 GIT binary patch literal 672 zcma))yGz4R6vn?KzJ=03w20DMMGzk}MN#TxA5sy;QbelY&?Yerm?kD^t($KC6N01Y z;3^L8f=dzq2^Sa9#ldqMOS||ukb8dj>NdA3I$?jLZraw+0GaX|OE#JT8mjkBt`3VF_m z9mRI|zn{cwrfI2wxJo=(Rdmutn^#5BXuC#|g^M*n%=KQ`%Kk*k&N^=kZ literal 0 HcmV?d00001 diff --git a/test/unit/metadata.js b/test/unit/metadata.js index 84fe50e5a..820868dde 100644 --- a/test/unit/metadata.js +++ b/test/unit/metadata.js @@ -598,6 +598,24 @@ describe('Image metadata', function () { assert.strictEqual(undefined, metadata.icc); }); + it('transform to invalid ICC profile emits warning', async () => { + const img = sharp({ create }) + .png() + .withIccProfile(fixtures.path('invalid-illuminant.icc')); + + let warningEmitted = ''; + img.on('warning', (warning) => { + warningEmitted = warning; + }); + + const data = await img.toBuffer(); + assert.strictEqual('Invalid profile', warningEmitted); + + const metadata = await sharp(data).metadata(); + assert.strictEqual(3, metadata.channels); + assert.strictEqual(undefined, metadata.icc); + }); + it('Apply CMYK output ICC profile', function (done) { const output = fixtures.path('output.icc-cmyk.jpg'); sharp(fixtures.inputJpg)