UNPKG

8.09 kBtext/x-cView Raw
1// Copyright 2013 Lovell Fuller and others.
2// SPDX-License-Identifier: Apache-2.0
3
4#include <cmath>
5#include <string>
6
7#include <napi.h>
8#include <vips/vips8>
9#include <vips/vector.h>
10
11#include "common.h"
12#include "operations.h"
13#include "utilities.h"
14
15/*
16 Get and set cache limits
17*/
18Napi::Value cache(const Napi::CallbackInfo& info) {
19 Napi::Env env = info.Env();
20
21 // Set memory limit
22 if (info[size_t(0)].IsNumber()) {
23 vips_cache_set_max_mem(info[size_t(0)].As<Napi::Number>().Int32Value() * 1048576);
24 }
25 // Set file limit
26 if (info[size_t(1)].IsNumber()) {
27 vips_cache_set_max_files(info[size_t(1)].As<Napi::Number>().Int32Value());
28 }
29 // Set items limit
30 if (info[size_t(2)].IsNumber()) {
31 vips_cache_set_max(info[size_t(2)].As<Napi::Number>().Int32Value());
32 }
33
34 // Get memory stats
35 Napi::Object memory = Napi::Object::New(env);
36 memory.Set("current", round(vips_tracked_get_mem() / 1048576));
37 memory.Set("high", round(vips_tracked_get_mem_highwater() / 1048576));
38 memory.Set("max", round(vips_cache_get_max_mem() / 1048576));
39 // Get file stats
40 Napi::Object files = Napi::Object::New(env);
41 files.Set("current", vips_tracked_get_files());
42 files.Set("max", vips_cache_get_max_files());
43
44 // Get item stats
45 Napi::Object items = Napi::Object::New(env);
46 items.Set("current", vips_cache_get_size());
47 items.Set("max", vips_cache_get_max());
48
49 Napi::Object cache = Napi::Object::New(env);
50 cache.Set("memory", memory);
51 cache.Set("files", files);
52 cache.Set("items", items);
53 return cache;
54}
55
56/*
57 Get and set size of thread pool
58*/
59Napi::Value concurrency(const Napi::CallbackInfo& info) {
60 // Set concurrency
61 if (info[size_t(0)].IsNumber()) {
62 vips_concurrency_set(info[size_t(0)].As<Napi::Number>().Int32Value());
63 }
64 // Get concurrency
65 return Napi::Number::New(info.Env(), vips_concurrency_get());
66}
67
68/*
69 Get internal counters (queued tasks, processing tasks)
70*/
71Napi::Value counters(const Napi::CallbackInfo& info) {
72 Napi::Object counters = Napi::Object::New(info.Env());
73 counters.Set("queue", sharp::counterQueue);
74 counters.Set("process", sharp::counterProcess);
75 return counters;
76}
77
78/*
79 Get and set use of SIMD vector unit instructions
80*/
81Napi::Value simd(const Napi::CallbackInfo& info) {
82 // Set state
83 if (info[size_t(0)].IsBoolean()) {
84 vips_vector_set_enabled(info[size_t(0)].As<Napi::Boolean>().Value());
85 }
86 // Get state
87 return Napi::Boolean::New(info.Env(), vips_vector_isenabled());
88}
89
90/*
91 Get libvips version
92*/
93Napi::Value libvipsVersion(const Napi::CallbackInfo& info) {
94 char version[9];
95 g_snprintf(version, sizeof(version), "%d.%d.%d", vips_version(0), vips_version(1), vips_version(2));
96 return Napi::String::New(info.Env(), version);
97}
98
99/*
100 Get available input/output file/buffer/stream formats
101*/
102Napi::Value format(const Napi::CallbackInfo& info) {
103 Napi::Env env = info.Env();
104 Napi::Object format = Napi::Object::New(env);
105 for (std::string const f : {
106 "jpeg", "png", "webp", "tiff", "magick", "openslide", "dz",
107 "ppm", "fits", "gif", "svg", "heif", "pdf", "vips", "jp2k", "jxl"
108 }) {
109 // Input
110 const VipsObjectClass *oc = vips_class_find("VipsOperation", (f + "load").c_str());
111 Napi::Boolean hasInputFile = Napi::Boolean::New(env, oc);
112 Napi::Boolean hasInputBuffer =
113 Napi::Boolean::New(env, vips_type_find("VipsOperation", (f + "load_buffer").c_str()));
114 Napi::Object input = Napi::Object::New(env);
115 input.Set("file", hasInputFile);
116 input.Set("buffer", hasInputBuffer);
117 input.Set("stream", hasInputBuffer);
118 if (hasInputFile) {
119 const VipsForeignClass *fc = VIPS_FOREIGN_CLASS(oc);
120 if (fc->suffs) {
121 Napi::Array fileSuffix = Napi::Array::New(env);
122 const char **suffix = fc->suffs;
123 for (int i = 0; *suffix; i++, suffix++) {
124 fileSuffix.Set(i, Napi::String::New(env, *suffix));
125 }
126 input.Set("fileSuffix", fileSuffix);
127 }
128 }
129 // Output
130 Napi::Boolean hasOutputFile =
131 Napi::Boolean::New(env, vips_type_find("VipsOperation", (f + "save").c_str()));
132 Napi::Boolean hasOutputBuffer =
133 Napi::Boolean::New(env, vips_type_find("VipsOperation", (f + "save_buffer").c_str()));
134 Napi::Object output = Napi::Object::New(env);
135 output.Set("file", hasOutputFile);
136 output.Set("buffer", hasOutputBuffer);
137 output.Set("stream", hasOutputBuffer);
138 // Other attributes
139 Napi::Object container = Napi::Object::New(env);
140 container.Set("id", f);
141 container.Set("input", input);
142 container.Set("output", output);
143 // Add to set of formats
144 format.Set(f, container);
145 }
146
147 // Raw, uncompressed data
148 Napi::Boolean supported = Napi::Boolean::New(env, true);
149 Napi::Boolean unsupported = Napi::Boolean::New(env, false);
150 Napi::Object rawInput = Napi::Object::New(env);
151 rawInput.Set("file", unsupported);
152 rawInput.Set("buffer", supported);
153 rawInput.Set("stream", supported);
154 Napi::Object rawOutput = Napi::Object::New(env);
155 rawOutput.Set("file", unsupported);
156 rawOutput.Set("buffer", supported);
157 rawOutput.Set("stream", supported);
158 Napi::Object raw = Napi::Object::New(env);
159 raw.Set("id", "raw");
160 raw.Set("input", rawInput);
161 raw.Set("output", rawOutput);
162 format.Set("raw", raw);
163
164 return format;
165}
166
167/*
168 Synchronous, internal-only method used by some of the functional tests.
169 Calculates the maximum colour distance using the DE2000 algorithm
170 between two images of the same dimensions and number of channels.
171*/
172Napi::Value _maxColourDistance(const Napi::CallbackInfo& info) {
173 Napi::Env env = info.Env();
174
175 // Open input files
176 VImage image1;
177 sharp::ImageType imageType1 = sharp::DetermineImageType(info[size_t(0)].As<Napi::String>().Utf8Value().data());
178 if (imageType1 != sharp::ImageType::UNKNOWN) {
179 try {
180 image1 = VImage::new_from_file(info[size_t(0)].As<Napi::String>().Utf8Value().c_str());
181 } catch (...) {
182 throw Napi::Error::New(env, "Input file 1 has corrupt header");
183 }
184 } else {
185 throw Napi::Error::New(env, "Input file 1 is of an unsupported image format");
186 }
187 VImage image2;
188 sharp::ImageType imageType2 = sharp::DetermineImageType(info[size_t(1)].As<Napi::String>().Utf8Value().data());
189 if (imageType2 != sharp::ImageType::UNKNOWN) {
190 try {
191 image2 = VImage::new_from_file(info[size_t(1)].As<Napi::String>().Utf8Value().c_str());
192 } catch (...) {
193 throw Napi::Error::New(env, "Input file 2 has corrupt header");
194 }
195 } else {
196 throw Napi::Error::New(env, "Input file 2 is of an unsupported image format");
197 }
198 // Ensure same number of channels
199 if (image1.bands() != image2.bands()) {
200 throw Napi::Error::New(env, "mismatchedBands");
201 }
202 // Ensure same dimensions
203 if (image1.width() != image2.width() || image1.height() != image2.height()) {
204 throw Napi::Error::New(env, "mismatchedDimensions");
205 }
206
207 double maxColourDistance;
208 try {
209 // Premultiply and remove alpha
210 if (sharp::HasAlpha(image1)) {
211 image1 = image1.premultiply().extract_band(1, VImage::option()->set("n", image1.bands() - 1));
212 }
213 if (sharp::HasAlpha(image2)) {
214 image2 = image2.premultiply().extract_band(1, VImage::option()->set("n", image2.bands() - 1));
215 }
216 // Calculate colour distance
217 maxColourDistance = image1.dE00(image2).max();
218 } catch (vips::VError const &err) {
219 throw Napi::Error::New(env, err.what());
220 }
221
222 // Clean up libvips' per-request data and threads
223 vips_error_clear();
224 vips_thread_shutdown();
225
226 return Napi::Number::New(env, maxColourDistance);
227}
228
229#if defined(__GNUC__)
230// mallctl will be resolved by the runtime linker when jemalloc is being used
231extern "C" {
232 int mallctl(const char *name, void *oldp, size_t *oldlenp, void *newp, size_t newlen) __attribute__((weak));
233}
234Napi::Value _isUsingJemalloc(const Napi::CallbackInfo& info) {
235 Napi::Env env = info.Env();
236 return Napi::Boolean::New(env, mallctl != nullptr);
237}
238#else
239Napi::Value _isUsingJemalloc(const Napi::CallbackInfo& info) {
240 Napi::Env env = info.Env();
241 return Napi::Boolean::New(env, false);
242}
243#endif