mirror of
https://github.com/lovell/sharp.git
synced 2025-07-09 10:30:15 +02:00
273 lines
8.4 KiB
C++
273 lines
8.4 KiB
C++
// Copyright 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020 Lovell Fuller and contributors.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
#include <cmath>
|
|
#include <string>
|
|
|
|
#include <node.h>
|
|
#include <nan.h>
|
|
#include <vips/vips8>
|
|
#include <vips/vector.h>
|
|
|
|
#include "common.h"
|
|
#include "operations.h"
|
|
#include "utilities.h"
|
|
|
|
using v8::Boolean;
|
|
using v8::Integer;
|
|
using v8::Local;
|
|
using v8::Number;
|
|
using v8::Object;
|
|
using v8::String;
|
|
|
|
using Nan::HandleScope;
|
|
using Nan::New;
|
|
using Nan::Set;
|
|
using Nan::ThrowError;
|
|
using Nan::To;
|
|
using Nan::Utf8String;
|
|
|
|
/*
|
|
Get and set cache limits
|
|
*/
|
|
NAN_METHOD(cache) {
|
|
HandleScope();
|
|
|
|
// Set memory limit
|
|
if (info[0]->IsInt32()) {
|
|
vips_cache_set_max_mem(To<int32_t>(info[0]).FromJust() * 1048576);
|
|
}
|
|
// Set file limit
|
|
if (info[1]->IsInt32()) {
|
|
vips_cache_set_max_files(To<int32_t>(info[1]).FromJust());
|
|
}
|
|
// Set items limit
|
|
if (info[2]->IsInt32()) {
|
|
vips_cache_set_max(To<int32_t>(info[2]).FromJust());
|
|
}
|
|
|
|
// Get memory stats
|
|
Local<Object> memory = New<Object>();
|
|
Set(memory, New("current").ToLocalChecked(),
|
|
New<Integer>(static_cast<int>(round(vips_tracked_get_mem() / 1048576))));
|
|
Set(memory, New("high").ToLocalChecked(),
|
|
New<Integer>(static_cast<int>(round(vips_tracked_get_mem_highwater() / 1048576))));
|
|
Set(memory, New("max").ToLocalChecked(),
|
|
New<Integer>(static_cast<int>(round(vips_cache_get_max_mem() / 1048576))));
|
|
// Get file stats
|
|
Local<Object> files = New<Object>();
|
|
Set(files, New("current").ToLocalChecked(), New<Integer>(vips_tracked_get_files()));
|
|
Set(files, New("max").ToLocalChecked(), New<Integer>(vips_cache_get_max_files()));
|
|
|
|
// Get item stats
|
|
Local<Object> items = New<Object>();
|
|
Set(items, New("current").ToLocalChecked(), New<Integer>(vips_cache_get_size()));
|
|
Set(items, New("max").ToLocalChecked(), New<Integer>(vips_cache_get_max()));
|
|
|
|
Local<Object> cache = New<Object>();
|
|
Set(cache, New("memory").ToLocalChecked(), memory);
|
|
Set(cache, New("files").ToLocalChecked(), files);
|
|
Set(cache, New("items").ToLocalChecked(), items);
|
|
info.GetReturnValue().Set(cache);
|
|
}
|
|
|
|
/*
|
|
Get and set size of thread pool
|
|
*/
|
|
NAN_METHOD(concurrency) {
|
|
HandleScope();
|
|
|
|
// Set concurrency
|
|
if (info[0]->IsInt32()) {
|
|
vips_concurrency_set(To<int32_t>(info[0]).FromJust());
|
|
}
|
|
// Get concurrency
|
|
info.GetReturnValue().Set(New<Integer>(vips_concurrency_get()));
|
|
}
|
|
|
|
/*
|
|
Get internal counters (queued tasks, processing tasks)
|
|
*/
|
|
NAN_METHOD(counters) {
|
|
using sharp::counterProcess;
|
|
using sharp::counterQueue;
|
|
|
|
HandleScope();
|
|
Local<Object> counters = New<Object>();
|
|
Set(counters, New("queue").ToLocalChecked(), New<Integer>(counterQueue));
|
|
Set(counters, New("process").ToLocalChecked(), New<Integer>(counterProcess));
|
|
info.GetReturnValue().Set(counters);
|
|
}
|
|
|
|
/*
|
|
Get and set use of SIMD vector unit instructions
|
|
*/
|
|
NAN_METHOD(simd) {
|
|
HandleScope();
|
|
|
|
// Set state
|
|
if (info[0]->IsBoolean()) {
|
|
vips_vector_set_enabled(To<bool>(info[0]).FromJust());
|
|
}
|
|
// Get state
|
|
info.GetReturnValue().Set(New<Boolean>(vips_vector_isenabled()));
|
|
}
|
|
|
|
/*
|
|
Get libvips version
|
|
*/
|
|
NAN_METHOD(libvipsVersion) {
|
|
HandleScope();
|
|
char version[9];
|
|
g_snprintf(version, sizeof(version), "%d.%d.%d", vips_version(0), vips_version(1), vips_version(2));
|
|
info.GetReturnValue().Set(New(version).ToLocalChecked());
|
|
}
|
|
|
|
/*
|
|
Get available input/output file/buffer/stream formats
|
|
*/
|
|
NAN_METHOD(format) {
|
|
HandleScope();
|
|
|
|
// Attribute names
|
|
Local<String> attrId = New("id").ToLocalChecked();
|
|
Local<String> attrInput = New("input").ToLocalChecked();
|
|
Local<String> attrOutput = New("output").ToLocalChecked();
|
|
Local<String> attrFile = New("file").ToLocalChecked();
|
|
Local<String> attrBuffer = New("buffer").ToLocalChecked();
|
|
Local<String> attrStream = New("stream").ToLocalChecked();
|
|
|
|
// Which load/save operations are available for each compressed format?
|
|
Local<Object> format = New<Object>();
|
|
for (std::string const f : {
|
|
"jpeg", "png", "webp", "tiff", "magick", "openslide", "dz",
|
|
"ppm", "fits", "gif", "svg", "heif", "pdf", "vips"
|
|
}) {
|
|
// Input
|
|
Local<Boolean> hasInputFile =
|
|
New<Boolean>(vips_type_find("VipsOperation", (f + "load").c_str()));
|
|
Local<Boolean> hasInputBuffer =
|
|
New<Boolean>(vips_type_find("VipsOperation", (f + "load_buffer").c_str()));
|
|
Local<Object> input = New<Object>();
|
|
Set(input, attrFile, hasInputFile);
|
|
Set(input, attrBuffer, hasInputBuffer);
|
|
Set(input, attrStream, hasInputBuffer);
|
|
// Output
|
|
Local<Boolean> hasOutputFile =
|
|
New<Boolean>(vips_type_find("VipsOperation", (f + "save").c_str()));
|
|
Local<Boolean> hasOutputBuffer =
|
|
New<Boolean>(vips_type_find("VipsOperation", (f + "save_buffer").c_str()));
|
|
Local<Object> output = New<Object>();
|
|
Set(output, attrFile, hasOutputFile);
|
|
Set(output, attrBuffer, hasOutputBuffer);
|
|
Set(output, attrStream, hasOutputBuffer);
|
|
// Other attributes
|
|
Local<Object> container = New<Object>();
|
|
Local<String> formatId = New(f).ToLocalChecked();
|
|
Set(container, attrId, formatId);
|
|
Set(container, attrInput, input);
|
|
Set(container, attrOutput, output);
|
|
// Add to set of formats
|
|
Set(format, formatId, container);
|
|
}
|
|
|
|
// Raw, uncompressed data
|
|
Local<Object> raw = New<Object>();
|
|
Local<String> rawId = New("raw").ToLocalChecked();
|
|
Set(raw, attrId, rawId);
|
|
Set(format, rawId, raw);
|
|
Local<Boolean> supported = New<Boolean>(true);
|
|
Local<Boolean> unsupported = New<Boolean>(false);
|
|
Local<Object> rawInput = New<Object>();
|
|
Set(rawInput, attrFile, unsupported);
|
|
Set(rawInput, attrBuffer, supported);
|
|
Set(rawInput, attrStream, supported);
|
|
Set(raw, attrInput, rawInput);
|
|
Local<Object> rawOutput = New<Object>();
|
|
Set(rawOutput, attrFile, unsupported);
|
|
Set(rawOutput, attrBuffer, supported);
|
|
Set(rawOutput, attrStream, supported);
|
|
Set(raw, attrOutput, rawOutput);
|
|
|
|
info.GetReturnValue().Set(format);
|
|
}
|
|
|
|
/*
|
|
Synchronous, internal-only method used by some of the functional tests.
|
|
Calculates the maximum colour distance using the DE2000 algorithm
|
|
between two images of the same dimensions and number of channels.
|
|
*/
|
|
NAN_METHOD(_maxColourDistance) {
|
|
using vips::VImage;
|
|
using vips::VError;
|
|
using sharp::DetermineImageType;
|
|
using sharp::ImageType;
|
|
using sharp::HasAlpha;
|
|
|
|
HandleScope();
|
|
|
|
// Open input files
|
|
VImage image1;
|
|
ImageType imageType1 = DetermineImageType(*Utf8String(info[0]));
|
|
if (imageType1 != ImageType::UNKNOWN) {
|
|
try {
|
|
image1 = VImage::new_from_file(*Utf8String(info[0]));
|
|
} catch (...) {
|
|
return ThrowError("Input file 1 has corrupt header");
|
|
}
|
|
} else {
|
|
return ThrowError("Input file 1 is of an unsupported image format");
|
|
}
|
|
VImage image2;
|
|
ImageType imageType2 = DetermineImageType(*Utf8String(info[1]));
|
|
if (imageType2 != ImageType::UNKNOWN) {
|
|
try {
|
|
image2 = VImage::new_from_file(*Utf8String(info[1]));
|
|
} catch (...) {
|
|
return ThrowError("Input file 2 has corrupt header");
|
|
}
|
|
} else {
|
|
return ThrowError("Input file 2 is of an unsupported image format");
|
|
}
|
|
// Ensure same number of channels
|
|
if (image1.bands() != image2.bands()) {
|
|
return ThrowError("mismatchedBands");
|
|
}
|
|
// Ensure same dimensions
|
|
if (image1.width() != image2.width() || image1.height() != image2.height()) {
|
|
return ThrowError("mismatchedDimensions");
|
|
}
|
|
|
|
double maxColourDistance;
|
|
try {
|
|
// Premultiply and remove alpha
|
|
if (HasAlpha(image1)) {
|
|
image1 = image1.premultiply().extract_band(1, VImage::option()->set("n", image1.bands() - 1));
|
|
}
|
|
if (HasAlpha(image2)) {
|
|
image2 = image2.premultiply().extract_band(1, VImage::option()->set("n", image2.bands() - 1));
|
|
}
|
|
// Calculate colour distance
|
|
maxColourDistance = image1.dE00(image2).max();
|
|
} catch (VError const &err) {
|
|
return ThrowError(err.what());
|
|
}
|
|
|
|
// Clean up libvips' per-request data and threads
|
|
vips_error_clear();
|
|
vips_thread_shutdown();
|
|
|
|
info.GetReturnValue().Set(New<Number>(maxColourDistance));
|
|
}
|