Fix tint op by ensuring LAB and allowing negative values #1235

Add test cases for more tint colours and input interpretations
This commit is contained in:
Lovell Fuller 2018-05-23 20:51:47 +01:00
parent b1a9bf10a2
commit 54a71fc142
9 changed files with 55 additions and 9 deletions

View File

@ -4,6 +4,12 @@
Requires libvips v8.6.1. Requires libvips v8.6.1.
#### v0.20.3 - TBD
* Fix tint operation by ensuring LAB interpretation and allowing negative values.
[#1235](https://github.com/lovell/sharp/issues/1235)
[@wezside](https://github.com/wezside)
#### v0.20.2 - 28<sup>th</sup> April 2018 #### v0.20.2 - 28<sup>th</sup> April 2018
* Add tint operation to set image chroma. * Add tint operation to set image chroma.

View File

@ -152,8 +152,8 @@ const Sharp = function (input, options) {
fastShrinkOnLoad: true, fastShrinkOnLoad: true,
// operations // operations
background: [0, 0, 0, 255], background: [0, 0, 0, 255],
tintA: 0, tintA: 128,
tintB: 0, tintB: 128,
flatten: false, flatten: false,
negate: false, negate: false,
medianSize: 0, medianSize: 0,

View File

@ -161,13 +161,14 @@ namespace sharp {
if (typeBeforeTint == VIPS_INTERPRETATION_RGB) { if (typeBeforeTint == VIPS_INTERPRETATION_RGB) {
typeBeforeTint = VIPS_INTERPRETATION_sRGB; typeBeforeTint = VIPS_INTERPRETATION_sRGB;
} }
// Create 2 band image with every pixel set to the tint chroma
std::vector<double> chromaPixel {a, b};
VImage chroma = image.new_from_image(chromaPixel);
// Extract luminance // Extract luminance
VImage luminance = image.colourspace(VIPS_INTERPRETATION_LAB)[0]; VImage luminance = image.colourspace(VIPS_INTERPRETATION_LAB)[0];
// Create the tinted version by combining the L from the original and the chroma from the tint // Create the tinted version by combining the L from the original and the chroma from the tint
VImage tinted = luminance.bandjoin(chroma).colourspace(typeBeforeTint); std::vector<double> chroma {a, b};
VImage tinted = luminance
.bandjoin(chroma)
.copy(VImage::option()->set("interpretation", VIPS_INTERPRETATION_LAB))
.colourspace(typeBeforeTint);
// Attach original alpha channel, if any // Attach original alpha channel, if any
if (HasAlpha(image)) { if (HasAlpha(image)) {
// Extract original alpha channel // Extract original alpha channel

View File

@ -683,7 +683,7 @@ class PipelineWorker : public Nan::AsyncWorker {
} }
// Tint the image // Tint the image
if (baton->tintA > 0 || baton->tintB > 0) { if (baton->tintA < 128.0 || baton->tintB < 128.0) {
image = sharp::Tint(image, baton->tintA, baton->tintB); image = sharp::Tint(image, baton->tintA, baton->tintB);
} }

View File

@ -157,8 +157,8 @@ struct PipelineBaton {
cropOffsetLeft(0), cropOffsetLeft(0),
cropOffsetTop(0), cropOffsetTop(0),
premultiplied(false), premultiplied(false),
tintA(0.0), tintA(128.0),
tintB(0.0), tintB(128.0),
flatten(false), flatten(false),
negate(false), negate(false),
blurSigma(0.0), blurSigma(0.0),

BIN
test/fixtures/expected/tint-blue.jpg vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
test/fixtures/expected/tint-cmyk.jpg vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

BIN
test/fixtures/expected/tint-green.jpg vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -19,6 +19,32 @@ describe('Tint', function () {
}); });
}); });
it('tints rgb image green', function (done) {
const output = fixtures.path('output.tint-green.jpg');
sharp(fixtures.inputJpg)
.resize(320, 240)
.tint('#00FF00')
.toFile(output, function (err, info) {
if (err) throw err;
assert.strictEqual(true, info.size > 0);
fixtures.assertMaxColourDistance(output, fixtures.expected('tint-green.jpg'), 10);
done();
});
});
it('tints rgb image blue', function (done) {
const output = fixtures.path('output.tint-blue.jpg');
sharp(fixtures.inputJpg)
.resize(320, 240)
.tint('#0000FF')
.toFile(output, function (err, info) {
if (err) throw err;
assert.strictEqual(true, info.size > 0);
fixtures.assertMaxColourDistance(output, fixtures.expected('tint-blue.jpg'), 10);
done();
});
});
it('tints rgb image with sepia tone', function (done) { it('tints rgb image with sepia tone', function (done) {
const output = fixtures.path('output.tint-sepia.jpg'); const output = fixtures.path('output.tint-sepia.jpg');
sharp(fixtures.inputJpg) sharp(fixtures.inputJpg)
@ -60,4 +86,17 @@ describe('Tint', function () {
done(); done();
}); });
}); });
it('tints cmyk image red', function (done) {
const output = fixtures.path('output.tint-cmyk.jpg');
sharp(fixtures.inputJpgWithCmykProfile)
.resize(320, 240)
.tint('#FF0000')
.toFile(output, function (err, info) {
if (err) throw err;
assert.strictEqual(true, info.size > 0);
fixtures.assertMaxColourDistance(output, fixtures.expected('tint-cmyk.jpg'), 10);
done();
});
});
}); });