mirror of
https://github.com/lovell/sharp.git
synced 2025-07-16 13:40:13 +02:00
parent
045680fba5
commit
b7e0a6f277
@ -2,9 +2,16 @@ language: node_js
|
|||||||
node_js:
|
node_js:
|
||||||
- "0.10"
|
- "0.10"
|
||||||
- "0.12"
|
- "0.12"
|
||||||
- "iojs-v1"
|
|
||||||
- "iojs-v2"
|
- "iojs-v2"
|
||||||
|
- "iojs-v3"
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
sources:
|
||||||
|
- ubuntu-toolchain-r-test
|
||||||
|
packages:
|
||||||
|
- g++-4.8
|
||||||
before_install:
|
before_install:
|
||||||
|
- sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.8 90
|
||||||
- curl -s https://raw.githubusercontent.com/lovell/sharp/master/preinstall.sh | sudo bash -
|
- curl -s https://raw.githubusercontent.com/lovell/sharp/master/preinstall.sh | sudo bash -
|
||||||
after_success:
|
after_success:
|
||||||
- cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js
|
- cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js
|
||||||
|
@ -8,7 +8,7 @@ npm install sharp
|
|||||||
|
|
||||||
* Node.js v0.10+ or io.js
|
* Node.js v0.10+ or io.js
|
||||||
* [libvips](https://github.com/jcupitt/libvips) v7.40.0+ (7.42.0+ recommended)
|
* [libvips](https://github.com/jcupitt/libvips) v7.40.0+ (7.42.0+ recommended)
|
||||||
* C++11 compatible compiler such as gcc 4.6+, clang 3.0+ or MSVC 2013
|
* C++11 compatible compiler such as gcc 4.6+, clang 3.0+ or MSVC 2013 (io.js v3+ requires gcc 4.8+)
|
||||||
|
|
||||||
### Linux
|
### Linux
|
||||||
|
|
||||||
|
@ -47,7 +47,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"bluebird": "^2.9.33",
|
"bluebird": "^2.9.33",
|
||||||
"color": "^0.10.1",
|
"color": "^0.10.1",
|
||||||
"nan": "^1.8.4",
|
"nan": "^2.0.5",
|
||||||
"semver": "^5.0.1"
|
"semver": "^5.0.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
@ -16,6 +16,19 @@ using v8::Boolean;
|
|||||||
using v8::Function;
|
using v8::Function;
|
||||||
using v8::Exception;
|
using v8::Exception;
|
||||||
|
|
||||||
|
using Nan::AsyncQueueWorker;
|
||||||
|
using Nan::AsyncWorker;
|
||||||
|
using Nan::Callback;
|
||||||
|
using Nan::HandleScope;
|
||||||
|
using Nan::Utf8String;
|
||||||
|
using Nan::Has;
|
||||||
|
using Nan::Get;
|
||||||
|
using Nan::Set;
|
||||||
|
using Nan::New;
|
||||||
|
using Nan::NewBuffer;
|
||||||
|
using Nan::Null;
|
||||||
|
using Nan::Error;
|
||||||
|
|
||||||
using sharp::ImageType;
|
using sharp::ImageType;
|
||||||
using sharp::DetermineImageType;
|
using sharp::DetermineImageType;
|
||||||
using sharp::InitImage;
|
using sharp::InitImage;
|
||||||
@ -61,10 +74,10 @@ static void DeleteBuffer(VipsObject *object, char *buffer) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class MetadataWorker : public NanAsyncWorker {
|
class MetadataWorker : public AsyncWorker {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MetadataWorker(NanCallback *callback, MetadataBaton *baton) : NanAsyncWorker(callback), baton(baton) {}
|
MetadataWorker(Callback *callback, MetadataBaton *baton) : AsyncWorker(callback), baton(baton) {}
|
||||||
~MetadataWorker() {}
|
~MetadataWorker() {}
|
||||||
|
|
||||||
void Execute() {
|
void Execute() {
|
||||||
@ -152,30 +165,30 @@ class MetadataWorker : public NanAsyncWorker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void HandleOKCallback () {
|
void HandleOKCallback () {
|
||||||
NanScope();
|
HandleScope();
|
||||||
|
|
||||||
Handle<Value> argv[2] = { NanNull(), NanNull() };
|
Local<Value> argv[2] = { Null(), Null() };
|
||||||
if (!baton->err.empty()) {
|
if (!baton->err.empty()) {
|
||||||
// Error
|
// Error
|
||||||
argv[0] = Exception::Error(NanNew<String>(baton->err.data(), baton->err.size()));
|
argv[0] = Error(baton->err.c_str());
|
||||||
} else {
|
} else {
|
||||||
// Metadata Object
|
// Metadata Object
|
||||||
Local<Object> info = NanNew<Object>();
|
Local<Object> info = New<Object>();
|
||||||
info->Set(NanNew<String>("format"), NanNew<String>(baton->format));
|
Set(info, New("format").ToLocalChecked(), New<String>(baton->format).ToLocalChecked());
|
||||||
info->Set(NanNew<String>("width"), NanNew<Number>(baton->width));
|
Set(info, New("width").ToLocalChecked(), New<Number>(baton->width));
|
||||||
info->Set(NanNew<String>("height"), NanNew<Number>(baton->height));
|
Set(info, New("height").ToLocalChecked(), New<Number>(baton->height));
|
||||||
info->Set(NanNew<String>("space"), NanNew<String>(baton->space));
|
Set(info, New("space").ToLocalChecked(), New<String>(baton->space).ToLocalChecked());
|
||||||
info->Set(NanNew<String>("channels"), NanNew<Number>(baton->channels));
|
Set(info, New("channels").ToLocalChecked(), New<Number>(baton->channels));
|
||||||
info->Set(NanNew<String>("hasProfile"), NanNew<Boolean>(baton->hasProfile));
|
Set(info, New("hasProfile").ToLocalChecked(), New<Boolean>(baton->hasProfile));
|
||||||
info->Set(NanNew<String>("hasAlpha"), NanNew<Boolean>(baton->hasAlpha));
|
Set(info, New("hasAlpha").ToLocalChecked(), New<Boolean>(baton->hasAlpha));
|
||||||
if (baton->orientation > 0) {
|
if (baton->orientation > 0) {
|
||||||
info->Set(NanNew<String>("orientation"), NanNew<Number>(baton->orientation));
|
Set(info, New("orientation").ToLocalChecked(), New<Number>(baton->orientation));
|
||||||
}
|
}
|
||||||
if (baton->exifLength > 0) {
|
if (baton->exifLength > 0) {
|
||||||
info->Set(NanNew<String>("exif"), NanBufferUse(baton->exif, baton->exifLength));
|
Set(info, New("exif").ToLocalChecked(), NewBuffer(baton->exif, baton->exifLength).ToLocalChecked());
|
||||||
}
|
}
|
||||||
if (baton->iccLength > 0) {
|
if (baton->iccLength > 0) {
|
||||||
info->Set(NanNew<String>("icc"), NanBufferUse(baton->icc, baton->iccLength));
|
Set(info, New("icc").ToLocalChecked(), NewBuffer(baton->icc, baton->iccLength).ToLocalChecked());
|
||||||
}
|
}
|
||||||
argv[1] = info;
|
argv[1] = info;
|
||||||
}
|
}
|
||||||
@ -193,17 +206,17 @@ class MetadataWorker : public NanAsyncWorker {
|
|||||||
metadata(options, callback)
|
metadata(options, callback)
|
||||||
*/
|
*/
|
||||||
NAN_METHOD(metadata) {
|
NAN_METHOD(metadata) {
|
||||||
NanScope();
|
HandleScope();
|
||||||
|
|
||||||
// V8 objects are converted to non-V8 types held in the baton struct
|
// V8 objects are converted to non-V8 types held in the baton struct
|
||||||
MetadataBaton *baton = new MetadataBaton;
|
MetadataBaton *baton = new MetadataBaton;
|
||||||
Local<Object> options = args[0]->ToObject();
|
Local<Object> options = info[0].As<Object>();
|
||||||
|
|
||||||
// Input filename
|
// Input filename
|
||||||
baton->fileIn = *String::Utf8Value(options->Get(NanNew<String>("fileIn"))->ToString());
|
baton->fileIn = *Utf8String(Get(options, New("fileIn").ToLocalChecked()).ToLocalChecked());
|
||||||
// Input Buffer object
|
// Input Buffer object
|
||||||
if (options->Get(NanNew<String>("bufferIn"))->IsObject()) {
|
if (node::Buffer::HasInstance(Get(options, New("bufferIn").ToLocalChecked()).ToLocalChecked())) {
|
||||||
Local<Object> buffer = options->Get(NanNew<String>("bufferIn"))->ToObject();
|
Local<Object> buffer = Get(options, New("bufferIn").ToLocalChecked()).ToLocalChecked().As<Object>();
|
||||||
// Take a copy of the input Buffer to avoid problems with V8 heap compaction
|
// Take a copy of the input Buffer to avoid problems with V8 heap compaction
|
||||||
baton->bufferInLength = node::Buffer::Length(buffer);
|
baton->bufferInLength = node::Buffer::Length(buffer);
|
||||||
baton->bufferIn = new char[baton->bufferInLength];
|
baton->bufferIn = new char[baton->bufferInLength];
|
||||||
@ -211,11 +224,9 @@ NAN_METHOD(metadata) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Join queue for worker thread
|
// Join queue for worker thread
|
||||||
NanCallback *callback = new NanCallback(args[1].As<v8::Function>());
|
Callback *callback = new Callback(info[1].As<Function>());
|
||||||
NanAsyncQueueWorker(new MetadataWorker(callback, baton));
|
AsyncQueueWorker(new MetadataWorker(callback, baton));
|
||||||
|
|
||||||
// Increment queued task counter
|
// Increment queued task counter
|
||||||
g_atomic_int_inc(&counterQueue);
|
g_atomic_int_inc(&counterQueue);
|
||||||
|
|
||||||
NanReturnUndefined();
|
|
||||||
}
|
}
|
||||||
|
167
src/pipeline.cc
167
src/pipeline.cc
@ -22,6 +22,20 @@ using v8::Array;
|
|||||||
using v8::Function;
|
using v8::Function;
|
||||||
using v8::Exception;
|
using v8::Exception;
|
||||||
|
|
||||||
|
using Nan::AsyncQueueWorker;
|
||||||
|
using Nan::AsyncWorker;
|
||||||
|
using Nan::Callback;
|
||||||
|
using Nan::HandleScope;
|
||||||
|
using Nan::Utf8String;
|
||||||
|
using Nan::Has;
|
||||||
|
using Nan::Get;
|
||||||
|
using Nan::Set;
|
||||||
|
using Nan::To;
|
||||||
|
using Nan::New;
|
||||||
|
using Nan::CopyBuffer;
|
||||||
|
using Nan::Null;
|
||||||
|
using Nan::Equals;
|
||||||
|
|
||||||
using sharp::Composite;
|
using sharp::Composite;
|
||||||
using sharp::Premultiply;
|
using sharp::Premultiply;
|
||||||
using sharp::Unpremultiply;
|
using sharp::Unpremultiply;
|
||||||
@ -165,11 +179,11 @@ static void DeleteBuffer(VipsObject *object, char *buffer) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class PipelineWorker : public NanAsyncWorker {
|
class PipelineWorker : public AsyncWorker {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PipelineWorker(NanCallback *callback, PipelineBaton *baton, NanCallback *queueListener) :
|
PipelineWorker(Callback *callback, PipelineBaton *baton, Callback *queueListener) :
|
||||||
NanAsyncWorker(callback), baton(baton), queueListener(queueListener) {}
|
AsyncWorker(callback), baton(baton), queueListener(queueListener) {}
|
||||||
~PipelineWorker() {}
|
~PipelineWorker() {}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -963,12 +977,12 @@ class PipelineWorker : public NanAsyncWorker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void HandleOKCallback () {
|
void HandleOKCallback () {
|
||||||
NanScope();
|
HandleScope();
|
||||||
|
|
||||||
Handle<Value> argv[3] = { NanNull(), NanNull(), NanNull() };
|
Local<Value> argv[3] = { Null(), Null(), Null() };
|
||||||
if (!baton->err.empty()) {
|
if (!baton->err.empty()) {
|
||||||
// Error
|
// Error
|
||||||
argv[0] = Exception::Error(NanNew<String>(baton->err.data(), baton->err.size()));
|
argv[0] = Nan::Error(baton->err.c_str());
|
||||||
} else {
|
} else {
|
||||||
int width = baton->width;
|
int width = baton->width;
|
||||||
int height = baton->height;
|
int height = baton->height;
|
||||||
@ -981,32 +995,33 @@ class PipelineWorker : public NanAsyncWorker {
|
|||||||
height = baton->heightPost;
|
height = baton->heightPost;
|
||||||
}
|
}
|
||||||
// Info Object
|
// Info Object
|
||||||
Local<Object> info = NanNew<Object>();
|
Local<Object> info = New<Object>();
|
||||||
info->Set(NanNew<String>("format"), NanNew<String>(baton->outputFormat));
|
Set(info, New("format").ToLocalChecked(), New<String>(baton->outputFormat).ToLocalChecked());
|
||||||
info->Set(NanNew<String>("width"), NanNew<Uint32>(static_cast<uint32_t>(width)));
|
Set(info, New("width").ToLocalChecked(), New<Uint32>(static_cast<uint32_t>(width)));
|
||||||
info->Set(NanNew<String>("height"), NanNew<Uint32>(static_cast<uint32_t>(height)));
|
Set(info, New("height").ToLocalChecked(), New<Uint32>(static_cast<uint32_t>(height)));
|
||||||
|
|
||||||
if (baton->bufferOutLength > 0) {
|
if (baton->bufferOutLength > 0) {
|
||||||
// Copy data to new Buffer
|
// Copy data to new Buffer
|
||||||
argv[1] = NanNewBufferHandle(static_cast<char*>(baton->bufferOut), baton->bufferOutLength);
|
argv[1] = CopyBuffer(static_cast<char*>(baton->bufferOut), baton->bufferOutLength).ToLocalChecked();
|
||||||
// bufferOut was allocated via g_malloc
|
// bufferOut was allocated via g_malloc
|
||||||
g_free(baton->bufferOut);
|
g_free(baton->bufferOut);
|
||||||
// Add buffer size to info
|
// Add buffer size to info
|
||||||
info->Set(NanNew<String>("size"), NanNew<Uint32>(static_cast<uint32_t>(baton->bufferOutLength)));
|
Set(info, New("size").ToLocalChecked(), New<Uint32>(static_cast<uint32_t>(baton->bufferOutLength)));
|
||||||
argv[2] = info;
|
argv[2] = info;
|
||||||
} else {
|
} else {
|
||||||
// Add file size to info
|
// Add file size to info
|
||||||
GStatBuf st;
|
GStatBuf st;
|
||||||
g_stat(baton->output.c_str(), &st);
|
g_stat(baton->output.c_str(), &st);
|
||||||
info->Set(NanNew<String>("size"), NanNew<Uint32>(static_cast<uint32_t>(st.st_size)));
|
Set(info, New("size").ToLocalChecked(), New<Uint32>(static_cast<uint32_t>(st.st_size)));
|
||||||
argv[1] = info;
|
argv[1] = info;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
delete baton;
|
delete baton;
|
||||||
|
// to here
|
||||||
|
|
||||||
// Decrement processing task counter
|
// Decrement processing task counter
|
||||||
g_atomic_int_dec_and_test(&counterProcess);
|
g_atomic_int_dec_and_test(&counterProcess);
|
||||||
Handle<Value> queueLength[1] = { NanNew<Uint32>(counterQueue) };
|
Local<Value> queueLength[1] = { New<Uint32>(counterQueue) };
|
||||||
queueListener->Call(1, queueLength);
|
queueListener->Call(1, queueLength);
|
||||||
delete queueListener;
|
delete queueListener;
|
||||||
|
|
||||||
@ -1016,7 +1031,7 @@ class PipelineWorker : public NanAsyncWorker {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
PipelineBaton *baton;
|
PipelineBaton *baton;
|
||||||
NanCallback *queueListener;
|
Callback *queueListener;
|
||||||
VipsObject *hook;
|
VipsObject *hook;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1126,102 +1141,102 @@ class PipelineWorker : public NanAsyncWorker {
|
|||||||
pipeline(options, output, callback)
|
pipeline(options, output, callback)
|
||||||
*/
|
*/
|
||||||
NAN_METHOD(pipeline) {
|
NAN_METHOD(pipeline) {
|
||||||
NanScope();
|
HandleScope();
|
||||||
|
|
||||||
// V8 objects are converted to non-V8 types held in the baton struct
|
// V8 objects are converted to non-V8 types held in the baton struct
|
||||||
PipelineBaton *baton = new PipelineBaton;
|
PipelineBaton *baton = new PipelineBaton;
|
||||||
Local<Object> options = args[0]->ToObject();
|
Local<Object> options = info[0].As<Object>();
|
||||||
|
|
||||||
// Input filename
|
// Input filename
|
||||||
baton->fileIn = *String::Utf8Value(options->Get(NanNew<String>("fileIn"))->ToString());
|
baton->fileIn = *Utf8String(Get(options, New("fileIn").ToLocalChecked()).ToLocalChecked());
|
||||||
baton->accessMethod = options->Get(NanNew<String>("sequentialRead"))->BooleanValue() ? VIPS_ACCESS_SEQUENTIAL : VIPS_ACCESS_RANDOM;
|
baton->accessMethod =
|
||||||
|
To<bool>(Get(options, New("sequentialRead").ToLocalChecked()).ToLocalChecked()).FromJust() ?
|
||||||
|
VIPS_ACCESS_SEQUENTIAL : VIPS_ACCESS_RANDOM;
|
||||||
// Input Buffer object
|
// Input Buffer object
|
||||||
if (options->Get(NanNew<String>("bufferIn"))->IsObject()) {
|
if (node::Buffer::HasInstance(Get(options, New("bufferIn").ToLocalChecked()).ToLocalChecked())) {
|
||||||
Local<Object> buffer = options->Get(NanNew<String>("bufferIn"))->ToObject();
|
Local<Object> buffer = Get(options, New("bufferIn").ToLocalChecked()).ToLocalChecked().As<Object>();
|
||||||
// Take a copy of the input Buffer to avoid problems with V8 heap compaction
|
// Take a copy of the input Buffer to avoid problems with V8 heap compaction
|
||||||
baton->bufferInLength = node::Buffer::Length(buffer);
|
baton->bufferInLength = node::Buffer::Length(buffer);
|
||||||
baton->bufferIn = new char[baton->bufferInLength];
|
baton->bufferIn = new char[baton->bufferInLength];
|
||||||
memcpy(baton->bufferIn, node::Buffer::Data(buffer), baton->bufferInLength);
|
memcpy(baton->bufferIn, node::Buffer::Data(buffer), baton->bufferInLength);
|
||||||
}
|
}
|
||||||
// ICC profile to use when input CMYK image has no embedded profile
|
// ICC profile to use when input CMYK image has no embedded profile
|
||||||
baton->iccProfilePath = *String::Utf8Value(options->Get(NanNew<String>("iccProfilePath"))->ToString());
|
baton->iccProfilePath = *Utf8String(Get(options, New("iccProfilePath").ToLocalChecked()).ToLocalChecked());
|
||||||
// Limit input images to a given number of pixels, where pixels = width * height
|
// Limit input images to a given number of pixels, where pixels = width * height
|
||||||
baton->limitInputPixels = options->Get(NanNew<String>("limitInputPixels"))->Int32Value();
|
baton->limitInputPixels = To<int32_t>(Get(options, New("limitInputPixels").ToLocalChecked()).ToLocalChecked()).FromJust();
|
||||||
// Extract image options
|
// Extract image options
|
||||||
baton->topOffsetPre = options->Get(NanNew<String>("topOffsetPre"))->Int32Value();
|
baton->topOffsetPre = To<int32_t>(Get(options, New("topOffsetPre").ToLocalChecked()).ToLocalChecked()).FromJust();
|
||||||
baton->leftOffsetPre = options->Get(NanNew<String>("leftOffsetPre"))->Int32Value();
|
baton->leftOffsetPre = To<int32_t>(Get(options, New("leftOffsetPre").ToLocalChecked()).ToLocalChecked()).FromJust();
|
||||||
baton->widthPre = options->Get(NanNew<String>("widthPre"))->Int32Value();
|
baton->widthPre = To<int32_t>(Get(options, New("widthPre").ToLocalChecked()).ToLocalChecked()).FromJust();
|
||||||
baton->heightPre = options->Get(NanNew<String>("heightPre"))->Int32Value();
|
baton->heightPre = To<int32_t>(Get(options, New("heightPre").ToLocalChecked()).ToLocalChecked()).FromJust();
|
||||||
baton->topOffsetPost = options->Get(NanNew<String>("topOffsetPost"))->Int32Value();
|
baton->topOffsetPost = To<int32_t>(Get(options, New("topOffsetPost").ToLocalChecked()).ToLocalChecked()).FromJust();
|
||||||
baton->leftOffsetPost = options->Get(NanNew<String>("leftOffsetPost"))->Int32Value();
|
baton->leftOffsetPost = To<int32_t>(Get(options, New("leftOffsetPost").ToLocalChecked()).ToLocalChecked()).FromJust();
|
||||||
baton->widthPost = options->Get(NanNew<String>("widthPost"))->Int32Value();
|
baton->widthPost = To<int32_t>(Get(options, New("widthPost").ToLocalChecked()).ToLocalChecked()).FromJust();
|
||||||
baton->heightPost = options->Get(NanNew<String>("heightPost"))->Int32Value();
|
baton->heightPost = To<int32_t>(Get(options, New("heightPost").ToLocalChecked()).ToLocalChecked()).FromJust();
|
||||||
// Output image dimensions
|
// Output image dimensions
|
||||||
baton->width = options->Get(NanNew<String>("width"))->Int32Value();
|
baton->width = To<int32_t>(Get(options, New("width").ToLocalChecked()).ToLocalChecked()).FromJust();
|
||||||
baton->height = options->Get(NanNew<String>("height"))->Int32Value();
|
baton->height = To<int32_t>(Get(options, New("height").ToLocalChecked()).ToLocalChecked()).FromJust();
|
||||||
// Canvas option
|
// Canvas option
|
||||||
Local<String> canvas = options->Get(NanNew<String>("canvas"))->ToString();
|
Local<String> canvas = To<String>(Get(options, New("canvas").ToLocalChecked()).ToLocalChecked()).ToLocalChecked();
|
||||||
if (canvas->Equals(NanNew<String>("crop"))) {
|
if (Equals(canvas, New("crop").ToLocalChecked()).FromJust()) {
|
||||||
baton->canvas = Canvas::CROP;
|
baton->canvas = Canvas::CROP;
|
||||||
} else if (canvas->Equals(NanNew<String>("embed"))) {
|
} else if (Equals(canvas, New("embed").ToLocalChecked()).FromJust()) {
|
||||||
baton->canvas = Canvas::EMBED;
|
baton->canvas = Canvas::EMBED;
|
||||||
} else if (canvas->Equals(NanNew<String>("max"))) {
|
} else if (Equals(canvas, New("max").ToLocalChecked()).FromJust()) {
|
||||||
baton->canvas = Canvas::MAX;
|
baton->canvas = Canvas::MAX;
|
||||||
} else if (canvas->Equals(NanNew<String>("min"))) {
|
} else if (Equals(canvas, New("min").ToLocalChecked()).FromJust()) {
|
||||||
baton->canvas = Canvas::MIN;
|
baton->canvas = Canvas::MIN;
|
||||||
} else if (canvas->Equals(NanNew<String>("ignore_aspect"))) {
|
} else if (Equals(canvas, New("ignore_aspect").ToLocalChecked()).FromJust()) {
|
||||||
baton->canvas = Canvas::IGNORE_ASPECT;
|
baton->canvas = Canvas::IGNORE_ASPECT;
|
||||||
}
|
}
|
||||||
// Background colour
|
// Background colour
|
||||||
Local<Array> background = Local<Array>::Cast(options->Get(NanNew<String>("background")));
|
Local<Object> background = Get(options, New("background").ToLocalChecked()).ToLocalChecked().As<Object>();
|
||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < 4; i++) {
|
||||||
baton->background[i] = background->Get(i)->NumberValue();
|
baton->background[i] = To<int32_t>(Get(background, i).ToLocalChecked()).FromJust();
|
||||||
}
|
}
|
||||||
// Overlay options
|
// Overlay options
|
||||||
baton->overlayPath = *String::Utf8Value(options->Get(NanNew<String>("overlayPath"))->ToString());
|
baton->overlayPath = *Utf8String(Get(options, New("overlayPath").ToLocalChecked()).ToLocalChecked());
|
||||||
// Resize options
|
// Resize options
|
||||||
baton->withoutEnlargement = options->Get(NanNew<String>("withoutEnlargement"))->BooleanValue();
|
baton->withoutEnlargement = To<bool>(Get(options, New("withoutEnlargement").ToLocalChecked()).ToLocalChecked()).FromJust();
|
||||||
baton->gravity = options->Get(NanNew<String>("gravity"))->Int32Value();
|
baton->gravity = To<int32_t>(Get(options, New("gravity").ToLocalChecked()).ToLocalChecked()).FromJust();
|
||||||
baton->interpolator = *String::Utf8Value(options->Get(NanNew<String>("interpolator"))->ToString());
|
baton->interpolator = *Utf8String(Get(options, New("interpolator").ToLocalChecked()).ToLocalChecked());
|
||||||
// Operators
|
// Operators
|
||||||
baton->flatten = options->Get(NanNew<String>("flatten"))->BooleanValue();
|
baton->flatten = To<bool>(Get(options, New("flatten").ToLocalChecked()).ToLocalChecked()).FromJust();
|
||||||
baton->blurSigma = options->Get(NanNew<String>("blurSigma"))->NumberValue();
|
baton->blurSigma = To<int32_t>(Get(options, New("blurSigma").ToLocalChecked()).ToLocalChecked()).FromJust();
|
||||||
baton->sharpenRadius = options->Get(NanNew<String>("sharpenRadius"))->Int32Value();
|
baton->sharpenRadius = To<int32_t>(Get(options, New("sharpenRadius").ToLocalChecked()).ToLocalChecked()).FromJust();
|
||||||
baton->sharpenFlat = options->Get(NanNew<String>("sharpenFlat"))->NumberValue();
|
baton->sharpenFlat = To<int32_t>(Get(options, New("sharpenFlat").ToLocalChecked()).ToLocalChecked()).FromJust();
|
||||||
baton->sharpenJagged = options->Get(NanNew<String>("sharpenJagged"))->NumberValue();
|
baton->sharpenJagged = To<int32_t>(Get(options, New("sharpenJagged").ToLocalChecked()).ToLocalChecked()).FromJust();
|
||||||
baton->gamma = options->Get(NanNew<String>("gamma"))->NumberValue();
|
baton->gamma = To<int32_t>(Get(options, New("gamma").ToLocalChecked()).ToLocalChecked()).FromJust();
|
||||||
baton->greyscale = options->Get(NanNew<String>("greyscale"))->BooleanValue();
|
baton->greyscale = To<bool>(Get(options, New("greyscale").ToLocalChecked()).ToLocalChecked()).FromJust();
|
||||||
baton->normalize = options->Get(NanNew<String>("normalize"))->BooleanValue();
|
baton->normalize = To<bool>(Get(options, New("normalize").ToLocalChecked()).ToLocalChecked()).FromJust();
|
||||||
baton->angle = options->Get(NanNew<String>("angle"))->Int32Value();
|
baton->angle = To<int32_t>(Get(options, New("angle").ToLocalChecked()).ToLocalChecked()).FromJust();
|
||||||
baton->rotateBeforePreExtract = options->Get(NanNew<String>("rotateBeforePreExtract"))->BooleanValue();
|
baton->rotateBeforePreExtract = To<bool>(Get(options, New("rotateBeforePreExtract").ToLocalChecked()).ToLocalChecked()).FromJust();
|
||||||
baton->flip = options->Get(NanNew<String>("flip"))->BooleanValue();
|
baton->flip = To<bool>(Get(options, New("flip").ToLocalChecked()).ToLocalChecked()).FromJust();
|
||||||
baton->flop = options->Get(NanNew<String>("flop"))->BooleanValue();
|
baton->flop = To<bool>(Get(options, New("flop").ToLocalChecked()).ToLocalChecked()).FromJust();
|
||||||
// Output options
|
// Output options
|
||||||
baton->progressive = options->Get(NanNew<String>("progressive"))->BooleanValue();
|
baton->progressive = To<bool>(Get(options, New("progressive").ToLocalChecked()).ToLocalChecked()).FromJust();
|
||||||
baton->quality = options->Get(NanNew<String>("quality"))->Int32Value();
|
baton->quality = To<int32_t>(Get(options, New("quality").ToLocalChecked()).ToLocalChecked()).FromJust();
|
||||||
baton->compressionLevel = options->Get(NanNew<String>("compressionLevel"))->Int32Value();
|
baton->compressionLevel = To<int32_t>(Get(options, New("compressionLevel").ToLocalChecked()).ToLocalChecked()).FromJust();
|
||||||
baton->withoutAdaptiveFiltering = options->Get(NanNew<String>("withoutAdaptiveFiltering"))->BooleanValue();
|
baton->withoutAdaptiveFiltering = To<bool>(Get(options, New("withoutAdaptiveFiltering").ToLocalChecked()).ToLocalChecked()).FromJust();
|
||||||
baton->withoutChromaSubsampling = options->Get(NanNew<String>("withoutChromaSubsampling"))->BooleanValue();
|
baton->withoutChromaSubsampling = To<bool>(Get(options, New("withoutChromaSubsampling").ToLocalChecked()).ToLocalChecked()).FromJust();
|
||||||
baton->trellisQuantisation = options->Get(NanNew<String>("trellisQuantisation"))->BooleanValue();
|
baton->trellisQuantisation = To<bool>(Get(options, New("trellisQuantisation").ToLocalChecked()).ToLocalChecked()).FromJust();
|
||||||
baton->overshootDeringing = options->Get(NanNew<String>("overshootDeringing"))->BooleanValue();
|
baton->overshootDeringing = To<bool>(Get(options, New("overshootDeringing").ToLocalChecked()).ToLocalChecked()).FromJust();
|
||||||
baton->optimiseScans = options->Get(NanNew<String>("optimiseScans"))->BooleanValue();
|
baton->optimiseScans = To<bool>(Get(options, New("optimiseScans").ToLocalChecked()).ToLocalChecked()).FromJust();
|
||||||
baton->withMetadata = options->Get(NanNew<String>("withMetadata"))->BooleanValue();
|
baton->withMetadata = To<bool>(Get(options, New("withMetadata").ToLocalChecked()).ToLocalChecked()).FromJust();
|
||||||
baton->withMetadataOrientation = options->Get(NanNew<String>("withMetadataOrientation"))->Int32Value();
|
baton->withMetadataOrientation = To<int32_t>(Get(options, New("withMetadataOrientation").ToLocalChecked()).ToLocalChecked()).FromJust();
|
||||||
// Output filename or __format for Buffer
|
// Output filename or __format for Buffer
|
||||||
baton->output = *String::Utf8Value(options->Get(NanNew<String>("output"))->ToString());
|
baton->output = *Utf8String(Get(options, New("output").ToLocalChecked()).ToLocalChecked());
|
||||||
baton->tileSize = options->Get(NanNew<String>("tileSize"))->Int32Value();
|
baton->tileSize = To<int32_t>(Get(options, New("tileSize").ToLocalChecked()).ToLocalChecked()).FromJust();
|
||||||
baton->tileOverlap = options->Get(NanNew<String>("tileOverlap"))->Int32Value();
|
baton->tileOverlap = To<int32_t>(Get(options, New("tileOverlap").ToLocalChecked()).ToLocalChecked()).FromJust();
|
||||||
// Function to notify of queue length changes
|
// Function to notify of queue length changes
|
||||||
NanCallback *queueListener = new NanCallback(Handle<Function>::Cast(options->Get(NanNew<String>("queueListener"))));
|
Callback *queueListener = new Callback(Get(options, New("queueListener").ToLocalChecked()).ToLocalChecked().As<Function>());
|
||||||
|
|
||||||
// Join queue for worker thread
|
// Join queue for worker thread
|
||||||
NanCallback *callback = new NanCallback(args[1].As<Function>());
|
Callback *callback = new Callback(info[1].As<Function>());
|
||||||
NanAsyncQueueWorker(new PipelineWorker(callback, baton, queueListener));
|
AsyncQueueWorker(new PipelineWorker(callback, baton, queueListener));
|
||||||
|
|
||||||
// Increment queued task counter
|
// Increment queued task counter
|
||||||
g_atomic_int_inc(&counterQueue);
|
g_atomic_int_inc(&counterQueue);
|
||||||
Handle<Value> queueLength[1] = { NanNew<Uint32>(counterQueue) };
|
Local<Value> queueLength[1] = { New<Uint32>(counterQueue) };
|
||||||
queueListener->Call(1, queueLength);
|
queueListener->Call(1, queueLength);
|
||||||
|
|
||||||
NanReturnUndefined();
|
|
||||||
}
|
}
|
||||||
|
27
src/sharp.cc
27
src/sharp.cc
@ -8,8 +8,7 @@
|
|||||||
#include "pipeline.h"
|
#include "pipeline.h"
|
||||||
#include "utilities.h"
|
#include "utilities.h"
|
||||||
|
|
||||||
extern "C" void init(v8::Handle<v8::Object> target) {
|
NAN_MODULE_INIT(init) {
|
||||||
NanScope();
|
|
||||||
vips_init("sharp");
|
vips_init("sharp");
|
||||||
|
|
||||||
// Set libvips operation cache limits
|
// Set libvips operation cache limits
|
||||||
@ -17,14 +16,22 @@ extern "C" void init(v8::Handle<v8::Object> target) {
|
|||||||
vips_cache_set_max(500); // 500 operations
|
vips_cache_set_max(500); // 500 operations
|
||||||
|
|
||||||
// Methods available to JavaScript
|
// Methods available to JavaScript
|
||||||
NODE_SET_METHOD(target, "metadata", metadata);
|
Nan::Set(target, Nan::New("metadata").ToLocalChecked(),
|
||||||
NODE_SET_METHOD(target, "pipeline", pipeline);
|
Nan::GetFunction(Nan::New<v8::FunctionTemplate>(metadata)).ToLocalChecked());
|
||||||
NODE_SET_METHOD(target, "cache", cache);
|
Nan::Set(target, Nan::New("pipeline").ToLocalChecked(),
|
||||||
NODE_SET_METHOD(target, "concurrency", concurrency);
|
Nan::GetFunction(Nan::New<v8::FunctionTemplate>(pipeline)).ToLocalChecked());
|
||||||
NODE_SET_METHOD(target, "counters", counters);
|
Nan::Set(target, Nan::New("cache").ToLocalChecked(),
|
||||||
NODE_SET_METHOD(target, "libvipsVersion", libvipsVersion);
|
Nan::GetFunction(Nan::New<v8::FunctionTemplate>(cache)).ToLocalChecked());
|
||||||
NODE_SET_METHOD(target, "format", format);
|
Nan::Set(target, Nan::New("concurrency").ToLocalChecked(),
|
||||||
NODE_SET_METHOD(target, "_maxColourDistance", _maxColourDistance);
|
Nan::GetFunction(Nan::New<v8::FunctionTemplate>(concurrency)).ToLocalChecked());
|
||||||
|
Nan::Set(target, Nan::New("counters").ToLocalChecked(),
|
||||||
|
Nan::GetFunction(Nan::New<v8::FunctionTemplate>(counters)).ToLocalChecked());
|
||||||
|
Nan::Set(target, Nan::New("libvipsVersion").ToLocalChecked(),
|
||||||
|
Nan::GetFunction(Nan::New<v8::FunctionTemplate>(libvipsVersion)).ToLocalChecked());
|
||||||
|
Nan::Set(target, Nan::New("format").ToLocalChecked(),
|
||||||
|
Nan::GetFunction(Nan::New<v8::FunctionTemplate>(format)).ToLocalChecked());
|
||||||
|
Nan::Set(target, Nan::New("_maxColourDistance").ToLocalChecked(),
|
||||||
|
Nan::GetFunction(Nan::New<v8::FunctionTemplate>(_maxColourDistance)).ToLocalChecked());
|
||||||
}
|
}
|
||||||
|
|
||||||
NODE_MODULE(sharp, init)
|
NODE_MODULE(sharp, init)
|
||||||
|
181
src/utilities.cc
181
src/utilities.cc
@ -13,48 +13,50 @@ using v8::Number;
|
|||||||
using v8::String;
|
using v8::String;
|
||||||
using v8::Boolean;
|
using v8::Boolean;
|
||||||
|
|
||||||
|
using Nan::HandleScope;
|
||||||
|
using Nan::New;
|
||||||
|
using Nan::Set;
|
||||||
|
using Nan::ThrowError;
|
||||||
|
using Nan::To;
|
||||||
|
using Nan::Utf8String;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Get and set cache memory and item limits
|
Get and set cache memory and item limits
|
||||||
*/
|
*/
|
||||||
NAN_METHOD(cache) {
|
NAN_METHOD(cache) {
|
||||||
NanScope();
|
HandleScope();
|
||||||
|
|
||||||
// Set cache memory limit
|
// Set cache memory limit
|
||||||
if (args[0]->IsInt32()) {
|
if (info[0]->IsInt32()) {
|
||||||
int newMax = args[0]->Int32Value() * 1048576;
|
vips_cache_set_max_mem(To<int32_t>(info[0]).FromJust() * 1048576);
|
||||||
int oldMax = vips_cache_get_max_mem();
|
|
||||||
vips_cache_set_max_mem(newMax);
|
|
||||||
|
|
||||||
// Notify the V8 garbage collector of delta in max cache size
|
|
||||||
NanAdjustExternalMemory(newMax - oldMax);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set cache items limit
|
// Set cache items limit
|
||||||
if (args[1]->IsInt32()) {
|
if (info[1]->IsInt32()) {
|
||||||
vips_cache_set_max(args[1]->Int32Value());
|
vips_cache_set_max(To<int32_t>(info[1]).FromJust());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get cache statistics
|
// Get cache statistics
|
||||||
Local<Object> cache = NanNew<Object>();
|
Local<Object> cache = New<Object>();
|
||||||
cache->Set(NanNew<String>("current"), NanNew<Number>(vips_tracked_get_mem() / 1048576));
|
Set(cache, New("current").ToLocalChecked(), New<Number>(vips_tracked_get_mem() / 1048576));
|
||||||
cache->Set(NanNew<String>("high"), NanNew<Number>(vips_tracked_get_mem_highwater() / 1048576));
|
Set(cache, New("high").ToLocalChecked(), New<Number>(vips_tracked_get_mem_highwater() / 1048576));
|
||||||
cache->Set(NanNew<String>("memory"), NanNew<Number>(vips_cache_get_max_mem() / 1048576));
|
Set(cache, New("memory").ToLocalChecked(), New<Number>(vips_cache_get_max_mem() / 1048576));
|
||||||
cache->Set(NanNew<String>("items"), NanNew<Number>(vips_cache_get_max()));
|
Set(cache, New("items").ToLocalChecked(), New<Number>(vips_cache_get_max()));
|
||||||
NanReturnValue(cache);
|
info.GetReturnValue().Set(cache);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Get and set size of thread pool
|
Get and set size of thread pool
|
||||||
*/
|
*/
|
||||||
NAN_METHOD(concurrency) {
|
NAN_METHOD(concurrency) {
|
||||||
NanScope();
|
HandleScope();
|
||||||
|
|
||||||
// Set concurrency
|
// Set concurrency
|
||||||
if (args[0]->IsInt32()) {
|
if (info[0]->IsInt32()) {
|
||||||
vips_concurrency_set(args[0]->Int32Value());
|
vips_concurrency_set(To<int32_t>(info[0]).FromJust());
|
||||||
}
|
}
|
||||||
// Get concurrency
|
// Get concurrency
|
||||||
NanReturnValue(NanNew<Number>(vips_concurrency_get()));
|
info.GetReturnValue().Set(New<Number>(vips_concurrency_get()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -64,84 +66,89 @@ NAN_METHOD(counters) {
|
|||||||
using sharp::counterProcess;
|
using sharp::counterProcess;
|
||||||
using sharp::counterQueue;
|
using sharp::counterQueue;
|
||||||
|
|
||||||
NanScope();
|
HandleScope();
|
||||||
Local<Object> counters = NanNew<Object>();
|
Local<Object> counters = New<Object>();
|
||||||
counters->Set(NanNew<String>("queue"), NanNew<Number>(counterQueue));
|
Set(counters, New("queue").ToLocalChecked(), New<Number>(counterQueue));
|
||||||
counters->Set(NanNew<String>("process"), NanNew<Number>(counterProcess));
|
Set(counters, New("process").ToLocalChecked(), New<Number>(counterProcess));
|
||||||
NanReturnValue(counters);
|
info.GetReturnValue().Set(counters);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Get libvips version
|
Get libvips version
|
||||||
*/
|
*/
|
||||||
NAN_METHOD(libvipsVersion) {
|
NAN_METHOD(libvipsVersion) {
|
||||||
NanScope();
|
HandleScope();
|
||||||
char version[9];
|
char version[9];
|
||||||
g_snprintf(version, sizeof(version), "%d.%d.%d", vips_version(0), vips_version(1), vips_version(2));
|
g_snprintf(version, sizeof(version), "%d.%d.%d", vips_version(0), vips_version(1), vips_version(2));
|
||||||
NanReturnValue(NanNew<String>(version));
|
info.GetReturnValue().Set(New(version).ToLocalChecked());
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Get available input/output file/buffer/stream formats
|
Get available input/output file/buffer/stream formats
|
||||||
*/
|
*/
|
||||||
NAN_METHOD(format) {
|
NAN_METHOD(format) {
|
||||||
NanScope();
|
HandleScope();
|
||||||
|
|
||||||
// Attribute names
|
// Attribute names
|
||||||
Local<String> attrId = NanNew<String>("id");
|
Local<String> attrId = New("id").ToLocalChecked();
|
||||||
Local<String> attrInput = NanNew<String>("input");
|
Local<String> attrInput = New("input").ToLocalChecked();
|
||||||
Local<String> attrOutput = NanNew<String>("output");
|
Local<String> attrOutput = New("output").ToLocalChecked();
|
||||||
Local<String> attrFile = NanNew<String>("file");
|
Local<String> attrFile = New("file").ToLocalChecked();
|
||||||
Local<String> attrBuffer = NanNew<String>("buffer");
|
Local<String> attrBuffer = New("buffer").ToLocalChecked();
|
||||||
Local<String> attrStream = NanNew<String>("stream");
|
Local<String> attrStream = New("stream").ToLocalChecked();
|
||||||
|
|
||||||
// Which load/save operations are available for each compressed format?
|
// Which load/save operations are available for each compressed format?
|
||||||
Local<Object> format = NanNew<Object>();
|
Local<Object> format = New<Object>();
|
||||||
for (std::string f : {"jpeg", "png", "webp", "tiff", "magick", "openslide", "dz"}) {
|
for (std::string f : {"jpeg", "png", "webp", "tiff", "magick", "openslide", "dz"}) {
|
||||||
// Input
|
// Input
|
||||||
Local<Object> input = NanNew<Object>();
|
Local<Boolean> hasInputFile =
|
||||||
input->Set(attrFile, NanNew<Boolean>(
|
New<Boolean>(vips_type_find("VipsOperation", (f + "load").c_str()));
|
||||||
vips_type_find("VipsOperation", (f + "load").c_str())));
|
Local<Boolean> hasInputBuffer =
|
||||||
input->Set(attrBuffer, NanNew<Boolean>(
|
New<Boolean>(vips_type_find("VipsOperation", (f + "load_buffer").c_str()));
|
||||||
vips_type_find("VipsOperation", (f + "load_buffer").c_str())));
|
Local<Object> input = New<Object>();
|
||||||
input->Set(attrStream, input->Get(attrBuffer));
|
Set(input, attrFile, hasInputFile);
|
||||||
|
Set(input, attrBuffer, hasInputBuffer);
|
||||||
|
Set(input, attrStream, hasInputBuffer);
|
||||||
// Output
|
// Output
|
||||||
Local<Object> output = NanNew<Object>();
|
Local<Boolean> hasOutputFile =
|
||||||
output->Set(attrFile, NanNew<Boolean>(
|
New<Boolean>(vips_type_find("VipsOperation", (f + "save").c_str()));
|
||||||
vips_type_find("VipsOperation", (f + "save").c_str())));
|
Local<Boolean> hasOutputBuffer =
|
||||||
output->Set(attrBuffer, NanNew<Boolean>(
|
New<Boolean>(vips_type_find("VipsOperation", (f + "save_buffer").c_str()));
|
||||||
vips_type_find("VipsOperation", (f + "save_buffer").c_str())));
|
Local<Object> output = New<Object>();
|
||||||
output->Set(attrStream, output->Get(attrBuffer));
|
Set(output, attrFile, hasOutputFile);
|
||||||
|
Set(output, attrBuffer, hasOutputBuffer);
|
||||||
|
Set(output, attrStream, hasOutputBuffer);
|
||||||
// Other attributes
|
// Other attributes
|
||||||
Local<Object> container = NanNew<Object>();
|
Local<Object> container = New<Object>();
|
||||||
Local<String> formatId = NanNew<String>(f);
|
Local<String> formatId = New(f).ToLocalChecked();
|
||||||
container->Set(attrId, formatId);
|
Set(container, attrId, formatId);
|
||||||
container->Set(attrInput, input);
|
Set(container, attrInput, input);
|
||||||
container->Set(attrOutput, output);
|
Set(container, attrOutput, output);
|
||||||
// Add to set of formats
|
// Add to set of formats
|
||||||
format->Set(formatId, container);
|
Set(format, formatId, container);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Raw, uncompressed data
|
// Raw, uncompressed data
|
||||||
Local<Object> raw = NanNew<Object>();
|
Local<Object> raw = New<Object>();
|
||||||
raw->Set(attrId, NanNew<String>("raw"));
|
Local<String> rawId = New("raw").ToLocalChecked();
|
||||||
format->Set(NanNew<String>("raw"), raw);
|
Set(raw, attrId, rawId);
|
||||||
|
Set(format, rawId, raw);
|
||||||
// No support for raw input yet, so always false
|
// No support for raw input yet, so always false
|
||||||
Local<Boolean> unsupported = NanNew<Boolean>(false);
|
Local<Boolean> unsupported = New<Boolean>(false);
|
||||||
Local<Object> rawInput = NanNew<Object>();
|
Local<Object> rawInput = New<Object>();
|
||||||
rawInput->Set(attrFile, unsupported);
|
Set(rawInput, attrFile, unsupported);
|
||||||
rawInput->Set(attrBuffer, unsupported);
|
Set(rawInput, attrBuffer, unsupported);
|
||||||
rawInput->Set(attrStream, unsupported);
|
Set(rawInput, attrStream, unsupported);
|
||||||
raw->Set(attrInput, rawInput);
|
Set(raw, attrInput, rawInput);
|
||||||
// Raw output via Buffer/Stream is available in libvips >= 7.42.0
|
// Raw output via Buffer/Stream is available in libvips >= 7.42.0
|
||||||
Local<Boolean> supportsRawOutput = NanNew<Boolean>(vips_version(0) >= 8 || (vips_version(0) == 7 && vips_version(1) >= 42));
|
Local<Boolean> hasOutputBufferRaw = New<Boolean>(vips_version(0) >= 8 || (vips_version(0) == 7 && vips_version(1) >= 42));
|
||||||
Local<Object> rawOutput = NanNew<Object>();
|
Local<Object> rawOutput = New<Object>();
|
||||||
rawOutput->Set(attrFile, unsupported);
|
Set(rawOutput, attrFile, unsupported);
|
||||||
rawOutput->Set(attrBuffer, supportsRawOutput);
|
Set(rawOutput, attrBuffer, hasOutputBufferRaw);
|
||||||
rawOutput->Set(attrStream, supportsRawOutput);
|
Set(rawOutput, attrStream, hasOutputBufferRaw);
|
||||||
raw->Set(attrOutput, rawOutput);
|
Set(raw, attrOutput, rawOutput);
|
||||||
|
|
||||||
NanReturnValue(format);
|
info.GetReturnValue().Set(format);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -156,50 +163,50 @@ NAN_METHOD(_maxColourDistance) {
|
|||||||
using sharp::InitImage;
|
using sharp::InitImage;
|
||||||
using sharp::HasAlpha;
|
using sharp::HasAlpha;
|
||||||
|
|
||||||
NanScope();
|
HandleScope();
|
||||||
|
|
||||||
// Create "hook" VipsObject to hang image references from
|
// Create "hook" VipsObject to hang image references from
|
||||||
VipsObject *hook = reinterpret_cast<VipsObject*>(vips_image_new());
|
VipsObject *hook = reinterpret_cast<VipsObject*>(vips_image_new());
|
||||||
|
|
||||||
// Open input files
|
// Open input files
|
||||||
VipsImage *image1 = NULL;
|
VipsImage *image1 = NULL;
|
||||||
ImageType imageType1 = DetermineImageType(*String::Utf8Value(args[0]));
|
ImageType imageType1 = DetermineImageType(*Utf8String(info[0]));
|
||||||
if (imageType1 != ImageType::UNKNOWN) {
|
if (imageType1 != ImageType::UNKNOWN) {
|
||||||
image1 = InitImage(*String::Utf8Value(args[0]), VIPS_ACCESS_SEQUENTIAL);
|
image1 = InitImage(*Utf8String(info[0]), VIPS_ACCESS_SEQUENTIAL);
|
||||||
if (image1 == NULL) {
|
if (image1 == NULL) {
|
||||||
g_object_unref(hook);
|
g_object_unref(hook);
|
||||||
return NanThrowError("Input file 1 has corrupt header");
|
return ThrowError("Input file 1 has corrupt header");
|
||||||
} else {
|
} else {
|
||||||
vips_object_local(hook, image1);
|
vips_object_local(hook, image1);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
g_object_unref(hook);
|
g_object_unref(hook);
|
||||||
return NanThrowError("Input file 1 is of an unsupported image format");
|
return ThrowError("Input file 1 is of an unsupported image format");
|
||||||
}
|
}
|
||||||
VipsImage *image2 = NULL;
|
VipsImage *image2 = NULL;
|
||||||
ImageType imageType2 = DetermineImageType(*String::Utf8Value(args[1]));
|
ImageType imageType2 = DetermineImageType(*Utf8String(info[1]));
|
||||||
if (imageType2 != ImageType::UNKNOWN) {
|
if (imageType2 != ImageType::UNKNOWN) {
|
||||||
image2 = InitImage(*String::Utf8Value(args[1]), VIPS_ACCESS_SEQUENTIAL);
|
image2 = InitImage(*Utf8String(info[1]), VIPS_ACCESS_SEQUENTIAL);
|
||||||
if (image2 == NULL) {
|
if (image2 == NULL) {
|
||||||
g_object_unref(hook);
|
g_object_unref(hook);
|
||||||
return NanThrowError("Input file 2 has corrupt header");
|
return ThrowError("Input file 2 has corrupt header");
|
||||||
} else {
|
} else {
|
||||||
vips_object_local(hook, image2);
|
vips_object_local(hook, image2);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
g_object_unref(hook);
|
g_object_unref(hook);
|
||||||
return NanThrowError("Input file 2 is of an unsupported image format");
|
return ThrowError("Input file 2 is of an unsupported image format");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure same number of channels
|
// Ensure same number of channels
|
||||||
if (image1->Bands != image2->Bands) {
|
if (image1->Bands != image2->Bands) {
|
||||||
g_object_unref(hook);
|
g_object_unref(hook);
|
||||||
return NanThrowError("mismatchedBands");
|
return ThrowError("mismatchedBands");
|
||||||
}
|
}
|
||||||
// Ensure same dimensions
|
// Ensure same dimensions
|
||||||
if (image1->Xsize != image2->Xsize || image1->Ysize != image2->Ysize) {
|
if (image1->Xsize != image2->Xsize || image1->Ysize != image2->Ysize) {
|
||||||
g_object_unref(hook);
|
g_object_unref(hook);
|
||||||
return NanThrowError("mismatchedDimensions");
|
return ThrowError("mismatchedDimensions");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Premultiply and remove alpha
|
// Premultiply and remove alpha
|
||||||
@ -207,13 +214,13 @@ NAN_METHOD(_maxColourDistance) {
|
|||||||
VipsImage *imagePremultiplied1;
|
VipsImage *imagePremultiplied1;
|
||||||
if (Premultiply(hook, image1, &imagePremultiplied1)) {
|
if (Premultiply(hook, image1, &imagePremultiplied1)) {
|
||||||
g_object_unref(hook);
|
g_object_unref(hook);
|
||||||
return NanThrowError(vips_error_buffer());
|
return ThrowError(vips_error_buffer());
|
||||||
}
|
}
|
||||||
vips_object_local(hook, imagePremultiplied1);
|
vips_object_local(hook, imagePremultiplied1);
|
||||||
VipsImage *imagePremultipliedNoAlpha1;
|
VipsImage *imagePremultipliedNoAlpha1;
|
||||||
if (vips_extract_band(image1, &imagePremultipliedNoAlpha1, 1, "n", image1->Bands - 1, NULL)) {
|
if (vips_extract_band(image1, &imagePremultipliedNoAlpha1, 1, "n", image1->Bands - 1, NULL)) {
|
||||||
g_object_unref(hook);
|
g_object_unref(hook);
|
||||||
return NanThrowError(vips_error_buffer());
|
return ThrowError(vips_error_buffer());
|
||||||
}
|
}
|
||||||
vips_object_local(hook, imagePremultipliedNoAlpha1);
|
vips_object_local(hook, imagePremultipliedNoAlpha1);
|
||||||
image1 = imagePremultipliedNoAlpha1;
|
image1 = imagePremultipliedNoAlpha1;
|
||||||
@ -222,13 +229,13 @@ NAN_METHOD(_maxColourDistance) {
|
|||||||
VipsImage *imagePremultiplied2;
|
VipsImage *imagePremultiplied2;
|
||||||
if (Premultiply(hook, image2, &imagePremultiplied2)) {
|
if (Premultiply(hook, image2, &imagePremultiplied2)) {
|
||||||
g_object_unref(hook);
|
g_object_unref(hook);
|
||||||
return NanThrowError(vips_error_buffer());
|
return ThrowError(vips_error_buffer());
|
||||||
}
|
}
|
||||||
vips_object_local(hook, imagePremultiplied2);
|
vips_object_local(hook, imagePremultiplied2);
|
||||||
VipsImage *imagePremultipliedNoAlpha2;
|
VipsImage *imagePremultipliedNoAlpha2;
|
||||||
if (vips_extract_band(image2, &imagePremultipliedNoAlpha2, 1, "n", image2->Bands - 1, NULL)) {
|
if (vips_extract_band(image2, &imagePremultipliedNoAlpha2, 1, "n", image2->Bands - 1, NULL)) {
|
||||||
g_object_unref(hook);
|
g_object_unref(hook);
|
||||||
return NanThrowError(vips_error_buffer());
|
return ThrowError(vips_error_buffer());
|
||||||
}
|
}
|
||||||
vips_object_local(hook, imagePremultipliedNoAlpha2);
|
vips_object_local(hook, imagePremultipliedNoAlpha2);
|
||||||
image2 = imagePremultipliedNoAlpha2;
|
image2 = imagePremultipliedNoAlpha2;
|
||||||
@ -237,15 +244,15 @@ NAN_METHOD(_maxColourDistance) {
|
|||||||
VipsImage *difference;
|
VipsImage *difference;
|
||||||
if (vips_dE00(image1, image2, &difference, NULL)) {
|
if (vips_dE00(image1, image2, &difference, NULL)) {
|
||||||
g_object_unref(hook);
|
g_object_unref(hook);
|
||||||
return NanThrowError(vips_error_buffer());
|
return ThrowError(vips_error_buffer());
|
||||||
}
|
}
|
||||||
vips_object_local(hook, difference);
|
vips_object_local(hook, difference);
|
||||||
// Extract maximum distance
|
// Extract maximum distance
|
||||||
double maxColourDistance;
|
double maxColourDistance;
|
||||||
if (vips_max(difference, &maxColourDistance, NULL)) {
|
if (vips_max(difference, &maxColourDistance, NULL)) {
|
||||||
g_object_unref(hook);
|
g_object_unref(hook);
|
||||||
return NanThrowError(vips_error_buffer());
|
return ThrowError(vips_error_buffer());
|
||||||
}
|
}
|
||||||
g_object_unref(hook);
|
g_object_unref(hook);
|
||||||
NanReturnValue(maxColourDistance);
|
info.GetReturnValue().Set(New<Number>(maxColourDistance));
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user