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