mirror of
https://github.com/lovell/sharp.git
synced 2025-07-09 10:30:15 +02:00
Implements negation.
This commit is contained in:
parent
5dfeaa9fd1
commit
33a175eafb
@ -272,6 +272,10 @@ The default background is `{r: 0, g: 0, b: 0, a: 1}`, black without transparency
|
|||||||
|
|
||||||
Merge alpha transparency channel, if any, with `background`.
|
Merge alpha transparency channel, if any, with `background`.
|
||||||
|
|
||||||
|
#### negate()
|
||||||
|
|
||||||
|
Produces the "negative" of the image. White => Black, Black => White, Blue => Yellow, etc.
|
||||||
|
|
||||||
#### rotate([angle])
|
#### rotate([angle])
|
||||||
|
|
||||||
Rotate the output image by either an explicit angle or auto-orient based on the EXIF `Orientation` tag.
|
Rotate the output image by either an explicit angle or auto-orient based on the EXIF `Orientation` tag.
|
||||||
|
6
index.js
6
index.js
@ -58,6 +58,7 @@ var Sharp = function(input) {
|
|||||||
// operations
|
// operations
|
||||||
background: [0, 0, 0, 255],
|
background: [0, 0, 0, 255],
|
||||||
flatten: false,
|
flatten: false,
|
||||||
|
negate: false,
|
||||||
blurSigma: 0,
|
blurSigma: 0,
|
||||||
sharpenRadius: 0,
|
sharpenRadius: 0,
|
||||||
sharpenFlat: 1,
|
sharpenFlat: 1,
|
||||||
@ -215,6 +216,11 @@ Sharp.prototype.flatten = function(flatten) {
|
|||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Sharp.prototype.negate = function(negate) {
|
||||||
|
this.options.negate = (typeof negate === 'boolean') ? negate : true;
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
Sharp.prototype.overlayWith = function(overlayPath) {
|
Sharp.prototype.overlayWith = function(overlayPath) {
|
||||||
if (typeof overlayPath !== 'string') {
|
if (typeof overlayPath !== 'string') {
|
||||||
throw new Error('The overlay path must be a string');
|
throw new Error('The overlay path must be a string');
|
||||||
|
@ -100,6 +100,7 @@ struct PipelineBaton {
|
|||||||
std::string interpolator;
|
std::string interpolator;
|
||||||
double background[4];
|
double background[4];
|
||||||
bool flatten;
|
bool flatten;
|
||||||
|
bool negate;
|
||||||
double blurSigma;
|
double blurSigma;
|
||||||
int sharpenRadius;
|
int sharpenRadius;
|
||||||
double sharpenFlat;
|
double sharpenFlat;
|
||||||
@ -138,6 +139,7 @@ struct PipelineBaton {
|
|||||||
canvas(Canvas::CROP),
|
canvas(Canvas::CROP),
|
||||||
gravity(0),
|
gravity(0),
|
||||||
flatten(false),
|
flatten(false),
|
||||||
|
negate(false),
|
||||||
blurSigma(0.0),
|
blurSigma(0.0),
|
||||||
sharpenRadius(0),
|
sharpenRadius(0),
|
||||||
sharpenFlat(1.0),
|
sharpenFlat(1.0),
|
||||||
@ -451,6 +453,16 @@ class PipelineWorker : public AsyncWorker {
|
|||||||
image = flattened;
|
image = flattened;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Negate the colors in the image.
|
||||||
|
if (baton->negate) {
|
||||||
|
VipsImage *negated;
|
||||||
|
if (vips_invert(image, &negated, nullptr)) {
|
||||||
|
return Error();
|
||||||
|
}
|
||||||
|
vips_object_local(hook, negated);
|
||||||
|
image = negated;
|
||||||
|
}
|
||||||
|
|
||||||
// Gamma encoding (darken)
|
// Gamma encoding (darken)
|
||||||
if (baton->gamma >= 1 && baton->gamma <= 3 && !HasAlpha(image)) {
|
if (baton->gamma >= 1 && baton->gamma <= 3 && !HasAlpha(image)) {
|
||||||
VipsImage *gammaEncoded;
|
VipsImage *gammaEncoded;
|
||||||
@ -1212,6 +1224,7 @@ NAN_METHOD(pipeline) {
|
|||||||
baton->interpolator = *Utf8String(Get(options, New("interpolator").ToLocalChecked()).ToLocalChecked());
|
baton->interpolator = *Utf8String(Get(options, New("interpolator").ToLocalChecked()).ToLocalChecked());
|
||||||
// Operators
|
// Operators
|
||||||
baton->flatten = To<bool>(Get(options, New("flatten").ToLocalChecked()).ToLocalChecked()).FromJust();
|
baton->flatten = To<bool>(Get(options, New("flatten").ToLocalChecked()).ToLocalChecked()).FromJust();
|
||||||
|
baton->negate = To<bool>(Get(options, New("negate").ToLocalChecked()).ToLocalChecked()).FromJust();
|
||||||
baton->blurSigma = To<double>(Get(options, New("blurSigma").ToLocalChecked()).ToLocalChecked()).FromJust();
|
baton->blurSigma = To<double>(Get(options, New("blurSigma").ToLocalChecked()).ToLocalChecked()).FromJust();
|
||||||
baton->sharpenRadius = To<int32_t>(Get(options, New("sharpenRadius").ToLocalChecked()).ToLocalChecked()).FromJust();
|
baton->sharpenRadius = To<int32_t>(Get(options, New("sharpenRadius").ToLocalChecked()).ToLocalChecked()).FromJust();
|
||||||
baton->sharpenFlat = To<double>(Get(options, New("sharpenFlat").ToLocalChecked()).ToLocalChecked()).FromJust();
|
baton->sharpenFlat = To<double>(Get(options, New("sharpenFlat").ToLocalChecked()).ToLocalChecked()).FromJust();
|
||||||
|
BIN
test/fixtures/expected/negate-alpha.png
vendored
Normal file
BIN
test/fixtures/expected/negate-alpha.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 10 KiB |
BIN
test/fixtures/expected/negate-trans.png
vendored
Normal file
BIN
test/fixtures/expected/negate-trans.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.0 KiB |
BIN
test/fixtures/expected/negate-trans.webp
vendored
Normal file
BIN
test/fixtures/expected/negate-trans.webp
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 50 KiB |
BIN
test/fixtures/expected/negate.jpg
vendored
Normal file
BIN
test/fixtures/expected/negate.jpg
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
BIN
test/fixtures/expected/negate.png
vendored
Normal file
BIN
test/fixtures/expected/negate.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 45 KiB |
BIN
test/fixtures/expected/negate.webp
vendored
Normal file
BIN
test/fixtures/expected/negate.webp
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 22 KiB |
107
test/unit/negate.js
Normal file
107
test/unit/negate.js
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
var assert = require('assert');
|
||||||
|
|
||||||
|
var sharp = require('../../index');
|
||||||
|
var fixtures = require('../fixtures');
|
||||||
|
|
||||||
|
sharp.cache(0);
|
||||||
|
|
||||||
|
describe('Negate', function() {
|
||||||
|
it('negate (jpeg)', function(done) {
|
||||||
|
sharp(fixtures.inputJpg)
|
||||||
|
.resize(320, 240)
|
||||||
|
.negate()
|
||||||
|
.toBuffer(function(err, data, info) {
|
||||||
|
assert.strictEqual('jpeg', info.format);
|
||||||
|
assert.strictEqual(320, info.width);
|
||||||
|
assert.strictEqual(240, info.height);
|
||||||
|
fixtures.assertSimilar(fixtures.expected('negate.jpg'), data, done);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('negate (png)', function(done) {
|
||||||
|
sharp(fixtures.inputPng)
|
||||||
|
.resize(320, 240)
|
||||||
|
.negate()
|
||||||
|
.toBuffer(function(err, data, info) {
|
||||||
|
assert.strictEqual('png', info.format);
|
||||||
|
assert.strictEqual(320, info.width);
|
||||||
|
assert.strictEqual(240, info.height);
|
||||||
|
fixtures.assertSimilar(fixtures.expected('negate.png'), data, done);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('negate (png, trans)', function(done) {
|
||||||
|
sharp(fixtures.inputPngWithTransparency)
|
||||||
|
.resize(320, 240)
|
||||||
|
.negate()
|
||||||
|
.toBuffer(function(err, data, info) {
|
||||||
|
assert.strictEqual('png', info.format);
|
||||||
|
assert.strictEqual(320, info.width);
|
||||||
|
assert.strictEqual(240, info.height);
|
||||||
|
fixtures.assertSimilar(fixtures.expected('negate-trans.png'), data, done);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('negate (png, alpha)', function(done) {
|
||||||
|
sharp(fixtures.inputPngWithGreyAlpha)
|
||||||
|
.resize(320, 240)
|
||||||
|
.negate()
|
||||||
|
.toBuffer(function(err, data, info) {
|
||||||
|
assert.strictEqual('png', info.format);
|
||||||
|
assert.strictEqual(320, info.width);
|
||||||
|
assert.strictEqual(240, info.height);
|
||||||
|
fixtures.assertSimilar(fixtures.expected('negate-alpha.png'), data, done);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
if (sharp.format.webp.output.file) {
|
||||||
|
it('negate (webp)', function(done) {
|
||||||
|
sharp(fixtures.inputWebP)
|
||||||
|
.resize(320, 240)
|
||||||
|
.negate()
|
||||||
|
.toBuffer(function(err, data, info) {
|
||||||
|
assert.strictEqual('webp', info.format);
|
||||||
|
assert.strictEqual(320, info.width);
|
||||||
|
assert.strictEqual(240, info.height);
|
||||||
|
fixtures.assertSimilar(fixtures.expected('negate.webp'), data, done);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('negate (webp, trans)', function(done) {
|
||||||
|
sharp(fixtures.inputWebPWithTransparency)
|
||||||
|
.resize(320, 240)
|
||||||
|
.negate()
|
||||||
|
.toBuffer(function(err, data, info) {
|
||||||
|
assert.strictEqual('webp', info.format);
|
||||||
|
assert.strictEqual(320, info.width);
|
||||||
|
assert.strictEqual(240, info.height);
|
||||||
|
fixtures.assertSimilar(fixtures.expected('negate-trans.webp'), data, done);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
it('negate (true)', function(done) {
|
||||||
|
sharp(fixtures.inputJpg)
|
||||||
|
.resize(320, 240)
|
||||||
|
.negate(true)
|
||||||
|
.toBuffer(function(err, data, info) {
|
||||||
|
assert.strictEqual('jpeg', info.format);
|
||||||
|
assert.strictEqual(320, info.width);
|
||||||
|
assert.strictEqual(240, info.height);
|
||||||
|
fixtures.assertSimilar(fixtures.expected('negate.jpg'), data, done);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('negate (false)', function(done) {
|
||||||
|
var output = fixtures.path('output.unmodified-by-negate.png');
|
||||||
|
sharp(fixtures.inputJpgWithLowContrast)
|
||||||
|
.negate(false)
|
||||||
|
.toFile(output, function(err, info) {
|
||||||
|
if (err) done(err);
|
||||||
|
fixtures.assertMaxColourDistance(output, fixtures.inputJpgWithLowContrast, 0);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
Loading…
x
Reference in New Issue
Block a user