sharp 0.27.1 → 0.30.5
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 +19 -18
- package/binding.gyp +15 -14
- package/install/can-compile.js +11 -0
- package/install/dll-copy.js +10 -10
- package/install/libvips.js +128 -47
- package/lib/agent.js +1 -1
- package/lib/channel.js +38 -14
- package/lib/colour.js +51 -1
- package/lib/composite.js +19 -2
- package/lib/constructor.js +47 -46
- package/lib/input.js +112 -18
- package/lib/is.js +19 -5
- package/lib/libvips.js +64 -29
- package/lib/operation.js +239 -35
- package/lib/output.js +398 -116
- package/lib/platform.js +5 -3
- package/lib/resize.js +61 -15
- package/lib/sharp.js +32 -0
- package/lib/utility.js +58 -19
- package/package.json +46 -24
- package/src/common.cc +202 -52
- package/src/common.h +59 -10
- package/src/libvips/cplusplus/VConnection.cpp +0 -26
- package/src/libvips/cplusplus/VImage.cpp +88 -32
- package/src/libvips/cplusplus/VInterpolate.cpp +0 -13
- package/src/libvips/cplusplus/vips-operators.cpp +213 -1
- package/src/metadata.cc +26 -0
- package/src/metadata.h +4 -0
- package/src/operations.cc +141 -7
- package/src/operations.h +32 -3
- package/src/pipeline.cc +454 -306
- package/src/pipeline.h +64 -29
- package/src/sharp.cc +1 -0
- package/src/utilities.cc +17 -1
- package/src/utilities.h +1 -0
package/lib/output.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const path = require('path');
|
|
3
4
|
const is = require('./is');
|
|
4
|
-
const sharp = require('
|
|
5
|
+
const sharp = require('./sharp');
|
|
5
6
|
|
|
6
7
|
const formats = new Map([
|
|
7
8
|
['heic', 'heif'],
|
|
@@ -12,20 +13,31 @@ const formats = new Map([
|
|
|
12
13
|
['png', 'png'],
|
|
13
14
|
['raw', 'raw'],
|
|
14
15
|
['tiff', 'tiff'],
|
|
16
|
+
['tif', 'tiff'],
|
|
15
17
|
['webp', 'webp'],
|
|
16
|
-
['gif', 'gif']
|
|
18
|
+
['gif', 'gif'],
|
|
19
|
+
['jp2', 'jp2'],
|
|
20
|
+
['jpx', 'jp2'],
|
|
21
|
+
['j2k', 'jp2'],
|
|
22
|
+
['j2c', 'jp2']
|
|
17
23
|
]);
|
|
18
24
|
|
|
25
|
+
const errJp2Save = new Error('JP2 output requires libvips with support for OpenJPEG');
|
|
26
|
+
|
|
27
|
+
const bitdepthFromColourCount = (colours) => 1 << 31 - Math.clz32(Math.ceil(Math.log2(colours)));
|
|
28
|
+
|
|
19
29
|
/**
|
|
20
30
|
* Write output image data to a file.
|
|
21
31
|
*
|
|
22
32
|
* If an explicit output format is not selected, it will be inferred from the extension,
|
|
23
|
-
* with JPEG, PNG, WebP, AVIF, TIFF, DZI, and libvips' V format supported.
|
|
33
|
+
* with JPEG, PNG, WebP, AVIF, TIFF, GIF, DZI, and libvips' V format supported.
|
|
24
34
|
* Note that raw pixel data is only supported for buffer output.
|
|
25
35
|
*
|
|
26
36
|
* By default all metadata will be removed, which includes EXIF-based orientation.
|
|
27
37
|
* See {@link withMetadata} for control over this.
|
|
28
38
|
*
|
|
39
|
+
* The caller is responsible for ensuring directory structures and permissions exist.
|
|
40
|
+
*
|
|
29
41
|
* A `Promise` is returned when `callback` is not provided.
|
|
30
42
|
*
|
|
31
43
|
* @example
|
|
@@ -47,34 +59,32 @@ const formats = new Map([
|
|
|
47
59
|
* @throws {Error} Invalid parameters
|
|
48
60
|
*/
|
|
49
61
|
function toFile (fileOut, callback) {
|
|
50
|
-
|
|
51
|
-
|
|
62
|
+
let err;
|
|
63
|
+
if (!is.string(fileOut)) {
|
|
64
|
+
err = new Error('Missing output file path');
|
|
65
|
+
} else if (is.string(this.options.input.file) && path.resolve(this.options.input.file) === path.resolve(fileOut)) {
|
|
66
|
+
err = new Error('Cannot use same file for input and output');
|
|
67
|
+
}
|
|
68
|
+
if (err) {
|
|
52
69
|
if (is.fn(callback)) {
|
|
53
|
-
callback(
|
|
70
|
+
callback(err);
|
|
54
71
|
} else {
|
|
55
|
-
return Promise.reject(
|
|
72
|
+
return Promise.reject(err);
|
|
56
73
|
}
|
|
57
74
|
} 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
|
-
}
|
|
75
|
+
this.options.fileOut = fileOut;
|
|
76
|
+
return this._pipeline(callback);
|
|
69
77
|
}
|
|
70
78
|
return this;
|
|
71
79
|
}
|
|
72
80
|
|
|
73
81
|
/**
|
|
74
82
|
* Write output to a Buffer.
|
|
75
|
-
* JPEG, PNG, WebP, AVIF, TIFF and raw pixel data output are supported.
|
|
83
|
+
* JPEG, PNG, WebP, AVIF, TIFF, GIF and raw pixel data output are supported.
|
|
84
|
+
*
|
|
85
|
+
* Use {@link toFormat} or one of the format-specific functions such as {@link jpeg}, {@link png} etc. to set the output format.
|
|
76
86
|
*
|
|
77
|
-
* If no explicit format is set, the output format will match the input image, except
|
|
87
|
+
* If no explicit format is set, the output format will match the input image, except SVG input which becomes PNG output.
|
|
78
88
|
*
|
|
79
89
|
* By default all metadata will be removed, which includes EXIF-based orientation.
|
|
80
90
|
* See {@link withMetadata} for control over this.
|
|
@@ -100,15 +110,16 @@ function toFile (fileOut, callback) {
|
|
|
100
110
|
*
|
|
101
111
|
* @example
|
|
102
112
|
* sharp(input)
|
|
113
|
+
* .png()
|
|
103
114
|
* .toBuffer({ resolveWithObject: true })
|
|
104
115
|
* .then(({ data, info }) => { ... })
|
|
105
116
|
* .catch(err => { ... });
|
|
106
117
|
*
|
|
107
118
|
* @example
|
|
108
|
-
* const data = await sharp('my-image.jpg')
|
|
119
|
+
* const { data, info } = await sharp('my-image.jpg')
|
|
109
120
|
* // output the raw pixels
|
|
110
121
|
* .raw()
|
|
111
|
-
* .toBuffer();
|
|
122
|
+
* .toBuffer({ resolveWithObject: true });
|
|
112
123
|
*
|
|
113
124
|
* // create a more type safe way to work with the raw pixel data
|
|
114
125
|
* // this will not copy the data, instead it will change `data`s underlying ArrayBuffer
|
|
@@ -116,7 +127,9 @@ function toFile (fileOut, callback) {
|
|
|
116
127
|
* const pixelArray = new Uint8ClampedArray(data.buffer);
|
|
117
128
|
*
|
|
118
129
|
* // When you are done changing the pixelArray, sharp takes the `pixelArray` as an input
|
|
119
|
-
*
|
|
130
|
+
* const { width, height, channels } = info;
|
|
131
|
+
* await sharp(pixelArray, { raw: { width, height, channels } })
|
|
132
|
+
* .toFile('my-changed-image.jpg');
|
|
120
133
|
*
|
|
121
134
|
* @param {Object} [options]
|
|
122
135
|
* @param {boolean} [options.resolveWithObject] Resolve the Promise with an Object containing `data` and `info` properties instead of resolving only with `data`.
|
|
@@ -129,6 +142,7 @@ function toBuffer (options, callback) {
|
|
|
129
142
|
} else if (this.options.resolveWithObject) {
|
|
130
143
|
this.options.resolveWithObject = false;
|
|
131
144
|
}
|
|
145
|
+
this.options.fileOut = '';
|
|
132
146
|
return this._pipeline(is.fn(options) ? options : callback);
|
|
133
147
|
}
|
|
134
148
|
|
|
@@ -140,15 +154,37 @@ function toBuffer (options, callback) {
|
|
|
140
154
|
* The default behaviour, when `withMetadata` is not used, is to convert to the device-independent
|
|
141
155
|
* sRGB colour space and strip all metadata, including the removal of any ICC profile.
|
|
142
156
|
*
|
|
157
|
+
* EXIF metadata is unsupported for TIFF output.
|
|
158
|
+
*
|
|
143
159
|
* @example
|
|
144
160
|
* sharp('input.jpg')
|
|
145
161
|
* .withMetadata()
|
|
146
162
|
* .toFile('output-with-metadata.jpg')
|
|
147
163
|
* .then(info => { ... });
|
|
148
164
|
*
|
|
165
|
+
* @example
|
|
166
|
+
* // Set "IFD0-Copyright" in output EXIF metadata
|
|
167
|
+
* const data = await sharp(input)
|
|
168
|
+
* .withMetadata({
|
|
169
|
+
* exif: {
|
|
170
|
+
* IFD0: {
|
|
171
|
+
* Copyright: 'Wernham Hogg'
|
|
172
|
+
* }
|
|
173
|
+
* }
|
|
174
|
+
* })
|
|
175
|
+
* .toBuffer();
|
|
176
|
+
*
|
|
177
|
+
* @example
|
|
178
|
+
* // Set output metadata to 96 DPI
|
|
179
|
+
* const data = await sharp(input)
|
|
180
|
+
* .withMetadata({ density: 96 })
|
|
181
|
+
* .toBuffer();
|
|
182
|
+
*
|
|
149
183
|
* @param {Object} [options]
|
|
150
184
|
* @param {number} [options.orientation] value between 1 and 8, used to update the EXIF `Orientation` tag.
|
|
151
185
|
* @param {string} [options.icc] filesystem path to output ICC profile, defaults to sRGB.
|
|
186
|
+
* @param {Object<Object>} [options.exif={}] Object keyed by IFD0, IFD1 etc. of key/value string pairs to write as EXIF data.
|
|
187
|
+
* @param {number} [options.density] Number of pixels per inch (DPI).
|
|
152
188
|
* @returns {Sharp}
|
|
153
189
|
* @throws {Error} Invalid parameters
|
|
154
190
|
*/
|
|
@@ -162,6 +198,13 @@ function withMetadata (options) {
|
|
|
162
198
|
throw is.invalidParameterError('orientation', 'integer between 1 and 8', options.orientation);
|
|
163
199
|
}
|
|
164
200
|
}
|
|
201
|
+
if (is.defined(options.density)) {
|
|
202
|
+
if (is.number(options.density) && options.density > 0) {
|
|
203
|
+
this.options.withMetadataDensity = options.density;
|
|
204
|
+
} else {
|
|
205
|
+
throw is.invalidParameterError('density', 'positive number', options.density);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
165
208
|
if (is.defined(options.icc)) {
|
|
166
209
|
if (is.string(options.icc)) {
|
|
167
210
|
this.options.withMetadataIcc = options.icc;
|
|
@@ -169,6 +212,25 @@ function withMetadata (options) {
|
|
|
169
212
|
throw is.invalidParameterError('icc', 'string filesystem path to ICC profile', options.icc);
|
|
170
213
|
}
|
|
171
214
|
}
|
|
215
|
+
if (is.defined(options.exif)) {
|
|
216
|
+
if (is.object(options.exif)) {
|
|
217
|
+
for (const [ifd, entries] of Object.entries(options.exif)) {
|
|
218
|
+
if (is.object(entries)) {
|
|
219
|
+
for (const [k, v] of Object.entries(entries)) {
|
|
220
|
+
if (is.string(v)) {
|
|
221
|
+
this.options.withMetadataStrs[`exif-${ifd.toLowerCase()}-${k}`] = v;
|
|
222
|
+
} else {
|
|
223
|
+
throw is.invalidParameterError(`exif.${ifd}.${k}`, 'string', v);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
} else {
|
|
227
|
+
throw is.invalidParameterError(`exif.${ifd}`, 'object', entries);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
} else {
|
|
231
|
+
throw is.invalidParameterError('exif', 'object', options.exif);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
172
234
|
}
|
|
173
235
|
return this;
|
|
174
236
|
}
|
|
@@ -188,7 +250,7 @@ function withMetadata (options) {
|
|
|
188
250
|
* @throws {Error} unsupported format or options
|
|
189
251
|
*/
|
|
190
252
|
function toFormat (format, options) {
|
|
191
|
-
const actualFormat = formats.get(is.object(format) && is.string(format.id) ? format.id : format);
|
|
253
|
+
const actualFormat = formats.get((is.object(format) && is.string(format.id) ? format.id : format).toLowerCase());
|
|
192
254
|
if (!actualFormat) {
|
|
193
255
|
throw is.invalidParameterError('format', `one of: ${[...formats.keys()].join(', ')}`, format);
|
|
194
256
|
}
|
|
@@ -198,8 +260,6 @@ function toFormat (format, options) {
|
|
|
198
260
|
/**
|
|
199
261
|
* Use these JPEG options for output image.
|
|
200
262
|
*
|
|
201
|
-
* Some of these options require the use of a globally-installed libvips compiled with support for mozjpeg.
|
|
202
|
-
*
|
|
203
263
|
* @example
|
|
204
264
|
* // Convert any input to very high quality JPEG output
|
|
205
265
|
* const data = await sharp(input)
|
|
@@ -209,18 +269,25 @@ function toFormat (format, options) {
|
|
|
209
269
|
* })
|
|
210
270
|
* .toBuffer();
|
|
211
271
|
*
|
|
272
|
+
* @example
|
|
273
|
+
* // Use mozjpeg to reduce output JPEG file size (slower)
|
|
274
|
+
* const data = await sharp(input)
|
|
275
|
+
* .jpeg({ mozjpeg: true })
|
|
276
|
+
* .toBuffer();
|
|
277
|
+
*
|
|
212
278
|
* @param {Object} [options] - output options
|
|
213
279
|
* @param {number} [options.quality=80] - quality, integer 1-100
|
|
214
280
|
* @param {boolean} [options.progressive=false] - use progressive (interlace) scan
|
|
215
281
|
* @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
282
|
* @param {boolean} [options.optimiseCoding=true] - optimise Huffman coding tables
|
|
217
283
|
* @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.
|
|
284
|
+
* @param {boolean} [options.mozjpeg=false] - use mozjpeg defaults, equivalent to `{ trellisQuantisation: true, overshootDeringing: true, optimiseScans: true, quantisationTable: 3 }`
|
|
285
|
+
* @param {boolean} [options.trellisQuantisation=false] - apply trellis quantisation
|
|
286
|
+
* @param {boolean} [options.overshootDeringing=false] - apply overshoot deringing
|
|
287
|
+
* @param {boolean} [options.optimiseScans=false] - optimise progressive scans, forces progressive
|
|
288
|
+
* @param {boolean} [options.optimizeScans=false] - alternative spelling of optimiseScans
|
|
289
|
+
* @param {number} [options.quantisationTable=0] - quantization table to use, integer 0-8
|
|
290
|
+
* @param {number} [options.quantizationTable=0] - alternative spelling of quantisationTable
|
|
224
291
|
* @param {boolean} [options.force=true] - force JPEG output, otherwise attempt to use input format
|
|
225
292
|
* @returns {Sharp}
|
|
226
293
|
* @throws {Error} Invalid options
|
|
@@ -244,6 +311,23 @@ function jpeg (options) {
|
|
|
244
311
|
throw is.invalidParameterError('chromaSubsampling', 'one of: 4:2:0, 4:4:4', options.chromaSubsampling);
|
|
245
312
|
}
|
|
246
313
|
}
|
|
314
|
+
const optimiseCoding = is.bool(options.optimizeCoding) ? options.optimizeCoding : options.optimiseCoding;
|
|
315
|
+
if (is.defined(optimiseCoding)) {
|
|
316
|
+
this._setBooleanOption('jpegOptimiseCoding', optimiseCoding);
|
|
317
|
+
}
|
|
318
|
+
if (is.defined(options.mozjpeg)) {
|
|
319
|
+
if (is.bool(options.mozjpeg)) {
|
|
320
|
+
if (options.mozjpeg) {
|
|
321
|
+
this.options.jpegTrellisQuantisation = true;
|
|
322
|
+
this.options.jpegOvershootDeringing = true;
|
|
323
|
+
this.options.jpegOptimiseScans = true;
|
|
324
|
+
this.options.jpegProgressive = true;
|
|
325
|
+
this.options.jpegQuantisationTable = 3;
|
|
326
|
+
}
|
|
327
|
+
} else {
|
|
328
|
+
throw is.invalidParameterError('mozjpeg', 'boolean', options.mozjpeg);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
247
331
|
const trellisQuantisation = is.bool(options.trellisQuantization) ? options.trellisQuantization : options.trellisQuantisation;
|
|
248
332
|
if (is.defined(trellisQuantisation)) {
|
|
249
333
|
this._setBooleanOption('jpegTrellisQuantisation', trellisQuantisation);
|
|
@@ -258,10 +342,6 @@ function jpeg (options) {
|
|
|
258
342
|
this.options.jpegProgressive = true;
|
|
259
343
|
}
|
|
260
344
|
}
|
|
261
|
-
const optimiseCoding = is.bool(options.optimizeCoding) ? options.optimizeCoding : options.optimiseCoding;
|
|
262
|
-
if (is.defined(optimiseCoding)) {
|
|
263
|
-
this._setBooleanOption('jpegOptimiseCoding', optimiseCoding);
|
|
264
|
-
}
|
|
265
345
|
const quantisationTable = is.number(options.quantizationTable) ? options.quantizationTable : options.quantisationTable;
|
|
266
346
|
if (is.defined(quantisationTable)) {
|
|
267
347
|
if (is.integer(quantisationTable) && is.inRange(quantisationTable, 0, 8)) {
|
|
@@ -277,26 +357,32 @@ function jpeg (options) {
|
|
|
277
357
|
/**
|
|
278
358
|
* Use these PNG options for output image.
|
|
279
359
|
*
|
|
280
|
-
* PNG output is
|
|
360
|
+
* By default, PNG output is full colour at 8 or 16 bits per pixel.
|
|
281
361
|
* 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).
|
|
362
|
+
* Set `palette` to `true` for slower, indexed PNG output.
|
|
284
363
|
*
|
|
285
364
|
* @example
|
|
286
|
-
* // Convert any input to PNG output
|
|
365
|
+
* // Convert any input to full colour PNG output
|
|
287
366
|
* const data = await sharp(input)
|
|
288
367
|
* .png()
|
|
289
368
|
* .toBuffer();
|
|
290
369
|
*
|
|
370
|
+
* @example
|
|
371
|
+
* // Convert any input to indexed PNG output (slower)
|
|
372
|
+
* const data = await sharp(input)
|
|
373
|
+
* .png({ palette: true })
|
|
374
|
+
* .toBuffer();
|
|
375
|
+
*
|
|
291
376
|
* @param {Object} [options]
|
|
292
377
|
* @param {boolean} [options.progressive=false] - use progressive (interlace) scan
|
|
293
|
-
* @param {number} [options.compressionLevel=
|
|
378
|
+
* @param {number} [options.compressionLevel=6] - zlib compression level, 0 (fastest, largest) to 9 (slowest, smallest)
|
|
294
379
|
* @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.
|
|
298
|
-
* @param {number} [options.
|
|
299
|
-
* @param {number} [options.
|
|
380
|
+
* @param {boolean} [options.palette=false] - quantise to a palette-based image with alpha transparency support
|
|
381
|
+
* @param {number} [options.quality=100] - use the lowest number of colours needed to achieve given quality, sets `palette` to `true`
|
|
382
|
+
* @param {number} [options.effort=7] - CPU effort, between 1 (fastest) and 10 (slowest), sets `palette` to `true`
|
|
383
|
+
* @param {number} [options.colours=256] - maximum number of palette entries, sets `palette` to `true`
|
|
384
|
+
* @param {number} [options.colors=256] - alternative spelling of `options.colours`, sets `palette` to `true`
|
|
385
|
+
* @param {number} [options.dither=1.0] - level of Floyd-Steinberg error diffusion, sets `palette` to `true`
|
|
300
386
|
* @param {boolean} [options.force=true] - force PNG output, otherwise attempt to use input format
|
|
301
387
|
* @returns {Sharp}
|
|
302
388
|
* @throws {Error} Invalid options
|
|
@@ -318,7 +404,7 @@ function png (options) {
|
|
|
318
404
|
}
|
|
319
405
|
if (is.defined(options.palette)) {
|
|
320
406
|
this._setBooleanOption('pngPalette', options.palette);
|
|
321
|
-
} else if (
|
|
407
|
+
} else if ([options.quality, options.effort, options.colours, options.colors, options.dither].some(is.defined)) {
|
|
322
408
|
this._setBooleanOption('pngPalette', true);
|
|
323
409
|
}
|
|
324
410
|
if (this.options.pngPalette) {
|
|
@@ -329,10 +415,17 @@ function png (options) {
|
|
|
329
415
|
throw is.invalidParameterError('quality', 'integer between 0 and 100', options.quality);
|
|
330
416
|
}
|
|
331
417
|
}
|
|
418
|
+
if (is.defined(options.effort)) {
|
|
419
|
+
if (is.integer(options.effort) && is.inRange(options.effort, 1, 10)) {
|
|
420
|
+
this.options.pngEffort = options.effort;
|
|
421
|
+
} else {
|
|
422
|
+
throw is.invalidParameterError('effort', 'integer between 1 and 10', options.effort);
|
|
423
|
+
}
|
|
424
|
+
}
|
|
332
425
|
const colours = options.colours || options.colors;
|
|
333
426
|
if (is.defined(colours)) {
|
|
334
427
|
if (is.integer(colours) && is.inRange(colours, 2, 256)) {
|
|
335
|
-
this.options.
|
|
428
|
+
this.options.pngBitdepth = bitdepthFromColourCount(colours);
|
|
336
429
|
} else {
|
|
337
430
|
throw is.invalidParameterError('colours', 'integer between 2 and 256', colours);
|
|
338
431
|
}
|
|
@@ -358,99 +451,217 @@ function png (options) {
|
|
|
358
451
|
* .webp({ lossless: true })
|
|
359
452
|
* .toBuffer();
|
|
360
453
|
*
|
|
454
|
+
* @example
|
|
455
|
+
* // Optimise the file size of an animated WebP
|
|
456
|
+
* const outputWebp = await sharp(inputWebp, { animated: true })
|
|
457
|
+
* .webp({ effort: 6 })
|
|
458
|
+
* .toBuffer();
|
|
459
|
+
*
|
|
361
460
|
* @param {Object} [options] - output options
|
|
362
461
|
* @param {number} [options.quality=80] - quality, integer 1-100
|
|
363
462
|
* @param {number} [options.alphaQuality=100] - quality of alpha layer, integer 0-100
|
|
364
463
|
* @param {boolean} [options.lossless=false] - use lossless compression mode
|
|
365
464
|
* @param {boolean} [options.nearLossless=false] - use near_lossless compression mode
|
|
366
465
|
* @param {boolean} [options.smartSubsample=false] - use high quality chroma subsampling
|
|
367
|
-
* @param {number} [options.
|
|
368
|
-
* @param {number} [options.pageHeight] - page height for animated output
|
|
466
|
+
* @param {number} [options.effort=4] - CPU effort, between 0 (fastest) and 6 (slowest)
|
|
369
467
|
* @param {number} [options.loop=0] - number of animation iterations, use 0 for infinite animation
|
|
370
|
-
* @param {number[]} [options.delay] -
|
|
468
|
+
* @param {number|number[]} [options.delay] - delay(s) between animation frames (in milliseconds)
|
|
371
469
|
* @param {boolean} [options.force=true] - force WebP output, otherwise attempt to use input format
|
|
372
470
|
* @returns {Sharp}
|
|
373
471
|
* @throws {Error} Invalid options
|
|
374
472
|
*/
|
|
375
473
|
function webp (options) {
|
|
376
|
-
if (is.object(options)
|
|
377
|
-
if (is.
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
474
|
+
if (is.object(options)) {
|
|
475
|
+
if (is.defined(options.quality)) {
|
|
476
|
+
if (is.integer(options.quality) && is.inRange(options.quality, 1, 100)) {
|
|
477
|
+
this.options.webpQuality = options.quality;
|
|
478
|
+
} else {
|
|
479
|
+
throw is.invalidParameterError('quality', 'integer between 1 and 100', options.quality);
|
|
480
|
+
}
|
|
381
481
|
}
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
482
|
+
if (is.defined(options.alphaQuality)) {
|
|
483
|
+
if (is.integer(options.alphaQuality) && is.inRange(options.alphaQuality, 0, 100)) {
|
|
484
|
+
this.options.webpAlphaQuality = options.alphaQuality;
|
|
485
|
+
} else {
|
|
486
|
+
throw is.invalidParameterError('alphaQuality', 'integer between 0 and 100', options.alphaQuality);
|
|
487
|
+
}
|
|
388
488
|
}
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
489
|
+
if (is.defined(options.lossless)) {
|
|
490
|
+
this._setBooleanOption('webpLossless', options.lossless);
|
|
491
|
+
}
|
|
492
|
+
if (is.defined(options.nearLossless)) {
|
|
493
|
+
this._setBooleanOption('webpNearLossless', options.nearLossless);
|
|
494
|
+
}
|
|
495
|
+
if (is.defined(options.smartSubsample)) {
|
|
496
|
+
this._setBooleanOption('webpSmartSubsample', options.smartSubsample);
|
|
497
|
+
}
|
|
498
|
+
const effort = options.effort || options.reductionEffort;
|
|
499
|
+
if (is.defined(effort)) {
|
|
500
|
+
if (is.integer(effort) && is.inRange(effort, 0, 6)) {
|
|
501
|
+
this.options.webpEffort = effort;
|
|
502
|
+
} else {
|
|
503
|
+
throw is.invalidParameterError('effort', 'integer between 0 and 6', effort);
|
|
504
|
+
}
|
|
404
505
|
}
|
|
405
506
|
}
|
|
406
|
-
|
|
407
507
|
trySetAnimationOptions(options, this.options);
|
|
408
508
|
return this._updateFormatOut('webp', options);
|
|
409
509
|
}
|
|
410
510
|
|
|
411
511
|
/**
|
|
412
|
-
* Use these GIF options for output image.
|
|
512
|
+
* Use these GIF options for the output image.
|
|
413
513
|
*
|
|
414
|
-
*
|
|
415
|
-
*
|
|
416
|
-
*
|
|
514
|
+
* The first entry in the palette is reserved for transparency.
|
|
515
|
+
*
|
|
516
|
+
* @since 0.30.0
|
|
517
|
+
*
|
|
518
|
+
* @example
|
|
519
|
+
* // Convert PNG to GIF
|
|
520
|
+
* await sharp(pngBuffer)
|
|
521
|
+
* .gif()
|
|
522
|
+
* .toBuffer();
|
|
523
|
+
*
|
|
524
|
+
* @example
|
|
525
|
+
* // Convert animated WebP to animated GIF
|
|
526
|
+
* await sharp('animated.webp', { animated: true })
|
|
527
|
+
* .toFile('animated.gif');
|
|
528
|
+
*
|
|
529
|
+
* @example
|
|
530
|
+
* // Create a 128x128, cropped, non-dithered, animated thumbnail of an animated GIF
|
|
531
|
+
* const out = await sharp('in.gif', { animated: true })
|
|
532
|
+
* .resize({ width: 128, height: 128 })
|
|
533
|
+
* .gif({ dither: 0 })
|
|
534
|
+
* .toBuffer();
|
|
417
535
|
*
|
|
418
536
|
* @param {Object} [options] - output options
|
|
419
|
-
* @param {number} [options.
|
|
537
|
+
* @param {number} [options.colours=256] - maximum number of palette entries, including transparency, between 2 and 256
|
|
538
|
+
* @param {number} [options.colors=256] - alternative spelling of `options.colours`
|
|
539
|
+
* @param {number} [options.effort=7] - CPU effort, between 1 (fastest) and 10 (slowest)
|
|
540
|
+
* @param {number} [options.dither=1.0] - level of Floyd-Steinberg error diffusion, between 0 (least) and 1 (most)
|
|
420
541
|
* @param {number} [options.loop=0] - number of animation iterations, use 0 for infinite animation
|
|
421
|
-
* @param {number[]} [options.delay] -
|
|
542
|
+
* @param {number|number[]} [options.delay] - delay(s) between animation frames (in milliseconds)
|
|
422
543
|
* @param {boolean} [options.force=true] - force GIF output, otherwise attempt to use input format
|
|
423
544
|
* @returns {Sharp}
|
|
424
545
|
* @throws {Error} Invalid options
|
|
425
546
|
*/
|
|
426
|
-
/* istanbul ignore next */
|
|
427
547
|
function gif (options) {
|
|
428
|
-
if (
|
|
429
|
-
|
|
548
|
+
if (is.object(options)) {
|
|
549
|
+
const colours = options.colours || options.colors;
|
|
550
|
+
if (is.defined(colours)) {
|
|
551
|
+
if (is.integer(colours) && is.inRange(colours, 2, 256)) {
|
|
552
|
+
this.options.gifBitdepth = bitdepthFromColourCount(colours);
|
|
553
|
+
} else {
|
|
554
|
+
throw is.invalidParameterError('colours', 'integer between 2 and 256', colours);
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
if (is.defined(options.effort)) {
|
|
558
|
+
if (is.number(options.effort) && is.inRange(options.effort, 1, 10)) {
|
|
559
|
+
this.options.gifEffort = options.effort;
|
|
560
|
+
} else {
|
|
561
|
+
throw is.invalidParameterError('effort', 'integer between 1 and 10', options.effort);
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
if (is.defined(options.dither)) {
|
|
565
|
+
if (is.number(options.dither) && is.inRange(options.dither, 0, 1)) {
|
|
566
|
+
this.options.gifDither = options.dither;
|
|
567
|
+
} else {
|
|
568
|
+
throw is.invalidParameterError('dither', 'number between 0.0 and 1.0', options.dither);
|
|
569
|
+
}
|
|
570
|
+
}
|
|
430
571
|
}
|
|
431
572
|
trySetAnimationOptions(options, this.options);
|
|
432
573
|
return this._updateFormatOut('gif', options);
|
|
433
574
|
}
|
|
434
575
|
|
|
576
|
+
/**
|
|
577
|
+
* Use these JP2 options for output image.
|
|
578
|
+
*
|
|
579
|
+
* Requires libvips compiled with support for OpenJPEG.
|
|
580
|
+
* The prebuilt binaries do not include this - see
|
|
581
|
+
* {@link https://sharp.pixelplumbing.com/install#custom-libvips installing a custom libvips}.
|
|
582
|
+
*
|
|
583
|
+
* @example
|
|
584
|
+
* // Convert any input to lossless JP2 output
|
|
585
|
+
* const data = await sharp(input)
|
|
586
|
+
* .jp2({ lossless: true })
|
|
587
|
+
* .toBuffer();
|
|
588
|
+
*
|
|
589
|
+
* @example
|
|
590
|
+
* // Convert any input to very high quality JP2 output
|
|
591
|
+
* const data = await sharp(input)
|
|
592
|
+
* .jp2({
|
|
593
|
+
* quality: 100,
|
|
594
|
+
* chromaSubsampling: '4:4:4'
|
|
595
|
+
* })
|
|
596
|
+
* .toBuffer();
|
|
597
|
+
*
|
|
598
|
+
* @since 0.29.1
|
|
599
|
+
*
|
|
600
|
+
* @param {Object} [options] - output options
|
|
601
|
+
* @param {number} [options.quality=80] - quality, integer 1-100
|
|
602
|
+
* @param {boolean} [options.lossless=false] - use lossless compression mode
|
|
603
|
+
* @param {number} [options.tileWidth=512] - horizontal tile size
|
|
604
|
+
* @param {number} [options.tileHeight=512] - vertical tile size
|
|
605
|
+
* @param {string} [options.chromaSubsampling='4:4:4'] - set to '4:2:0' to use chroma subsampling
|
|
606
|
+
* @returns {Sharp}
|
|
607
|
+
* @throws {Error} Invalid options
|
|
608
|
+
*/
|
|
609
|
+
/* istanbul ignore next */
|
|
610
|
+
function jp2 (options) {
|
|
611
|
+
if (!this.constructor.format.jp2k.output.buffer) {
|
|
612
|
+
throw errJp2Save;
|
|
613
|
+
}
|
|
614
|
+
if (is.object(options)) {
|
|
615
|
+
if (is.defined(options.quality)) {
|
|
616
|
+
if (is.integer(options.quality) && is.inRange(options.quality, 1, 100)) {
|
|
617
|
+
this.options.jp2Quality = options.quality;
|
|
618
|
+
} else {
|
|
619
|
+
throw is.invalidParameterError('quality', 'integer between 1 and 100', options.quality);
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
if (is.defined(options.lossless)) {
|
|
623
|
+
if (is.bool(options.lossless)) {
|
|
624
|
+
this.options.jp2Lossless = options.lossless;
|
|
625
|
+
} else {
|
|
626
|
+
throw is.invalidParameterError('lossless', 'boolean', options.lossless);
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
if (is.defined(options.tileWidth)) {
|
|
630
|
+
if (is.integer(options.tileWidth) && is.inRange(options.tileWidth, 1, 32768)) {
|
|
631
|
+
this.options.jp2TileWidth = options.tileWidth;
|
|
632
|
+
} else {
|
|
633
|
+
throw is.invalidParameterError('tileWidth', 'integer between 1 and 32768', options.tileWidth);
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
if (is.defined(options.tileHeight)) {
|
|
637
|
+
if (is.integer(options.tileHeight) && is.inRange(options.tileHeight, 1, 32768)) {
|
|
638
|
+
this.options.jp2TileHeight = options.tileHeight;
|
|
639
|
+
} else {
|
|
640
|
+
throw is.invalidParameterError('tileHeight', 'integer between 1 and 32768', options.tileHeight);
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
if (is.defined(options.chromaSubsampling)) {
|
|
644
|
+
if (is.string(options.chromaSubsampling) && is.inArray(options.chromaSubsampling, ['4:2:0', '4:4:4'])) {
|
|
645
|
+
this.options.heifChromaSubsampling = options.chromaSubsampling;
|
|
646
|
+
} else {
|
|
647
|
+
throw is.invalidParameterError('chromaSubsampling', 'one of: 4:2:0, 4:4:4', options.chromaSubsampling);
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
return this._updateFormatOut('jp2', options);
|
|
652
|
+
}
|
|
653
|
+
|
|
435
654
|
/**
|
|
436
655
|
* Set animation options if available.
|
|
437
656
|
* @private
|
|
438
657
|
*
|
|
439
658
|
* @param {Object} [source] - output options
|
|
440
|
-
* @param {number} [source.pageHeight] - page height for animated output
|
|
441
659
|
* @param {number} [source.loop=0] - number of animation iterations, use 0 for infinite animation
|
|
442
660
|
* @param {number[]} [source.delay] - list of delays between animation frames (in milliseconds)
|
|
443
661
|
* @param {Object} [target] - target object for valid options
|
|
444
662
|
* @throws {Error} Invalid options
|
|
445
663
|
*/
|
|
446
664
|
function trySetAnimationOptions (source, target) {
|
|
447
|
-
if (is.object(source) && is.defined(source.pageHeight)) {
|
|
448
|
-
if (is.integer(source.pageHeight) && source.pageHeight > 0) {
|
|
449
|
-
target.pageHeight = source.pageHeight;
|
|
450
|
-
} else {
|
|
451
|
-
throw is.invalidParameterError('pageHeight', 'integer larger than 0', source.pageHeight);
|
|
452
|
-
}
|
|
453
|
-
}
|
|
454
665
|
if (is.object(source) && is.defined(source.loop)) {
|
|
455
666
|
if (is.integer(source.loop) && is.inRange(source.loop, 0, 65535)) {
|
|
456
667
|
target.loop = source.loop;
|
|
@@ -459,13 +670,16 @@ function trySetAnimationOptions (source, target) {
|
|
|
459
670
|
}
|
|
460
671
|
}
|
|
461
672
|
if (is.object(source) && is.defined(source.delay)) {
|
|
462
|
-
|
|
673
|
+
// We allow singular values as well
|
|
674
|
+
if (is.integer(source.delay) && is.inRange(source.delay, 0, 65535)) {
|
|
675
|
+
target.delay = [source.delay];
|
|
676
|
+
} else if (
|
|
463
677
|
Array.isArray(source.delay) &&
|
|
464
678
|
source.delay.every(is.integer) &&
|
|
465
679
|
source.delay.every(v => is.inRange(v, 0, 65535))) {
|
|
466
680
|
target.delay = source.delay;
|
|
467
681
|
} else {
|
|
468
|
-
throw is.invalidParameterError('delay', 'array of integers between 0 and 65535', source.delay);
|
|
682
|
+
throw is.invalidParameterError('delay', 'integer or an array of integers between 0 and 65535', source.delay);
|
|
469
683
|
}
|
|
470
684
|
}
|
|
471
685
|
}
|
|
@@ -473,6 +687,8 @@ function trySetAnimationOptions (source, target) {
|
|
|
473
687
|
/**
|
|
474
688
|
* Use these TIFF options for output image.
|
|
475
689
|
*
|
|
690
|
+
* The `density` can be set in pixels/inch via {@link withMetadata} instead of providing `xres` and `yres` in pixels/mm.
|
|
691
|
+
*
|
|
476
692
|
* @example
|
|
477
693
|
* // Convert SVG input to LZW-compressed, 1 bit per pixel TIFF output
|
|
478
694
|
* sharp('input.svg')
|
|
@@ -494,6 +710,7 @@ function trySetAnimationOptions (source, target) {
|
|
|
494
710
|
* @param {number} [options.tileHeight=256] - vertical tile size
|
|
495
711
|
* @param {number} [options.xres=1.0] - horizontal resolution in pixels/mm
|
|
496
712
|
* @param {number} [options.yres=1.0] - vertical resolution in pixels/mm
|
|
713
|
+
* @param {string} [options.resolutionUnit='inch'] - resolution unit options: inch, cm
|
|
497
714
|
* @param {number} [options.bitdepth=8] - reduce bitdepth to 1, 2 or 4 bit
|
|
498
715
|
* @returns {Sharp}
|
|
499
716
|
* @throws {Error} Invalid options
|
|
@@ -567,6 +784,14 @@ function tiff (options) {
|
|
|
567
784
|
throw is.invalidParameterError('predictor', 'one of: none, horizontal, float', options.predictor);
|
|
568
785
|
}
|
|
569
786
|
}
|
|
787
|
+
// resolutionUnit
|
|
788
|
+
if (is.defined(options.resolutionUnit)) {
|
|
789
|
+
if (is.string(options.resolutionUnit) && is.inArray(options.resolutionUnit, ['inch', 'cm'])) {
|
|
790
|
+
this.options.tiffResolutionUnit = options.resolutionUnit;
|
|
791
|
+
} else {
|
|
792
|
+
throw is.invalidParameterError('resolutionUnit', 'one of: inch, cm', options.resolutionUnit);
|
|
793
|
+
}
|
|
794
|
+
}
|
|
570
795
|
}
|
|
571
796
|
return this._updateFormatOut('tiff', options);
|
|
572
797
|
}
|
|
@@ -577,13 +802,15 @@ function tiff (options) {
|
|
|
577
802
|
* Whilst it is possible to create AVIF images smaller than 16x16 pixels,
|
|
578
803
|
* most web browsers do not display these properly.
|
|
579
804
|
*
|
|
805
|
+
* AVIF image sequences are not supported.
|
|
806
|
+
*
|
|
580
807
|
* @since 0.27.0
|
|
581
808
|
*
|
|
582
809
|
* @param {Object} [options] - output options
|
|
583
810
|
* @param {number} [options.quality=50] - quality, integer 1-100
|
|
584
811
|
* @param {boolean} [options.lossless=false] - use lossless compression
|
|
585
|
-
* @param {
|
|
586
|
-
* @param {string} [options.chromaSubsampling='4:
|
|
812
|
+
* @param {number} [options.effort=4] - CPU effort, between 0 (fastest) and 9 (slowest)
|
|
813
|
+
* @param {string} [options.chromaSubsampling='4:4:4'] - set to '4:2:0' to use chroma subsampling
|
|
587
814
|
* @returns {Sharp}
|
|
588
815
|
* @throws {Error} Invalid options
|
|
589
816
|
*/
|
|
@@ -603,8 +830,8 @@ function avif (options) {
|
|
|
603
830
|
* @param {number} [options.quality=50] - quality, integer 1-100
|
|
604
831
|
* @param {string} [options.compression='av1'] - compression format: av1, hevc
|
|
605
832
|
* @param {boolean} [options.lossless=false] - use lossless compression
|
|
606
|
-
* @param {number} [options.
|
|
607
|
-
* @param {string} [options.chromaSubsampling='4:
|
|
833
|
+
* @param {number} [options.effort=4] - CPU effort, between 0 (fastest) and 9 (slowest)
|
|
834
|
+
* @param {string} [options.chromaSubsampling='4:4:4'] - set to '4:2:0' to use chroma subsampling
|
|
608
835
|
* @returns {Sharp}
|
|
609
836
|
* @throws {Error} Invalid options
|
|
610
837
|
*/
|
|
@@ -631,11 +858,17 @@ function heif (options) {
|
|
|
631
858
|
throw is.invalidParameterError('compression', 'one of: av1, hevc', options.compression);
|
|
632
859
|
}
|
|
633
860
|
}
|
|
634
|
-
if (is.defined(options.
|
|
635
|
-
if (is.integer(options.
|
|
636
|
-
this.options.
|
|
861
|
+
if (is.defined(options.effort)) {
|
|
862
|
+
if (is.integer(options.effort) && is.inRange(options.effort, 0, 9)) {
|
|
863
|
+
this.options.heifEffort = options.effort;
|
|
637
864
|
} else {
|
|
638
|
-
throw is.invalidParameterError('
|
|
865
|
+
throw is.invalidParameterError('effort', 'integer between 0 and 9', options.effort);
|
|
866
|
+
}
|
|
867
|
+
} else if (is.defined(options.speed)) {
|
|
868
|
+
if (is.integer(options.speed) && is.inRange(options.speed, 0, 9)) {
|
|
869
|
+
this.options.heifEffort = 9 - options.speed;
|
|
870
|
+
} else {
|
|
871
|
+
throw is.invalidParameterError('speed', 'integer between 0 and 9', options.speed);
|
|
639
872
|
}
|
|
640
873
|
}
|
|
641
874
|
if (is.defined(options.chromaSubsampling)) {
|
|
@@ -650,28 +883,41 @@ function heif (options) {
|
|
|
650
883
|
}
|
|
651
884
|
|
|
652
885
|
/**
|
|
653
|
-
* Force output to be raw, uncompressed
|
|
886
|
+
* Force output to be raw, uncompressed pixel data.
|
|
654
887
|
* Pixel ordering is left-to-right, top-to-bottom, without padding.
|
|
655
888
|
* Channel ordering will be RGB or RGBA for non-greyscale colourspaces.
|
|
656
889
|
*
|
|
657
890
|
* @example
|
|
658
|
-
* // Extract raw RGB pixel data from JPEG input
|
|
891
|
+
* // Extract raw, unsigned 8-bit RGB pixel data from JPEG input
|
|
659
892
|
* const { data, info } = await sharp('input.jpg')
|
|
660
893
|
* .raw()
|
|
661
894
|
* .toBuffer({ resolveWithObject: true });
|
|
662
895
|
*
|
|
663
896
|
* @example
|
|
664
|
-
* // Extract alpha channel as raw pixel data from PNG input
|
|
897
|
+
* // Extract alpha channel as raw, unsigned 16-bit pixel data from PNG input
|
|
665
898
|
* const data = await sharp('input.png')
|
|
666
899
|
* .ensureAlpha()
|
|
667
900
|
* .extractChannel(3)
|
|
668
901
|
* .toColourspace('b-w')
|
|
669
|
-
* .raw()
|
|
902
|
+
* .raw({ depth: 'ushort' })
|
|
670
903
|
* .toBuffer();
|
|
671
904
|
*
|
|
672
|
-
* @
|
|
905
|
+
* @param {Object} [options] - output options
|
|
906
|
+
* @param {string} [options.depth='uchar'] - bit depth, one of: char, uchar (default), short, ushort, int, uint, float, complex, double, dpcomplex
|
|
907
|
+
* @throws {Error} Invalid options
|
|
673
908
|
*/
|
|
674
|
-
function raw () {
|
|
909
|
+
function raw (options) {
|
|
910
|
+
if (is.object(options)) {
|
|
911
|
+
if (is.defined(options.depth)) {
|
|
912
|
+
if (is.string(options.depth) && is.inArray(options.depth,
|
|
913
|
+
['char', 'uchar', 'short', 'ushort', 'int', 'uint', 'float', 'complex', 'double', 'dpcomplex']
|
|
914
|
+
)) {
|
|
915
|
+
this.options.rawDepth = options.depth;
|
|
916
|
+
} else {
|
|
917
|
+
throw is.invalidParameterError('depth', 'one of: char, uchar, short, ushort, int, uint, float, complex, double, dpcomplex', options.depth);
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
}
|
|
675
921
|
return this._updateFormatOut('raw');
|
|
676
922
|
}
|
|
677
923
|
|
|
@@ -680,8 +926,6 @@ function raw () {
|
|
|
680
926
|
* Set the format and options for tile images via the `toFormat`, `jpeg`, `png` or `webp` functions.
|
|
681
927
|
* Use a `.zip` or `.szi` file extension with `toFile` to write to a compressed archive file format.
|
|
682
928
|
*
|
|
683
|
-
* Warning: multiple sharp instances concurrently producing tile output can expose a possible race condition in some versions of libgsf.
|
|
684
|
-
*
|
|
685
929
|
* @example
|
|
686
930
|
* sharp('input.tiff')
|
|
687
931
|
* .png()
|
|
@@ -701,9 +945,10 @@ function raw () {
|
|
|
701
945
|
* @param {string} [options.depth] how deep to make the pyramid, possible values are `onepixel`, `onetile` or `one`, default based on layout.
|
|
702
946
|
* @param {number} [options.skipBlanks=-1] threshold to skip tile generation, a value 0 - 255 for 8-bit images or 0 - 65535 for 16-bit images
|
|
703
947
|
* @param {string} [options.container='fs'] tile container, with value `fs` (filesystem) or `zip` (compressed file).
|
|
704
|
-
* @param {string} [options.layout='dz'] filesystem layout, possible values are `dz`, `iiif`, `zoomify` or `google`.
|
|
948
|
+
* @param {string} [options.layout='dz'] filesystem layout, possible values are `dz`, `iiif`, `iiif3`, `zoomify` or `google`.
|
|
705
949
|
* @param {boolean} [options.centre=false] centre image in tile.
|
|
706
950
|
* @param {boolean} [options.center=false] alternative spelling of centre.
|
|
951
|
+
* @param {string} [options.id='https://example.com/iiif'] when `layout` is `iiif`/`iiif3`, sets the `@id`/`id` attribute of `info.json`
|
|
707
952
|
* @returns {Sharp}
|
|
708
953
|
* @throws {Error} Invalid parameters
|
|
709
954
|
*/
|
|
@@ -738,10 +983,10 @@ function tile (options) {
|
|
|
738
983
|
}
|
|
739
984
|
// Layout
|
|
740
985
|
if (is.defined(options.layout)) {
|
|
741
|
-
if (is.string(options.layout) && is.inArray(options.layout, ['dz', 'google', 'iiif', 'zoomify'])) {
|
|
986
|
+
if (is.string(options.layout) && is.inArray(options.layout, ['dz', 'google', 'iiif', 'iiif3', 'zoomify'])) {
|
|
742
987
|
this.options.tileLayout = options.layout;
|
|
743
988
|
} else {
|
|
744
|
-
throw is.invalidParameterError('layout', 'one of: dz, google, iiif, zoomify', options.layout);
|
|
989
|
+
throw is.invalidParameterError('layout', 'one of: dz, google, iiif, iiif3, zoomify', options.layout);
|
|
745
990
|
}
|
|
746
991
|
}
|
|
747
992
|
// Angle of rotation,
|
|
@@ -777,6 +1022,14 @@ function tile (options) {
|
|
|
777
1022
|
if (is.defined(centre)) {
|
|
778
1023
|
this._setBooleanOption('tileCentre', centre);
|
|
779
1024
|
}
|
|
1025
|
+
// @id attribute for IIIF layout
|
|
1026
|
+
if (is.defined(options.id)) {
|
|
1027
|
+
if (is.string(options.id)) {
|
|
1028
|
+
this.options.tileId = options.id;
|
|
1029
|
+
} else {
|
|
1030
|
+
throw is.invalidParameterError('id', 'string', options.id);
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
780
1033
|
}
|
|
781
1034
|
// Format
|
|
782
1035
|
if (is.inArray(this.options.formatOut, ['jpeg', 'png', 'webp'])) {
|
|
@@ -787,6 +1040,31 @@ function tile (options) {
|
|
|
787
1040
|
return this._updateFormatOut('dz');
|
|
788
1041
|
}
|
|
789
1042
|
|
|
1043
|
+
/**
|
|
1044
|
+
* Set a timeout for processing, in seconds.
|
|
1045
|
+
* Use a value of zero to continue processing indefinitely, the default behaviour.
|
|
1046
|
+
*
|
|
1047
|
+
* The clock starts when libvips opens an input image for processing.
|
|
1048
|
+
* Time spent waiting for a libuv thread to become available is not included.
|
|
1049
|
+
*
|
|
1050
|
+
* @since 0.29.2
|
|
1051
|
+
*
|
|
1052
|
+
* @param {Object} options
|
|
1053
|
+
* @param {number} options.seconds - Number of seconds after which processing will be stopped
|
|
1054
|
+
* @returns {Sharp}
|
|
1055
|
+
*/
|
|
1056
|
+
function timeout (options) {
|
|
1057
|
+
if (!is.plainObject(options)) {
|
|
1058
|
+
throw is.invalidParameterError('options', 'object', options);
|
|
1059
|
+
}
|
|
1060
|
+
if (is.integer(options.seconds) && is.inRange(options.seconds, 0, 3600)) {
|
|
1061
|
+
this.options.timeoutSeconds = options.seconds;
|
|
1062
|
+
} else {
|
|
1063
|
+
throw is.invalidParameterError('seconds', 'integer between 0 and 3600', options.seconds);
|
|
1064
|
+
}
|
|
1065
|
+
return this;
|
|
1066
|
+
}
|
|
1067
|
+
|
|
790
1068
|
/**
|
|
791
1069
|
* Update the output format unless options.force is false,
|
|
792
1070
|
* in which case revert to input format.
|
|
@@ -863,6 +1141,7 @@ function _pipeline (callback) {
|
|
|
863
1141
|
this.push(data);
|
|
864
1142
|
}
|
|
865
1143
|
this.push(null);
|
|
1144
|
+
this.emit('close');
|
|
866
1145
|
});
|
|
867
1146
|
});
|
|
868
1147
|
if (this.streamInFinished) {
|
|
@@ -878,6 +1157,7 @@ function _pipeline (callback) {
|
|
|
878
1157
|
this.push(data);
|
|
879
1158
|
}
|
|
880
1159
|
this.push(null);
|
|
1160
|
+
this.emit('close');
|
|
881
1161
|
});
|
|
882
1162
|
}
|
|
883
1163
|
return this;
|
|
@@ -932,6 +1212,7 @@ module.exports = function (Sharp) {
|
|
|
932
1212
|
withMetadata,
|
|
933
1213
|
toFormat,
|
|
934
1214
|
jpeg,
|
|
1215
|
+
jp2,
|
|
935
1216
|
png,
|
|
936
1217
|
webp,
|
|
937
1218
|
tiff,
|
|
@@ -940,6 +1221,7 @@ module.exports = function (Sharp) {
|
|
|
940
1221
|
gif,
|
|
941
1222
|
raw,
|
|
942
1223
|
tile,
|
|
1224
|
+
timeout,
|
|
943
1225
|
// Private
|
|
944
1226
|
_updateFormatOut,
|
|
945
1227
|
_setBooleanOption,
|