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.
@@ -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(\'./lib/libvips\').minimumLibvipsVersion")',
4
- 'platform_and_arch': '<!(node -p "require(\'./lib/platform\')()")',
5
- 'sharp_vendor_dir': './vendor/<(vips_version)/<(platform_and_arch)'
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
- 'src/libvips/cplusplus/VConnection.cpp',
19
- 'src/libvips/cplusplus/VError.cpp',
20
- 'src/libvips/cplusplus/VImage.cpp',
21
- 'src/libvips/cplusplus/VInterpolate.cpp',
22
- 'src/libvips/cplusplus/VRegion.cpp'
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
- '<(sharp_vendor_dir)/include',
26
- '<(sharp_vendor_dir)/include/glib-2.0',
27
- '<(sharp_vendor_dir)/lib/glib-2.0/include'
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': ['<(sharp_vendor_dir)/lib'],
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=7',
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(\'./lib/libvips\').pkgConfigPath()")',
86
- 'use_global_libvips': '<!(node -p "Boolean(require(\'./lib/libvips\').useGlobalLibvips()).toString()")'
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
- 'src/common.cc',
95
- 'src/metadata.cc',
96
- 'src/stats.cc',
97
- 'src/operations.cc',
98
- 'src/pipeline.cc',
99
- 'src/utilities.cc',
100
- 'src/sharp.cc'
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
- '<(sharp_vendor_dir)/include',
126
- '<(sharp_vendor_dir)/include/glib-2.0',
127
- '<(sharp_vendor_dir)/lib/glib-2.0/include'
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/../../<(sharp_vendor_dir)/lib\''
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
- # Ensure runtime linking is relative to sharp.node
169
- '-Wl,-s -Wl,--disable-new-dtags -Wl,-rpath=\'$$ORIGIN/../../<(sharp_vendor_dir)/lib\''
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 = TRUE;
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
- volatile int counterQueue = 0;
169
+ std::atomic<int> counterQueue{0};
170
170
 
171
171
  // How many tasks are being processed?
172
- volatile int counterProcess = 0;
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", TRUE);
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", TRUE);
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 (image.get_typeof(VIPS_META_ICC_NAME) != 0) ? TRUE : FALSE;
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, TRUE);
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, TRUE);
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, VipsAccess access, bool condition) {
1037
- if (access == VIPS_ACCESS_SEQUENTIAL && condition) {
1038
- return image.copy_memory();
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 < 14) || \
18
- (VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION == 14 && VIPS_MICRO_VERSION < 5)
19
- #error "libvips version 8.14.5+ is required - please see https://sharp.pixelplumbing.com/install"
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(FALSE),
82
+ unlimited(false),
82
83
  access(VIPS_ACCESS_RANDOM),
83
84
  bufferLength(0),
84
- isBuffer(FALSE),
85
+ isBuffer(false),
85
86
  density(72.0),
86
- ignoreIcc(FALSE),
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(FALSE),
106
+ textJustify(false),
106
107
  textDpi(72),
107
- textRgba(FALSE),
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 volatile int counterQueue;
165
+ extern std::atomic<int> counterQueue;
165
166
 
166
167
  // How many tasks are being processed?
167
- extern volatile int counterProcess;
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, VipsAccess access, bool condition = TRUE);
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
- g_atomic_int_dec_and_test(&sharp::counterQueue);
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.MakeCallback(Receiver().Value(), { Napi::String::New(env, warning) });
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().MakeCallback(Receiver().Value(), { env.Null(), info });
249
+ Callback().Call(Receiver().Value(), { env.Null(), info });
250
250
  } else {
251
- Callback().MakeCallback(Receiver().Value(), { Napi::Error::New(env, sharp::TrimEnd(baton->err)).Value() });
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
- g_atomic_int_inc(&sharp::counterQueue);
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 specified chroma, preserving the original image luminance
19
+ * Tint an image using the provided RGB.
20
20
  */
21
- VImage Tint(VImage image, double const a, double const b) {
22
- // Get original colourspace
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
- // Extract luminance
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
- // Join alpha channel to normalised image
40
- tinted = tinted.bandjoin(alpha);
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 tinted;
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 specified chroma, preserving the original image luminance
18
+ * Tint an image using the provided RGB.
19
19
  */
20
- VImage Tint(VImage image, double const a, double const b);
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 threshold);
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)