Ensure image is unpremultiplied before composite #3334

This commit is contained in:
Lovell Fuller 2022-08-21 17:51:05 +01:00
parent a44168c8c7
commit a618ce7a15
3 changed files with 37 additions and 12 deletions

View File

@ -52,6 +52,9 @@ Requires libvips v8.13.0
Emit warnings when previous calls in the same pipeline will be ignored. Emit warnings when previous calls in the same pipeline will be ignored.
[#3319](https://github.com/lovell/sharp/issues/3319) [#3319](https://github.com/lovell/sharp/issues/3319)
* Ensure resized image is unpremultiplied before composite.
[#3334](https://github.com/lovell/sharp/issues/3334)
## v0.30 - *dresser* ## v0.30 - *dresser*
Requires libvips v8.12.2 Requires libvips v8.12.2

View File

@ -590,6 +590,18 @@ class PipelineWorker : public Napi::AsyncWorker {
baton->sharpenX1, baton->sharpenY2, baton->sharpenY3); baton->sharpenX1, baton->sharpenY2, baton->sharpenY3);
} }
// Reverse premultiplication after all transformations
if (shouldPremultiplyAlpha) {
image = image.unpremultiply();
// Cast pixel values to integer
if (sharp::Is16Bit(image.interpretation())) {
image = image.cast(VIPS_FORMAT_USHORT);
} else {
image = image.cast(VIPS_FORMAT_UCHAR);
}
}
baton->premultiplied = shouldPremultiplyAlpha;
// Composite // Composite
if (shouldComposite) { if (shouldComposite) {
std::vector<VImage> images = { image }; std::vector<VImage> images = { image };
@ -670,18 +682,6 @@ class PipelineWorker : public Napi::AsyncWorker {
image = VImage::composite(images, modes, VImage::option()->set("x", xs)->set("y", ys)); image = VImage::composite(images, modes, VImage::option()->set("x", xs)->set("y", ys));
} }
// Reverse premultiplication after all transformations:
if (shouldPremultiplyAlpha) {
image = image.unpremultiply();
// Cast pixel values to integer
if (sharp::Is16Bit(image.interpretation())) {
image = image.cast(VIPS_FORMAT_USHORT);
} else {
image = image.cast(VIPS_FORMAT_UCHAR);
}
}
baton->premultiplied = shouldPremultiplyAlpha;
// Gamma decoding (brighten) // Gamma decoding (brighten)
if (baton->gammaOut >= 1 && baton->gammaOut <= 3) { if (baton->gammaOut >= 1 && baton->gammaOut <= 3) {
image = sharp::Gamma(image, baton->gammaOut); image = sharp::Gamma(image, baton->gammaOut);

View File

@ -447,4 +447,26 @@ describe('composite', () => {
assert.strictEqual(info.width, 40); assert.strictEqual(info.width, 40);
assert.strictEqual(info.height, 40); assert.strictEqual(info.height, 40);
}); });
it('Ensure implict unpremultiply after resize but before composite', async () => {
const [r, g, b, a] = await sharp({
create: {
width: 1, height: 1, channels: 4, background: 'saddlebrown'
}
})
.resize({ width: 8 })
.composite([{
input: Buffer.from([255, 255, 255, 128]),
raw: { width: 1, height: 1, channels: 4 },
tile: true,
blend: 'dest-in'
}])
.raw()
.toBuffer();
assert.strictEqual(r, 139);
assert.strictEqual(g, 69);
assert.strictEqual(b, 19);
assert.strictEqual(a, 128);
});
}); });