Skip to content

Commit

Permalink
Add premultiply option to fromBytes
Browse files Browse the repository at this point in the history
  • Loading branch information
Dane Springmeyer committed Jan 5, 2017
1 parent d2a7271 commit f8d02d0
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 16 deletions.
35 changes: 32 additions & 3 deletions src/mapnik_image.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2385,12 +2385,13 @@ v8::Local<v8::Value> Image::_openSync(Nan::NAN_METHOD_ARGS_TYPE info)
typedef struct {
uv_work_t request;
image_ptr im;
const char *data;
size_t dataLength;
bool error;
std::string error_name;
Nan::Persistent<v8::Object> buffer;
Nan::Persistent<v8::Function> cb;
bool premultiply;
const char *data;
size_t dataLength;
bool error;
} image_mem_ptr_baton_t;

typedef struct {
Expand Down Expand Up @@ -3302,6 +3303,8 @@ v8::Local<v8::Value> Image::_fromBufferSync(Nan::NAN_METHOD_ARGS_TYPE info)
*
* @name fromBytesSync
* @param {Buffer} buffer - image buffer
* @param {Object} [options]
* @param {Boolean} [options.premultiply] - Default false, if true, then the image will be premultiplied before being returned
* @returns {mapnik.Image} image object
* @instance
* @memberof Image
Expand Down Expand Up @@ -3399,13 +3402,36 @@ NAN_METHOD(Image::fromBytes)
return;
}

bool premultiply = false;
if (info.Length() >= 2)
{
if (info[1]->IsObject())
{
v8::Local<v8::Object> options = v8::Local<v8::Object>::Cast(info[1]);
if (options->Has(Nan::New("premultiply").ToLocalChecked()))
{
v8::Local<v8::Value> pre_val = options->Get(Nan::New("premultiply").ToLocalChecked());
if (!pre_val.IsEmpty() && pre_val->IsBoolean())
{
premultiply = pre_val->BooleanValue();
}
else
{
Nan::ThrowTypeError("premultiply option must be a boolean");
return;
}
}
}
}

image_mem_ptr_baton_t *closure = new image_mem_ptr_baton_t();
closure->request.data = closure;
closure->error = false;
closure->cb.Reset(callback.As<v8::Function>());
closure->buffer.Reset(obj.As<v8::Object>());
closure->data = node::Buffer::Data(obj);
closure->dataLength = node::Buffer::Length(obj);
closure->premultiply = premultiply;
uv_queue_work(uv_default_loop(), &closure->request, EIO_FromBytes, (uv_after_work_cb)EIO_AfterFromBytes);
return;
}
Expand All @@ -3420,6 +3446,9 @@ void Image::EIO_FromBytes(uv_work_t* req)
if (reader.get())
{
closure->im = std::make_shared<mapnik::image_any>(reader->read(0,0,reader->width(),reader->height()));
if (closure->premultiply) {
mapnik::premultiply_alpha(*closure->im);
}
}
else
{
Expand Down
42 changes: 29 additions & 13 deletions test/image.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,22 +92,24 @@ describe('mapnik.Image ', function() {
});

it('should throw with invalid binary read from buffer', function(done) {
assert.throws(function() { new mapnik.Image.fromBytesSync(); });
assert.throws(function() { new mapnik.Image.fromBytes(); });
assert.throws(function() { new mapnik.Image.fromBytes(null); });
assert.throws(function() { new mapnik.Image.fromBytes(null, function(err, result) {}); });
assert.throws(function() { new mapnik.Image.fromBytes({}); });
assert.throws(function() { new mapnik.Image.fromBytes({}, function(err, result) {}); });
assert.throws(function() { new mapnik.Image.fromBytesSync({}); });
assert.throws(function() { new mapnik.Image.fromBytes(new Buffer(0)); });
assert.throws(function() { new mapnik.Image.fromBytes(new Buffer(0), null); });
assert.throws(function() { new mapnik.Image.fromBytesSync(new Buffer(1024)); });
assert.throws(function() { mapnik.Image.fromBytesSync(); });
assert.throws(function() { mapnik.Image.fromBytes(); });
assert.throws(function() { mapnik.Image.fromBytes(null); });
assert.throws(function() { mapnik.Image.fromBytes(null, function(err, result) {}); });
assert.throws(function() { mapnik.Image.fromBytes({}); });
assert.throws(function() { mapnik.Image.fromBytes({}, function(err, result) {}); });
assert.throws(function() { mapnik.Image.fromBytesSync({}); });
assert.throws(function() { mapnik.Image.fromBytes(new Buffer(0)); });
assert.throws(function() { mapnik.Image.fromBytes(new Buffer(0),{premultiply:1},function(){}); });
assert.throws(function() { mapnik.Image.fromBytes(new Buffer(0), null); });
assert.throws(function() { mapnik.Image.fromBytesSync(new Buffer(1024)); });
var buffer = new Buffer('\x89\x50\x4E\x47\x0D\x0A\x1A\x0A' + new Array(48).join('\0'), 'binary');
assert.throws(function() { new mapnik.Image.fromBytesSync(buffer); });
assert.throws(function() { mapnik.Image.fromBytesSync(buffer); });
buffer = new Buffer('\x89\x50\x4E\x47\x0D\x0A\x1A\x0A', 'binary');
assert.throws(function() { new mapnik.Image.fromBytesSync(buffer); });
var stuff = new mapnik.Image.fromBytes(buffer, function(err, result) {
assert.throws(function() { mapnik.Image.fromBytesSync(buffer); });
var stuff = mapnik.Image.fromBytes(buffer, function(err, result) {
assert.throws(function() { if (err) throw err; });

done();
});
});
Expand Down Expand Up @@ -1576,6 +1578,20 @@ describe('mapnik.Image ', function() {
assert.throws(function() { var im = new mapnik.Image.fromBufferSync(2, 2, b, {'painted':null}); });
});

it('fromBytes can premultiply in async/threadpool', function(done) {
var data = require('fs').readFileSync(__dirname + '/support/a.png');
var image = mapnik.Image.fromBytesSync(data);
mapnik.Image.fromBytes(data, {premultiply:false}, function(err, im) {
if (err) throw err;
assert.ok(!im.premultiplied());
mapnik.Image.fromBytes(data, {premultiply:true}, function(err, im) {
if (err) throw err;
assert.ok(im.premultiplied());
done();
});
});
});

it('resizes consistently', function(done) {
var data = require('fs').readFileSync(__dirname + '/support/a.png');
var image = mapnik.Image.fromBytesSync(data);
Expand Down

0 comments on commit f8d02d0

Please sign in to comment.