sharp 0.25.3 → 0.25.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/binding.gyp +30 -6
- package/install/libvips.js +2 -1
- package/lib/channel.js +5 -8
- package/lib/constructor.js +26 -17
- package/lib/input.js +13 -0
- package/lib/is.js +4 -4
- package/lib/libvips.js +1 -1
- package/lib/output.js +34 -28
- package/package.json +7 -6
- package/src/common.cc +10 -0
- package/src/common.h +2 -0
- package/src/metadata.cc +20 -0
- package/src/metadata.h +1 -0
- package/src/pipeline.cc +6 -2
- package/src/stats.cc +11 -1
- package/src/stats.h +3 -1
package/binding.gyp
CHANGED
|
@@ -29,10 +29,22 @@
|
|
|
29
29
|
'Release': {
|
|
30
30
|
'msvs_settings': {
|
|
31
31
|
'VCCLCompilerTool': {
|
|
32
|
-
'ExceptionHandling': 1
|
|
32
|
+
'ExceptionHandling': 1,
|
|
33
|
+
'WholeProgramOptimization': 'true'
|
|
34
|
+
},
|
|
35
|
+
'VCLibrarianTool': {
|
|
36
|
+
'AdditionalOptions': [
|
|
37
|
+
'/LTCG:INCREMENTAL'
|
|
38
|
+
]
|
|
33
39
|
},
|
|
34
40
|
'VCLinkerTool': {
|
|
35
|
-
'ImageHasSafeExceptionHandlers': 'false'
|
|
41
|
+
'ImageHasSafeExceptionHandlers': 'false',
|
|
42
|
+
'OptimizeReferences': 2,
|
|
43
|
+
'EnableCOMDATFolding': 2,
|
|
44
|
+
'LinkIncremental': 1,
|
|
45
|
+
'AdditionalOptions': [
|
|
46
|
+
'/LTCG:INCREMENTAL'
|
|
47
|
+
]
|
|
36
48
|
}
|
|
37
49
|
},
|
|
38
50
|
'msvs_disabled_warnings': [
|
|
@@ -121,7 +133,7 @@
|
|
|
121
133
|
'../vendor/lib/libglib-2.0.0.dylib',
|
|
122
134
|
'../vendor/lib/libgobject-2.0.0.dylib',
|
|
123
135
|
# Ensure runtime linking is relative to sharp.node
|
|
124
|
-
'-rpath \'@loader_path/../../vendor/lib\''
|
|
136
|
+
'-Wl,-s -rpath \'@loader_path/../../vendor/lib\''
|
|
125
137
|
]
|
|
126
138
|
}],
|
|
127
139
|
['OS == "linux"', {
|
|
@@ -164,7 +176,7 @@
|
|
|
164
176
|
'../vendor/lib/libxml2.so',
|
|
165
177
|
'../vendor/lib/libz.so',
|
|
166
178
|
# Ensure runtime linking is relative to sharp.node
|
|
167
|
-
'-Wl,--disable-new-dtags -Wl,-rpath=\'$${ORIGIN}/../../vendor/lib\''
|
|
179
|
+
'-Wl,-s -Wl,--disable-new-dtags -Wl,-rpath=\'$${ORIGIN}/../../vendor/lib\''
|
|
168
180
|
]
|
|
169
181
|
}]
|
|
170
182
|
]
|
|
@@ -204,10 +216,22 @@
|
|
|
204
216
|
['OS == "win"', {
|
|
205
217
|
'msvs_settings': {
|
|
206
218
|
'VCCLCompilerTool': {
|
|
207
|
-
'ExceptionHandling': 1
|
|
219
|
+
'ExceptionHandling': 1,
|
|
220
|
+
'WholeProgramOptimization': 'true'
|
|
221
|
+
},
|
|
222
|
+
'VCLibrarianTool': {
|
|
223
|
+
'AdditionalOptions': [
|
|
224
|
+
'/LTCG:INCREMENTAL'
|
|
225
|
+
]
|
|
208
226
|
},
|
|
209
227
|
'VCLinkerTool': {
|
|
210
|
-
'ImageHasSafeExceptionHandlers': 'false'
|
|
228
|
+
'ImageHasSafeExceptionHandlers': 'false',
|
|
229
|
+
'OptimizeReferences': 2,
|
|
230
|
+
'EnableCOMDATFolding': 2,
|
|
231
|
+
'LinkIncremental': 1,
|
|
232
|
+
'AdditionalOptions': [
|
|
233
|
+
'/LTCG:INCREMENTAL'
|
|
234
|
+
]
|
|
211
235
|
}
|
|
212
236
|
},
|
|
213
237
|
'msvs_disabled_warnings': [
|
package/install/libvips.js
CHANGED
|
@@ -21,7 +21,8 @@ const minimumGlibcVersionByArch = {
|
|
|
21
21
|
};
|
|
22
22
|
|
|
23
23
|
const { minimumLibvipsVersion, minimumLibvipsVersionLabelled } = libvips;
|
|
24
|
-
const
|
|
24
|
+
const distHost = process.env.npm_config_sharp_libvips_binary_host || 'https://github.com/lovell/sharp-libvips/releases/download';
|
|
25
|
+
const distBaseUrl = process.env.npm_config_sharp_dist_base_url || process.env.SHARP_DIST_BASE_URL || `${distHost}/v${minimumLibvipsVersionLabelled}/`;
|
|
25
26
|
|
|
26
27
|
const fail = function (err) {
|
|
27
28
|
npmLog.error('sharp', err.message);
|
package/lib/channel.js
CHANGED
|
@@ -60,22 +60,19 @@ function ensureAlpha () {
|
|
|
60
60
|
* // green.jpg is a greyscale image containing the green channel of the input
|
|
61
61
|
* });
|
|
62
62
|
*
|
|
63
|
-
* @param {number|string} channel - zero-indexed band number to extract, or `red`, `green
|
|
63
|
+
* @param {number|string} channel - zero-indexed channel/band number to extract, or `red`, `green`, `blue` or `alpha`.
|
|
64
64
|
* @returns {Sharp}
|
|
65
65
|
* @throws {Error} Invalid channel
|
|
66
66
|
*/
|
|
67
67
|
function extractChannel (channel) {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
channel = 1;
|
|
72
|
-
} else if (channel === 'blue') {
|
|
73
|
-
channel = 2;
|
|
68
|
+
const channelMap = { red: 0, green: 1, blue: 2, alpha: 3 };
|
|
69
|
+
if (Object.keys(channelMap).includes(channel)) {
|
|
70
|
+
channel = channelMap[channel];
|
|
74
71
|
}
|
|
75
72
|
if (is.integer(channel) && is.inRange(channel, 0, 4)) {
|
|
76
73
|
this.options.extractChannel = channel;
|
|
77
74
|
} else {
|
|
78
|
-
throw is.invalidParameterError('channel', 'integer or one of: red, green, blue', channel);
|
|
75
|
+
throw is.invalidParameterError('channel', 'integer or one of: red, green, blue, alpha', channel);
|
|
79
76
|
}
|
|
80
77
|
return this;
|
|
81
78
|
}
|
package/lib/constructor.js
CHANGED
|
@@ -38,15 +38,20 @@ try {
|
|
|
38
38
|
const debuglog = util.debuglog('sharp');
|
|
39
39
|
|
|
40
40
|
/**
|
|
41
|
-
* @constructs sharp
|
|
42
|
-
*
|
|
43
41
|
* Constructor factory to create an instance of `sharp`, to which further methods are chained.
|
|
44
42
|
*
|
|
45
43
|
* JPEG, PNG, WebP or TIFF format image data can be streamed out from this object.
|
|
46
44
|
* When using Stream based output, derived attributes are available from the `info` event.
|
|
47
45
|
*
|
|
46
|
+
* Non-critical problems encountered during processing are emitted as `warning` events.
|
|
47
|
+
*
|
|
48
48
|
* Implements the [stream.Duplex](http://nodejs.org/api/stream.html#stream_class_stream_duplex) class.
|
|
49
49
|
*
|
|
50
|
+
* @constructs Sharp
|
|
51
|
+
*
|
|
52
|
+
* @emits Sharp#info
|
|
53
|
+
* @emits Sharp#warning
|
|
54
|
+
*
|
|
50
55
|
* @example
|
|
51
56
|
* sharp('input.jpg')
|
|
52
57
|
* .resize(300, 200)
|
|
@@ -81,30 +86,31 @@ const debuglog = util.debuglog('sharp');
|
|
|
81
86
|
* .toBuffer()
|
|
82
87
|
* .then( ... );
|
|
83
88
|
*
|
|
84
|
-
* @param {(Buffer|
|
|
89
|
+
* @param {(Buffer|string)} [input] - if present, can be
|
|
85
90
|
* a Buffer containing JPEG, PNG, WebP, GIF, SVG, TIFF or raw pixel image data, or
|
|
86
91
|
* a String containing the filesystem path to an JPEG, PNG, WebP, GIF, SVG or TIFF image file.
|
|
87
92
|
* JPEG, PNG, WebP, GIF, SVG, TIFF or raw pixel image data can be streamed into the object when not present.
|
|
88
93
|
* @param {Object} [options] - if present, is an Object with optional attributes.
|
|
89
|
-
* @param {
|
|
94
|
+
* @param {boolean} [options.failOnError=true] - by default halt processing and raise an error when loading invalid images.
|
|
90
95
|
* Set this flag to `false` if you'd rather apply a "best effort" to decode images, even if the data is corrupt or invalid.
|
|
91
|
-
* @param {
|
|
96
|
+
* @param {number|boolean} [options.limitInputPixels=268402689] - Do not process input images where the number of pixels
|
|
92
97
|
* (width x height) exceeds this limit. Assumes image dimensions contained in the input metadata can be trusted.
|
|
93
98
|
* An integral Number of pixels, zero or false to remove limit, true to use default limit of 268402689 (0x3FFF x 0x3FFF).
|
|
94
|
-
* @param {
|
|
99
|
+
* @param {boolean} [options.sequentialRead=false] - Set this to `true` to use sequential rather than random access where possible.
|
|
95
100
|
* This can reduce memory usage and might improve performance on some systems.
|
|
96
|
-
* @param {
|
|
97
|
-
* @param {
|
|
98
|
-
* @param {
|
|
101
|
+
* @param {number} [options.density=72] - number representing the DPI for vector images.
|
|
102
|
+
* @param {number} [options.pages=1] - number of pages to extract for multi-page input (GIF, TIFF, PDF), use -1 for all pages.
|
|
103
|
+
* @param {number} [options.page=0] - page number to start extracting from for multi-page input (GIF, TIFF, PDF), zero based.
|
|
104
|
+
* @param {number} [options.level=0] - level to extract from a multi-level input (OpenSlide), zero based.
|
|
99
105
|
* @param {Object} [options.raw] - describes raw pixel input image data. See `raw()` for pixel ordering.
|
|
100
|
-
* @param {
|
|
101
|
-
* @param {
|
|
102
|
-
* @param {
|
|
106
|
+
* @param {number} [options.raw.width]
|
|
107
|
+
* @param {number} [options.raw.height]
|
|
108
|
+
* @param {number} [options.raw.channels] - 1-4
|
|
103
109
|
* @param {Object} [options.create] - describes a new image to be created.
|
|
104
|
-
* @param {
|
|
105
|
-
* @param {
|
|
106
|
-
* @param {
|
|
107
|
-
* @param {
|
|
110
|
+
* @param {number} [options.create.width]
|
|
111
|
+
* @param {number} [options.create.height]
|
|
112
|
+
* @param {number} [options.create.channels] - 3-4
|
|
113
|
+
* @param {string|Object} [options.create.background] - parsed by the [color](https://www.npmjs.org/package/color) module to extract values for red, green, blue and alpha.
|
|
108
114
|
* @returns {Sharp}
|
|
109
115
|
* @throws {Error} Invalid parameters
|
|
110
116
|
*/
|
|
@@ -229,7 +235,10 @@ const Sharp = function (input, options) {
|
|
|
229
235
|
linearA: 1,
|
|
230
236
|
linearB: 0,
|
|
231
237
|
// Function to notify of libvips warnings
|
|
232
|
-
debuglog:
|
|
238
|
+
debuglog: warning => {
|
|
239
|
+
this.emit('warning', warning);
|
|
240
|
+
debuglog(warning);
|
|
241
|
+
},
|
|
233
242
|
// Function to notify of queue length changes
|
|
234
243
|
queueListener: function (queueLength) {
|
|
235
244
|
Sharp.queue.emit('change', queueLength);
|
package/lib/input.js
CHANGED
|
@@ -113,6 +113,14 @@ function _createInputDescriptor (input, inputOptions, containerOptions) {
|
|
|
113
113
|
throw is.invalidParameterError('page', 'integer between 0 and 100000', inputOptions.page);
|
|
114
114
|
}
|
|
115
115
|
}
|
|
116
|
+
// Multi-level input (OpenSlide)
|
|
117
|
+
if (is.defined(inputOptions.level)) {
|
|
118
|
+
if (is.integer(inputOptions.level) && is.inRange(inputOptions.level, 0, 256)) {
|
|
119
|
+
inputDescriptor.level = inputOptions.level;
|
|
120
|
+
} else {
|
|
121
|
+
throw is.invalidParameterError('level', 'integer between 0 and 256', inputOptions.level);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
116
124
|
// Create new image
|
|
117
125
|
if (is.defined(inputOptions.create)) {
|
|
118
126
|
if (
|
|
@@ -208,6 +216,7 @@ function _isStreamInput () {
|
|
|
208
216
|
* - `loop`: Number of times to loop an animated image, zero refers to a continuous loop.
|
|
209
217
|
* - `delay`: Delay in ms between each page in an animated image, provided as an array of integers.
|
|
210
218
|
* - `pagePrimary`: Number of the primary page in a HEIF image
|
|
219
|
+
* - `levels`: Details of each level in a multi-level image provided as an array of objects, requires libvips compiled with support for OpenSlide
|
|
211
220
|
* - `hasProfile`: Boolean indicating the presence of an embedded ICC profile
|
|
212
221
|
* - `hasAlpha`: Boolean indicating the presence of an alpha transparency channel
|
|
213
222
|
* - `orientation`: Number value of the EXIF Orientation header, if present
|
|
@@ -290,6 +299,7 @@ function metadata (callback) {
|
|
|
290
299
|
* - `maxY` (y-coordinate of one of the pixel where the maximum lies)
|
|
291
300
|
* - `isOpaque`: Is the image fully opaque? Will be `true` if the image has no alpha channel or if every pixel is fully opaque.
|
|
292
301
|
* - `entropy`: Histogram-based estimation of greyscale entropy, discarding alpha channel if any (experimental)
|
|
302
|
+
* - `sharpness`: Estimation of greyscale sharpness based on the standard deviation of a Laplacian convolution, discarding alpha channel if any (experimental)
|
|
293
303
|
*
|
|
294
304
|
* @example
|
|
295
305
|
* const image = sharp(inputJpg);
|
|
@@ -299,6 +309,9 @@ function metadata (callback) {
|
|
|
299
309
|
* // stats contains the channel-wise statistics array and the isOpaque value
|
|
300
310
|
* });
|
|
301
311
|
*
|
|
312
|
+
* @example
|
|
313
|
+
* const { entropy, sharpness } = await sharp(input).stats();
|
|
314
|
+
*
|
|
302
315
|
* @param {Function} [callback] - called with the arguments `(err, stats)`
|
|
303
316
|
* @returns {Promise<Object>}
|
|
304
317
|
*/
|
package/lib/is.js
CHANGED
|
@@ -21,7 +21,7 @@ const object = function (val) {
|
|
|
21
21
|
* @private
|
|
22
22
|
*/
|
|
23
23
|
const plainObject = function (val) {
|
|
24
|
-
return
|
|
24
|
+
return Object.prototype.toString.call(val) === '[object Object]';
|
|
25
25
|
};
|
|
26
26
|
|
|
27
27
|
/**
|
|
@@ -45,7 +45,7 @@ const bool = function (val) {
|
|
|
45
45
|
* @private
|
|
46
46
|
*/
|
|
47
47
|
const buffer = function (val) {
|
|
48
|
-
return
|
|
48
|
+
return val instanceof Buffer;
|
|
49
49
|
};
|
|
50
50
|
|
|
51
51
|
/**
|
|
@@ -69,7 +69,7 @@ const number = function (val) {
|
|
|
69
69
|
* @private
|
|
70
70
|
*/
|
|
71
71
|
const integer = function (val) {
|
|
72
|
-
return
|
|
72
|
+
return Number.isInteger(val);
|
|
73
73
|
};
|
|
74
74
|
|
|
75
75
|
/**
|
|
@@ -85,7 +85,7 @@ const inRange = function (val, min, max) {
|
|
|
85
85
|
* @private
|
|
86
86
|
*/
|
|
87
87
|
const inArray = function (val, list) {
|
|
88
|
-
return list.
|
|
88
|
+
return list.includes(val);
|
|
89
89
|
};
|
|
90
90
|
|
|
91
91
|
/**
|
package/lib/libvips.js
CHANGED
|
@@ -65,7 +65,7 @@ const hasVendoredLibvips = function () {
|
|
|
65
65
|
if (currentPlatformId === vendorPlatformId) {
|
|
66
66
|
return true;
|
|
67
67
|
} else {
|
|
68
|
-
throw new Error(`'${vendorPlatformId}' binaries cannot be used on the '${currentPlatformId}' platform. Please remove the 'node_modules/sharp
|
|
68
|
+
throw new Error(`'${vendorPlatformId}' binaries cannot be used on the '${currentPlatformId}' platform. Please remove the 'node_modules/sharp' directory and run 'npm install' on the '${currentPlatformId}' platform.`);
|
|
69
69
|
}
|
|
70
70
|
} else {
|
|
71
71
|
return false;
|
package/lib/output.js
CHANGED
|
@@ -173,6 +173,8 @@ function toFormat (format, options) {
|
|
|
173
173
|
/**
|
|
174
174
|
* Use these JPEG options for output image.
|
|
175
175
|
*
|
|
176
|
+
* Some of these options require the use of a globally-installed libvips compiled with support for mozjpeg.
|
|
177
|
+
*
|
|
176
178
|
* @example
|
|
177
179
|
* // Convert any input to very high quality JPEG output
|
|
178
180
|
* const data = await sharp(input)
|
|
@@ -186,14 +188,14 @@ function toFormat (format, options) {
|
|
|
186
188
|
* @param {number} [options.quality=80] - quality, integer 1-100
|
|
187
189
|
* @param {boolean} [options.progressive=false] - use progressive (interlace) scan
|
|
188
190
|
* @param {string} [options.chromaSubsampling='4:2:0'] - for quality < 90, set to '4:4:4' to prevent chroma subsampling otherwise defaults to '4:2:0' (use chroma subsampling); for quality >= 90 chroma is never subsampled
|
|
191
|
+
* @param {boolean} [options.optimiseCoding=true] - optimise Huffman coding tables
|
|
192
|
+
* @param {boolean} [options.optimizeCoding=true] - alternative spelling of optimiseCoding
|
|
189
193
|
* @param {boolean} [options.trellisQuantisation=false] - apply trellis quantisation, requires libvips compiled with support for mozjpeg
|
|
190
194
|
* @param {boolean} [options.overshootDeringing=false] - apply overshoot deringing, requires libvips compiled with support for mozjpeg
|
|
191
195
|
* @param {boolean} [options.optimiseScans=false] - optimise progressive scans, forces progressive, requires libvips compiled with support for mozjpeg
|
|
192
|
-
* @param {boolean} [options.optimizeScans=false] - alternative spelling of optimiseScans
|
|
193
|
-
* @param {boolean} [options.optimiseCoding=true] - optimise Huffman coding tables
|
|
194
|
-
* @param {boolean} [options.optimizeCoding=true] - alternative spelling of optimiseCoding
|
|
196
|
+
* @param {boolean} [options.optimizeScans=false] - alternative spelling of optimiseScans, requires libvips compiled with support for mozjpeg
|
|
195
197
|
* @param {number} [options.quantisationTable=0] - quantization table to use, integer 0-8, requires libvips compiled with support for mozjpeg
|
|
196
|
-
* @param {number} [options.quantizationTable=0] - alternative spelling of quantisationTable
|
|
198
|
+
* @param {number} [options.quantizationTable=0] - alternative spelling of quantisationTable, requires libvips compiled with support for mozjpeg
|
|
197
199
|
* @param {boolean} [options.force=true] - force JPEG output, otherwise attempt to use input format
|
|
198
200
|
* @returns {Sharp}
|
|
199
201
|
* @throws {Error} Invalid options
|
|
@@ -253,6 +255,8 @@ function jpeg (options) {
|
|
|
253
255
|
* PNG output is always full colour at 8 or 16 bits per pixel.
|
|
254
256
|
* Indexed PNG input at 1, 2 or 4 bits per pixel is converted to 8 bits per pixel.
|
|
255
257
|
*
|
|
258
|
+
* Some of these options require the use of a globally-installed libvips compiled with support for libimagequant (GPL).
|
|
259
|
+
*
|
|
256
260
|
* @example
|
|
257
261
|
* // Convert any input to PNG output
|
|
258
262
|
* const data = await sharp(input)
|
|
@@ -264,10 +268,10 @@ function jpeg (options) {
|
|
|
264
268
|
* @param {number} [options.compressionLevel=9] - zlib compression level, 0-9
|
|
265
269
|
* @param {boolean} [options.adaptiveFiltering=false] - use adaptive row filtering
|
|
266
270
|
* @param {boolean} [options.palette=false] - quantise to a palette-based image with alpha transparency support, requires libvips compiled with support for libimagequant
|
|
267
|
-
* @param {number} [options.quality=100] - use the lowest number of colours needed to achieve given quality, requires libvips compiled with support for libimagequant
|
|
268
|
-
* @param {number} [options.colours=256] - maximum number of palette entries, requires libvips compiled with support for libimagequant
|
|
269
|
-
* @param {number} [options.colors=256] - alternative spelling of `options.colours`, requires libvips compiled with support for libimagequant
|
|
270
|
-
* @param {number} [options.dither=1.0] - level of Floyd-Steinberg error diffusion, requires libvips compiled with support for libimagequant
|
|
271
|
+
* @param {number} [options.quality=100] - use the lowest number of colours needed to achieve given quality, sets `palette` to `true`, requires libvips compiled with support for libimagequant
|
|
272
|
+
* @param {number} [options.colours=256] - maximum number of palette entries, sets `palette` to `true`, requires libvips compiled with support for libimagequant
|
|
273
|
+
* @param {number} [options.colors=256] - alternative spelling of `options.colours`, sets `palette` to `true`, requires libvips compiled with support for libimagequant
|
|
274
|
+
* @param {number} [options.dither=1.0] - level of Floyd-Steinberg error diffusion, sets `palette` to `true`, requires libvips compiled with support for libimagequant
|
|
271
275
|
* @param {boolean} [options.force=true] - force PNG output, otherwise attempt to use input format
|
|
272
276
|
* @returns {Sharp}
|
|
273
277
|
* @throws {Error} Invalid options
|
|
@@ -289,28 +293,30 @@ function png (options) {
|
|
|
289
293
|
}
|
|
290
294
|
if (is.defined(options.palette)) {
|
|
291
295
|
this._setBooleanOption('pngPalette', options.palette);
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
296
|
+
} else if (is.defined(options.quality) || is.defined(options.colours || options.colors) || is.defined(options.dither)) {
|
|
297
|
+
this._setBooleanOption('pngPalette', true);
|
|
298
|
+
}
|
|
299
|
+
if (this.options.pngPalette) {
|
|
300
|
+
if (is.defined(options.quality)) {
|
|
301
|
+
if (is.integer(options.quality) && is.inRange(options.quality, 0, 100)) {
|
|
302
|
+
this.options.pngQuality = options.quality;
|
|
303
|
+
} else {
|
|
304
|
+
throw is.invalidParameterError('quality', 'integer between 0 and 100', options.quality);
|
|
299
305
|
}
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
306
|
+
}
|
|
307
|
+
const colours = options.colours || options.colors;
|
|
308
|
+
if (is.defined(colours)) {
|
|
309
|
+
if (is.integer(colours) && is.inRange(colours, 2, 256)) {
|
|
310
|
+
this.options.pngColours = colours;
|
|
311
|
+
} else {
|
|
312
|
+
throw is.invalidParameterError('colours', 'integer between 2 and 256', colours);
|
|
307
313
|
}
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
+
}
|
|
315
|
+
if (is.defined(options.dither)) {
|
|
316
|
+
if (is.number(options.dither) && is.inRange(options.dither, 0, 1)) {
|
|
317
|
+
this.options.pngDither = options.dither;
|
|
318
|
+
} else {
|
|
319
|
+
throw is.invalidParameterError('dither', 'number between 0.0 and 1.0', options.dither);
|
|
314
320
|
}
|
|
315
321
|
}
|
|
316
322
|
}
|
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 and TIFF images",
|
|
4
|
-
"version": "0.25.
|
|
4
|
+
"version": "0.25.4",
|
|
5
5
|
"author": "Lovell Fuller <npm@lovell.info>",
|
|
6
6
|
"homepage": "https://github.com/lovell/sharp",
|
|
7
7
|
"contributors": [
|
|
@@ -66,7 +66,8 @@
|
|
|
66
66
|
"Paul Neave <paul.neave@gmail.com>",
|
|
67
67
|
"Brendan Kennedy <brenwken@gmail.com>",
|
|
68
68
|
"Brychan Bennett-Odlum <git@brychan.io>",
|
|
69
|
-
"Edward Silverton <e.silverton@gmail.com>"
|
|
69
|
+
"Edward Silverton <e.silverton@gmail.com>",
|
|
70
|
+
"Roman Malieiev <aromaleev@gmail.com>"
|
|
70
71
|
],
|
|
71
72
|
"scripts": {
|
|
72
73
|
"install": "(node install/libvips && node install/dll-copy && prebuild-install --runtime=napi) || (node-gyp rebuild && node install/dll-copy)",
|
|
@@ -112,7 +113,7 @@
|
|
|
112
113
|
"detect-libc": "^1.0.3",
|
|
113
114
|
"node-addon-api": "^3.0.0",
|
|
114
115
|
"npmlog": "^4.1.2",
|
|
115
|
-
"prebuild-install": "^5.3.
|
|
116
|
+
"prebuild-install": "^5.3.4",
|
|
116
117
|
"semver": "^7.3.2",
|
|
117
118
|
"simple-get": "^4.0.0",
|
|
118
119
|
"tar": "^6.0.2",
|
|
@@ -122,13 +123,13 @@
|
|
|
122
123
|
"async": "^3.2.0",
|
|
123
124
|
"cc": "^2.0.1",
|
|
124
125
|
"decompress-zip": "^0.3.2",
|
|
125
|
-
"documentation": "^13.0.
|
|
126
|
+
"documentation": "^13.0.1",
|
|
126
127
|
"exif-reader": "^1.0.3",
|
|
127
128
|
"icc": "^1.0.0",
|
|
128
129
|
"license-checker": "^25.0.1",
|
|
129
|
-
"mocha": "^
|
|
130
|
+
"mocha": "^8.0.1",
|
|
130
131
|
"mock-fs": "^4.12.0",
|
|
131
|
-
"nyc": "^15.0
|
|
132
|
+
"nyc": "^15.1.0",
|
|
132
133
|
"prebuild": "^10.0.0",
|
|
133
134
|
"prebuild-ci": "^3.1.0",
|
|
134
135
|
"rimraf": "^3.0.2",
|
package/src/common.cc
CHANGED
|
@@ -88,6 +88,10 @@ namespace sharp {
|
|
|
88
88
|
if (HasAttr(input, "page")) {
|
|
89
89
|
descriptor->page = AttrAsUint32(input, "page");
|
|
90
90
|
}
|
|
91
|
+
// Multi-level input (OpenSlide)
|
|
92
|
+
if (HasAttr(input, "level")) {
|
|
93
|
+
descriptor->level = AttrAsUint32(input, "level");
|
|
94
|
+
}
|
|
91
95
|
// Create new image
|
|
92
96
|
if (HasAttr(input, "createChannels")) {
|
|
93
97
|
descriptor->createChannels = AttrAsUint32(input, "createChannels");
|
|
@@ -292,6 +296,9 @@ namespace sharp {
|
|
|
292
296
|
option->set("n", descriptor->pages);
|
|
293
297
|
option->set("page", descriptor->page);
|
|
294
298
|
}
|
|
299
|
+
if (imageType == ImageType::OPENSLIDE) {
|
|
300
|
+
option->set("level", descriptor->level);
|
|
301
|
+
}
|
|
295
302
|
image = VImage::new_from_buffer(descriptor->buffer, descriptor->bufferLength, nullptr, option);
|
|
296
303
|
if (imageType == ImageType::SVG || imageType == ImageType::PDF || imageType == ImageType::MAGICK) {
|
|
297
304
|
image = SetDensity(image, descriptor->density);
|
|
@@ -341,6 +348,9 @@ namespace sharp {
|
|
|
341
348
|
option->set("n", descriptor->pages);
|
|
342
349
|
option->set("page", descriptor->page);
|
|
343
350
|
}
|
|
351
|
+
if (imageType == ImageType::OPENSLIDE) {
|
|
352
|
+
option->set("level", descriptor->level);
|
|
353
|
+
}
|
|
344
354
|
image = VImage::new_from_file(descriptor->file.data(), option);
|
|
345
355
|
if (imageType == ImageType::SVG || imageType == ImageType::PDF || imageType == ImageType::MAGICK) {
|
|
346
356
|
image = SetDensity(image, descriptor->density);
|
package/src/common.h
CHANGED
|
@@ -57,6 +57,7 @@ namespace sharp {
|
|
|
57
57
|
int rawHeight;
|
|
58
58
|
int pages;
|
|
59
59
|
int page;
|
|
60
|
+
int level;
|
|
60
61
|
int createChannels;
|
|
61
62
|
int createWidth;
|
|
62
63
|
int createHeight;
|
|
@@ -75,6 +76,7 @@ namespace sharp {
|
|
|
75
76
|
rawHeight(0),
|
|
76
77
|
pages(1),
|
|
77
78
|
page(0),
|
|
79
|
+
level(0),
|
|
78
80
|
createChannels(0),
|
|
79
81
|
createWidth(0),
|
|
80
82
|
createHeight(0),
|
package/src/metadata.cc
CHANGED
|
@@ -74,6 +74,15 @@ class MetadataWorker : public Napi::AsyncWorker {
|
|
|
74
74
|
if (image.get_typeof("heif-primary") == G_TYPE_INT) {
|
|
75
75
|
baton->pagePrimary = image.get_int("heif-primary");
|
|
76
76
|
}
|
|
77
|
+
if (image.get_typeof("openslide.level-count") == VIPS_TYPE_REF_STRING) {
|
|
78
|
+
int const levels = std::stoi(image.get_string("openslide.level-count"));
|
|
79
|
+
for (int l = 0; l < levels; l++) {
|
|
80
|
+
std::string prefix = "openslide.level[" + std::to_string(l) + "].";
|
|
81
|
+
int const width = std::stoi(image.get_string((prefix + "width").data()));
|
|
82
|
+
int const height = std::stoi(image.get_string((prefix + "height").data()));
|
|
83
|
+
baton->levels.push_back(std::pair<int, int>(width, height));
|
|
84
|
+
}
|
|
85
|
+
}
|
|
77
86
|
baton->hasProfile = sharp::HasProfile(image);
|
|
78
87
|
// Derived attributes
|
|
79
88
|
baton->hasAlpha = sharp::HasAlpha(image);
|
|
@@ -177,6 +186,17 @@ class MetadataWorker : public Napi::AsyncWorker {
|
|
|
177
186
|
if (baton->pagePrimary > -1) {
|
|
178
187
|
info.Set("pagePrimary", baton->pagePrimary);
|
|
179
188
|
}
|
|
189
|
+
if (!baton->levels.empty()) {
|
|
190
|
+
int i = 0;
|
|
191
|
+
Napi::Array levels = Napi::Array::New(env, static_cast<size_t>(baton->levels.size()));
|
|
192
|
+
for (std::pair<int, int> const l : baton->levels) {
|
|
193
|
+
Napi::Object level = Napi::Object::New(env);
|
|
194
|
+
level.Set("width", l.first);
|
|
195
|
+
level.Set("height", l.second);
|
|
196
|
+
levels.Set(i++, level);
|
|
197
|
+
}
|
|
198
|
+
info.Set("levels", levels);
|
|
199
|
+
}
|
|
180
200
|
info.Set("hasProfile", baton->hasProfile);
|
|
181
201
|
info.Set("hasAlpha", baton->hasAlpha);
|
|
182
202
|
if (baton->orientation > 0) {
|
package/src/metadata.h
CHANGED
package/src/pipeline.cc
CHANGED
|
@@ -645,8 +645,12 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
645
645
|
// Extract an image channel (aka vips band)
|
|
646
646
|
if (baton->extractChannel > -1) {
|
|
647
647
|
if (baton->extractChannel >= image.bands()) {
|
|
648
|
-
(baton->
|
|
649
|
-
|
|
648
|
+
if (baton->extractChannel == 3 && sharp::HasAlpha(image)) {
|
|
649
|
+
baton->extractChannel = image.bands() - 1;
|
|
650
|
+
} else {
|
|
651
|
+
(baton->err).append("Cannot extract channel from image. Too few channels in image.");
|
|
652
|
+
return Error();
|
|
653
|
+
}
|
|
650
654
|
}
|
|
651
655
|
VipsInterpretation const interpretation = sharp::Is16Bit(image.interpretation())
|
|
652
656
|
? VIPS_INTERPRETATION_GREY16
|
package/src/stats.cc
CHANGED
|
@@ -75,8 +75,17 @@ class StatsWorker : public Napi::AsyncWorker {
|
|
|
75
75
|
baton->isOpaque = false;
|
|
76
76
|
}
|
|
77
77
|
}
|
|
78
|
+
// Convert to greyscale
|
|
79
|
+
vips::VImage greyscale = image.colourspace(VIPS_INTERPRETATION_B_W)[0];
|
|
78
80
|
// Estimate entropy via histogram of greyscale value frequency
|
|
79
|
-
baton->entropy = std::abs(
|
|
81
|
+
baton->entropy = std::abs(greyscale.hist_find().hist_entropy());
|
|
82
|
+
// Estimate sharpness via standard deviation of greyscale laplacian
|
|
83
|
+
VImage laplacian = VImage::new_matrixv(3, 3,
|
|
84
|
+
0.0, 1.0, 0.0,
|
|
85
|
+
1.0, -4.0, 1.0,
|
|
86
|
+
0.0, 1.0, 0.0);
|
|
87
|
+
laplacian.set("scale", 9.0);
|
|
88
|
+
baton->sharpness = greyscale.conv(laplacian).deviate();
|
|
80
89
|
} catch (vips::VError const &err) {
|
|
81
90
|
(baton->err).append(err.what());
|
|
82
91
|
}
|
|
@@ -123,6 +132,7 @@ class StatsWorker : public Napi::AsyncWorker {
|
|
|
123
132
|
info.Set("channels", channels);
|
|
124
133
|
info.Set("isOpaque", baton->isOpaque);
|
|
125
134
|
info.Set("entropy", baton->entropy);
|
|
135
|
+
info.Set("sharpness", baton->sharpness);
|
|
126
136
|
Callback().MakeCallback(Receiver().Value(), { env.Null(), info });
|
|
127
137
|
} else {
|
|
128
138
|
Callback().MakeCallback(Receiver().Value(), { Napi::Error::New(env, baton->err).Value() });
|
package/src/stats.h
CHANGED
|
@@ -47,13 +47,15 @@ struct StatsBaton {
|
|
|
47
47
|
std::vector<ChannelStats> channelStats;
|
|
48
48
|
bool isOpaque;
|
|
49
49
|
double entropy;
|
|
50
|
+
double sharpness;
|
|
50
51
|
|
|
51
52
|
std::string err;
|
|
52
53
|
|
|
53
54
|
StatsBaton():
|
|
54
55
|
input(nullptr),
|
|
55
56
|
isOpaque(true),
|
|
56
|
-
entropy(0.0)
|
|
57
|
+
entropy(0.0),
|
|
58
|
+
sharpness(0.0)
|
|
57
59
|
{}
|
|
58
60
|
};
|
|
59
61
|
|