1 |
|
2 |
|
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 |
|
17 |
|
18 | Napi::Value cache(const Napi::CallbackInfo& info) {
|
19 | Napi::Env env = info.Env();
|
20 |
|
21 |
|
22 | if (info[size_t(0)].IsNumber()) {
|
23 | vips_cache_set_max_mem(info[size_t(0)].As<Napi::Number>().Int32Value() * 1048576);
|
24 | }
|
25 |
|
26 | if (info[size_t(1)].IsNumber()) {
|
27 | vips_cache_set_max_files(info[size_t(1)].As<Napi::Number>().Int32Value());
|
28 | }
|
29 |
|
30 | if (info[size_t(2)].IsNumber()) {
|
31 | vips_cache_set_max(info[size_t(2)].As<Napi::Number>().Int32Value());
|
32 | }
|
33 |
|
34 |
|
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 |
|
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 |
|
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 |
|
58 |
|
59 | Napi::Value concurrency(const Napi::CallbackInfo& info) {
|
60 |
|
61 | if (info[size_t(0)].IsNumber()) {
|
62 | vips_concurrency_set(info[size_t(0)].As<Napi::Number>().Int32Value());
|
63 | }
|
64 |
|
65 | return Napi::Number::New(info.Env(), vips_concurrency_get());
|
66 | }
|
67 |
|
68 |
|
69 |
|
70 |
|
71 | Napi::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 |
|
80 |
|
81 | Napi::Value simd(const Napi::CallbackInfo& info) {
|
82 |
|
83 | if (info[size_t(0)].IsBoolean()) {
|
84 | vips_vector_set_enabled(info[size_t(0)].As<Napi::Boolean>().Value());
|
85 | }
|
86 |
|
87 | return Napi::Boolean::New(info.Env(), vips_vector_isenabled());
|
88 | }
|
89 |
|
90 |
|
91 |
|
92 |
|
93 | Napi::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 |
|
101 |
|
102 | Napi::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 |
|
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 |
|
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 |
|
139 | Napi::Object container = Napi::Object::New(env);
|
140 | container.Set("id", f);
|
141 | container.Set("input", input);
|
142 | container.Set("output", output);
|
143 |
|
144 | format.Set(f, container);
|
145 | }
|
146 |
|
147 |
|
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 |
|
169 |
|
170 |
|
171 |
|
172 | Napi::Value _maxColourDistance(const Napi::CallbackInfo& info) {
|
173 | Napi::Env env = info.Env();
|
174 |
|
175 |
|
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 |
|
199 | if (image1.bands() != image2.bands()) {
|
200 | throw Napi::Error::New(env, "mismatchedBands");
|
201 | }
|
202 |
|
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 |
|
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 |
|
217 | maxColourDistance = image1.dE00(image2).max();
|
218 | } catch (vips::VError const &err) {
|
219 | throw Napi::Error::New(env, err.what());
|
220 | }
|
221 |
|
222 |
|
223 | vips_error_clear();
|
224 | vips_thread_shutdown();
|
225 |
|
226 | return Napi::Number::New(env, maxColourDistance);
|
227 | }
|
228 |
|
229 | #if defined(__GNUC__)
|
230 |
|
231 | extern "C" {
|
232 | int mallctl(const char *name, void *oldp, size_t *oldlenp, void *newp, size_t newlen) __attribute__((weak));
|
233 | }
|
234 | Napi::Value _isUsingJemalloc(const Napi::CallbackInfo& info) {
|
235 | Napi::Env env = info.Env();
|
236 | return Napi::Boolean::New(env, mallctl != nullptr);
|
237 | }
|
238 | #else
|
239 | Napi::Value _isUsingJemalloc(const Napi::CallbackInfo& info) {
|
240 | Napi::Env env = info.Env();
|
241 | return Napi::Boolean::New(env, false);
|
242 | }
|
243 | #endif
|