Improve extractChannel support for 16-bit output #3453

This commit is contained in:
Lovell Fuller 2022-11-15 15:00:32 +00:00
parent 789d4851ea
commit 01ffa80338
5 changed files with 38 additions and 39 deletions

View File

@ -12,6 +12,9 @@ Requires libvips v8.13.3
* Prevent possible race condition awaiting metadata of Stream-based input. * Prevent possible race condition awaiting metadata of Stream-based input.
[#3451](https://github.com/lovell/sharp/issues/3451) [#3451](https://github.com/lovell/sharp/issues/3451)
* Improve `extractChannel` support for 16-bit output colourspaces.
[#3453](https://github.com/lovell/sharp/issues/3453)
### v0.31.2 - 4th November 2022 ### v0.31.2 - 4th November 2022
* Upgrade to libvips v8.13.3 for upstream bug fixes. * Upgrade to libvips v8.13.3 for upstream bug fixes.

View File

@ -98,7 +98,7 @@ function extractChannel (channel) {
} else { } else {
throw is.invalidParameterError('channel', 'integer or one of: red, green, blue, alpha', channel); throw is.invalidParameterError('channel', 'integer or one of: red, green, blue, alpha', channel);
} }
return this.toColourspace('b-w'); return this;
} }
/** /**

View File

@ -701,24 +701,6 @@ class PipelineWorker : public Napi::AsyncWorker {
image = sharp::Tint(image, baton->tintA, baton->tintB); image = sharp::Tint(image, baton->tintA, baton->tintB);
} }
// Extract an image channel (aka vips band)
if (baton->extractChannel > -1) {
if (baton->extractChannel >= image.bands()) {
if (baton->extractChannel == 3 && sharp::HasAlpha(image)) {
baton->extractChannel = image.bands() - 1;
} else {
(baton->err).append("Cannot extract channel from image. Too few channels in image.");
return Error();
}
}
VipsInterpretation const interpretation = sharp::Is16Bit(image.interpretation())
? VIPS_INTERPRETATION_GREY16
: VIPS_INTERPRETATION_B_W;
image = image
.extract_band(baton->extractChannel)
.copy(VImage::option()->set("interpretation", interpretation));
}
// Remove alpha channel, if any // Remove alpha channel, if any
if (baton->removeAlpha) { if (baton->removeAlpha) {
image = sharp::RemoveAlpha(image); image = sharp::RemoveAlpha(image);
@ -744,6 +726,26 @@ class PipelineWorker : public Napi::AsyncWorker {
} }
} }
// Extract channel
if (baton->extractChannel > -1) {
if (baton->extractChannel >= image.bands()) {
if (baton->extractChannel == 3 && sharp::HasAlpha(image)) {
baton->extractChannel = image.bands() - 1;
} else {
(baton->err)
.append("Cannot extract channel ").append(std::to_string(baton->extractChannel))
.append(" from image with channels 0-").append(std::to_string(image.bands() - 1));
return Error();
}
}
VipsInterpretation colourspace = sharp::Is16Bit(image.interpretation())
? VIPS_INTERPRETATION_GREY16
: VIPS_INTERPRETATION_B_W;
image = image
.extract_band(baton->extractChannel)
.copy(VImage::option()->set("interpretation", colourspace));
}
// Apply output ICC profile // Apply output ICC profile
if (!baton->withMetadataIcc.empty()) { if (!baton->withMetadataIcc.empty()) {
image = image.icc_transform( image = image.icc_transform(

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

View File

@ -54,19 +54,13 @@ describe('Image channel extraction', function () {
}); });
}); });
it('With colorspace conversion', function (done) { it('With colorspace conversion', async () => {
const output = fixtures.path('output.extract-lch.jpg'); const [chroma] = await sharp({ create: { width: 1, height: 1, channels: 3, background: 'red' } })
sharp(fixtures.inputJpg)
.extractChannel(1)
.toColourspace('lch') .toColourspace('lch')
.resize(320, 240, { fastShrinkOnLoad: false }) .extractChannel(1)
.toFile(output, function (err, info) { .toBuffer();
if (err) throw err;
assert.strictEqual(320, info.width); assert.strictEqual(chroma, 104);
assert.strictEqual(240, info.height);
fixtures.assertMaxColourDistance(output, fixtures.expected('extract-lch.jpg'), 9);
done();
});
}); });
it('Alpha from 16-bit PNG', function (done) { it('Alpha from 16-bit PNG', function (done) {
@ -108,12 +102,12 @@ describe('Image channel extraction', function () {
}); });
}); });
it('Non-existent channel', function (done) { it('Non-existent channel', async () =>
sharp(fixtures.inputPng) await assert.rejects(
.extractChannel(1) () => sharp({ create: { width: 1, height: 1, channels: 3, background: 'red' } })
.toBuffer(function (err) { .extractChannel(3)
assert(err instanceof Error); .toBuffer(),
done(); /Cannot extract channel 3 from image with channels 0-2/
}); )
}); );
}); });