sharp 0.32.6 → 0.33.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -2
- package/install/check.js +41 -0
- package/lib/colour.js +5 -9
- package/lib/constructor.js +29 -18
- package/lib/index.d.ts +100 -26
- package/lib/input.js +44 -18
- package/lib/is.js +28 -14
- package/lib/libvips.js +118 -57
- package/lib/operation.js +2 -0
- package/lib/output.js +247 -75
- package/lib/resize.js +54 -49
- package/lib/sharp.js +100 -23
- package/lib/utility.js +31 -29
- package/package.json +62 -47
- package/{binding.gyp → src/binding.gyp} +92 -48
- package/src/common.cc +62 -13
- package/src/common.h +27 -11
- package/src/metadata.cc +5 -5
- package/src/operations.cc +35 -18
- package/src/operations.h +3 -3
- package/src/pipeline.cc +142 -112
- package/src/pipeline.h +17 -11
- package/src/sharp.cc +6 -7
- package/src/stats.cc +5 -5
- package/src/utilities.cc +20 -5
- package/install/can-compile.js +0 -14
- package/install/dll-copy.js +0 -40
- package/install/libvips.js +0 -222
- package/lib/agent.js +0 -44
- package/lib/platform.js +0 -30
- package/src/libvips/cplusplus/VConnection.cpp +0 -151
- package/src/libvips/cplusplus/VError.cpp +0 -49
- package/src/libvips/cplusplus/VImage.cpp +0 -1548
- package/src/libvips/cplusplus/VInterpolate.cpp +0 -62
- package/src/libvips/cplusplus/VRegion.cpp +0 -27
- package/src/libvips/cplusplus/vips-operators.cpp +0 -3760
|
@@ -1,8 +1,15 @@
|
|
|
1
|
+
# Copyright 2013 Lovell Fuller and others.
|
|
2
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
1
4
|
{
|
|
2
5
|
'variables': {
|
|
3
|
-
'vips_version': '<!(node -p "require(\'
|
|
4
|
-
'platform_and_arch': '<!(node -p "require(\'
|
|
5
|
-
'
|
|
6
|
+
'vips_version': '<!(node -p "require(\'../lib/libvips\').minimumLibvipsVersion")',
|
|
7
|
+
'platform_and_arch': '<!(node -p "require(\'../lib/libvips\').buildPlatformArch()")',
|
|
8
|
+
'sharp_libvips_version': '<!(node -p "require(\'../package.json\').optionalDependencies[\'@img/sharp-libvips-<(platform_and_arch)\']")',
|
|
9
|
+
'sharp_libvips_yarn_locator': '<!(node -p "require(\'../lib/libvips\').yarnLocator()")',
|
|
10
|
+
'sharp_libvips_include_dir': '<!(node -p "require(\'../lib/libvips\').buildSharpLibvipsIncludeDir()")',
|
|
11
|
+
'sharp_libvips_cplusplus_dir': '<!(node -p "require(\'../lib/libvips\').buildSharpLibvipsCPlusPlusDir()")',
|
|
12
|
+
'sharp_libvips_lib_dir': '<!(node -p "require(\'../lib/libvips\').buildSharpLibvipsLibDir()")'
|
|
6
13
|
},
|
|
7
14
|
'targets': [{
|
|
8
15
|
'target_name': 'libvips-cpp',
|
|
@@ -15,23 +22,23 @@
|
|
|
15
22
|
'_ALLOW_KEYWORD_MACROS'
|
|
16
23
|
],
|
|
17
24
|
'sources': [
|
|
18
|
-
'
|
|
19
|
-
'
|
|
20
|
-
'
|
|
21
|
-
'
|
|
22
|
-
'
|
|
25
|
+
'<(sharp_libvips_cplusplus_dir)/VConnection.cpp',
|
|
26
|
+
'<(sharp_libvips_cplusplus_dir)/VError.cpp',
|
|
27
|
+
'<(sharp_libvips_cplusplus_dir)/VImage.cpp',
|
|
28
|
+
'<(sharp_libvips_cplusplus_dir)/VInterpolate.cpp',
|
|
29
|
+
'<(sharp_libvips_cplusplus_dir)/VRegion.cpp'
|
|
23
30
|
],
|
|
24
31
|
'include_dirs': [
|
|
25
|
-
'<(
|
|
26
|
-
'<(
|
|
27
|
-
'<(
|
|
32
|
+
'<(sharp_libvips_include_dir)',
|
|
33
|
+
'<(sharp_libvips_include_dir)/glib-2.0',
|
|
34
|
+
'<(sharp_libvips_lib_dir)/glib-2.0/include'
|
|
28
35
|
],
|
|
29
36
|
'link_settings': {
|
|
30
|
-
'library_dirs': [
|
|
37
|
+
'library_dirs': [
|
|
38
|
+
'<(sharp_libvips_lib_dir)'
|
|
39
|
+
],
|
|
31
40
|
'libraries': [
|
|
32
|
-
'libvips.lib'
|
|
33
|
-
'libglib-2.0.lib',
|
|
34
|
-
'libgobject-2.0.lib'
|
|
41
|
+
'libvips.lib'
|
|
35
42
|
],
|
|
36
43
|
},
|
|
37
44
|
'configurations': {
|
|
@@ -70,7 +77,7 @@
|
|
|
70
77
|
}, {
|
|
71
78
|
'target_name': 'sharp-<(platform_and_arch)',
|
|
72
79
|
'defines': [
|
|
73
|
-
'NAPI_VERSION=
|
|
80
|
+
'NAPI_VERSION=9',
|
|
74
81
|
'NODE_ADDON_API_DISABLE_DEPRECATED',
|
|
75
82
|
'NODE_API_SWALLOW_UNTHROWABLE_EXCEPTIONS'
|
|
76
83
|
],
|
|
@@ -79,11 +86,10 @@
|
|
|
79
86
|
'libvips-cpp'
|
|
80
87
|
],
|
|
81
88
|
'variables': {
|
|
82
|
-
'runtime_link%': 'shared',
|
|
83
89
|
'conditions': [
|
|
84
90
|
['OS != "win"', {
|
|
85
|
-
'pkg_config_path': '<!(node -p "require(\'
|
|
86
|
-
'use_global_libvips': '<!(node -p "Boolean(require(\'
|
|
91
|
+
'pkg_config_path': '<!(node -p "require(\'../lib/libvips\').pkgConfigPath()")',
|
|
92
|
+
'use_global_libvips': '<!(node -p "Boolean(require(\'../lib/libvips\').useGlobalLibvips()).toString()")'
|
|
87
93
|
}, {
|
|
88
94
|
'pkg_config_path': '',
|
|
89
95
|
'use_global_libvips': ''
|
|
@@ -91,13 +97,13 @@
|
|
|
91
97
|
]
|
|
92
98
|
},
|
|
93
99
|
'sources': [
|
|
94
|
-
'
|
|
95
|
-
'
|
|
96
|
-
'
|
|
97
|
-
'
|
|
98
|
-
'
|
|
99
|
-
'
|
|
100
|
-
'
|
|
100
|
+
'common.cc',
|
|
101
|
+
'metadata.cc',
|
|
102
|
+
'stats.cc',
|
|
103
|
+
'operations.cc',
|
|
104
|
+
'pipeline.cc',
|
|
105
|
+
'utilities.cc',
|
|
106
|
+
'sharp.cc'
|
|
101
107
|
],
|
|
102
108
|
'include_dirs': [
|
|
103
109
|
'<!(node -p "require(\'node-addon-api\').include_dir")',
|
|
@@ -106,12 +112,11 @@
|
|
|
106
112
|
['use_global_libvips == "true"', {
|
|
107
113
|
# Use pkg-config for include and lib
|
|
108
114
|
'include_dirs': ['<!@(PKG_CONFIG_PATH="<(pkg_config_path)" pkg-config --cflags-only-I vips-cpp vips glib-2.0 | sed s\/-I//g)'],
|
|
115
|
+
'libraries': ['<!@(PKG_CONFIG_PATH="<(pkg_config_path)" pkg-config --libs vips-cpp)'],
|
|
116
|
+
'defines': [
|
|
117
|
+
'SHARP_USE_GLOBAL_LIBVIPS'
|
|
118
|
+
],
|
|
109
119
|
'conditions': [
|
|
110
|
-
['runtime_link == "static"', {
|
|
111
|
-
'libraries': ['<!@(PKG_CONFIG_PATH="<(pkg_config_path)" pkg-config --libs --static vips-cpp)']
|
|
112
|
-
}, {
|
|
113
|
-
'libraries': ['<!@(PKG_CONFIG_PATH="<(pkg_config_path)" pkg-config --libs vips-cpp)']
|
|
114
|
-
}],
|
|
115
120
|
['OS == "linux"', {
|
|
116
121
|
'defines': [
|
|
117
122
|
# Inspect libvips-cpp.so to determine which C++11 ABI version was used and set _GLIBCXX_USE_CXX11_ABI accordingly. This is quite horrible.
|
|
@@ -122,9 +127,12 @@
|
|
|
122
127
|
}, {
|
|
123
128
|
# Use pre-built libvips stored locally within node_modules
|
|
124
129
|
'include_dirs': [
|
|
125
|
-
'<(
|
|
126
|
-
'<(
|
|
127
|
-
'<(
|
|
130
|
+
'<(sharp_libvips_include_dir)',
|
|
131
|
+
'<(sharp_libvips_include_dir)/glib-2.0',
|
|
132
|
+
'<(sharp_libvips_lib_dir)/glib-2.0/include'
|
|
133
|
+
],
|
|
134
|
+
'library_dirs': [
|
|
135
|
+
'<(sharp_libvips_lib_dir)'
|
|
128
136
|
],
|
|
129
137
|
'conditions': [
|
|
130
138
|
['OS == "win"', {
|
|
@@ -133,17 +141,13 @@
|
|
|
133
141
|
'_FILE_OFFSET_BITS=64'
|
|
134
142
|
],
|
|
135
143
|
'link_settings': {
|
|
136
|
-
'library_dirs': ['<(sharp_vendor_dir)/lib'],
|
|
137
144
|
'libraries': [
|
|
138
|
-
'libvips.lib'
|
|
139
|
-
'libglib-2.0.lib',
|
|
140
|
-
'libgobject-2.0.lib'
|
|
145
|
+
'libvips.lib'
|
|
141
146
|
]
|
|
142
147
|
}
|
|
143
148
|
}],
|
|
144
149
|
['OS == "mac"', {
|
|
145
150
|
'link_settings': {
|
|
146
|
-
'library_dirs': ['../<(sharp_vendor_dir)/lib'],
|
|
147
151
|
'libraries': [
|
|
148
152
|
'libvips-cpp.42.dylib'
|
|
149
153
|
]
|
|
@@ -151,7 +155,11 @@
|
|
|
151
155
|
'xcode_settings': {
|
|
152
156
|
'OTHER_LDFLAGS': [
|
|
153
157
|
# Ensure runtime linking is relative to sharp.node
|
|
154
|
-
'-Wl,-rpath,\'@loader_path
|
|
158
|
+
'-Wl,-rpath,\'@loader_path/../../sharp-libvips-<(platform_and_arch)/lib\'',
|
|
159
|
+
'-Wl,-rpath,\'@loader_path/../../../sharp-libvips-<(platform_and_arch)/<(sharp_libvips_version)/lib\'',
|
|
160
|
+
'-Wl,-rpath,\'@loader_path/../../node_modules/@img/sharp-libvips-<(platform_and_arch)/lib\'',
|
|
161
|
+
'-Wl,-rpath,\'@loader_path/../../../node_modules/@img/sharp-libvips-<(platform_and_arch)/lib\'',
|
|
162
|
+
'-Wl,-rpath,\'@loader_path/../../../../../@img-sharp-libvips-<(platform_and_arch)-npm-<(sharp_libvips_version)-<(sharp_libvips_yarn_locator)/node_modules/@img/sharp-libvips-<(platform_and_arch)/lib\''
|
|
155
163
|
]
|
|
156
164
|
}
|
|
157
165
|
}],
|
|
@@ -160,15 +168,40 @@
|
|
|
160
168
|
'_GLIBCXX_USE_CXX11_ABI=1'
|
|
161
169
|
],
|
|
162
170
|
'link_settings': {
|
|
163
|
-
'library_dirs': ['../<(sharp_vendor_dir)/lib'],
|
|
164
171
|
'libraries': [
|
|
165
172
|
'-l:libvips-cpp.so.42'
|
|
166
173
|
],
|
|
167
174
|
'ldflags': [
|
|
168
|
-
|
|
169
|
-
'-Wl
|
|
175
|
+
'-Wl,-s',
|
|
176
|
+
'-Wl,--disable-new-dtags',
|
|
177
|
+
'-Wl,-z,nodelete',
|
|
178
|
+
'-Wl,-rpath=\'$$ORIGIN/../../sharp-libvips-<(platform_and_arch)/lib\'',
|
|
179
|
+
'-Wl,-rpath=\'$$ORIGIN/../../../sharp-libvips-<(platform_and_arch)/<(sharp_libvips_version)/lib\'',
|
|
180
|
+
'-Wl,-rpath=\'$$ORIGIN/../../node_modules/@img/sharp-libvips-<(platform_and_arch)/lib\'',
|
|
181
|
+
'-Wl,-rpath=\'$$ORIGIN/../../../node_modules/@img/sharp-libvips-<(platform_and_arch)/lib\'',
|
|
182
|
+
'-Wl,-rpath,\'$$ORIGIN/../../../../../@img-sharp-libvips-<(platform_and_arch)-npm-<(sharp_libvips_version)-<(sharp_libvips_yarn_locator)/node_modules/@img/sharp-libvips-<(platform_and_arch)/lib\''
|
|
170
183
|
]
|
|
171
184
|
}
|
|
185
|
+
}],
|
|
186
|
+
['OS == "emscripten"', {
|
|
187
|
+
'product_extension': 'node.js',
|
|
188
|
+
'link_settings': {
|
|
189
|
+
'ldflags': [
|
|
190
|
+
'-fexceptions',
|
|
191
|
+
'--pre-js=<!(node -p "require.resolve(\'./emscripten/pre.js\')")',
|
|
192
|
+
'-Oz',
|
|
193
|
+
'-sALLOW_MEMORY_GROWTH',
|
|
194
|
+
'-sENVIRONMENT=node',
|
|
195
|
+
'-sEXPORTED_FUNCTIONS=["_vips_shutdown", "_uv_library_shutdown"]',
|
|
196
|
+
'-sNODERAWFS',
|
|
197
|
+
'-sTEXTDECODER=0',
|
|
198
|
+
'-sWASM_ASYNC_COMPILATION=0',
|
|
199
|
+
'-sWASM_BIGINT'
|
|
200
|
+
],
|
|
201
|
+
'libraries': [
|
|
202
|
+
'<!@(PKG_CONFIG_PATH="<!(node -p "require(\'@img/sharp-libvips-dev-wasm32/lib\')")/pkgconfig" pkg-config --static --libs vips-cpp)'
|
|
203
|
+
],
|
|
204
|
+
}
|
|
172
205
|
}]
|
|
173
206
|
]
|
|
174
207
|
}]
|
|
@@ -193,11 +226,6 @@
|
|
|
193
226
|
'configurations': {
|
|
194
227
|
'Release': {
|
|
195
228
|
'conditions': [
|
|
196
|
-
['OS == "linux"', {
|
|
197
|
-
'cflags_cc': [
|
|
198
|
-
'-Wno-cast-function-type'
|
|
199
|
-
]
|
|
200
|
-
}],
|
|
201
229
|
['target_arch == "arm"', {
|
|
202
230
|
'cflags_cc': [
|
|
203
231
|
'-Wno-psabi'
|
|
@@ -232,5 +260,21 @@
|
|
|
232
260
|
]
|
|
233
261
|
}
|
|
234
262
|
},
|
|
263
|
+
}, {
|
|
264
|
+
'target_name': 'copy-dll',
|
|
265
|
+
'type': 'none',
|
|
266
|
+
'dependencies': [
|
|
267
|
+
'sharp-<(platform_and_arch)'
|
|
268
|
+
],
|
|
269
|
+
'conditions': [
|
|
270
|
+
['OS == "win"', {
|
|
271
|
+
'copies': [{
|
|
272
|
+
'destination': 'build/Release',
|
|
273
|
+
'files': [
|
|
274
|
+
'<(sharp_libvips_lib_dir)/libvips-42.dll'
|
|
275
|
+
]
|
|
276
|
+
}]
|
|
277
|
+
}]
|
|
278
|
+
]
|
|
235
279
|
}]
|
|
236
280
|
}
|
package/src/common.cc
CHANGED
|
@@ -75,7 +75,7 @@ namespace sharp {
|
|
|
75
75
|
Napi::Buffer<char> buffer = input.Get("buffer").As<Napi::Buffer<char>>();
|
|
76
76
|
descriptor->bufferLength = buffer.Length();
|
|
77
77
|
descriptor->buffer = buffer.Data();
|
|
78
|
-
descriptor->isBuffer =
|
|
78
|
+
descriptor->isBuffer = true;
|
|
79
79
|
}
|
|
80
80
|
descriptor->failOn = AttrAsEnum<VipsFailOn>(input, "failOn", VIPS_TYPE_FAIL_ON);
|
|
81
81
|
// Density for vector-based input
|
|
@@ -166,10 +166,10 @@ namespace sharp {
|
|
|
166
166
|
}
|
|
167
167
|
|
|
168
168
|
// How many tasks are in the queue?
|
|
169
|
-
|
|
169
|
+
std::atomic<int> counterQueue{0};
|
|
170
170
|
|
|
171
171
|
// How many tasks are being processed?
|
|
172
|
-
|
|
172
|
+
std::atomic<int> counterProcess{0};
|
|
173
173
|
|
|
174
174
|
// Filename extension checkers
|
|
175
175
|
static bool EndsWith(std::string const &str, std::string const &end) {
|
|
@@ -363,12 +363,13 @@ namespace sharp {
|
|
|
363
363
|
if (descriptor->isBuffer) {
|
|
364
364
|
if (descriptor->rawChannels > 0) {
|
|
365
365
|
// Raw, uncompressed pixel data
|
|
366
|
+
bool const is8bit = vips_band_format_is8bit(descriptor->rawDepth);
|
|
366
367
|
image = VImage::new_from_memory(descriptor->buffer, descriptor->bufferLength,
|
|
367
368
|
descriptor->rawWidth, descriptor->rawHeight, descriptor->rawChannels, descriptor->rawDepth);
|
|
368
369
|
if (descriptor->rawChannels < 3) {
|
|
369
|
-
image.get_image()->Type = VIPS_INTERPRETATION_B_W;
|
|
370
|
+
image.get_image()->Type = is8bit ? VIPS_INTERPRETATION_B_W : VIPS_INTERPRETATION_GREY16;
|
|
370
371
|
} else {
|
|
371
|
-
image.get_image()->Type = VIPS_INTERPRETATION_sRGB;
|
|
372
|
+
image.get_image()->Type = is8bit ? VIPS_INTERPRETATION_sRGB : VIPS_INTERPRETATION_RGB16;
|
|
372
373
|
}
|
|
373
374
|
if (descriptor->rawPremultiplied) {
|
|
374
375
|
image = image.unpremultiply();
|
|
@@ -383,7 +384,7 @@ namespace sharp {
|
|
|
383
384
|
->set("access", descriptor->access)
|
|
384
385
|
->set("fail_on", descriptor->failOn);
|
|
385
386
|
if (descriptor->unlimited && ImageTypeSupportsUnlimited(imageType)) {
|
|
386
|
-
option->set("unlimited",
|
|
387
|
+
option->set("unlimited", true);
|
|
387
388
|
}
|
|
388
389
|
if (imageType == ImageType::SVG || imageType == ImageType::PDF) {
|
|
389
390
|
option->set("dpi", descriptor->density);
|
|
@@ -487,7 +488,7 @@ namespace sharp {
|
|
|
487
488
|
->set("access", descriptor->access)
|
|
488
489
|
->set("fail_on", descriptor->failOn);
|
|
489
490
|
if (descriptor->unlimited && ImageTypeSupportsUnlimited(imageType)) {
|
|
490
|
-
option->set("unlimited",
|
|
491
|
+
option->set("unlimited", true);
|
|
491
492
|
}
|
|
492
493
|
if (imageType == ImageType::SVG || imageType == ImageType::PDF) {
|
|
493
494
|
option->set("dpi", descriptor->density);
|
|
@@ -530,7 +531,33 @@ namespace sharp {
|
|
|
530
531
|
Does this image have an embedded profile?
|
|
531
532
|
*/
|
|
532
533
|
bool HasProfile(VImage image) {
|
|
533
|
-
return
|
|
534
|
+
return image.get_typeof(VIPS_META_ICC_NAME) == VIPS_TYPE_BLOB;
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
/*
|
|
538
|
+
Get copy of embedded profile.
|
|
539
|
+
*/
|
|
540
|
+
std::pair<char*, size_t> GetProfile(VImage image) {
|
|
541
|
+
std::pair<char*, size_t> icc(nullptr, 0);
|
|
542
|
+
if (HasProfile(image)) {
|
|
543
|
+
size_t length;
|
|
544
|
+
const void *data = image.get_blob(VIPS_META_ICC_NAME, &length);
|
|
545
|
+
icc.first = static_cast<char*>(g_malloc(length));
|
|
546
|
+
icc.second = length;
|
|
547
|
+
memcpy(icc.first, data, length);
|
|
548
|
+
}
|
|
549
|
+
return icc;
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
/*
|
|
553
|
+
Set embedded profile.
|
|
554
|
+
*/
|
|
555
|
+
VImage SetProfile(VImage image, std::pair<char*, size_t> icc) {
|
|
556
|
+
if (icc.first != nullptr) {
|
|
557
|
+
image = image.copy();
|
|
558
|
+
image.set(VIPS_META_ICC_NAME, reinterpret_cast<VipsCallbackFn>(vips_area_free_cb), icc.first, icc.second);
|
|
559
|
+
}
|
|
560
|
+
return image;
|
|
534
561
|
}
|
|
535
562
|
|
|
536
563
|
/*
|
|
@@ -541,6 +568,27 @@ namespace sharp {
|
|
|
541
568
|
return image.has_alpha();
|
|
542
569
|
}
|
|
543
570
|
|
|
571
|
+
static void* RemoveExifCallback(VipsImage *image, char const *field, GValue *value, void *data) {
|
|
572
|
+
std::vector<std::string> *fieldNames = static_cast<std::vector<std::string> *>(data);
|
|
573
|
+
std::string fieldName(field);
|
|
574
|
+
if (fieldName.substr(0, 8) == ("exif-ifd")) {
|
|
575
|
+
fieldNames->push_back(fieldName);
|
|
576
|
+
}
|
|
577
|
+
return nullptr;
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
/*
|
|
581
|
+
Remove all EXIF-related image fields.
|
|
582
|
+
*/
|
|
583
|
+
VImage RemoveExif(VImage image) {
|
|
584
|
+
std::vector<std::string> fieldNames;
|
|
585
|
+
vips_image_map(image.get_image(), static_cast<VipsImageMapFn>(RemoveExifCallback), &fieldNames);
|
|
586
|
+
for (const auto& f : fieldNames) {
|
|
587
|
+
image.remove(f.data());
|
|
588
|
+
}
|
|
589
|
+
return image;
|
|
590
|
+
}
|
|
591
|
+
|
|
544
592
|
/*
|
|
545
593
|
Get EXIF Orientation of image, if any.
|
|
546
594
|
*/
|
|
@@ -720,7 +768,7 @@ namespace sharp {
|
|
|
720
768
|
int *timeout = VIPS_NEW(im, int);
|
|
721
769
|
*timeout = seconds;
|
|
722
770
|
g_signal_connect(im, "eval", G_CALLBACK(VipsProgressCallBack), timeout);
|
|
723
|
-
vips_image_set_progress(im,
|
|
771
|
+
vips_image_set_progress(im, true);
|
|
724
772
|
}
|
|
725
773
|
}
|
|
726
774
|
}
|
|
@@ -730,7 +778,7 @@ namespace sharp {
|
|
|
730
778
|
*/
|
|
731
779
|
void VipsProgressCallBack(VipsImage *im, VipsProgress *progress, int *timeout) {
|
|
732
780
|
if (*timeout > 0 && progress->run >= *timeout) {
|
|
733
|
-
vips_image_set_kill(im,
|
|
781
|
+
vips_image_set_kill(im, true);
|
|
734
782
|
vips_error("timeout", "%d%% complete", progress->percent);
|
|
735
783
|
*timeout = 0;
|
|
736
784
|
}
|
|
@@ -1033,9 +1081,10 @@ namespace sharp {
|
|
|
1033
1081
|
/*
|
|
1034
1082
|
Ensure decoding remains sequential.
|
|
1035
1083
|
*/
|
|
1036
|
-
VImage StaySequential(VImage image,
|
|
1037
|
-
if (
|
|
1038
|
-
|
|
1084
|
+
VImage StaySequential(VImage image, bool condition) {
|
|
1085
|
+
if (vips_image_is_sequential(image.get_image()) && condition) {
|
|
1086
|
+
image = image.copy_memory().copy();
|
|
1087
|
+
image.remove(VIPS_META_SEQUENTIAL);
|
|
1039
1088
|
}
|
|
1040
1089
|
return image;
|
|
1041
1090
|
}
|
package/src/common.h
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
#include <string>
|
|
8
8
|
#include <tuple>
|
|
9
9
|
#include <vector>
|
|
10
|
+
#include <atomic>
|
|
10
11
|
|
|
11
12
|
#include <napi.h>
|
|
12
13
|
#include <vips/vips8>
|
|
@@ -14,9 +15,9 @@
|
|
|
14
15
|
// Verify platform and compiler compatibility
|
|
15
16
|
|
|
16
17
|
#if (VIPS_MAJOR_VERSION < 8) || \
|
|
17
|
-
(VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION <
|
|
18
|
-
(VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION ==
|
|
19
|
-
#error "libvips version 8.
|
|
18
|
+
(VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION < 15) || \
|
|
19
|
+
(VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION == 15 && VIPS_MICRO_VERSION < 2)
|
|
20
|
+
#error "libvips version 8.15.2+ is required - please see https://sharp.pixelplumbing.com/install"
|
|
20
21
|
#endif
|
|
21
22
|
|
|
22
23
|
#if ((!defined(__clang__)) && defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 6)))
|
|
@@ -78,12 +79,12 @@ namespace sharp {
|
|
|
78
79
|
buffer(nullptr),
|
|
79
80
|
failOn(VIPS_FAIL_ON_WARNING),
|
|
80
81
|
limitInputPixels(0x3FFF * 0x3FFF),
|
|
81
|
-
unlimited(
|
|
82
|
+
unlimited(false),
|
|
82
83
|
access(VIPS_ACCESS_RANDOM),
|
|
83
84
|
bufferLength(0),
|
|
84
|
-
isBuffer(
|
|
85
|
+
isBuffer(false),
|
|
85
86
|
density(72.0),
|
|
86
|
-
ignoreIcc(
|
|
87
|
+
ignoreIcc(false),
|
|
87
88
|
rawDepth(VIPS_FORMAT_UCHAR),
|
|
88
89
|
rawChannels(0),
|
|
89
90
|
rawWidth(0),
|
|
@@ -102,9 +103,9 @@ namespace sharp {
|
|
|
102
103
|
textWidth(0),
|
|
103
104
|
textHeight(0),
|
|
104
105
|
textAlign(VIPS_ALIGN_LOW),
|
|
105
|
-
textJustify(
|
|
106
|
+
textJustify(false),
|
|
106
107
|
textDpi(72),
|
|
107
|
-
textRgba(
|
|
108
|
+
textRgba(false),
|
|
108
109
|
textSpacing(0),
|
|
109
110
|
textWrap(VIPS_TEXT_WRAP_WORD),
|
|
110
111
|
textAutofitDpi(0) {}
|
|
@@ -161,10 +162,10 @@ namespace sharp {
|
|
|
161
162
|
};
|
|
162
163
|
|
|
163
164
|
// How many tasks are in the queue?
|
|
164
|
-
extern
|
|
165
|
+
extern std::atomic<int> counterQueue;
|
|
165
166
|
|
|
166
167
|
// How many tasks are being processed?
|
|
167
|
-
extern
|
|
168
|
+
extern std::atomic<int> counterProcess;
|
|
168
169
|
|
|
169
170
|
// Filename extension checkers
|
|
170
171
|
bool IsJpeg(std::string const &str);
|
|
@@ -221,12 +222,27 @@ namespace sharp {
|
|
|
221
222
|
*/
|
|
222
223
|
bool HasProfile(VImage image);
|
|
223
224
|
|
|
225
|
+
/*
|
|
226
|
+
Get copy of embedded profile.
|
|
227
|
+
*/
|
|
228
|
+
std::pair<char*, size_t> GetProfile(VImage image);
|
|
229
|
+
|
|
230
|
+
/*
|
|
231
|
+
Set embedded profile.
|
|
232
|
+
*/
|
|
233
|
+
VImage SetProfile(VImage image, std::pair<char*, size_t> icc);
|
|
234
|
+
|
|
224
235
|
/*
|
|
225
236
|
Does this image have an alpha channel?
|
|
226
237
|
Uses colour space interpretation with number of channels to guess this.
|
|
227
238
|
*/
|
|
228
239
|
bool HasAlpha(VImage image);
|
|
229
240
|
|
|
241
|
+
/*
|
|
242
|
+
Remove all EXIF-related image fields.
|
|
243
|
+
*/
|
|
244
|
+
VImage RemoveExif(VImage image);
|
|
245
|
+
|
|
230
246
|
/*
|
|
231
247
|
Get EXIF Orientation of image, if any.
|
|
232
248
|
*/
|
|
@@ -370,7 +386,7 @@ namespace sharp {
|
|
|
370
386
|
/*
|
|
371
387
|
Ensure decoding remains sequential.
|
|
372
388
|
*/
|
|
373
|
-
VImage StaySequential(VImage image,
|
|
389
|
+
VImage StaySequential(VImage image, bool condition = true);
|
|
374
390
|
|
|
375
391
|
} // namespace sharp
|
|
376
392
|
|
package/src/metadata.cc
CHANGED
|
@@ -18,7 +18,7 @@ class MetadataWorker : public Napi::AsyncWorker {
|
|
|
18
18
|
|
|
19
19
|
void Execute() {
|
|
20
20
|
// Decrement queued task counter
|
|
21
|
-
|
|
21
|
+
sharp::counterQueue--;
|
|
22
22
|
|
|
23
23
|
vips::VImage image;
|
|
24
24
|
sharp::ImageType imageType = sharp::ImageType::UNKNOWN;
|
|
@@ -145,7 +145,7 @@ class MetadataWorker : public Napi::AsyncWorker {
|
|
|
145
145
|
// Handle warnings
|
|
146
146
|
std::string warning = sharp::VipsWarningPop();
|
|
147
147
|
while (!warning.empty()) {
|
|
148
|
-
debuglog.
|
|
148
|
+
debuglog.Call(Receiver().Value(), { Napi::String::New(env, warning) });
|
|
149
149
|
warning = sharp::VipsWarningPop();
|
|
150
150
|
}
|
|
151
151
|
|
|
@@ -246,9 +246,9 @@ class MetadataWorker : public Napi::AsyncWorker {
|
|
|
246
246
|
Napi::Buffer<char>::NewOrCopy(env, baton->tifftagPhotoshop,
|
|
247
247
|
baton->tifftagPhotoshopLength, sharp::FreeCallback));
|
|
248
248
|
}
|
|
249
|
-
Callback().
|
|
249
|
+
Callback().Call(Receiver().Value(), { env.Null(), info });
|
|
250
250
|
} else {
|
|
251
|
-
Callback().
|
|
251
|
+
Callback().Call(Receiver().Value(), { Napi::Error::New(env, sharp::TrimEnd(baton->err)).Value() });
|
|
252
252
|
}
|
|
253
253
|
|
|
254
254
|
delete baton->input;
|
|
@@ -281,7 +281,7 @@ Napi::Value metadata(const Napi::CallbackInfo& info) {
|
|
|
281
281
|
worker->Queue();
|
|
282
282
|
|
|
283
283
|
// Increment queued task counter
|
|
284
|
-
|
|
284
|
+
sharp::counterQueue++;
|
|
285
285
|
|
|
286
286
|
return info.Env().Undefined();
|
|
287
287
|
}
|
package/src/operations.cc
CHANGED
|
@@ -16,30 +16,44 @@ using vips::VError;
|
|
|
16
16
|
|
|
17
17
|
namespace sharp {
|
|
18
18
|
/*
|
|
19
|
-
* Tint an image using the
|
|
19
|
+
* Tint an image using the provided RGB.
|
|
20
20
|
*/
|
|
21
|
-
VImage Tint(VImage image, double const
|
|
22
|
-
|
|
21
|
+
VImage Tint(VImage image, std::vector<double> const tint) {
|
|
22
|
+
std::vector<double> const tintLab = (VImage::black(1, 1) + tint)
|
|
23
|
+
.colourspace(VIPS_INTERPRETATION_LAB, VImage::option()->set("source_space", VIPS_INTERPRETATION_sRGB))
|
|
24
|
+
.getpoint(0, 0);
|
|
25
|
+
// LAB identity function
|
|
26
|
+
VImage identityLab = VImage::identity(VImage::option()->set("bands", 3))
|
|
27
|
+
.colourspace(VIPS_INTERPRETATION_LAB, VImage::option()->set("source_space", VIPS_INTERPRETATION_sRGB));
|
|
28
|
+
// Scale luminance range, 0.0 to 1.0
|
|
29
|
+
VImage l = identityLab[0] / 100;
|
|
30
|
+
// Weighting functions
|
|
31
|
+
VImage weightL = 1.0 - 4.0 * ((l - 0.5) * (l - 0.5));
|
|
32
|
+
VImage weightAB = (weightL * tintLab).extract_band(1, VImage::option()->set("n", 2));
|
|
33
|
+
identityLab = identityLab[0].bandjoin(weightAB);
|
|
34
|
+
// Convert lookup table to sRGB
|
|
35
|
+
VImage lut = identityLab.colourspace(VIPS_INTERPRETATION_sRGB,
|
|
36
|
+
VImage::option()->set("source_space", VIPS_INTERPRETATION_LAB));
|
|
37
|
+
// Original colourspace
|
|
23
38
|
VipsInterpretation typeBeforeTint = image.interpretation();
|
|
24
39
|
if (typeBeforeTint == VIPS_INTERPRETATION_RGB) {
|
|
25
40
|
typeBeforeTint = VIPS_INTERPRETATION_sRGB;
|
|
26
41
|
}
|
|
27
|
-
//
|
|
28
|
-
VImage luminance = image.colourspace(VIPS_INTERPRETATION_LAB)[0];
|
|
29
|
-
// Create the tinted version by combining the L from the original and the chroma from the tint
|
|
30
|
-
std::vector<double> chroma {a, b};
|
|
31
|
-
VImage tinted = luminance
|
|
32
|
-
.bandjoin(chroma)
|
|
33
|
-
.copy(VImage::option()->set("interpretation", VIPS_INTERPRETATION_LAB))
|
|
34
|
-
.colourspace(typeBeforeTint);
|
|
35
|
-
// Attach original alpha channel, if any
|
|
42
|
+
// Apply lookup table
|
|
36
43
|
if (HasAlpha(image)) {
|
|
37
|
-
// Extract original alpha channel
|
|
38
44
|
VImage alpha = image[image.bands() - 1];
|
|
39
|
-
|
|
40
|
-
|
|
45
|
+
image = RemoveAlpha(image)
|
|
46
|
+
.colourspace(VIPS_INTERPRETATION_B_W)
|
|
47
|
+
.maplut(lut)
|
|
48
|
+
.colourspace(typeBeforeTint)
|
|
49
|
+
.bandjoin(alpha);
|
|
50
|
+
} else {
|
|
51
|
+
image = image
|
|
52
|
+
.colourspace(VIPS_INTERPRETATION_B_W)
|
|
53
|
+
.maplut(lut)
|
|
54
|
+
.colourspace(typeBeforeTint);
|
|
41
55
|
}
|
|
42
|
-
return
|
|
56
|
+
return image;
|
|
43
57
|
}
|
|
44
58
|
|
|
45
59
|
/*
|
|
@@ -141,7 +155,7 @@ namespace sharp {
|
|
|
141
155
|
return image.conv(blur);
|
|
142
156
|
} else {
|
|
143
157
|
// Slower, accurate Gaussian blur
|
|
144
|
-
return image.gaussblur(sigma);
|
|
158
|
+
return StaySequential(image).gaussblur(sigma);
|
|
145
159
|
}
|
|
146
160
|
}
|
|
147
161
|
|
|
@@ -265,7 +279,7 @@ namespace sharp {
|
|
|
265
279
|
/*
|
|
266
280
|
Trim an image
|
|
267
281
|
*/
|
|
268
|
-
VImage Trim(VImage image, std::vector<double> background, double threshold) {
|
|
282
|
+
VImage Trim(VImage image, std::vector<double> background, double threshold, bool const lineArt) {
|
|
269
283
|
if (image.width() < 3 && image.height() < 3) {
|
|
270
284
|
throw VError("Image to trim must be at least 3x3 pixels");
|
|
271
285
|
}
|
|
@@ -287,6 +301,7 @@ namespace sharp {
|
|
|
287
301
|
int left, top, width, height;
|
|
288
302
|
left = image.find_trim(&top, &width, &height, VImage::option()
|
|
289
303
|
->set("background", background)
|
|
304
|
+
->set("line_art", lineArt)
|
|
290
305
|
->set("threshold", threshold));
|
|
291
306
|
if (HasAlpha(image)) {
|
|
292
307
|
// Search alpha channel (A)
|
|
@@ -294,6 +309,7 @@ namespace sharp {
|
|
|
294
309
|
VImage alpha = image[image.bands() - 1];
|
|
295
310
|
leftA = alpha.find_trim(&topA, &widthA, &heightA, VImage::option()
|
|
296
311
|
->set("background", backgroundAlpha)
|
|
312
|
+
->set("line_art", lineArt)
|
|
297
313
|
->set("threshold", threshold));
|
|
298
314
|
if (widthA > 0 && heightA > 0) {
|
|
299
315
|
if (width > 0 && height > 0) {
|
|
@@ -370,6 +386,7 @@ namespace sharp {
|
|
|
370
386
|
pages.reserve(nPages);
|
|
371
387
|
|
|
372
388
|
// Split the image into cropped frames
|
|
389
|
+
image = StaySequential(image);
|
|
373
390
|
for (int i = 0; i < nPages; i++) {
|
|
374
391
|
pages.push_back(
|
|
375
392
|
image.extract_area(left, *pageHeight * i + top, width, height));
|
package/src/operations.h
CHANGED
|
@@ -15,9 +15,9 @@ using vips::VImage;
|
|
|
15
15
|
namespace sharp {
|
|
16
16
|
|
|
17
17
|
/*
|
|
18
|
-
* Tint an image using the
|
|
18
|
+
* Tint an image using the provided RGB.
|
|
19
19
|
*/
|
|
20
|
-
VImage Tint(VImage image, double const
|
|
20
|
+
VImage Tint(VImage image, std::vector<double> const tint);
|
|
21
21
|
|
|
22
22
|
/*
|
|
23
23
|
* Stretch luminance to cover full dynamic range.
|
|
@@ -79,7 +79,7 @@ namespace sharp {
|
|
|
79
79
|
/*
|
|
80
80
|
Trim an image
|
|
81
81
|
*/
|
|
82
|
-
VImage Trim(VImage image, std::vector<double> background, double const
|
|
82
|
+
VImage Trim(VImage image, std::vector<double> background, double threshold, bool const lineArt);
|
|
83
83
|
|
|
84
84
|
/*
|
|
85
85
|
* Linear adjustment (a * in + b)
|