diff --git a/docs/api-operation.md b/docs/api-operation.md index 5422a194..0fc3a8c6 100644 --- a/docs/api-operation.md +++ b/docs/api-operation.md @@ -134,6 +134,7 @@ when applying a gamma correction. ### Parameters - `gamma` **[Number][1]** value between 1.0 and 3.0. (optional, default `2.2`) +- `gammaOut` ** [Number][1]** value between 1.0 and 3.0. (optional, defaults to same as `gamma`) - Throws **[Error][5]** Invalid parameters diff --git a/docs/changelog.md b/docs/changelog.md index 5a54e0af..3f9b4aa4 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -14,6 +14,10 @@ Requires libvips v8.7.0. [#1438](https://github.com/lovell/sharp/pull/1438) [@Daiz](https://github.com/Daiz) +* Add support for different output gamma from what is used for scaling. + [#1439](https://github.com/lovell/sharp/pull/1439) + [@Daiz](https://github.com/Daiz) + #### v0.21.0 - 4th October 2018 * Deprecate the following resize-related functions: diff --git a/lib/constructor.js b/lib/constructor.js index 24a2eb69..130f3bab 100644 --- a/lib/constructor.js +++ b/lib/constructor.js @@ -136,6 +136,7 @@ const Sharp = function (input, options) { thresholdGrayscale: true, trimThreshold: 0, gamma: 0, + gammaOut: 0, greyscale: false, normalise: 0, booleanBufferIn: null, diff --git a/lib/operation.js b/lib/operation.js index 4eb86f5f..1f03b64d 100644 --- a/lib/operation.js +++ b/lib/operation.js @@ -189,12 +189,13 @@ function flatten (options) { * then increasing the encoding (brighten) post-resize at a factor of `gamma`. * This can improve the perceived brightness of a resized image in non-linear colour spaces. * JPEG and WebP input images will not take advantage of the shrink-on-load performance optimisation - * when applying a gamma correction. + * when applying a gamma correction. Supply a second argument to use a different output gamma value, otherwise the first value is used in both cases. * @param {Number} [gamma=2.2] value between 1.0 and 3.0. + * @param {Number} [gammaOut] value between 1.0 and 3.0. Defaults to same as gamma. * @returns {Sharp} * @throws {Error} Invalid parameters */ -function gamma (gamma) { +function gamma (gamma, gammaOut) { if (!is.defined(gamma)) { // Default gamma correction of 2.2 (sRGB) this.options.gamma = 2.2; @@ -203,6 +204,14 @@ function gamma (gamma) { } else { throw new Error('Invalid gamma correction (1.0 to 3.0) ' + gamma); } + if (!is.defined(gammaOut)) { + // Default gamma correction for output is same as input + this.options.gammaOut = this.options.gamma; + } else if (is.number(gammaOut) && is.inRange(gammaOut, 1, 3)) { + this.options.gammaOut = gammaOut; + } else { + throw new Error('Invalid post gamma correction (1.0 to 3.0) ' + gammaOut); + } return this; } diff --git a/src/pipeline.cc b/src/pipeline.cc index 97597b48..d230b1e4 100644 --- a/src/pipeline.cc +++ b/src/pipeline.cc @@ -612,8 +612,8 @@ class PipelineWorker : public Nan::AsyncWorker { baton->premultiplied = shouldPremultiplyAlpha; // Gamma decoding (brighten) - if (baton->gamma >= 1 && baton->gamma <= 3) { - image = sharp::Gamma(image, baton->gamma); + if (baton->gammaOut >= 1 && baton->gammaOut <= 3) { + image = sharp::Gamma(image, baton->gammaOut); } // Linear adjustment (a * in + b) @@ -1193,6 +1193,7 @@ NAN_METHOD(pipeline) { baton->thresholdGrayscale = AttrTo(options, "thresholdGrayscale"); baton->trimThreshold = AttrTo(options, "trimThreshold"); baton->gamma = AttrTo(options, "gamma"); + baton->gammaOut = AttrTo(options, "gammaOut"); baton->linearA = AttrTo(options, "linearA"); baton->linearB = AttrTo(options, "linearB"); baton->greyscale = AttrTo(options, "greyscale"); diff --git a/src/pipeline.h b/src/pipeline.h index cd763a86..fb18ab2b 100644 --- a/src/pipeline.h +++ b/src/pipeline.h @@ -87,6 +87,7 @@ struct PipelineBaton { double linearA; double linearB; double gamma; + double gammaOut; bool greyscale; bool normalise; bool useExifOrientation; diff --git a/test/fixtures/expected/gamma-in-2.2-out-3.0.jpg b/test/fixtures/expected/gamma-in-2.2-out-3.0.jpg new file mode 100644 index 00000000..50ddb9d1 Binary files /dev/null and b/test/fixtures/expected/gamma-in-2.2-out-3.0.jpg differ diff --git a/test/unit/gamma.js b/test/unit/gamma.js index b5c56e1b..da8feea9 100644 --- a/test/unit/gamma.js +++ b/test/unit/gamma.js @@ -44,6 +44,19 @@ describe('Gamma correction', function () { }); }); + it('input value of 2.2, output value of 3.0', function (done) { + sharp(fixtures.inputJpgWithGammaHoliness) + .resize(129, 111) + .gamma(2.2, 3.0) + .toBuffer(function (err, data, info) { + if (err) throw err; + assert.strictEqual('jpeg', info.format); + assert.strictEqual(129, info.width); + assert.strictEqual(111, info.height); + fixtures.assertSimilar(fixtures.expected('gamma-in-2.2-out-3.0.jpg'), data, { threshold: 6 }, done); + }); + }); + it('alpha transparency', function (done) { sharp(fixtures.inputPngOverlayLayer1) .resize(320) @@ -57,9 +70,15 @@ describe('Gamma correction', function () { }); }); - it('invalid value', function () { + it('invalid first parameter value', function () { assert.throws(function () { sharp(fixtures.inputJpgWithGammaHoliness).gamma(4); }); }); + + it('invalid second parameter value', function () { + assert.throws(function () { + sharp(fixtures.inputJpgWithGammaHoliness).gamma(2.2, 4); + }); + }); });