sharp 0.27.1 → 0.28.2
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 +14 -13
- package/binding.gyp +3 -5
- package/install/dll-copy.js +4 -4
- package/install/libvips.js +85 -38
- package/lib/agent.js +1 -1
- package/lib/channel.js +25 -7
- package/lib/constructor.js +10 -6
- package/lib/input.js +19 -3
- package/lib/libvips.js +27 -4
- package/lib/operation.js +9 -4
- package/lib/output.js +129 -43
- package/lib/resize.js +42 -15
- package/lib/utility.js +17 -10
- package/package.json +14 -13
- package/src/common.cc +25 -11
- package/src/common.h +8 -3
- package/src/metadata.cc +6 -0
- package/src/metadata.h +2 -0
- package/src/operations.cc +1 -1
- package/src/pipeline.cc +42 -9
- package/src/pipeline.h +8 -3
- package/src/sharp.cc +1 -0
- package/src/utilities.cc +16 -0
- package/src/utilities.h +1 -0
package/lib/output.js
CHANGED
|
@@ -16,6 +16,8 @@ const formats = new Map([
|
|
|
16
16
|
['gif', 'gif']
|
|
17
17
|
]);
|
|
18
18
|
|
|
19
|
+
const errMagickSave = new Error('GIF output requires libvips with support for ImageMagick');
|
|
20
|
+
|
|
19
21
|
/**
|
|
20
22
|
* Write output image data to a file.
|
|
21
23
|
*
|
|
@@ -47,25 +49,23 @@ const formats = new Map([
|
|
|
47
49
|
* @throws {Error} Invalid parameters
|
|
48
50
|
*/
|
|
49
51
|
function toFile (fileOut, callback) {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
+
let err;
|
|
53
|
+
if (!is.string(fileOut)) {
|
|
54
|
+
err = new Error('Missing output file path');
|
|
55
|
+
} else if (this.options.input.file === fileOut) {
|
|
56
|
+
err = new Error('Cannot use same file for input and output');
|
|
57
|
+
} else if (this.options.formatOut === 'input' && fileOut.toLowerCase().endsWith('.gif') && !this.constructor.format.magick.output.file) {
|
|
58
|
+
err = errMagickSave;
|
|
59
|
+
}
|
|
60
|
+
if (err) {
|
|
52
61
|
if (is.fn(callback)) {
|
|
53
|
-
callback(
|
|
62
|
+
callback(err);
|
|
54
63
|
} else {
|
|
55
|
-
return Promise.reject(
|
|
64
|
+
return Promise.reject(err);
|
|
56
65
|
}
|
|
57
66
|
} else {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
if (is.fn(callback)) {
|
|
61
|
-
callback(errOutputIsInput);
|
|
62
|
-
} else {
|
|
63
|
-
return Promise.reject(errOutputIsInput);
|
|
64
|
-
}
|
|
65
|
-
} else {
|
|
66
|
-
this.options.fileOut = fileOut;
|
|
67
|
-
return this._pipeline(callback);
|
|
68
|
-
}
|
|
67
|
+
this.options.fileOut = fileOut;
|
|
68
|
+
return this._pipeline(callback);
|
|
69
69
|
}
|
|
70
70
|
return this;
|
|
71
71
|
}
|
|
@@ -105,10 +105,10 @@ function toFile (fileOut, callback) {
|
|
|
105
105
|
* .catch(err => { ... });
|
|
106
106
|
*
|
|
107
107
|
* @example
|
|
108
|
-
* const data = await sharp('my-image.jpg')
|
|
108
|
+
* const { data, info } = await sharp('my-image.jpg')
|
|
109
109
|
* // output the raw pixels
|
|
110
110
|
* .raw()
|
|
111
|
-
* .toBuffer();
|
|
111
|
+
* .toBuffer({ resolveWithObject: true });
|
|
112
112
|
*
|
|
113
113
|
* // create a more type safe way to work with the raw pixel data
|
|
114
114
|
* // this will not copy the data, instead it will change `data`s underlying ArrayBuffer
|
|
@@ -116,7 +116,9 @@ function toFile (fileOut, callback) {
|
|
|
116
116
|
* const pixelArray = new Uint8ClampedArray(data.buffer);
|
|
117
117
|
*
|
|
118
118
|
* // When you are done changing the pixelArray, sharp takes the `pixelArray` as an input
|
|
119
|
-
*
|
|
119
|
+
* const { width, height, channels } = info;
|
|
120
|
+
* await sharp(pixelArray, { raw: { width, height, channels } })
|
|
121
|
+
* .toFile('my-changed-image.jpg');
|
|
120
122
|
*
|
|
121
123
|
* @param {Object} [options]
|
|
122
124
|
* @param {boolean} [options.resolveWithObject] Resolve the Promise with an Object containing `data` and `info` properties instead of resolving only with `data`.
|
|
@@ -146,9 +148,29 @@ function toBuffer (options, callback) {
|
|
|
146
148
|
* .toFile('output-with-metadata.jpg')
|
|
147
149
|
* .then(info => { ... });
|
|
148
150
|
*
|
|
151
|
+
* @example
|
|
152
|
+
* // Set "IFD0-Copyright" in output EXIF metadata
|
|
153
|
+
* const data = await sharp(input)
|
|
154
|
+
* .withMetadata({
|
|
155
|
+
* exif: {
|
|
156
|
+
* IFD0: {
|
|
157
|
+
* Copyright: 'Wernham Hogg'
|
|
158
|
+
* }
|
|
159
|
+
* }
|
|
160
|
+
* })
|
|
161
|
+
* .toBuffer();
|
|
162
|
+
*
|
|
163
|
+
* * @example
|
|
164
|
+
* // Set output metadata to 96 DPI
|
|
165
|
+
* const data = await sharp(input)
|
|
166
|
+
* .withMetadata({ density: 96 })
|
|
167
|
+
* .toBuffer();
|
|
168
|
+
*
|
|
149
169
|
* @param {Object} [options]
|
|
150
170
|
* @param {number} [options.orientation] value between 1 and 8, used to update the EXIF `Orientation` tag.
|
|
151
171
|
* @param {string} [options.icc] filesystem path to output ICC profile, defaults to sRGB.
|
|
172
|
+
* @param {Object<Object>} [options.exif={}] Object keyed by IFD0, IFD1 etc. of key/value string pairs to write as EXIF data.
|
|
173
|
+
* @param {number} [options.density] Number of pixels per inch (DPI).
|
|
152
174
|
* @returns {Sharp}
|
|
153
175
|
* @throws {Error} Invalid parameters
|
|
154
176
|
*/
|
|
@@ -162,6 +184,13 @@ function withMetadata (options) {
|
|
|
162
184
|
throw is.invalidParameterError('orientation', 'integer between 1 and 8', options.orientation);
|
|
163
185
|
}
|
|
164
186
|
}
|
|
187
|
+
if (is.defined(options.density)) {
|
|
188
|
+
if (is.number(options.density) && options.density > 0) {
|
|
189
|
+
this.options.withMetadataDensity = options.density;
|
|
190
|
+
} else {
|
|
191
|
+
throw is.invalidParameterError('density', 'positive number', options.density);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
165
194
|
if (is.defined(options.icc)) {
|
|
166
195
|
if (is.string(options.icc)) {
|
|
167
196
|
this.options.withMetadataIcc = options.icc;
|
|
@@ -169,6 +198,25 @@ function withMetadata (options) {
|
|
|
169
198
|
throw is.invalidParameterError('icc', 'string filesystem path to ICC profile', options.icc);
|
|
170
199
|
}
|
|
171
200
|
}
|
|
201
|
+
if (is.defined(options.exif)) {
|
|
202
|
+
if (is.object(options.exif)) {
|
|
203
|
+
for (const [ifd, entries] of Object.entries(options.exif)) {
|
|
204
|
+
if (is.object(entries)) {
|
|
205
|
+
for (const [k, v] of Object.entries(entries)) {
|
|
206
|
+
if (is.string(v)) {
|
|
207
|
+
this.options.withMetadataStrs[`exif-${ifd.toLowerCase()}-${k}`] = v;
|
|
208
|
+
} else {
|
|
209
|
+
throw is.invalidParameterError(`exif.${ifd}.${k}`, 'string', v);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
} else {
|
|
213
|
+
throw is.invalidParameterError(`exif.${ifd}`, 'object', entries);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
} else {
|
|
217
|
+
throw is.invalidParameterError('exif', 'object', options.exif);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
172
220
|
}
|
|
173
221
|
return this;
|
|
174
222
|
}
|
|
@@ -188,7 +236,7 @@ function withMetadata (options) {
|
|
|
188
236
|
* @throws {Error} unsupported format or options
|
|
189
237
|
*/
|
|
190
238
|
function toFormat (format, options) {
|
|
191
|
-
const actualFormat = formats.get(is.object(format) && is.string(format.id) ? format.id : format);
|
|
239
|
+
const actualFormat = formats.get((is.object(format) && is.string(format.id) ? format.id : format).toLowerCase());
|
|
192
240
|
if (!actualFormat) {
|
|
193
241
|
throw is.invalidParameterError('format', `one of: ${[...formats.keys()].join(', ')}`, format);
|
|
194
242
|
}
|
|
@@ -198,8 +246,6 @@ function toFormat (format, options) {
|
|
|
198
246
|
/**
|
|
199
247
|
* Use these JPEG options for output image.
|
|
200
248
|
*
|
|
201
|
-
* Some of these options require the use of a globally-installed libvips compiled with support for mozjpeg.
|
|
202
|
-
*
|
|
203
249
|
* @example
|
|
204
250
|
* // Convert any input to very high quality JPEG output
|
|
205
251
|
* const data = await sharp(input)
|
|
@@ -209,18 +255,25 @@ function toFormat (format, options) {
|
|
|
209
255
|
* })
|
|
210
256
|
* .toBuffer();
|
|
211
257
|
*
|
|
258
|
+
* @example
|
|
259
|
+
* // Use mozjpeg to reduce output JPEG file size (slower)
|
|
260
|
+
* const data = await sharp(input)
|
|
261
|
+
* .jpeg({ mozjpeg: true })
|
|
262
|
+
* .toBuffer();
|
|
263
|
+
*
|
|
212
264
|
* @param {Object} [options] - output options
|
|
213
265
|
* @param {number} [options.quality=80] - quality, integer 1-100
|
|
214
266
|
* @param {boolean} [options.progressive=false] - use progressive (interlace) scan
|
|
215
267
|
* @param {string} [options.chromaSubsampling='4:2:0'] - set to '4:4:4' to prevent chroma subsampling otherwise defaults to '4:2:0' chroma subsampling
|
|
216
268
|
* @param {boolean} [options.optimiseCoding=true] - optimise Huffman coding tables
|
|
217
269
|
* @param {boolean} [options.optimizeCoding=true] - alternative spelling of optimiseCoding
|
|
218
|
-
* @param {boolean} [options.
|
|
219
|
-
* @param {boolean} [options.
|
|
220
|
-
* @param {boolean} [options.
|
|
221
|
-
* @param {boolean} [options.
|
|
222
|
-
* @param {
|
|
223
|
-
* @param {number} [options.
|
|
270
|
+
* @param {boolean} [options.mozjpeg=false] - use mozjpeg defaults, equivalent to `{ trellisQuantisation: true, overshootDeringing: true, optimiseScans: true, quantisationTable: 3 }`
|
|
271
|
+
* @param {boolean} [options.trellisQuantisation=false] - apply trellis quantisation
|
|
272
|
+
* @param {boolean} [options.overshootDeringing=false] - apply overshoot deringing
|
|
273
|
+
* @param {boolean} [options.optimiseScans=false] - optimise progressive scans, forces progressive
|
|
274
|
+
* @param {boolean} [options.optimizeScans=false] - alternative spelling of optimiseScans
|
|
275
|
+
* @param {number} [options.quantisationTable=0] - quantization table to use, integer 0-8
|
|
276
|
+
* @param {number} [options.quantizationTable=0] - alternative spelling of quantisationTable
|
|
224
277
|
* @param {boolean} [options.force=true] - force JPEG output, otherwise attempt to use input format
|
|
225
278
|
* @returns {Sharp}
|
|
226
279
|
* @throws {Error} Invalid options
|
|
@@ -244,6 +297,23 @@ function jpeg (options) {
|
|
|
244
297
|
throw is.invalidParameterError('chromaSubsampling', 'one of: 4:2:0, 4:4:4', options.chromaSubsampling);
|
|
245
298
|
}
|
|
246
299
|
}
|
|
300
|
+
const optimiseCoding = is.bool(options.optimizeCoding) ? options.optimizeCoding : options.optimiseCoding;
|
|
301
|
+
if (is.defined(optimiseCoding)) {
|
|
302
|
+
this._setBooleanOption('jpegOptimiseCoding', optimiseCoding);
|
|
303
|
+
}
|
|
304
|
+
if (is.defined(options.mozjpeg)) {
|
|
305
|
+
if (is.bool(options.mozjpeg)) {
|
|
306
|
+
if (options.mozjpeg) {
|
|
307
|
+
this.options.jpegTrellisQuantisation = true;
|
|
308
|
+
this.options.jpegOvershootDeringing = true;
|
|
309
|
+
this.options.jpegOptimiseScans = true;
|
|
310
|
+
this.options.jpegProgressive = true;
|
|
311
|
+
this.options.jpegQuantisationTable = 3;
|
|
312
|
+
}
|
|
313
|
+
} else {
|
|
314
|
+
throw is.invalidParameterError('mozjpeg', 'boolean', options.mozjpeg);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
247
317
|
const trellisQuantisation = is.bool(options.trellisQuantization) ? options.trellisQuantization : options.trellisQuantisation;
|
|
248
318
|
if (is.defined(trellisQuantisation)) {
|
|
249
319
|
this._setBooleanOption('jpegTrellisQuantisation', trellisQuantisation);
|
|
@@ -258,10 +328,6 @@ function jpeg (options) {
|
|
|
258
328
|
this.options.jpegProgressive = true;
|
|
259
329
|
}
|
|
260
330
|
}
|
|
261
|
-
const optimiseCoding = is.bool(options.optimizeCoding) ? options.optimizeCoding : options.optimiseCoding;
|
|
262
|
-
if (is.defined(optimiseCoding)) {
|
|
263
|
-
this._setBooleanOption('jpegOptimiseCoding', optimiseCoding);
|
|
264
|
-
}
|
|
265
331
|
const quantisationTable = is.number(options.quantizationTable) ? options.quantizationTable : options.quantisationTable;
|
|
266
332
|
if (is.defined(quantisationTable)) {
|
|
267
333
|
if (is.integer(quantisationTable) && is.inRange(quantisationTable, 0, 8)) {
|
|
@@ -277,26 +343,31 @@ function jpeg (options) {
|
|
|
277
343
|
/**
|
|
278
344
|
* Use these PNG options for output image.
|
|
279
345
|
*
|
|
280
|
-
* PNG output is
|
|
346
|
+
* By default, PNG output is full colour at 8 or 16 bits per pixel.
|
|
281
347
|
* Indexed PNG input at 1, 2 or 4 bits per pixel is converted to 8 bits per pixel.
|
|
282
|
-
*
|
|
283
|
-
* Some of these options require the use of a globally-installed libvips compiled with support for libimagequant (GPL).
|
|
348
|
+
* Set `palette` to `true` for slower, indexed PNG output.
|
|
284
349
|
*
|
|
285
350
|
* @example
|
|
286
|
-
* // Convert any input to PNG output
|
|
351
|
+
* // Convert any input to full colour PNG output
|
|
287
352
|
* const data = await sharp(input)
|
|
288
353
|
* .png()
|
|
289
354
|
* .toBuffer();
|
|
290
355
|
*
|
|
356
|
+
* @example
|
|
357
|
+
* // Convert any input to indexed PNG output (slower)
|
|
358
|
+
* const data = await sharp(input)
|
|
359
|
+
* .png({ palette: true })
|
|
360
|
+
* .toBuffer();
|
|
361
|
+
*
|
|
291
362
|
* @param {Object} [options]
|
|
292
363
|
* @param {boolean} [options.progressive=false] - use progressive (interlace) scan
|
|
293
|
-
* @param {number} [options.compressionLevel=
|
|
364
|
+
* @param {number} [options.compressionLevel=6] - zlib compression level, 0 (fastest, largest) to 9 (slowest, smallest)
|
|
294
365
|
* @param {boolean} [options.adaptiveFiltering=false] - use adaptive row filtering
|
|
295
|
-
* @param {boolean} [options.palette=false] - quantise to a palette-based image with alpha transparency support
|
|
296
|
-
* @param {number} [options.quality=100] - use the lowest number of colours needed to achieve given quality, sets `palette` to `true
|
|
297
|
-
* @param {number} [options.colours=256] - maximum number of palette entries, sets `palette` to `true
|
|
298
|
-
* @param {number} [options.colors=256] - alternative spelling of `options.colours`, sets `palette` to `true
|
|
299
|
-
* @param {number} [options.dither=1.0] - level of Floyd-Steinberg error diffusion, sets `palette` to `true
|
|
366
|
+
* @param {boolean} [options.palette=false] - quantise to a palette-based image with alpha transparency support
|
|
367
|
+
* @param {number} [options.quality=100] - use the lowest number of colours needed to achieve given quality, sets `palette` to `true`
|
|
368
|
+
* @param {number} [options.colours=256] - maximum number of palette entries, sets `palette` to `true`
|
|
369
|
+
* @param {number} [options.colors=256] - alternative spelling of `options.colours`, sets `palette` to `true`
|
|
370
|
+
* @param {number} [options.dither=1.0] - level of Floyd-Steinberg error diffusion, sets `palette` to `true`
|
|
300
371
|
* @param {boolean} [options.force=true] - force PNG output, otherwise attempt to use input format
|
|
301
372
|
* @returns {Sharp}
|
|
302
373
|
* @throws {Error} Invalid options
|
|
@@ -358,6 +429,12 @@ function png (options) {
|
|
|
358
429
|
* .webp({ lossless: true })
|
|
359
430
|
* .toBuffer();
|
|
360
431
|
*
|
|
432
|
+
* @example
|
|
433
|
+
* // Optimise the file size of an animated WebP
|
|
434
|
+
* const outputWebp = await sharp(inputWebp, { animated: true })
|
|
435
|
+
* .webp({ reductionEffort: 6 })
|
|
436
|
+
* .toBuffer();
|
|
437
|
+
*
|
|
361
438
|
* @param {Object} [options] - output options
|
|
362
439
|
* @param {number} [options.quality=80] - quality, integer 1-100
|
|
363
440
|
* @param {number} [options.alphaQuality=100] - quality of alpha layer, integer 0-100
|
|
@@ -426,7 +503,7 @@ function webp (options) {
|
|
|
426
503
|
/* istanbul ignore next */
|
|
427
504
|
function gif (options) {
|
|
428
505
|
if (!this.constructor.format.magick.output.buffer) {
|
|
429
|
-
throw
|
|
506
|
+
throw errMagickSave;
|
|
430
507
|
}
|
|
431
508
|
trySetAnimationOptions(options, this.options);
|
|
432
509
|
return this._updateFormatOut('gif', options);
|
|
@@ -582,7 +659,7 @@ function tiff (options) {
|
|
|
582
659
|
* @param {Object} [options] - output options
|
|
583
660
|
* @param {number} [options.quality=50] - quality, integer 1-100
|
|
584
661
|
* @param {boolean} [options.lossless=false] - use lossless compression
|
|
585
|
-
* @param {
|
|
662
|
+
* @param {number} [options.speed=5] - CPU effort vs file size, 0 (slowest/smallest) to 8 (fastest/largest)
|
|
586
663
|
* @param {string} [options.chromaSubsampling='4:2:0'] - set to '4:4:4' to prevent chroma subsampling otherwise defaults to '4:2:0' chroma subsampling, requires libvips v8.11.0
|
|
587
664
|
* @returns {Sharp}
|
|
588
665
|
* @throws {Error} Invalid options
|
|
@@ -704,6 +781,7 @@ function raw () {
|
|
|
704
781
|
* @param {string} [options.layout='dz'] filesystem layout, possible values are `dz`, `iiif`, `zoomify` or `google`.
|
|
705
782
|
* @param {boolean} [options.centre=false] centre image in tile.
|
|
706
783
|
* @param {boolean} [options.center=false] alternative spelling of centre.
|
|
784
|
+
* @param {string} [options.id='https://example.com/iiif'] when `layout` is `iiif`, sets the `@id` attribute of `info.json`
|
|
707
785
|
* @returns {Sharp}
|
|
708
786
|
* @throws {Error} Invalid parameters
|
|
709
787
|
*/
|
|
@@ -777,6 +855,14 @@ function tile (options) {
|
|
|
777
855
|
if (is.defined(centre)) {
|
|
778
856
|
this._setBooleanOption('tileCentre', centre);
|
|
779
857
|
}
|
|
858
|
+
// @id attribute for IIIF layout
|
|
859
|
+
if (is.defined(options.id)) {
|
|
860
|
+
if (is.string(options.id)) {
|
|
861
|
+
this.options.tileId = options.id;
|
|
862
|
+
} else {
|
|
863
|
+
throw is.invalidParameterError('id', 'string', options.id);
|
|
864
|
+
}
|
|
865
|
+
}
|
|
780
866
|
}
|
|
781
867
|
// Format
|
|
782
868
|
if (is.inArray(this.options.formatOut, ['jpeg', 'png', 'webp'])) {
|
package/lib/resize.js
CHANGED
|
@@ -302,11 +302,20 @@ function resize (width, height, options) {
|
|
|
302
302
|
* })
|
|
303
303
|
* ...
|
|
304
304
|
*
|
|
305
|
+
* @example
|
|
306
|
+
* // Add a row of 10 red pixels to the bottom
|
|
307
|
+
* sharp(input)
|
|
308
|
+
* .extend({
|
|
309
|
+
* bottom: 10,
|
|
310
|
+
* background: 'red'
|
|
311
|
+
* })
|
|
312
|
+
* ...
|
|
313
|
+
*
|
|
305
314
|
* @param {(number|Object)} extend - single pixel count to add to all edges or an Object with per-edge counts
|
|
306
|
-
* @param {number} [extend.top]
|
|
307
|
-
* @param {number} [extend.left]
|
|
308
|
-
* @param {number} [extend.bottom]
|
|
309
|
-
* @param {number} [extend.right]
|
|
315
|
+
* @param {number} [extend.top=0]
|
|
316
|
+
* @param {number} [extend.left=0]
|
|
317
|
+
* @param {number} [extend.bottom=0]
|
|
318
|
+
* @param {number} [extend.right=0]
|
|
310
319
|
* @param {String|Object} [extend.background={r: 0, g: 0, b: 0, alpha: 1}] - background colour, parsed by the [color](https://www.npmjs.org/package/color) module, defaults to black without transparency.
|
|
311
320
|
* @returns {Sharp}
|
|
312
321
|
* @throws {Error} Invalid parameters
|
|
@@ -317,17 +326,35 @@ function extend (extend) {
|
|
|
317
326
|
this.options.extendBottom = extend;
|
|
318
327
|
this.options.extendLeft = extend;
|
|
319
328
|
this.options.extendRight = extend;
|
|
320
|
-
} else if (
|
|
321
|
-
is.
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
329
|
+
} else if (is.object(extend)) {
|
|
330
|
+
if (is.defined(extend.top)) {
|
|
331
|
+
if (is.integer(extend.top) && extend.top >= 0) {
|
|
332
|
+
this.options.extendTop = extend.top;
|
|
333
|
+
} else {
|
|
334
|
+
throw is.invalidParameterError('top', 'positive integer', extend.top);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
if (is.defined(extend.bottom)) {
|
|
338
|
+
if (is.integer(extend.bottom) && extend.bottom >= 0) {
|
|
339
|
+
this.options.extendBottom = extend.bottom;
|
|
340
|
+
} else {
|
|
341
|
+
throw is.invalidParameterError('bottom', 'positive integer', extend.bottom);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
if (is.defined(extend.left)) {
|
|
345
|
+
if (is.integer(extend.left) && extend.left >= 0) {
|
|
346
|
+
this.options.extendLeft = extend.left;
|
|
347
|
+
} else {
|
|
348
|
+
throw is.invalidParameterError('left', 'positive integer', extend.left);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
if (is.defined(extend.right)) {
|
|
352
|
+
if (is.integer(extend.right) && extend.right >= 0) {
|
|
353
|
+
this.options.extendRight = extend.right;
|
|
354
|
+
} else {
|
|
355
|
+
throw is.invalidParameterError('right', 'positive integer', extend.right);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
331
358
|
this._setBackgroundColourOption('extendBackground', extend.background);
|
|
332
359
|
} else {
|
|
333
360
|
throw is.invalidParameterError('extend', 'integer or object', extend);
|
package/lib/utility.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const events = require('events');
|
|
4
|
+
const detectLibc = require('detect-libc');
|
|
5
|
+
|
|
4
6
|
const is = require('./is');
|
|
5
7
|
const sharp = require('../build/Release/sharp.node');
|
|
6
8
|
|
|
@@ -84,8 +86,12 @@ cache(true);
|
|
|
84
86
|
/**
|
|
85
87
|
* Gets or, when a concurrency is provided, sets
|
|
86
88
|
* the number of threads _libvips'_ should create to process each image.
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
+
*
|
|
90
|
+
* The default value is the number of CPU cores,
|
|
91
|
+
* except when using glibc-based Linux without jemalloc,
|
|
92
|
+
* where the default is `1` to help reduce memory fragmentation.
|
|
93
|
+
*
|
|
94
|
+
* A value of `0` will reset this to the number of CPU cores.
|
|
89
95
|
*
|
|
90
96
|
* The maximum number of images that can be processed in parallel
|
|
91
97
|
* is limited by libuv's `UV_THREADPOOL_SIZE` environment variable.
|
|
@@ -103,6 +109,11 @@ cache(true);
|
|
|
103
109
|
function concurrency (concurrency) {
|
|
104
110
|
return sharp.concurrency(is.integer(concurrency) ? concurrency : null);
|
|
105
111
|
}
|
|
112
|
+
/* istanbul ignore next */
|
|
113
|
+
if (detectLibc.family === detectLibc.GLIBC && !sharp._isUsingJemalloc()) {
|
|
114
|
+
// Reduce default concurrency to 1 when using glibc memory allocator
|
|
115
|
+
sharp.concurrency(1);
|
|
116
|
+
}
|
|
106
117
|
|
|
107
118
|
/**
|
|
108
119
|
* An EventEmitter that emits a `change` event when a task is either:
|
|
@@ -157,14 +168,10 @@ simd(true);
|
|
|
157
168
|
* @private
|
|
158
169
|
*/
|
|
159
170
|
module.exports = function (Sharp) {
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
simd
|
|
165
|
-
].forEach(function (f) {
|
|
166
|
-
Sharp[f.name] = f;
|
|
167
|
-
});
|
|
171
|
+
Sharp.cache = cache;
|
|
172
|
+
Sharp.concurrency = concurrency;
|
|
173
|
+
Sharp.counters = counters;
|
|
174
|
+
Sharp.simd = simd;
|
|
168
175
|
Sharp.format = format;
|
|
169
176
|
Sharp.interpolators = interpolators;
|
|
170
177
|
Sharp.versions = versions;
|
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, AVIF and TIFF images",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.28.2",
|
|
5
5
|
"author": "Lovell Fuller <npm@lovell.info>",
|
|
6
6
|
"homepage": "https://github.com/lovell/sharp",
|
|
7
7
|
"contributors": [
|
|
@@ -74,13 +74,16 @@
|
|
|
74
74
|
"Christian Flintrup <chr@gigahost.dk>",
|
|
75
75
|
"Manan Jadhav <manan@motionden.com>",
|
|
76
76
|
"Leon Radley <leon@radley.se>",
|
|
77
|
-
"alza54 <alza54@thiocod.in>"
|
|
77
|
+
"alza54 <alza54@thiocod.in>",
|
|
78
|
+
"Jacob Smith <jacob@frende.me>",
|
|
79
|
+
"Michael Nutt <michael@nutt.im>"
|
|
78
80
|
],
|
|
79
81
|
"scripts": {
|
|
80
82
|
"install": "(node install/libvips && node install/dll-copy && prebuild-install) || (node-gyp rebuild && node install/dll-copy)",
|
|
81
83
|
"clean": "rm -rf node_modules/ build/ vendor/ .nyc_output/ coverage/ test/fixtures/output.*",
|
|
82
|
-
"test": "
|
|
83
|
-
"test-
|
|
84
|
+
"test": "npm run test-lint && npm run test-unit && npm run test-licensing",
|
|
85
|
+
"test-lint": "semistandard && cpplint",
|
|
86
|
+
"test-unit": "nyc --reporter=lcov --branches=99 mocha --slow=1000 --timeout=60000 ./test/unit/*.js",
|
|
84
87
|
"test-licensing": "license-checker --production --summary --onlyAllow=\"Apache-2.0;BSD;ISC;MIT\"",
|
|
85
88
|
"test-coverage": "./test/coverage/report.sh",
|
|
86
89
|
"test-leak": "./test/leak/leak.sh",
|
|
@@ -117,14 +120,12 @@
|
|
|
117
120
|
"vips"
|
|
118
121
|
],
|
|
119
122
|
"dependencies": {
|
|
120
|
-
"array-flatten": "^3.0.0",
|
|
121
123
|
"color": "^3.1.3",
|
|
122
124
|
"detect-libc": "^1.0.3",
|
|
123
125
|
"node-addon-api": "^3.1.0",
|
|
124
|
-
"
|
|
125
|
-
"
|
|
126
|
-
"
|
|
127
|
-
"simple-get": "^4.0.0",
|
|
126
|
+
"prebuild-install": "^6.1.2",
|
|
127
|
+
"semver": "^7.3.5",
|
|
128
|
+
"simple-get": "^3.1.0",
|
|
128
129
|
"tar-fs": "^2.1.1",
|
|
129
130
|
"tunnel-agent": "^0.6.0"
|
|
130
131
|
},
|
|
@@ -132,12 +133,12 @@
|
|
|
132
133
|
"async": "^3.2.0",
|
|
133
134
|
"cc": "^3.0.1",
|
|
134
135
|
"decompress-zip": "^0.3.3",
|
|
135
|
-
"documentation": "^13.
|
|
136
|
+
"documentation": "^13.2.5",
|
|
136
137
|
"exif-reader": "^1.0.3",
|
|
137
138
|
"icc": "^2.0.0",
|
|
138
139
|
"license-checker": "^25.0.1",
|
|
139
|
-
"mocha": "^8.
|
|
140
|
-
"mock-fs": "^4.
|
|
140
|
+
"mocha": "^8.4.0",
|
|
141
|
+
"mock-fs": "^4.14.0",
|
|
141
142
|
"nyc": "^15.1.0",
|
|
142
143
|
"prebuild": "^10.0.1",
|
|
143
144
|
"rimraf": "^3.0.2",
|
|
@@ -145,7 +146,7 @@
|
|
|
145
146
|
},
|
|
146
147
|
"license": "Apache-2.0",
|
|
147
148
|
"config": {
|
|
148
|
-
"libvips": "8.10.
|
|
149
|
+
"libvips": "8.10.6",
|
|
149
150
|
"runtime": "napi",
|
|
150
151
|
"target": 3
|
|
151
152
|
},
|
package/src/common.cc
CHANGED
|
@@ -36,6 +36,9 @@ namespace sharp {
|
|
|
36
36
|
std::string AttrAsStr(Napi::Object obj, std::string attr) {
|
|
37
37
|
return obj.Get(attr).As<Napi::String>();
|
|
38
38
|
}
|
|
39
|
+
std::string AttrAsStr(Napi::Object obj, unsigned int const attr) {
|
|
40
|
+
return obj.Get(attr).As<Napi::String>();
|
|
41
|
+
}
|
|
39
42
|
uint32_t AttrAsUint32(Napi::Object obj, std::string attr) {
|
|
40
43
|
return obj.Get(attr).As<Napi::Number>().Uint32Value();
|
|
41
44
|
}
|
|
@@ -92,6 +95,7 @@ namespace sharp {
|
|
|
92
95
|
descriptor->rawChannels = AttrAsUint32(input, "rawChannels");
|
|
93
96
|
descriptor->rawWidth = AttrAsUint32(input, "rawWidth");
|
|
94
97
|
descriptor->rawHeight = AttrAsUint32(input, "rawHeight");
|
|
98
|
+
descriptor->rawPremultiplied = AttrAsBool(input, "rawPremultiplied");
|
|
95
99
|
}
|
|
96
100
|
// Multi-page input (GIF, TIFF, PDF)
|
|
97
101
|
if (HasAttr(input, "pages")) {
|
|
@@ -104,6 +108,10 @@ namespace sharp {
|
|
|
104
108
|
if (HasAttr(input, "level")) {
|
|
105
109
|
descriptor->level = AttrAsUint32(input, "level");
|
|
106
110
|
}
|
|
111
|
+
// subIFD (OME-TIFF)
|
|
112
|
+
if (HasAttr(input, "subifd")) {
|
|
113
|
+
descriptor->subifd = AttrAsInt32(input, "subifd");
|
|
114
|
+
}
|
|
107
115
|
// Create new image
|
|
108
116
|
if (HasAttr(input, "createChannels")) {
|
|
109
117
|
descriptor->createChannels = AttrAsUint32(input, "createChannels");
|
|
@@ -213,6 +221,8 @@ namespace sharp {
|
|
|
213
221
|
{ "VipsForeignLoadTiffBuffer", ImageType::TIFF },
|
|
214
222
|
{ "VipsForeignLoadGifFile", ImageType::GIF },
|
|
215
223
|
{ "VipsForeignLoadGifBuffer", ImageType::GIF },
|
|
224
|
+
{ "VipsForeignLoadNsgifFile", ImageType::GIF },
|
|
225
|
+
{ "VipsForeignLoadNsgifBuffer", ImageType::GIF },
|
|
216
226
|
{ "VipsForeignLoadSvgFile", ImageType::SVG },
|
|
217
227
|
{ "VipsForeignLoadSvgBuffer", ImageType::SVG },
|
|
218
228
|
{ "VipsForeignLoadHeifFile", ImageType::HEIF },
|
|
@@ -226,6 +236,7 @@ namespace sharp {
|
|
|
226
236
|
{ "VipsForeignLoadFits", ImageType::FITS },
|
|
227
237
|
{ "VipsForeignLoadOpenexr", ImageType::EXR },
|
|
228
238
|
{ "VipsForeignLoadVips", ImageType::VIPS },
|
|
239
|
+
{ "VipsForeignLoadVipsFile", ImageType::VIPS },
|
|
229
240
|
{ "VipsForeignLoadRaw", ImageType::RAW }
|
|
230
241
|
};
|
|
231
242
|
|
|
@@ -292,6 +303,9 @@ namespace sharp {
|
|
|
292
303
|
} else {
|
|
293
304
|
image.get_image()->Type = VIPS_INTERPRETATION_sRGB;
|
|
294
305
|
}
|
|
306
|
+
if (descriptor->rawPremultiplied) {
|
|
307
|
+
image = image.unpremultiply();
|
|
308
|
+
}
|
|
295
309
|
imageType = ImageType::RAW;
|
|
296
310
|
} else {
|
|
297
311
|
// Compressed data
|
|
@@ -317,6 +331,9 @@ namespace sharp {
|
|
|
317
331
|
if (imageType == ImageType::OPENSLIDE) {
|
|
318
332
|
option->set("level", descriptor->level);
|
|
319
333
|
}
|
|
334
|
+
if (imageType == ImageType::TIFF) {
|
|
335
|
+
option->set("subifd", descriptor->subifd);
|
|
336
|
+
}
|
|
320
337
|
image = VImage::new_from_buffer(descriptor->buffer, descriptor->bufferLength, nullptr, option);
|
|
321
338
|
if (imageType == ImageType::SVG || imageType == ImageType::PDF || imageType == ImageType::MAGICK) {
|
|
322
339
|
image = SetDensity(image, descriptor->density);
|
|
@@ -389,6 +406,9 @@ namespace sharp {
|
|
|
389
406
|
if (imageType == ImageType::OPENSLIDE) {
|
|
390
407
|
option->set("level", descriptor->level);
|
|
391
408
|
}
|
|
409
|
+
if (imageType == ImageType::TIFF) {
|
|
410
|
+
option->set("subifd", descriptor->subifd);
|
|
411
|
+
}
|
|
392
412
|
image = VImage::new_from_file(descriptor->file.data(), option);
|
|
393
413
|
if (imageType == ImageType::SVG || imageType == ImageType::PDF || imageType == ImageType::MAGICK) {
|
|
394
414
|
image = SetDensity(image, descriptor->density);
|
|
@@ -421,12 +441,7 @@ namespace sharp {
|
|
|
421
441
|
Uses colour space interpretation with number of channels to guess this.
|
|
422
442
|
*/
|
|
423
443
|
bool HasAlpha(VImage image) {
|
|
424
|
-
|
|
425
|
-
VipsInterpretation const interpretation = image.interpretation();
|
|
426
|
-
return (
|
|
427
|
-
(bands == 2 && interpretation == VIPS_INTERPRETATION_B_W) ||
|
|
428
|
-
(bands == 4 && interpretation != VIPS_INTERPRETATION_CMYK) ||
|
|
429
|
-
(bands == 5 && interpretation == VIPS_INTERPRETATION_CMYK));
|
|
444
|
+
return image.has_alpha();
|
|
430
445
|
}
|
|
431
446
|
|
|
432
447
|
/*
|
|
@@ -510,9 +525,8 @@ namespace sharp {
|
|
|
510
525
|
VImage SetDensity(VImage image, const double density) {
|
|
511
526
|
const double pixelsPerMm = density / 25.4;
|
|
512
527
|
VImage copy = image.copy();
|
|
513
|
-
copy.
|
|
514
|
-
copy.
|
|
515
|
-
copy.set(VIPS_META_RESOLUTION_UNIT, "in");
|
|
528
|
+
copy.get_image()->Xres = pixelsPerMm;
|
|
529
|
+
copy.get_image()->Yres = pixelsPerMm;
|
|
516
530
|
return copy;
|
|
517
531
|
}
|
|
518
532
|
|
|
@@ -802,10 +816,10 @@ namespace sharp {
|
|
|
802
816
|
/*
|
|
803
817
|
Ensures alpha channel, if missing.
|
|
804
818
|
*/
|
|
805
|
-
VImage EnsureAlpha(VImage image) {
|
|
819
|
+
VImage EnsureAlpha(VImage image, double const value) {
|
|
806
820
|
if (!HasAlpha(image)) {
|
|
807
821
|
std::vector<double> alpha;
|
|
808
|
-
alpha.push_back(sharp::MaximumImageAlpha(image.interpretation()));
|
|
822
|
+
alpha.push_back(value * sharp::MaximumImageAlpha(image.interpretation()));
|
|
809
823
|
image = image.bandjoin_const(alpha);
|
|
810
824
|
}
|
|
811
825
|
return image;
|