sharp 0.33.0-alpha.9 → 0.33.0-rc.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 CHANGED
@@ -2,10 +2,14 @@
2
2
 
3
3
  <img src="https://cdn.jsdelivr.net/gh/lovell/sharp@main/docs/image/sharp-logo.svg" width="160" height="160" alt="sharp logo" align="right">
4
4
 
5
- The typical use case for this high speed Node.js module
5
+ The typical use case for this high speed Node-API module
6
6
  is to convert large images in common formats to
7
7
  smaller, web-friendly JPEG, PNG, WebP, GIF and AVIF images of varying dimensions.
8
8
 
9
+ It can be used with all JavaScript runtimes
10
+ that provide support for Node-API v9, including
11
+ Node.js >= 18.17.0, Deno and Bun.
12
+
9
13
  Resizing an image is typically 4x-5x faster than using the
10
14
  quickest ImageMagick and GraphicsMagick settings
11
15
  due to its use of [libvips](https://github.com/libvips/libvips).
@@ -16,7 +20,7 @@ Lanczos resampling ensures quality is not sacrificed for speed.
16
20
  As well as image resizing, operations such as
17
21
  rotation, extraction, compositing and gamma correction are available.
18
22
 
19
- Most modern macOS, Windows and Linux systems running Node.js >= 18.17.0
23
+ Most modern macOS, Windows and Linux systems
20
24
  do not require any additional install or runtime dependencies.
21
25
 
22
26
  ## Documentation
package/lib/colour.js CHANGED
@@ -19,7 +19,7 @@ const colourspace = {
19
19
  };
20
20
 
21
21
  /**
22
- * Tint the image using the provided chroma while preserving the image luminance.
22
+ * Tint the image using the provided colour.
23
23
  * An alpha channel may be present and will be unchanged by the operation.
24
24
  *
25
25
  * @example
@@ -27,14 +27,12 @@ const colourspace = {
27
27
  * .tint({ r: 255, g: 240, b: 16 })
28
28
  * .toBuffer();
29
29
  *
30
- * @param {string|Object} rgb - parsed by the [color](https://www.npmjs.org/package/color) module to extract chroma values.
30
+ * @param {string|Object} tint - Parsed by the [color](https://www.npmjs.org/package/color) module.
31
31
  * @returns {Sharp}
32
32
  * @throws {Error} Invalid parameter
33
33
  */
34
- function tint (rgb) {
35
- const colour = color(rgb);
36
- this.options.tintA = colour.a();
37
- this.options.tintB = colour.b();
34
+ function tint (tint) {
35
+ this._setBackgroundColourOption('tint', tint);
38
36
  return this;
39
37
  }
40
38
 
@@ -121,7 +121,7 @@ const debuglog = util.debuglog('sharp');
121
121
  * a String containing the filesystem path to an JPEG, PNG, WebP, AVIF, GIF, SVG or TIFF image file.
122
122
  * JPEG, PNG, WebP, AVIF, GIF, SVG, TIFF or raw pixel image data can be streamed into the object when not present.
123
123
  * @param {Object} [options] - if present, is an Object with optional attributes.
124
- * @param {string} [options.failOn='warning'] - when to abort processing of invalid pixel data, one of (in order of sensitivity): 'none' (least), 'truncated', 'error' or 'warning' (most), higher levels imply lower levels, invalid metadata will always abort.
124
+ * @param {string} [options.failOn='warning'] - When to abort processing of invalid pixel data, one of (in order of sensitivity, least to most): 'none', 'truncated', 'error', 'warning'. Higher levels imply lower levels. Invalid metadata will always abort.
125
125
  * @param {number|boolean} [options.limitInputPixels=268402689] - Do not process input images where the number of pixels
126
126
  * (width x height) exceeds this limit. Assumes image dimensions contained in the input metadata can be trusted.
127
127
  * An integral Number of pixels, zero or false to remove limit, true to use default limit of 268402689 (0x3FFF x 0x3FFF).
@@ -212,8 +212,7 @@ const Sharp = function (input, options) {
212
212
  kernel: 'lanczos3',
213
213
  fastShrinkOnLoad: true,
214
214
  // operations
215
- tintA: 128,
216
- tintB: 128,
215
+ tint: [-1, 0, 0, 0],
217
216
  flatten: false,
218
217
  flattenBackground: [0, 0, 0],
219
218
  unflatten: false,
@@ -230,7 +229,8 @@ const Sharp = function (input, options) {
230
229
  threshold: 0,
231
230
  thresholdGrayscale: true,
232
231
  trimBackground: [],
233
- trimThreshold: 0,
232
+ trimThreshold: -1,
233
+ trimLineArt: false,
234
234
  gamma: 0,
235
235
  gammaOut: 0,
236
236
  greyscale: false,
@@ -257,11 +257,12 @@ const Sharp = function (input, options) {
257
257
  fileOut: '',
258
258
  formatOut: 'input',
259
259
  streamOut: false,
260
- withMetadata: false,
260
+ keepMetadata: 0,
261
261
  withMetadataOrientation: -1,
262
262
  withMetadataDensity: 0,
263
- withMetadataIcc: '',
264
- withMetadataStrs: {},
263
+ withIccProfile: '',
264
+ withExif: {},
265
+ withExifMerge: true,
265
266
  resolveWithObject: false,
266
267
  // output format
267
268
  jpegQuality: 80,
@@ -305,6 +306,7 @@ const Sharp = function (input, options) {
305
306
  tiffCompression: 'jpeg',
306
307
  tiffPredictor: 'horizontal',
307
308
  tiffPyramid: false,
309
+ tiffMiniswhite: false,
308
310
  tiffBitdepth: 8,
309
311
  tiffTile: false,
310
312
  tiffTileHeight: 256,
package/lib/index.d.ts CHANGED
@@ -239,12 +239,12 @@ declare namespace sharp {
239
239
  //#region Color functions
240
240
 
241
241
  /**
242
- * Tint the image using the provided chroma while preserving the image luminance.
242
+ * Tint the image using the provided colour.
243
243
  * An alpha channel may be present and will be unchanged by the operation.
244
- * @param rgb Parsed by the color module to extract chroma values.
244
+ * @param tint Parsed by the color module.
245
245
  * @returns A sharp instance that can be used to chain operations
246
246
  */
247
- tint(rgb: Color): Sharp;
247
+ tint(tint: Color): Sharp;
248
248
 
249
249
  /**
250
250
  * Convert to 8-bit greyscale; 256 shades of grey.
@@ -633,6 +633,43 @@ declare namespace sharp {
633
633
  */
634
634
  toBuffer(options: { resolveWithObject: true }): Promise<{ data: Buffer; info: OutputInfo }>;
635
635
 
636
+ /**
637
+ * Keep all EXIF metadata from the input image in the output image.
638
+ * EXIF metadata is unsupported for TIFF output.
639
+ * @returns A sharp instance that can be used to chain operations
640
+ */
641
+ keepExif(): Sharp;
642
+
643
+ /**
644
+ * Set EXIF metadata in the output image, ignoring any EXIF in the input image.
645
+ * @param {Exif} exif Object keyed by IFD0, IFD1 etc. of key/value string pairs to write as EXIF data.
646
+ * @returns A sharp instance that can be used to chain operations
647
+ * @throws {Error} Invalid parameters
648
+ */
649
+ withExif(exif: Exif): Sharp;
650
+
651
+ /**
652
+ * Update EXIF metadata from the input image in the output image.
653
+ * @param {Exif} exif Object keyed by IFD0, IFD1 etc. of key/value string pairs to write as EXIF data.
654
+ * @returns A sharp instance that can be used to chain operations
655
+ * @throws {Error} Invalid parameters
656
+ */
657
+ withExifMerge(exif: Exif): Sharp;
658
+
659
+ /**
660
+ * Keep ICC profile from the input image in the output image where possible.
661
+ * @returns A sharp instance that can be used to chain operations
662
+ */
663
+ keepIccProfile(): Sharp;
664
+
665
+ /**
666
+ * Transform using an ICC profile and attach to the output image.
667
+ * @param {string} icc - Absolute filesystem path to output ICC profile or built-in profile name (srgb, p3, cmyk).
668
+ * @returns A sharp instance that can be used to chain operations
669
+ * @throws {Error} Invalid parameters
670
+ */
671
+ withIccProfile(icc: string, options?: WithIccProfileOptions): Sharp;
672
+
636
673
  /**
637
674
  * Include all metadata (EXIF, XMP, IPTC) from the input image in the output image.
638
675
  * The default behaviour, when withMetadata is not used, is to strip all metadata and convert to the device-independent sRGB colour space.
@@ -640,7 +677,7 @@ declare namespace sharp {
640
677
  * @param withMetadata
641
678
  * @throws {Error} Invalid parameters.
642
679
  */
643
- withMetadata(withMetadata?: boolean | WriteableMetadata): Sharp;
680
+ withMetadata(withMetadata?: WriteableMetadata): Sharp;
644
681
 
645
682
  /**
646
683
  * Use these JPEG options for output image.
@@ -847,11 +884,11 @@ declare namespace sharp {
847
884
  * Trim pixels from all edges that contain values similar to the given background colour, which defaults to that of the top-left pixel.
848
885
  * Images with an alpha channel will use the combined bounding box of alpha and non-alpha channels.
849
886
  * The info response Object will contain trimOffsetLeft and trimOffsetTop properties.
850
- * @param trim The specific background colour to trim, the threshold for doing so or an Object with both.
887
+ * @param options trim options
851
888
  * @throws {Error} Invalid parameters
852
889
  * @returns A sharp instance that can be used to chain operations
853
890
  */
854
- trim(trim?: string | number | TrimOptions): Sharp;
891
+ trim(options?: TrimOptions): Sharp;
855
892
 
856
893
  //#endregion
857
894
  }
@@ -978,15 +1015,32 @@ declare namespace sharp {
978
1015
  wrap?: TextWrap;
979
1016
  }
980
1017
 
1018
+ interface ExifDir {
1019
+ [k: string]: string;
1020
+ }
1021
+
1022
+ interface Exif {
1023
+ 'IFD0'?: ExifDir;
1024
+ 'IFD1'?: ExifDir;
1025
+ 'IFD2'?: ExifDir;
1026
+ 'IFD3'?: ExifDir;
1027
+ }
1028
+
981
1029
  interface WriteableMetadata {
1030
+ /** Number of pixels per inch (DPI) */
1031
+ density?: number | undefined;
982
1032
  /** Value between 1 and 8, used to update the EXIF Orientation tag. */
983
1033
  orientation?: number | undefined;
984
- /** Filesystem path to output ICC profile, defaults to sRGB. */
1034
+ /**
1035
+ * Filesystem path to output ICC profile, defaults to sRGB.
1036
+ * @deprecated Use `withIccProfile()` instead.
1037
+ */
985
1038
  icc?: string | undefined;
986
- /** Object keyed by IFD0, IFD1 etc. of key/value string pairs to write as EXIF data. (optional, default {}) */
987
- exif?: Record<string, any> | undefined;
988
- /** Number of pixels per inch (DPI) */
989
- density?: number | undefined;
1039
+ /**
1040
+ * Object keyed by IFD0, IFD1 etc. of key/value string pairs to write as EXIF data.
1041
+ * @deprecated Use `withExif()` or `withExifMerge()` instead.
1042
+ */
1043
+ exif?: Exif | undefined;
990
1044
  }
991
1045
 
992
1046
  interface Metadata {
@@ -1096,6 +1150,11 @@ declare namespace sharp {
1096
1150
  force?: boolean | undefined;
1097
1151
  }
1098
1152
 
1153
+ interface WithIccProfileOptions {
1154
+ /** Should the ICC profile be included in the output image metadata? (optional, default true) */
1155
+ attach?: boolean | undefined;
1156
+ }
1157
+
1099
1158
  interface JpegOptions extends OutputOptions {
1100
1159
  /** Quality, integer 1-100 (optional, default 80) */
1101
1160
  quality?: number | undefined;
@@ -1234,6 +1293,8 @@ declare namespace sharp {
1234
1293
  yres?: number | undefined;
1235
1294
  /** Reduce bitdepth to 1, 2 or 4 bit (optional, default 8) */
1236
1295
  bitdepth?: 1 | 2 | 4 | 8 | undefined;
1296
+ /** Write 1-bit images as miniswhite (optional, default false) */
1297
+ miniswhite?: boolean | undefined;
1237
1298
  /** Resolution unit options: inch, cm (optional, default 'inch') */
1238
1299
  resolutionUnit?: 'inch' | 'cm' | undefined;
1239
1300
  }
@@ -1340,10 +1401,12 @@ declare namespace sharp {
1340
1401
  }
1341
1402
 
1342
1403
  interface TrimOptions {
1343
- /** background colour, parsed by the color module, defaults to that of the top-left pixel. (optional) */
1404
+ /** Background colour, parsed by the color module, defaults to that of the top-left pixel. (optional) */
1344
1405
  background?: Color | undefined;
1345
- /** the allowed difference from the above colour, a positive number. (optional, default `10`) */
1406
+ /** Allowed difference from the above colour, a positive number. (optional, default 10) */
1346
1407
  threshold?: number | undefined;
1408
+ /** Does the input more closely resemble line art (e.g. vector) rather than being photographic? (optional, default false) */
1409
+ lineArt?: boolean | undefined;
1347
1410
  }
1348
1411
 
1349
1412
  interface RawOptions {
package/lib/libvips.js CHANGED
@@ -16,7 +16,7 @@ const minimumLibvipsVersion = semverCoerce(minimumLibvipsVersionLabelled).versio
16
16
 
17
17
  const prebuiltPlatforms = [
18
18
  'darwin-arm64', 'darwin-x64',
19
- 'linux-arm', 'linux-arm64', 'linux-x64',
19
+ 'linux-arm', 'linux-arm64', 'linux-s390x', 'linux-x64',
20
20
  'linuxmusl-arm64', 'linuxmusl-x64',
21
21
  'win32-ia32', 'win32-x64'
22
22
  ];
@@ -41,15 +41,23 @@ const runtimePlatformArch = () => `${process.platform}${runtimeLibc()}-${process
41
41
 
42
42
  /* istanbul ignore next */
43
43
  const buildPlatformArch = () => {
44
+ if (isEmscripten()) {
45
+ return 'wasm32';
46
+ }
44
47
  /* eslint camelcase: ["error", { allow: ["^npm_config_"] }] */
45
48
  const { npm_config_arch, npm_config_platform, npm_config_libc } = process.env;
46
- return `${npm_config_platform || process.platform}${npm_config_libc || runtimeLibc()}-${npm_config_arch || process.arch}`;
49
+ const libc = typeof npm_config_libc === 'string' ? npm_config_libc : runtimeLibc();
50
+ return `${npm_config_platform || process.platform}${libc}-${npm_config_arch || process.arch}`;
47
51
  };
48
52
 
49
53
  const buildSharpLibvipsIncludeDir = () => {
50
54
  try {
51
- return require('@img/sharp-libvips-dev/include');
52
- } catch {}
55
+ return require(`@img/sharp-libvips-dev-${buildPlatformArch()}/include`);
56
+ } catch {
57
+ try {
58
+ return require('@img/sharp-libvips-dev/include');
59
+ } catch {}
60
+ }
53
61
  /* istanbul ignore next */
54
62
  return '';
55
63
  };
@@ -64,12 +72,22 @@ const buildSharpLibvipsCPlusPlusDir = () => {
64
72
 
65
73
  const buildSharpLibvipsLibDir = () => {
66
74
  try {
67
- return require(`@img/sharp-libvips-${buildPlatformArch()}/lib`);
68
- } catch {}
75
+ return require(`@img/sharp-libvips-dev-${buildPlatformArch()}/lib`);
76
+ } catch {
77
+ try {
78
+ return require(`@img/sharp-libvips-${buildPlatformArch()}/lib`);
79
+ } catch {}
80
+ }
69
81
  /* istanbul ignore next */
70
82
  return '';
71
83
  };
72
84
 
85
+ /* istanbul ignore next */
86
+ const isEmscripten = () => {
87
+ const { CC } = process.env;
88
+ return Boolean(CC && CC.endsWith('/emcc'));
89
+ };
90
+
73
91
  const isRosetta = () => {
74
92
  /* istanbul ignore next */
75
93
  if (process.platform === 'darwin' && process.arch === 'x64') {
@@ -81,7 +99,7 @@ const isRosetta = () => {
81
99
 
82
100
  /* istanbul ignore next */
83
101
  const spawnRebuild = () =>
84
- spawnSync('node-gyp rebuild --directory=src', {
102
+ spawnSync(`node-gyp rebuild --directory=src ${isEmscripten() ? '--nodedir=emscripten' : ''}`, {
85
103
  ...spawnSyncOptions,
86
104
  stdio: 'inherit'
87
105
  }).status;
package/lib/output.js CHANGED
@@ -163,39 +163,185 @@ function toBuffer (options, callback) {
163
163
  }
164
164
 
165
165
  /**
166
- * Include all metadata (EXIF, XMP, IPTC) from the input image in the output image.
167
- * This will also convert to and add a web-friendly sRGB ICC profile if appropriate,
168
- * unless a custom output profile is provided.
169
- *
170
- * The default behaviour, when `withMetadata` is not used, is to convert to the device-independent
171
- * sRGB colour space and strip all metadata, including the removal of any ICC profile.
166
+ * Keep all EXIF metadata from the input image in the output image.
172
167
  *
173
168
  * EXIF metadata is unsupported for TIFF output.
174
169
  *
170
+ * @since 0.33.0
171
+ *
175
172
  * @example
176
- * sharp('input.jpg')
177
- * .withMetadata()
178
- * .toFile('output-with-metadata.jpg')
179
- * .then(info => { ... });
173
+ * const outputWithExif = await sharp(inputWithExif)
174
+ * .keepExif()
175
+ * .toBuffer();
176
+ *
177
+ * @returns {Sharp}
178
+ */
179
+ function keepExif () {
180
+ this.options.keepMetadata |= 0b00001;
181
+ return this;
182
+ }
183
+
184
+ /**
185
+ * Set EXIF metadata in the output image, ignoring any EXIF in the input image.
186
+ *
187
+ * @since 0.33.0
180
188
  *
181
189
  * @example
182
- * // Set output EXIF metadata
183
- * const data = await sharp(input)
184
- * .withMetadata({
185
- * exif: {
186
- * IFD0: {
187
- * Copyright: 'The National Gallery'
188
- * },
189
- * IFD3: {
190
- * GPSLatitudeRef: 'N',
191
- * GPSLatitude: '51/1 30/1 3230/100',
192
- * GPSLongitudeRef: 'W',
193
- * GPSLongitude: '0/1 7/1 4366/100'
194
- * }
190
+ * const dataWithExif = await sharp(input)
191
+ * .withExif({
192
+ * IFD0: {
193
+ * Copyright: 'The National Gallery'
194
+ * },
195
+ * IFD3: {
196
+ * GPSLatitudeRef: 'N',
197
+ * GPSLatitude: '51/1 30/1 3230/100',
198
+ * GPSLongitudeRef: 'W',
199
+ * GPSLongitude: '0/1 7/1 4366/100'
200
+ * }
201
+ * })
202
+ * .toBuffer();
203
+ *
204
+ * @param {Object<string, Object<string, string>>} exif Object keyed by IFD0, IFD1 etc. of key/value string pairs to write as EXIF data.
205
+ * @returns {Sharp}
206
+ * @throws {Error} Invalid parameters
207
+ */
208
+ function withExif (exif) {
209
+ if (is.object(exif)) {
210
+ for (const [ifd, entries] of Object.entries(exif)) {
211
+ if (is.object(entries)) {
212
+ for (const [k, v] of Object.entries(entries)) {
213
+ if (is.string(v)) {
214
+ this.options.withExif[`exif-${ifd.toLowerCase()}-${k}`] = v;
215
+ } else {
216
+ throw is.invalidParameterError(`${ifd}.${k}`, 'string', v);
217
+ }
218
+ }
219
+ } else {
220
+ throw is.invalidParameterError(ifd, 'object', entries);
221
+ }
222
+ }
223
+ } else {
224
+ throw is.invalidParameterError('exif', 'object', exif);
225
+ }
226
+ this.options.withExifMerge = false;
227
+ return this.keepExif();
228
+ }
229
+
230
+ /**
231
+ * Update EXIF metadata from the input image in the output image.
232
+ *
233
+ * @since 0.33.0
234
+ *
235
+ * @example
236
+ * const dataWithMergedExif = await sharp(inputWithExif)
237
+ * .withExifMerge({
238
+ * IFD0: {
239
+ * Copyright: 'The National Gallery'
195
240
  * }
196
241
  * })
197
242
  * .toBuffer();
198
243
  *
244
+ * @param {Object<string, Object<string, string>>} exif Object keyed by IFD0, IFD1 etc. of key/value string pairs to write as EXIF data.
245
+ * @returns {Sharp}
246
+ * @throws {Error} Invalid parameters
247
+ */
248
+ function withExifMerge (exif) {
249
+ this.withExif(exif);
250
+ this.options.withExifMerge = true;
251
+ return this;
252
+ }
253
+
254
+ /**
255
+ * Keep ICC profile from the input image in the output image.
256
+ *
257
+ * Where necessary, will attempt to convert the output colour space to match the profile.
258
+ *
259
+ * @since 0.33.0
260
+ *
261
+ * @example
262
+ * const outputWithIccProfile = await sharp(inputWithIccProfile)
263
+ * .keepIccProfile()
264
+ * .toBuffer();
265
+ *
266
+ * @returns {Sharp}
267
+ */
268
+ function keepIccProfile () {
269
+ this.options.keepMetadata |= 0b01000;
270
+ return this;
271
+ }
272
+
273
+ /**
274
+ * Transform using an ICC profile and attach to the output image.
275
+ *
276
+ * This can either be an absolute filesystem path or
277
+ * built-in profile name (`srgb`, `p3`, `cmyk`).
278
+ *
279
+ * @since 0.33.0
280
+ *
281
+ * @example
282
+ * const outputWithP3 = await sharp(input)
283
+ * .withIccProfile('p3')
284
+ * .toBuffer();
285
+ *
286
+ * @param {string} icc - Absolute filesystem path to output ICC profile or built-in profile name (srgb, p3, cmyk).
287
+ * @param {Object} [options]
288
+ * @param {number} [options.attach=true] Should the ICC profile be included in the output image metadata?
289
+ * @returns {Sharp}
290
+ * @throws {Error} Invalid parameters
291
+ */
292
+ function withIccProfile (icc, options) {
293
+ if (is.string(icc)) {
294
+ this.options.withIccProfile = icc;
295
+ } else {
296
+ throw is.invalidParameterError('icc', 'string', icc);
297
+ }
298
+ this.keepIccProfile();
299
+ if (is.object(options)) {
300
+ if (is.defined(options.attach)) {
301
+ if (is.bool(options.attach)) {
302
+ if (!options.attach) {
303
+ this.options.keepMetadata &= ~0b01000;
304
+ }
305
+ } else {
306
+ throw is.invalidParameterError('attach', 'boolean', options.attach);
307
+ }
308
+ }
309
+ }
310
+ return this;
311
+ }
312
+
313
+ /**
314
+ * Keep all metadata (EXIF, ICC, XMP, IPTC) from the input image in the output image.
315
+ *
316
+ * The default behaviour, when `keepMetadata` is not used, is to convert to the device-independent
317
+ * sRGB colour space and strip all metadata, including the removal of any ICC profile.
318
+ *
319
+ * @since 0.33.0
320
+ *
321
+ * @example
322
+ * const outputWithMetadata = await sharp(inputWithMetadata)
323
+ * .keepMetadata()
324
+ * .toBuffer();
325
+ *
326
+ * @returns {Sharp}
327
+ */
328
+ function keepMetadata () {
329
+ this.options.keepMetadata = 0b11111;
330
+ return this;
331
+ }
332
+
333
+ /**
334
+ * Keep most metadata (EXIF, XMP, IPTC) from the input image in the output image.
335
+ *
336
+ * This will also convert to and add a web-friendly sRGB ICC profile if appropriate.
337
+ *
338
+ * Allows orientation and density to be set or updated.
339
+ *
340
+ * @example
341
+ * const outputSrgbWithMetadata = await sharp(inputRgbWithMetadata)
342
+ * .withMetadata()
343
+ * .toBuffer();
344
+ *
199
345
  * @example
200
346
  * // Set output metadata to 96 DPI
201
347
  * const data = await sharp(input)
@@ -203,15 +349,14 @@ function toBuffer (options, callback) {
203
349
  * .toBuffer();
204
350
  *
205
351
  * @param {Object} [options]
206
- * @param {number} [options.orientation] value between 1 and 8, used to update the EXIF `Orientation` tag.
207
- * @param {string} [options.icc='srgb'] Filesystem path to output ICC profile, relative to `process.cwd()`, defaults to built-in sRGB.
208
- * @param {Object<Object>} [options.exif={}] Object keyed by IFD0, IFD1 etc. of key/value string pairs to write as EXIF data.
352
+ * @param {number} [options.orientation] Used to update the EXIF `Orientation` tag, integer between 1 and 8.
209
353
  * @param {number} [options.density] Number of pixels per inch (DPI).
210
354
  * @returns {Sharp}
211
355
  * @throws {Error} Invalid parameters
212
356
  */
213
357
  function withMetadata (options) {
214
- this.options.withMetadata = is.bool(options) ? options : true;
358
+ this.keepMetadata();
359
+ this.withIccProfile('srgb');
215
360
  if (is.object(options)) {
216
361
  if (is.defined(options.orientation)) {
217
362
  if (is.integer(options.orientation) && is.inRange(options.orientation, 1, 8)) {
@@ -228,30 +373,10 @@ function withMetadata (options) {
228
373
  }
229
374
  }
230
375
  if (is.defined(options.icc)) {
231
- if (is.string(options.icc)) {
232
- this.options.withMetadataIcc = options.icc;
233
- } else {
234
- throw is.invalidParameterError('icc', 'string filesystem path to ICC profile', options.icc);
235
- }
376
+ this.withIccProfile(options.icc);
236
377
  }
237
378
  if (is.defined(options.exif)) {
238
- if (is.object(options.exif)) {
239
- for (const [ifd, entries] of Object.entries(options.exif)) {
240
- if (is.object(entries)) {
241
- for (const [k, v] of Object.entries(entries)) {
242
- if (is.string(v)) {
243
- this.options.withMetadataStrs[`exif-${ifd.toLowerCase()}-${k}`] = v;
244
- } else {
245
- throw is.invalidParameterError(`exif.${ifd}.${k}`, 'string', v);
246
- }
247
- }
248
- } else {
249
- throw is.invalidParameterError(`exif.${ifd}`, 'object', entries);
250
- }
251
- }
252
- } else {
253
- throw is.invalidParameterError('exif', 'object', options.exif);
254
- }
379
+ this.withExifMerge(options.exif);
255
380
  }
256
381
  }
257
382
  return this;
@@ -782,6 +907,7 @@ function trySetAnimationOptions (source, target) {
782
907
  * @param {number} [options.yres=1.0] - vertical resolution in pixels/mm
783
908
  * @param {string} [options.resolutionUnit='inch'] - resolution unit options: inch, cm
784
909
  * @param {number} [options.bitdepth=8] - reduce bitdepth to 1, 2 or 4 bit
910
+ * @param {boolean} [options.miniswhite=false] - write 1-bit images as miniswhite
785
911
  * @returns {Sharp}
786
912
  * @throws {Error} Invalid options
787
913
  */
@@ -819,6 +945,10 @@ function tiff (options) {
819
945
  throw is.invalidParameterError('tileHeight', 'integer greater than zero', options.tileHeight);
820
946
  }
821
947
  }
948
+ // miniswhite
949
+ if (is.defined(options.miniswhite)) {
950
+ this._setBooleanOption('tiffMiniswhite', options.miniswhite);
951
+ }
822
952
  // pyramid
823
953
  if (is.defined(options.pyramid)) {
824
954
  this._setBooleanOption('tiffPyramid', options.pyramid);
@@ -1402,6 +1532,12 @@ module.exports = function (Sharp) {
1402
1532
  // Public
1403
1533
  toFile,
1404
1534
  toBuffer,
1535
+ keepExif,
1536
+ withExif,
1537
+ withExifMerge,
1538
+ keepIccProfile,
1539
+ withIccProfile,
1540
+ keepMetadata,
1405
1541
  withMetadata,
1406
1542
  toFormat,
1407
1543
  jpeg,