sharp 0.31.3 → 0.32.1

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/lib/utility.js CHANGED
@@ -1,3 +1,6 @@
1
+ // Copyright 2013 Lovell Fuller and others.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
1
4
  'use strict';
2
5
 
3
6
  const fs = require('fs');
@@ -43,7 +46,7 @@ const interpolators = {
43
46
  };
44
47
 
45
48
  /**
46
- * An Object containing the version numbers of libvips and its dependencies.
49
+ * An Object containing the version numbers of sharp, libvips and its dependencies.
47
50
  * @member
48
51
  * @example
49
52
  * console.log(sharp.versions);
@@ -54,6 +57,7 @@ let versions = {
54
57
  try {
55
58
  versions = require(`../vendor/${versions.vips}/${platformAndArch}/versions.json`);
56
59
  } catch (_err) { /* ignore */ }
60
+ versions.sharp = require('../package.json').version;
57
61
 
58
62
  /**
59
63
  * An Object containing the platform and architecture
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "sharp",
3
3
  "description": "High performance Node.js image processing, the fastest module to resize JPEG, PNG, WebP, GIF, AVIF and TIFF images",
4
- "version": "0.31.3",
4
+ "version": "0.32.1",
5
5
  "author": "Lovell Fuller <npm@lovell.info>",
6
6
  "homepage": "https://github.com/lovell/sharp",
7
7
  "contributors": [
@@ -85,21 +85,24 @@
85
85
  "Brodan <christopher.hranj@gmail.com",
86
86
  "Ankur Parihar <ankur.github@gmail.com>",
87
87
  "Brahim Ait elhaj <brahima@gmail.com>",
88
- "Mart Jansink <m.jansink@gmail.com>"
88
+ "Mart Jansink <m.jansink@gmail.com>",
89
+ "Lachlan Newman <lachnewman007@gmail.com>"
89
90
  ],
90
91
  "scripts": {
91
92
  "install": "(node install/libvips && node install/dll-copy && prebuild-install) || (node install/can-compile && node-gyp rebuild && node install/dll-copy)",
92
93
  "clean": "rm -rf node_modules/ build/ vendor/ .nyc_output/ coverage/ test/fixtures/output.*",
93
- "test": "npm run test-lint && npm run test-unit && npm run test-licensing",
94
+ "test": "npm run test-lint && npm run test-unit && npm run test-licensing && npm run test-types",
94
95
  "test-lint": "semistandard && cpplint",
95
96
  "test-unit": "nyc --reporter=lcov --reporter=text --check-coverage --branches=100 mocha",
96
97
  "test-licensing": "license-checker --production --summary --onlyAllow=\"Apache-2.0;BSD;ISC;MIT\"",
97
98
  "test-leak": "./test/leak/leak.sh",
98
- "docs-build": "documentation lint lib && node docs/build && node docs/search-index/build",
99
+ "test-types": "tsd",
100
+ "docs-build": "node docs/build && node docs/search-index/build",
99
101
  "docs-serve": "cd docs && npx serve",
100
102
  "docs-publish": "cd docs && npx firebase-tools deploy --project pixelplumbing --only hosting:pixelplumbing-sharp"
101
103
  },
102
104
  "main": "lib/index.js",
105
+ "types": "lib/index.d.ts",
103
106
  "files": [
104
107
  "binding.gyp",
105
108
  "install/**",
@@ -131,43 +134,44 @@
131
134
  "dependencies": {
132
135
  "color": "^4.2.3",
133
136
  "detect-libc": "^2.0.1",
134
- "node-addon-api": "^5.0.0",
137
+ "node-addon-api": "^6.1.0",
135
138
  "prebuild-install": "^7.1.1",
136
- "semver": "^7.3.8",
139
+ "semver": "^7.5.0",
137
140
  "simple-get": "^4.0.1",
138
141
  "tar-fs": "^2.1.1",
139
142
  "tunnel-agent": "^0.6.0"
140
143
  },
141
144
  "devDependencies": {
145
+ "@types/node": "*",
142
146
  "async": "^3.2.4",
143
147
  "cc": "^3.0.1",
144
- "documentation": "^14.0.1",
145
- "exif-reader": "^1.0.3",
148
+ "exif-reader": "^1.2.0",
146
149
  "extract-zip": "^2.0.1",
147
- "icc": "^2.0.0",
150
+ "icc": "^3.0.0",
151
+ "jsdoc-to-markdown": "^8.0.0",
148
152
  "license-checker": "^25.0.1",
149
153
  "mocha": "^10.2.0",
150
154
  "mock-fs": "^5.2.0",
151
155
  "nyc": "^15.1.0",
152
156
  "prebuild": "^11.0.4",
153
- "rimraf": "^3.0.2",
154
- "semistandard": "^16.0.1"
157
+ "semistandard": "^16.0.1",
158
+ "tsd": "^0.28.1"
155
159
  },
156
160
  "license": "Apache-2.0",
157
161
  "config": {
158
- "libvips": "8.13.3",
162
+ "libvips": "8.14.2",
159
163
  "integrity": {
160
- "darwin-arm64v8": "sha512-xFgYt7CtQSZcWoyUdzPTDNHbioZIrZSEU+gkMxzH4Cgjhi4/N49UsonnIZhKQoTBGloAqEexHeMx4rYTQ2Kgvw==",
161
- "darwin-x64": "sha512-6SivWKzu15aUMMohe0wg7sNYMPETVnOe40BuWsnKOgzl3o5FpQqNSgs+68Mi8Za3Qti9/DaR+H/fyD0x48Af2w==",
162
- "linux-arm64v8": "sha512-b+iI9V/ehgDabXYRQcvqa5CEysh+1FQsgFmYc358StCrJCDahwNmsQdsiH1GOVd5WaWh5wHUGByPwMmFOO16Aw==",
163
- "linux-armv6": "sha512-zRP2F+EiustLE4bXSH8AHCxwfemh9d+QuvmPjira/HL6uJOUuA7SyQgVV1TPwTQle2ioCNnKPm7FEB/MAiT+ug==",
164
- "linux-armv7": "sha512-6OCChowE5lBXXXAZrnGdA9dVktg7UdODEBpE5qTroiAJYZv4yXRMgyDFYajok7du2NTgoklhxGk8d9+4vGv5hg==",
165
- "linux-x64": "sha512-OTmlmP2r8ozGKdB96X+K5oQE1ojVZanqLqqKlwDpEnfixyIaDGYbVzcjWBNGU3ai/26bvkaCkjynnc2ecYcsuA==",
166
- "linuxmusl-arm64v8": "sha512-Qh5Wi+bkKTohFYHzSPssfjMhIkD6z6EHbVmnwmWSsgY9zsUBStFp6+mKcNTQfP5YM5Mz06vJOkLHX2OzEr5TzA==",
167
- "linuxmusl-x64": "sha512-DwB4Fs3+ISw9etaLCANkueZDdk758iOS+wNp4TKZkHdq0al6B/3Pk7OHLR8a9E3H6wYDD328u++dcJzip5tacA==",
168
- "win32-arm64v8": "sha512-96r3W+O4BtX602B1MtxU5Ru4lKzRRTZqM4OQEBJ//TNL3fiCZdd9agD+RQBjaeR4KFIyBSt3F7IE425ZWmxz+w==",
169
- "win32-ia32": "sha512-qfN1MsfQGek1QQd1UNW7JT+5K5Ne1suFQ2GpgpYm3JLSpIve/tz2vOGEGzvTVssOBADJvAkTDFt+yIi3PgU9pA==",
170
- "win32-x64": "sha512-eb3aAmjbVVBVRbiYgebQwoxkAt69WI8nwmKlilSQ3kWqoc0pXfIe322rF2UR8ebbISCGvYRUfzD2r1k92RXISQ=="
164
+ "darwin-arm64v8": "sha512-eUuxg6H0tXgX4z2lsaGtZ4cbPAm7yoFgkvPDd4csxoiVt+QUB25pEJwiXw7oB53VlBFIp3O8lbydSFS5zH8MQQ==",
165
+ "darwin-x64": "sha512-cMT4v76IgzSR0VoXqLk/yftRyzMEZ+SBVMLzXCgqP/lmnYisrpmHHNqrWnoZbUUBXbPXLn6KMultYOJHe/c9ZQ==",
166
+ "linux-arm64v8": "sha512-OcDJ/ly80pxwaKnw0W91sSvZczPtWsjmzrY/+6NMiQZT84LkmeaRuwErbHhorKDxnl7iZuNn9Uj5V25Xmj+LDQ==",
167
+ "linux-armv6": "sha512-hk2ohSOYTJEtVQxEQFyQ+tuayKpYqx6NiXa7AE+8MF+yscxt+g+mLJ7TjDqtmb4ttFGH4IVfsEfU2YXIqWqkpg==",
168
+ "linux-armv7": "sha512-/5Ci2Cd+yLZmTaEt9lVJ89elxX3RMJpps0ESjj43X40yrwka51QfXeg1QV38uNzZpCDIZkrbXZK0lyKldjpLuA==",
169
+ "linux-x64": "sha512-wjCKmWfBb0uz1UB7rPDLvO0s+VWuoAY/Vv/YGCRFEQUkdSLQUgHExrOMMbOM3FleuYfQqznDYCXXphkl7X44+w==",
170
+ "linuxmusl-arm64v8": "sha512-QtD2n90yi+rLE65C0gksFUU5uMUFPICI/pS3A0bgthpIcoCejAOYs3ZjVWpZbHQuV/lWahIUYO78MB9CzY860A==",
171
+ "linuxmusl-x64": "sha512-TokQ/ETCJAsPYuxIMOPYDp25rlcwtpmIMtRUR9PB75TmZEJe7abRfCEInIPYeD8F/HxxnJSLiEdlbn1z1Jfzng==",
172
+ "win32-arm64v8": "sha512-IIuj4EAgLqEVAoOuYH79C61a7TcJXlU/RBwk+5JsGWc2mr4J/Ar5J01e6XBvU4Lu3eqcU+3GPaACZEa1511buA==",
173
+ "win32-ia32": "sha512-CsZi7lrReX3B6tmYgOGJ0IiAfcN5APDC6l+3gdosxfTfwpLLO+jXaSmyNwIGeMqrdgckG/gwwc+IrUZmkmjJ/A==",
174
+ "win32-x64": "sha512-J7znmNKUK4ZKo6SnSnEtzT1xRAwvkGXxIx9/QihAadu1TFdS06yNhcENmwC4973+KZBlAdVpWbZ8sLrEoWkdCA=="
171
175
  },
172
176
  "runtime": "napi",
173
177
  "target": 7
@@ -193,5 +197,8 @@
193
197
  "filter": [
194
198
  "build/include"
195
199
  ]
200
+ },
201
+ "tsd": {
202
+ "directory": "test/types/"
196
203
  }
197
204
  }
package/src/common.cc CHANGED
@@ -1,16 +1,5 @@
1
- // Copyright 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020 Lovell Fuller and contributors.
2
- //
3
- // Licensed under the Apache License, Version 2.0 (the "License");
4
- // you may not use this file except in compliance with the License.
5
- // You may obtain a copy of the License at
6
- //
7
- // http://www.apache.org/licenses/LICENSE-2.0
8
- //
9
- // Unless required by applicable law or agreed to in writing, software
10
- // distributed under the License is distributed on an "AS IS" BASIS,
11
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- // See the License for the specific language governing permissions and
13
- // limitations under the License.
1
+ // Copyright 2013 Lovell Fuller and others.
2
+ // SPDX-License-Identifier: Apache-2.0
14
3
 
15
4
  #include <cstdlib>
16
5
  #include <string>
@@ -76,14 +65,6 @@ namespace sharp {
76
65
  }
77
66
  return vector;
78
67
  }
79
- Napi::Buffer<char> NewOrCopyBuffer(Napi::Env env, char* data, size_t len) {
80
- try {
81
- return Napi::Buffer<char>::New(env, data, len, FreeCallback);
82
- } catch (Napi::Error const &err) {}
83
- Napi::Buffer<char> buf = Napi::Buffer<char>::Copy(env, data, len);
84
- FreeCallback(nullptr, data);
85
- return buf;
86
- }
87
68
 
88
69
  // Create an InputDescriptor instance from a Napi::Object describing an input image
89
70
  InputDescriptor* CreateInputDescriptor(Napi::Object input) {
@@ -101,6 +82,10 @@ namespace sharp {
101
82
  if (HasAttr(input, "density")) {
102
83
  descriptor->density = AttrAsDouble(input, "density");
103
84
  }
85
+ // Should we ignore any embedded ICC profile
86
+ if (HasAttr(input, "ignoreIcc")) {
87
+ descriptor->ignoreIcc = AttrAsBool(input, "ignoreIcc");
88
+ }
104
89
  // Raw pixel input
105
90
  if (HasAttr(input, "rawChannels")) {
106
91
  descriptor->rawDepth = AttrAsEnum<VipsBandFormat>(input, "rawDepth", VIPS_TYPE_BAND_FORMAT);
@@ -167,6 +152,9 @@ namespace sharp {
167
152
  if (HasAttr(input, "textSpacing")) {
168
153
  descriptor->textSpacing = AttrAsUint32(input, "textSpacing");
169
154
  }
155
+ if (HasAttr(input, "textWrap")) {
156
+ descriptor->textWrap = AttrAsEnum<VipsTextWrap>(input, "textWrap", VIPS_TYPE_TEXT_WRAP);
157
+ }
170
158
  }
171
159
  // Limit input images to a given number of pixels, where pixels = width * height
172
160
  descriptor->limitInputPixels = static_cast<uint64_t>(AttrAsInt64(input, "limitInputPixels"));
@@ -228,6 +216,13 @@ namespace sharp {
228
216
  return EndsWith(str, ".v") || EndsWith(str, ".V") || EndsWith(str, ".vips") || EndsWith(str, ".VIPS");
229
217
  }
230
218
 
219
+ /*
220
+ Trim space from end of string.
221
+ */
222
+ std::string TrimEnd(std::string const &str) {
223
+ return str.substr(0, str.find_last_not_of(" \n\r\f") + 1);
224
+ }
225
+
231
226
  /*
232
227
  Provide a string identifier for the given image type.
233
228
  */
@@ -454,6 +449,7 @@ namespace sharp {
454
449
  ->set("justify", descriptor->textJustify)
455
450
  ->set("rgba", descriptor->textRgba)
456
451
  ->set("spacing", descriptor->textSpacing)
452
+ ->set("wrap", descriptor->textWrap)
457
453
  ->set("autofit_dpi", &descriptor->textAutofitDpi);
458
454
  if (descriptor->textWidth > 0) {
459
455
  textOptions->set("width", descriptor->textWidth);
@@ -612,6 +608,15 @@ namespace sharp {
612
608
  return copy;
613
609
  }
614
610
 
611
+ /*
612
+ Remove GIF palette from image.
613
+ */
614
+ VImage RemoveGifPalette(VImage image) {
615
+ VImage copy = image.copy();
616
+ copy.remove("gif-palette");
617
+ return copy;
618
+ }
619
+
615
620
  /*
616
621
  Does this image have a non-default density?
617
622
  */
package/src/common.h CHANGED
@@ -1,16 +1,5 @@
1
- // Copyright 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020 Lovell Fuller and contributors.
2
- //
3
- // Licensed under the Apache License, Version 2.0 (the "License");
4
- // you may not use this file except in compliance with the License.
5
- // You may obtain a copy of the License at
6
- //
7
- // http://www.apache.org/licenses/LICENSE-2.0
8
- //
9
- // Unless required by applicable law or agreed to in writing, software
10
- // distributed under the License is distributed on an "AS IS" BASIS,
11
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- // See the License for the specific language governing permissions and
13
- // limitations under the License.
1
+ // Copyright 2013 Lovell Fuller and others.
2
+ // SPDX-License-Identifier: Apache-2.0
14
3
 
15
4
  #ifndef SRC_COMMON_H_
16
5
  #define SRC_COMMON_H_
@@ -25,9 +14,9 @@
25
14
  // Verify platform and compiler compatibility
26
15
 
27
16
  #if (VIPS_MAJOR_VERSION < 8) || \
28
- (VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION < 13) || \
29
- (VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION == 13 && VIPS_MICRO_VERSION < 3)
30
- #error "libvips version 8.13.3+ is required - please see https://sharp.pixelplumbing.com/install"
17
+ (VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION < 14) || \
18
+ (VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION == 14 && VIPS_MICRO_VERSION < 2)
19
+ #error "libvips version 8.14.2+ is required - please see https://sharp.pixelplumbing.com/install"
31
20
  #endif
32
21
 
33
22
  #if ((!defined(__clang__)) && defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 6)))
@@ -55,6 +44,7 @@ namespace sharp {
55
44
  size_t bufferLength;
56
45
  bool isBuffer;
57
46
  double density;
47
+ bool ignoreIcc;
58
48
  VipsBandFormat rawDepth;
59
49
  int rawChannels;
60
50
  int rawWidth;
@@ -81,6 +71,7 @@ namespace sharp {
81
71
  int textDpi;
82
72
  bool textRgba;
83
73
  int textSpacing;
74
+ VipsTextWrap textWrap;
84
75
  int textAutofitDpi;
85
76
 
86
77
  InputDescriptor():
@@ -92,6 +83,7 @@ namespace sharp {
92
83
  bufferLength(0),
93
84
  isBuffer(FALSE),
94
85
  density(72.0),
86
+ ignoreIcc(FALSE),
95
87
  rawDepth(VIPS_FORMAT_UCHAR),
96
88
  rawChannels(0),
97
89
  rawWidth(0),
@@ -114,6 +106,7 @@ namespace sharp {
114
106
  textDpi(72),
115
107
  textRgba(FALSE),
116
108
  textSpacing(0),
109
+ textWrap(VIPS_TEXT_WRAP_WORD),
117
110
  textAutofitDpi(0) {}
118
111
  };
119
112
 
@@ -133,7 +126,6 @@ namespace sharp {
133
126
  return static_cast<T>(
134
127
  vips_enum_from_nick(nullptr, type, AttrAsStr(obj, attr).data()));
135
128
  }
136
- Napi::Buffer<char> NewOrCopyBuffer(Napi::Env env, char* data, size_t len);
137
129
 
138
130
  // Create an InputDescriptor instance from a Napi::Object describing an input image
139
131
  InputDescriptor* CreateInputDescriptor(Napi::Object input);
@@ -189,6 +181,11 @@ namespace sharp {
189
181
  bool IsDzZip(std::string const &str);
190
182
  bool IsV(std::string const &str);
191
183
 
184
+ /*
185
+ Trim space from end of string.
186
+ */
187
+ std::string TrimEnd(std::string const &str);
188
+
192
189
  /*
193
190
  Provide a string identifier for the given image type.
194
191
  */
@@ -255,6 +252,11 @@ namespace sharp {
255
252
  */
256
253
  VImage RemoveAnimationProperties(VImage image);
257
254
 
255
+ /*
256
+ Remove GIF palette from image.
257
+ */
258
+ VImage RemoveGifPalette(VImage image);
259
+
258
260
  /*
259
261
  Does this image have a non-default density?
260
262
  */
@@ -3679,6 +3679,13 @@ VipsBlob *VImage::webpsave_buffer( VOption *options ) const
3679
3679
  return( buffer );
3680
3680
  }
3681
3681
 
3682
+ void VImage::webpsave_mime( VOption *options ) const
3683
+ {
3684
+ call( "webpsave_mime",
3685
+ (options ? options : VImage::option())->
3686
+ set( "in", *this ) );
3687
+ }
3688
+
3682
3689
  void VImage::webpsave_target( VTarget target, VOption *options ) const
3683
3690
  {
3684
3691
  call( "webpsave_target",
package/src/metadata.cc CHANGED
@@ -1,16 +1,5 @@
1
- // Copyright 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020 Lovell Fuller and contributors.
2
- //
3
- // Licensed under the Apache License, Version 2.0 (the "License");
4
- // you may not use this file except in compliance with the License.
5
- // You may obtain a copy of the License at
6
- //
7
- // http://www.apache.org/licenses/LICENSE-2.0
8
- //
9
- // Unless required by applicable law or agreed to in writing, software
10
- // distributed under the License is distributed on an "AS IS" BASIS,
11
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- // See the License for the specific language governing permissions and
13
- // limitations under the License.
1
+ // Copyright 2013 Lovell Fuller and others.
2
+ // SPDX-License-Identifier: Apache-2.0
14
3
 
15
4
  #include <numeric>
16
5
  #include <vector>
@@ -80,6 +69,9 @@ class MetadataWorker : public Napi::AsyncWorker {
80
69
  if (image.get_typeof(VIPS_META_RESOLUTION_UNIT) == VIPS_TYPE_REF_STRING) {
81
70
  baton->resolutionUnit = image.get_string(VIPS_META_RESOLUTION_UNIT);
82
71
  }
72
+ if (image.get_typeof("magick-format") == VIPS_TYPE_REF_STRING) {
73
+ baton->formatMagick = image.get_string("magick-format");
74
+ }
83
75
  if (image.get_typeof("openslide.level-count") == VIPS_TYPE_REF_STRING) {
84
76
  int const levels = std::stoi(image.get_string("openslide.level-count"));
85
77
  for (int l = 0; l < levels; l++) {
@@ -153,7 +145,7 @@ class MetadataWorker : public Napi::AsyncWorker {
153
145
  // Handle warnings
154
146
  std::string warning = sharp::VipsWarningPop();
155
147
  while (!warning.empty()) {
156
- debuglog.Call({ Napi::String::New(env, warning) });
148
+ debuglog.MakeCallback(Receiver().Value(), { Napi::String::New(env, warning) });
157
149
  warning = sharp::VipsWarningPop();
158
150
  }
159
151
 
@@ -204,6 +196,9 @@ class MetadataWorker : public Napi::AsyncWorker {
204
196
  if (!baton->resolutionUnit.empty()) {
205
197
  info.Set("resolutionUnit", baton->resolutionUnit == "in" ? "inch" : baton->resolutionUnit);
206
198
  }
199
+ if (!baton->formatMagick.empty()) {
200
+ info.Set("formatMagick", baton->formatMagick);
201
+ }
207
202
  if (!baton->levels.empty()) {
208
203
  int i = 0;
209
204
  Napi::Array levels = Napi::Array::New(env, static_cast<size_t>(baton->levels.size()));
@@ -235,24 +230,25 @@ class MetadataWorker : public Napi::AsyncWorker {
235
230
  info.Set("orientation", baton->orientation);
236
231
  }
237
232
  if (baton->exifLength > 0) {
238
- info.Set("exif", sharp::NewOrCopyBuffer(env, baton->exif, baton->exifLength));
233
+ info.Set("exif", Napi::Buffer<char>::NewOrCopy(env, baton->exif, baton->exifLength, sharp::FreeCallback));
239
234
  }
240
235
  if (baton->iccLength > 0) {
241
- info.Set("icc", sharp::NewOrCopyBuffer(env, baton->icc, baton->iccLength));
236
+ info.Set("icc", Napi::Buffer<char>::NewOrCopy(env, baton->icc, baton->iccLength, sharp::FreeCallback));
242
237
  }
243
238
  if (baton->iptcLength > 0) {
244
- info.Set("iptc", sharp::NewOrCopyBuffer(env, baton->iptc, baton->iptcLength));
239
+ info.Set("iptc", Napi::Buffer<char>::NewOrCopy(env, baton->iptc, baton->iptcLength, sharp::FreeCallback));
245
240
  }
246
241
  if (baton->xmpLength > 0) {
247
- info.Set("xmp", sharp::NewOrCopyBuffer(env, baton->xmp, baton->xmpLength));
242
+ info.Set("xmp", Napi::Buffer<char>::NewOrCopy(env, baton->xmp, baton->xmpLength, sharp::FreeCallback));
248
243
  }
249
244
  if (baton->tifftagPhotoshopLength > 0) {
250
245
  info.Set("tifftagPhotoshop",
251
- sharp::NewOrCopyBuffer(env, baton->tifftagPhotoshop, baton->tifftagPhotoshopLength));
246
+ Napi::Buffer<char>::NewOrCopy(env, baton->tifftagPhotoshop,
247
+ baton->tifftagPhotoshopLength, sharp::FreeCallback));
252
248
  }
253
249
  Callback().MakeCallback(Receiver().Value(), { env.Null(), info });
254
250
  } else {
255
- Callback().MakeCallback(Receiver().Value(), { Napi::Error::New(env, baton->err).Value() });
251
+ Callback().MakeCallback(Receiver().Value(), { Napi::Error::New(env, sharp::TrimEnd(baton->err)).Value() });
256
252
  }
257
253
 
258
254
  delete baton->input;
@@ -270,7 +266,7 @@ class MetadataWorker : public Napi::AsyncWorker {
270
266
  Napi::Value metadata(const Napi::CallbackInfo& info) {
271
267
  // V8 objects are converted to non-V8 types held in the baton struct
272
268
  MetadataBaton *baton = new MetadataBaton;
273
- Napi::Object options = info[0].As<Napi::Object>();
269
+ Napi::Object options = info[size_t(0)].As<Napi::Object>();
274
270
 
275
271
  // Input
276
272
  baton->input = sharp::CreateInputDescriptor(options.Get("input").As<Napi::Object>());
@@ -279,7 +275,7 @@ Napi::Value metadata(const Napi::CallbackInfo& info) {
279
275
  Napi::Function debuglog = options.Get("debuglog").As<Napi::Function>();
280
276
 
281
277
  // Join queue for worker thread
282
- Napi::Function callback = info[1].As<Napi::Function>();
278
+ Napi::Function callback = info[size_t(1)].As<Napi::Function>();
283
279
  MetadataWorker *worker = new MetadataWorker(callback, baton, debuglog);
284
280
  worker->Receiver().Set("options", options);
285
281
  worker->Queue();
package/src/metadata.h CHANGED
@@ -1,16 +1,5 @@
1
- // Copyright 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020 Lovell Fuller and contributors.
2
- //
3
- // Licensed under the Apache License, Version 2.0 (the "License");
4
- // you may not use this file except in compliance with the License.
5
- // You may obtain a copy of the License at
6
- //
7
- // http://www.apache.org/licenses/LICENSE-2.0
8
- //
9
- // Unless required by applicable law or agreed to in writing, software
10
- // distributed under the License is distributed on an "AS IS" BASIS,
11
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- // See the License for the specific language governing permissions and
13
- // limitations under the License.
1
+ // Copyright 2013 Lovell Fuller and others.
2
+ // SPDX-License-Identifier: Apache-2.0
14
3
 
15
4
  #ifndef SRC_METADATA_H_
16
5
  #define SRC_METADATA_H_
@@ -41,6 +30,7 @@ struct MetadataBaton {
41
30
  int pagePrimary;
42
31
  std::string compression;
43
32
  std::string resolutionUnit;
33
+ std::string formatMagick;
44
34
  std::vector<std::pair<int, int>> levels;
45
35
  int subifds;
46
36
  std::vector<double> background;
package/src/operations.cc CHANGED
@@ -1,23 +1,11 @@
1
- // Copyright 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020 Lovell Fuller and contributors.
2
- //
3
- // Licensed under the Apache License, Version 2.0 (the "License");
4
- // you may not use this file except in compliance with the License.
5
- // You may obtain a copy of the License at
6
- //
7
- // http://www.apache.org/licenses/LICENSE-2.0
8
- //
9
- // Unless required by applicable law or agreed to in writing, software
10
- // distributed under the License is distributed on an "AS IS" BASIS,
11
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- // See the License for the specific language governing permissions and
13
- // limitations under the License.
1
+ // Copyright 2013 Lovell Fuller and others.
2
+ // SPDX-License-Identifier: Apache-2.0
14
3
 
15
4
  #include <algorithm>
16
5
  #include <functional>
17
6
  #include <memory>
18
7
  #include <tuple>
19
8
  #include <vector>
20
-
21
9
  #include <vips/vips8>
22
10
 
23
11
  #include "common.h"
@@ -57,7 +45,7 @@ namespace sharp {
57
45
  /*
58
46
  * Stretch luminance to cover full dynamic range.
59
47
  */
60
- VImage Normalise(VImage image) {
48
+ VImage Normalise(VImage image, int const lower, int const upper) {
61
49
  // Get original colourspace
62
50
  VipsInterpretation typeBeforeNormalize = image.interpretation();
63
51
  if (typeBeforeNormalize == VIPS_INTERPRETATION_RGB) {
@@ -67,9 +55,11 @@ namespace sharp {
67
55
  VImage lab = image.colourspace(VIPS_INTERPRETATION_LAB);
68
56
  // Extract luminance
69
57
  VImage luminance = lab[0];
58
+
70
59
  // Find luminance range
71
- int const min = luminance.percent(1);
72
- int const max = luminance.percent(99);
60
+ int const min = lower == 0 ? luminance.min() : luminance.percent(lower);
61
+ int const max = upper == 100 ? luminance.max() : luminance.percent(upper);
62
+
73
63
  if (std::abs(max - min) > 1) {
74
64
  // Extract chroma
75
65
  VImage chroma = lab.extract_band(1, VImage::option()->set("n", 2));
@@ -196,6 +186,7 @@ namespace sharp {
196
186
 
197
187
  VImage Modulate(VImage image, double const brightness, double const saturation,
198
188
  int const hue, double const lightness) {
189
+ VipsInterpretation colourspaceBeforeModulate = image.interpretation();
199
190
  if (HasAlpha(image)) {
200
191
  // Separate alpha channel
201
192
  VImage alpha = image[image.bands() - 1];
@@ -205,7 +196,7 @@ namespace sharp {
205
196
  { brightness, saturation, 1},
206
197
  { lightness, 0.0, static_cast<double>(hue) }
207
198
  )
208
- .colourspace(VIPS_INTERPRETATION_sRGB)
199
+ .colourspace(colourspaceBeforeModulate)
209
200
  .bandjoin(alpha);
210
201
  } else {
211
202
  return image
@@ -214,7 +205,7 @@ namespace sharp {
214
205
  { brightness, saturation, 1 },
215
206
  { lightness, 0.0, static_cast<double>(hue) }
216
207
  )
217
- .colourspace(VIPS_INTERPRETATION_sRGB);
208
+ .colourspace(colourspaceBeforeModulate);
218
209
  }
219
210
  }
220
211
 
@@ -278,30 +269,20 @@ namespace sharp {
278
269
  if (image.width() < 3 && image.height() < 3) {
279
270
  throw VError("Image to trim must be at least 3x3 pixels");
280
271
  }
281
-
282
- // Scale up 8-bit values to match 16-bit input image
283
- double multiplier = sharp::Is16Bit(image.interpretation()) ? 256.0 : 1.0;
284
- threshold *= multiplier;
285
-
286
- std::vector<double> backgroundAlpha(1);
287
272
  if (background.size() == 0) {
288
273
  // Top-left pixel provides the default background colour if none is given
289
274
  background = image.extract_area(0, 0, 1, 1)(0, 0);
290
- multiplier = 1.0;
291
- }
292
- if (HasAlpha(image) && background.size() == 4) {
293
- // Just discard the alpha because flattening the background colour with
294
- // itself (effectively what find_trim() does) gives the same result
295
- backgroundAlpha[0] = background[3] * multiplier;
275
+ } else if (sharp::Is16Bit(image.interpretation())) {
276
+ for (size_t i = 0; i < background.size(); i++) {
277
+ background[i] *= 256.0;
278
+ }
279
+ threshold *= 256.0;
296
280
  }
297
- if (image.bands() > 2) {
298
- background = {
299
- background[0] * multiplier,
300
- background[1] * multiplier,
301
- background[2] * multiplier
302
- };
281
+ std::vector<double> backgroundAlpha({ background.back() });
282
+ if (HasAlpha(image)) {
283
+ background.pop_back();
303
284
  } else {
304
- background[0] = background[0] * multiplier;
285
+ background.resize(image.bands());
305
286
  }
306
287
  int left, top, width, height;
307
288
  left = image.find_trim(&top, &width, &height, VImage::option()
@@ -342,12 +323,26 @@ namespace sharp {
342
323
  if (a.size() > bands) {
343
324
  throw VError("Band expansion using linear is unsupported");
344
325
  }
326
+ bool const uchar = !Is16Bit(image.interpretation());
345
327
  if (HasAlpha(image) && a.size() != bands && (a.size() == 1 || a.size() == bands - 1 || bands - 1 == 1)) {
346
328
  // Separate alpha channel
347
329
  VImage alpha = image[bands - 1];
348
- return RemoveAlpha(image).linear(a, b, VImage::option()->set("uchar", TRUE)).bandjoin(alpha);
330
+ return RemoveAlpha(image).linear(a, b, VImage::option()->set("uchar", uchar)).bandjoin(alpha);
331
+ } else {
332
+ return image.linear(a, b, VImage::option()->set("uchar", uchar));
333
+ }
334
+ }
335
+
336
+ /*
337
+ * Unflatten
338
+ */
339
+ VImage Unflatten(VImage image) {
340
+ if (HasAlpha(image)) {
341
+ VImage alpha = image[image.bands() - 1];
342
+ VImage noAlpha = RemoveAlpha(image);
343
+ return noAlpha.bandjoin(alpha & (noAlpha.colourspace(VIPS_INTERPRETATION_B_W) < 255));
349
344
  } else {
350
- return image.linear(a, b, VImage::option()->set("uchar", TRUE));
345
+ return image.bandjoin(image.colourspace(VIPS_INTERPRETATION_B_W) < 255);
351
346
  }
352
347
  }
353
348
 
@@ -395,11 +390,11 @@ namespace sharp {
395
390
  * Split into frames, embed each frame, reassemble, and update pageHeight.
396
391
  */
397
392
  VImage EmbedMultiPage(VImage image, int left, int top, int width, int height,
398
- std::vector<double> background, int nPages, int *pageHeight) {
393
+ VipsExtend extendWith, std::vector<double> background, int nPages, int *pageHeight) {
399
394
  if (top == 0 && height == *pageHeight) {
400
395
  // Fast path; no need to adjust the height of the multi-page image
401
396
  return image.embed(left, 0, width, image.height(), VImage::option()
402
- ->set("extend", VIPS_EXTEND_BACKGROUND)
397
+ ->set("extend", extendWith)
403
398
  ->set("background", background));
404
399
  } else if (left == 0 && width == image.width()) {
405
400
  // Fast path; no need to adjust the width of the multi-page image
@@ -411,7 +406,7 @@ namespace sharp {
411
406
 
412
407
  // Do the embed on the wide image
413
408
  image = image.embed(0, top, image.width(), height, VImage::option()
414
- ->set("extend", VIPS_EXTEND_BACKGROUND)
409
+ ->set("extend", extendWith)
415
410
  ->set("background", background));
416
411
 
417
412
  // Split the wide image into frames
@@ -441,7 +436,7 @@ namespace sharp {
441
436
  // Embed each frame in the target size
442
437
  for (int i = 0; i < nPages; i++) {
443
438
  pages[i] = pages[i].embed(left, top, width, height, VImage::option()
444
- ->set("extend", VIPS_EXTEND_BACKGROUND)
439
+ ->set("extend", extendWith)
445
440
  ->set("background", background));
446
441
  }
447
442