Skip to content

Commit

Permalink
Add greyscale option to threshold operation (#480)
Browse files Browse the repository at this point in the history
  • Loading branch information
mhirsch authored and lovell committed Jul 3, 2016
1 parent 4b98dbb commit 85f20c6
Show file tree
Hide file tree
Showing 8 changed files with 55 additions and 3 deletions.
4 changes: 3 additions & 1 deletion docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -391,12 +391,14 @@ When a `sigma` is provided, performs a slower, more accurate sharpen of the L ch
* `flat`, if present, is a Number representing the level of sharpening to apply to "flat" areas, defaulting to a value of 1.0.
* `jagged`, if present, is a Number representing the level of sharpening to apply to "jagged" areas, defaulting to a value of 2.0.

#### threshold([threshold])
#### threshold([threshold], [options])

Converts all pixels in the image to greyscale white or black. Any pixel greather-than-or-equal-to the threshold (0..255) will be white. All others will be black.

* `threshold`, if present, is a Number, representing the level above which pixels will be forced to white.

* `options`, an options object that may contain a boolean `grayscale` or `greyscale`. When `grayscale` is `true`, `threshold` returns a black and white image, and when `false` a color image with each channel thresholded independently. The default is `grayscale: true` when omitted.

#### gamma([gamma])

Apply a gamma correction by reducing the encoding (darken) pre-resize at a factor of `1/gamma` then increasing the encoding (brighten) post-resize at a factor of `gamma`.
Expand Down
11 changes: 10 additions & 1 deletion index.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ var Sharp = function(input, options) {
sharpenFlat: 1,
sharpenJagged: 2,
threshold: 0,
thresholdGrayscale: true,
gamma: 0,
greyscale: false,
normalize: 0,
Expand Down Expand Up @@ -487,7 +488,7 @@ Sharp.prototype.sharpen = function(sigma, flat, jagged) {
return this;
};

Sharp.prototype.threshold = function(threshold) {
Sharp.prototype.threshold = function(threshold, options) {
if (typeof threshold === 'undefined') {
this.options.threshold = 128;
} else if (typeof threshold === 'boolean') {
Expand All @@ -497,6 +498,14 @@ Sharp.prototype.threshold = function(threshold) {
} else {
throw new Error('Invalid threshold (0 to 255) ' + threshold);
}

if(typeof options === 'undefined' ||
options.greyscale === true || options.grayscale === true) {
this.options.thresholdGrayscale = true;
} else {
this.options.thresholdGrayscale = false;
}

return this;
};

Expand Down
7 changes: 7 additions & 0 deletions src/operations.cc
Original file line number Diff line number Diff line change
Expand Up @@ -327,4 +327,11 @@ namespace sharp {
);
}

VImage Threshold(VImage image, double const threshold, bool const thresholdGrayscale) {
if(!thresholdGrayscale) {
return image >= threshold;
}
return image.colourspace(VIPS_INTERPRETATION_B_W) >= threshold;
}

} // namespace sharp
5 changes: 5 additions & 0 deletions src/operations.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@ namespace sharp {
*/
VImage TileCache(VImage image, double const factor);

/*
Threshold an image
*/
VImage Threshold(VImage image, double const threshold, bool const thresholdColor);

} // namespace sharp

#endif // SRC_OPERATIONS_H_
4 changes: 3 additions & 1 deletion src/pipeline.cc
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ using sharp::Blur;
using sharp::Sharpen;
using sharp::EntropyCrop;
using sharp::TileCache;
using sharp::Threshold;

using sharp::ImageType;
using sharp::ImageTypeId;
Expand Down Expand Up @@ -625,7 +626,7 @@ class PipelineWorker : public AsyncWorker {

// Threshold - must happen before blurring, due to the utility of blurring after thresholding
if (shouldThreshold) {
image = image.colourspace(VIPS_INTERPRETATION_B_W) >= baton->threshold;
image = Threshold(image, baton->threshold, baton->thresholdGrayscale);
}

// Blur
Expand Down Expand Up @@ -1107,6 +1108,7 @@ NAN_METHOD(pipeline) {
baton->sharpenFlat = attrAs<double>(options, "sharpenFlat");
baton->sharpenJagged = attrAs<double>(options, "sharpenJagged");
baton->threshold = attrAs<int32_t>(options, "threshold");
baton->thresholdGrayscale = attrAs<bool>(options, "thresholdGrayscale");
baton->gamma = attrAs<double>(options, "gamma");
baton->greyscale = attrAs<bool>(options, "greyscale");
baton->normalize = attrAs<bool>(options, "normalize");
Expand Down
2 changes: 2 additions & 0 deletions src/pipeline.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ struct PipelineBaton {
double sharpenFlat;
double sharpenJagged;
int threshold;
bool thresholdGrayscale;
double gamma;
bool greyscale;
bool normalize;
Expand Down Expand Up @@ -113,6 +114,7 @@ struct PipelineBaton {
sharpenFlat(1.0),
sharpenJagged(2.0),
threshold(0),
thresholdGrayscale(true),
gamma(0.0),
greyscale(false),
normalize(false),
Expand Down
Binary file added test/fixtures/expected/threshold-color-128.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
25 changes: 25 additions & 0 deletions test/unit/threshold.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,21 @@ describe('Threshold', function() {
assert.strictEqual(240, info.height);
fixtures.assertSimilar(fixtures.expected('threshold-128.jpg'), data, done);
});
});

it('threshold grayscale: true (=128)', function(done) {
sharp(fixtures.inputJpg)
.resize(320, 240)
.threshold(128,{'grayscale':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('threshold-128.jpg'), data, done);
});
});


it('threshold default jpeg', function(done) {
sharp(fixtures.inputJpg)
.resize(320, 240)
Expand Down Expand Up @@ -101,6 +114,18 @@ describe('Threshold', function() {
});
}

it('color threshold', function(done) {
sharp(fixtures.inputJpg)
.resize(320, 240)
.threshold(128,{'grayscale':false})
.toBuffer(function(err, data, info) {
assert.strictEqual('jpeg', info.format);
assert.strictEqual(320, info.width);
assert.strictEqual(240, info.height);
fixtures.assertSimilar(fixtures.expected('threshold-color-128.jpg'), data, done);
});
});

it('invalid threshold -1', function() {
assert.throws(function() {
sharp(fixtures.inputJpg).threshold(-1);
Expand Down

0 comments on commit 85f20c6

Please sign in to comment.