@ohos-ports/sharp 0.34.5-beta.8 → 0.35.5-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/LICENSE +191 -0
  2. package/README.md +112 -0
  3. package/{lib/channel.js → dist/channel.cjs} +1 -1
  4. package/dist/channel.mjs +177 -0
  5. package/{lib/colour.js → dist/colour.cjs} +12 -8
  6. package/dist/colour.mjs +199 -0
  7. package/{lib/composite.js → dist/composite.cjs} +8 -7
  8. package/dist/composite.mjs +213 -0
  9. package/{lib/constructor.js → dist/constructor.cjs} +42 -30
  10. package/dist/constructor.mjs +511 -0
  11. package/dist/index.cjs +25 -0
  12. package/{lib/index.d.ts → dist/index.d.cts} +113 -85
  13. package/dist/index.d.mts +2046 -0
  14. package/dist/index.mjs +25 -0
  15. package/{lib/input.js → dist/input.cjs} +47 -37
  16. package/dist/input.mjs +819 -0
  17. package/{lib/is.js → dist/is.cjs} +9 -3
  18. package/dist/is.mjs +149 -0
  19. package/{lib/libvips.js → dist/libvips.cjs} +35 -30
  20. package/dist/libvips.mjs +213 -0
  21. package/{lib/operation.js → dist/operation.cjs} +39 -53
  22. package/dist/operation.mjs +1002 -0
  23. package/{lib/output.js → dist/output.cjs} +167 -47
  24. package/dist/output.mjs +1786 -0
  25. package/{lib/resize.js → dist/resize.cjs} +54 -32
  26. package/dist/resize.mjs +617 -0
  27. package/dist/sharp.cjs +177 -0
  28. package/dist/sharp.mjs +177 -0
  29. package/{lib/utility.js → dist/utility.cjs} +23 -25
  30. package/dist/utility.mjs +301 -0
  31. package/install/build.js +3 -3
  32. package/package.json +56 -56
  33. package/src/binding.gyp +21 -269
  34. package/src/common.cc +81 -25
  35. package/src/common.h +23 -4
  36. package/src/metadata.cc +66 -8
  37. package/src/metadata.h +6 -1
  38. package/src/operations.cc +25 -8
  39. package/src/operations.h +1 -1
  40. package/src/pipeline.cc +231 -72
  41. package/src/pipeline.h +15 -1
  42. package/src/stats.cc +6 -6
  43. package/src/utilities.cc +8 -7
  44. package/install/check.js +0 -73
  45. package/lib/index.js +0 -16
  46. package/lib/sharp.js +0 -154
@@ -4,8 +4,8 @@
4
4
  */
5
5
 
6
6
  const path = require('node:path');
7
- const is = require('./is');
8
- const sharp = require('./sharp');
7
+ const is = require('./is.cjs');
8
+ const sharp = require('./sharp.cjs');
9
9
 
10
10
  const formats = new Map([
11
11
  ['heic', 'heif'],
@@ -33,7 +33,7 @@ const jp2Regex = /\.(jp[2x]|j2[kc])$/i;
33
33
 
34
34
  const errJp2Save = () => new Error('JP2 output requires libvips with support for OpenJPEG');
35
35
 
36
- const bitdepthFromColourCount = (colours) => 1 << 31 - Math.clz32(Math.ceil(Math.log2(colours)));
36
+ const bitdepthFromColourCount = (colours) => 1 << 32 - Math.clz32(Math.ceil(Math.log2(colours)) - 1);
37
37
 
38
38
  /**
39
39
  * Write output image data to a file.
@@ -76,7 +76,7 @@ function toFile (fileOut, callback) {
76
76
  err = new Error('Missing output file path');
77
77
  } else if (is.string(this.options.input.file) && path.resolve(this.options.input.file) === path.resolve(fileOut)) {
78
78
  err = new Error('Cannot use same file for input and output');
79
- } else if (jp2Regex.test(path.extname(fileOut)) && !this.constructor.format.jp2k.output.file) {
79
+ } else if (jp2Regex.test(path.extname(fileOut)) && !this.constructor.format.jp2.output.file) {
80
80
  err = errJp2Save();
81
81
  }
82
82
  if (err) {
@@ -113,24 +113,20 @@ function toFile (fileOut, callback) {
113
113
  * Animated output will also contain `pageHeight` and `pages`.
114
114
  * May also contain `textAutofitDpi` (dpi the font was rendered at) if image was created from text.
115
115
  *
116
- * A `Promise` is returned when `callback` is not provided.
116
+ * The underlying `ArrayBuffer` may be marked as non-transferable by some JavaScript runtimes.
117
+ * Use {@link #touint8array toUint8Array} for a guaranteed transferable `ArrayBuffer`.
117
118
  *
118
- * @example
119
- * sharp(input)
120
- * .toBuffer((err, data, info) => { ... });
119
+ * A `Promise` is returned when `callback` is not provided.
121
120
  *
122
121
  * @example
123
- * sharp(input)
124
- * .toBuffer()
125
- * .then(data => { ... })
126
- * .catch(err => { ... });
122
+ * const data = await sharp(input)
123
+ * .png()
124
+ * .toBuffer();
127
125
  *
128
126
  * @example
129
- * sharp(input)
127
+ * const { data, info } = await sharp(input)
130
128
  * .png()
131
- * .toBuffer({ resolveWithObject: true })
132
- * .then(({ data, info }) => { ... })
133
- * .catch(err => { ... });
129
+ * .toBuffer({ resolveWithObject: true });
134
130
  *
135
131
  * @example
136
132
  * const { data, info } = await sharp('my-image.jpg')
@@ -164,6 +160,64 @@ function toBuffer (options, callback) {
164
160
  return this._pipeline(is.fn(options) ? options : callback, stack);
165
161
  }
166
162
 
163
+ /**
164
+ * Write output to a `Uint8Array` backed by a transferable `ArrayBuffer`.
165
+ * JPEG, PNG, WebP, AVIF, TIFF, GIF and raw pixel data output are supported.
166
+ *
167
+ * Use {@link #toformat toFormat} or one of the format-specific functions such as {@link #jpeg jpeg}, {@link #png png} etc. to set the output format.
168
+ *
169
+ * If no explicit format is set, the output format will match the input image, except SVG input which becomes PNG output.
170
+ *
171
+ * By default all metadata will be removed, which includes EXIF-based orientation.
172
+ * See {@link #keepexif keepExif} and similar methods for control over this.
173
+ *
174
+ * Resolves with an `Object` containing:
175
+ * - `data` is the output image as a `Uint8Array` backed by a transferable `ArrayBuffer`.
176
+ * - `info` contains properties relating to the output image such as `width` and `height`.
177
+ *
178
+ * @since v0.35.0
179
+ *
180
+ * @example
181
+ * const { data, info } = await sharp(input).toUint8Array();
182
+ *
183
+ * @example
184
+ * const { data } = await sharp(input)
185
+ * .avif()
186
+ * .toUint8Array();
187
+ * const base64String = data.toBase64();
188
+ *
189
+ * @returns {Promise<{ data: Uint8Array, info: Object }>}
190
+ */
191
+ function toUint8Array () {
192
+ this.options.resolveWithObject = true;
193
+ this.options.typedArrayOut = true;
194
+ const stack = Error();
195
+ return this._pipeline(null, stack);
196
+ }
197
+
198
+ /**
199
+ * Set output density (DPI) in EXIF metadata.
200
+ *
201
+ * @since 0.35.0
202
+ *
203
+ * @example
204
+ * const data = await sharp(input)
205
+ * .withDensity(96)
206
+ * .toBuffer();
207
+ *
208
+ * @param {number} density Number of pixels per inch (DPI).
209
+ * @returns {Sharp}
210
+ * @throws {Error} Invalid parameters
211
+ */
212
+ function withDensity (density) {
213
+ if (is.number(density) && density > 0) {
214
+ this.options.withMetadataDensity = density;
215
+ } else {
216
+ throw is.invalidParameterError('density', 'positive number', density);
217
+ }
218
+ return this.keepExif();
219
+ }
220
+
167
221
  /**
168
222
  * Keep all EXIF metadata from the input image in the output image.
169
223
  *
@@ -319,6 +373,60 @@ function withIccProfile (icc, options) {
319
373
  return this;
320
374
  }
321
375
 
376
+ /**
377
+ * If the input contains gain map metadata, attempt to process the image and gain map separately,
378
+ * recombining them into a single output image.
379
+ *
380
+ * This approach is faster and should produce better results than {@link #withgainmap withGainMap},
381
+ * however not all operations are supported.
382
+ *
383
+ * Only JPEG input and output are supported.
384
+ * JPEG output options other than `quality` are ignored.
385
+ *
386
+ * This feature is experimental and the API may change.
387
+ *
388
+ * @since 0.35.0
389
+ *
390
+ * @example
391
+ * const outputWithResizedGainMap = await sharp(inputWithGainMap)
392
+ * .keepGainMap()
393
+ * .resize({ width: 64 })
394
+ * .toBuffer();
395
+ *
396
+ * @returns {Sharp}
397
+ */
398
+ function keepGainMap() {
399
+ this.options.keepGainMap = true;
400
+ this.options.withGainMap = false;
401
+ this.options.keepMetadata |= 0b100000;
402
+ return this;
403
+ }
404
+
405
+ /**
406
+ * If the input contains gain map metadata, use it to convert the main image to HDR (High Dynamic Range) before further processing.
407
+ * The input gain map is discarded.
408
+ *
409
+ * If the output is JPEG, generate and attach a new ISO 21496-1 gain map.
410
+ * JPEG output options other than `quality` are ignored.
411
+ *
412
+ * This feature is experimental and the API may change.
413
+ *
414
+ * @since 0.35.0
415
+ *
416
+ * @example
417
+ * const outputWithRegeneratedGainMap = await sharp(inputWithGainMap)
418
+ * .withGainMap()
419
+ * .toBuffer();
420
+ *
421
+ * @returns {Sharp}
422
+ */
423
+ function withGainMap() {
424
+ this.options.withGainMap = true;
425
+ this.options.keepGainMap = false;
426
+ this.options.colourspace = 'scrgb';
427
+ return this;
428
+ }
429
+
322
430
  /**
323
431
  * Keep XMP metadata from the input image in the output image.
324
432
  *
@@ -388,7 +496,7 @@ function withXmp (xmp) {
388
496
  * @returns {Sharp}
389
497
  */
390
498
  function keepMetadata () {
391
- this.options.keepMetadata = 0b11111;
499
+ this.options.keepMetadata |= 0b11111;
392
500
  return this;
393
501
  }
394
502
 
@@ -690,6 +798,7 @@ function png (options) {
690
798
  * @param {number|number[]} [options.delay] - delay(s) between animation frames (in milliseconds)
691
799
  * @param {boolean} [options.minSize=false] - prevent use of animation key frames to minimise file size (slow)
692
800
  * @param {boolean} [options.mixed=false] - allow mixture of lossy and lossless animation frames (slow)
801
+ * @param {boolean} [options.exact=false] - preserve the colour data in transparent pixels
693
802
  * @param {boolean} [options.force=true] - force WebP output, otherwise attempt to use input format
694
803
  * @returns {Sharp}
695
804
  * @throws {Error} Invalid options
@@ -742,6 +851,9 @@ function webp (options) {
742
851
  if (is.defined(options.mixed)) {
743
852
  this._setBooleanOption('webpMixed', options.mixed);
744
853
  }
854
+ if (is.defined(options.exact)) {
855
+ this._setBooleanOption('webpExact', options.exact);
856
+ }
745
857
  }
746
858
  trySetAnimationOptions(options, this.options);
747
859
  return this._updateFormatOut('webp', options);
@@ -813,7 +925,7 @@ function gif (options) {
813
925
  }
814
926
  }
815
927
  if (is.defined(options.effort)) {
816
- if (is.number(options.effort) && is.inRange(options.effort, 1, 10)) {
928
+ if (is.integer(options.effort) && is.inRange(options.effort, 1, 10)) {
817
929
  this.options.gifEffort = options.effort;
818
930
  } else {
819
931
  throw is.invalidParameterError('effort', 'integer between 1 and 10', options.effort);
@@ -887,7 +999,7 @@ function gif (options) {
887
999
  */
888
1000
  function jp2 (options) {
889
1001
  /* node:coverage ignore next 41 */
890
- if (!this.constructor.format.jp2k.output.buffer) {
1002
+ if (!this.constructor.format.jp2.output.buffer) {
891
1003
  throw errJp2Save();
892
1004
  }
893
1005
  if (is.object(options)) {
@@ -954,6 +1066,7 @@ function trySetAnimationOptions (source, target) {
954
1066
  target.delay = [source.delay];
955
1067
  } else if (
956
1068
  Array.isArray(source.delay) &&
1069
+ is.inRange(source.delay.length, 1, 1000000) &&
957
1070
  source.delay.every(is.integer) &&
958
1071
  source.delay.every(v => is.inRange(v, 0, 65535))) {
959
1072
  target.delay = source.delay;
@@ -987,12 +1100,12 @@ function trySetAnimationOptions (source, target) {
987
1100
  * @param {string} [options.predictor='horizontal'] - compression predictor options: none, horizontal, float
988
1101
  * @param {boolean} [options.pyramid=false] - write an image pyramid
989
1102
  * @param {boolean} [options.tile=false] - write a tiled tiff
990
- * @param {number} [options.tileWidth=256] - horizontal tile size
991
- * @param {number} [options.tileHeight=256] - vertical tile size
992
- * @param {number} [options.xres=1.0] - horizontal resolution in pixels/mm
993
- * @param {number} [options.yres=1.0] - vertical resolution in pixels/mm
1103
+ * @param {number} [options.tileWidth=256] - horizontal tile size, valid values are integers in the range 1-32768
1104
+ * @param {number} [options.tileHeight=256] - vertical tile size, valid values are integers in the range 1-32768
1105
+ * @param {number} [options.xres=1.0] - horizontal resolution in pixels/mm, valid values are numbers in the range 0.001-1000000
1106
+ * @param {number} [options.yres=1.0] - vertical resolution in pixels/mm, valid values are numbers in the range 0.001-1000000
994
1107
  * @param {string} [options.resolutionUnit='inch'] - resolution unit options: inch, cm
995
- * @param {number} [options.bitdepth=8] - reduce bitdepth to 1, 2 or 4 bit
1108
+ * @param {number} [options.bitdepth=0] - reduce bitdepth to 1, 2 or 4 bit
996
1109
  * @param {boolean} [options.miniswhite=false] - write 1-bit images as miniswhite
997
1110
  * @returns {Sharp}
998
1111
  * @throws {Error} Invalid options
@@ -1007,10 +1120,10 @@ function tiff (options) {
1007
1120
  }
1008
1121
  }
1009
1122
  if (is.defined(options.bitdepth)) {
1010
- if (is.integer(options.bitdepth) && is.inArray(options.bitdepth, [1, 2, 4, 8])) {
1123
+ if (is.integer(options.bitdepth) && is.inArray(options.bitdepth, [1, 2, 4])) {
1011
1124
  this.options.tiffBitdepth = options.bitdepth;
1012
1125
  } else {
1013
- throw is.invalidParameterError('bitdepth', '1, 2, 4 or 8', options.bitdepth);
1126
+ throw is.invalidParameterError('bitdepth', '1, 2 or 4', options.bitdepth);
1014
1127
  }
1015
1128
  }
1016
1129
  // tiling
@@ -1018,17 +1131,17 @@ function tiff (options) {
1018
1131
  this._setBooleanOption('tiffTile', options.tile);
1019
1132
  }
1020
1133
  if (is.defined(options.tileWidth)) {
1021
- if (is.integer(options.tileWidth) && options.tileWidth > 0) {
1134
+ if (is.integer(options.tileWidth) && is.inRange(options.tileWidth, 1, 32768)) {
1022
1135
  this.options.tiffTileWidth = options.tileWidth;
1023
1136
  } else {
1024
- throw is.invalidParameterError('tileWidth', 'integer greater than zero', options.tileWidth);
1137
+ throw is.invalidParameterError('tileWidth', 'integer between 1 and 32768', options.tileWidth);
1025
1138
  }
1026
1139
  }
1027
1140
  if (is.defined(options.tileHeight)) {
1028
- if (is.integer(options.tileHeight) && options.tileHeight > 0) {
1141
+ if (is.integer(options.tileHeight) && is.inRange(options.tileHeight, 1, 32768)) {
1029
1142
  this.options.tiffTileHeight = options.tileHeight;
1030
1143
  } else {
1031
- throw is.invalidParameterError('tileHeight', 'integer greater than zero', options.tileHeight);
1144
+ throw is.invalidParameterError('tileHeight', 'integer between 1 and 32768', options.tileHeight);
1032
1145
  }
1033
1146
  }
1034
1147
  // miniswhite
@@ -1041,17 +1154,17 @@ function tiff (options) {
1041
1154
  }
1042
1155
  // resolution
1043
1156
  if (is.defined(options.xres)) {
1044
- if (is.number(options.xres) && options.xres > 0) {
1157
+ if (is.number(options.xres) && is.inRange(options.xres, 0.001, 1000000)) {
1045
1158
  this.options.tiffXres = options.xres;
1046
1159
  } else {
1047
- throw is.invalidParameterError('xres', 'number greater than zero', options.xres);
1160
+ throw is.invalidParameterError('xres', 'number between 0.001 and 1000000', options.xres);
1048
1161
  }
1049
1162
  }
1050
1163
  if (is.defined(options.yres)) {
1051
- if (is.number(options.yres) && options.yres > 0) {
1164
+ if (is.number(options.yres) && is.inRange(options.yres, 0.001, 1000000)) {
1052
1165
  this.options.tiffYres = options.yres;
1053
1166
  } else {
1054
- throw is.invalidParameterError('yres', 'number greater than zero', options.yres);
1167
+ throw is.invalidParameterError('yres', 'number between 0.001 and 1000000', options.yres);
1055
1168
  }
1056
1169
  }
1057
1170
  // compression
@@ -1090,10 +1203,6 @@ function tiff (options) {
1090
1203
  * Use these AVIF options for output image.
1091
1204
  *
1092
1205
  * AVIF image sequences are not supported.
1093
- * Prebuilt binaries support a bitdepth of 8 only.
1094
- *
1095
- * This feature is experimental on the Windows ARM64 platform
1096
- * and requires a CPU with ARM64v8.4 or later.
1097
1206
  *
1098
1207
  * @example
1099
1208
  * const data = await sharp(input)
@@ -1113,6 +1222,7 @@ function tiff (options) {
1113
1222
  * @param {number} [options.effort=4] - CPU effort, between 0 (fastest) and 9 (slowest)
1114
1223
  * @param {string} [options.chromaSubsampling='4:4:4'] - set to '4:2:0' to use chroma subsampling
1115
1224
  * @param {number} [options.bitdepth=8] - set bitdepth to 8, 10 or 12 bit
1225
+ * @param {string} [options.tune='auto'] - tune output for a quality metric, one of 'auto' (default), 'iq', 'psnr' or 'ssim'
1116
1226
  * @returns {Sharp}
1117
1227
  * @throws {Error} Invalid options
1118
1228
  */
@@ -1140,6 +1250,7 @@ function avif (options) {
1140
1250
  * @param {number} [options.effort=4] - CPU effort, between 0 (fastest) and 9 (slowest)
1141
1251
  * @param {string} [options.chromaSubsampling='4:4:4'] - set to '4:2:0' to use chroma subsampling
1142
1252
  * @param {number} [options.bitdepth=8] - set bitdepth to 8, 10 or 12 bit
1253
+ * @param {string} [options.tune='auto'] - tune output for a quality metric, one of 'auto' (default), 'iq', 'psnr' or 'ssim'
1143
1254
  * @returns {Sharp}
1144
1255
  * @throws {Error} Invalid options
1145
1256
  */
@@ -1180,14 +1291,22 @@ function heif (options) {
1180
1291
  }
1181
1292
  if (is.defined(options.bitdepth)) {
1182
1293
  if (is.integer(options.bitdepth) && is.inArray(options.bitdepth, [8, 10, 12])) {
1183
- if (options.bitdepth !== 8 && this.constructor.versions.heif) {
1184
- throw is.invalidParameterError('bitdepth when using prebuilt binaries', 8, options.bitdepth);
1185
- }
1186
1294
  this.options.heifBitdepth = options.bitdepth;
1187
1295
  } else {
1188
1296
  throw is.invalidParameterError('bitdepth', '8, 10 or 12', options.bitdepth);
1189
1297
  }
1190
1298
  }
1299
+ if (is.defined(options.tune)) {
1300
+ if (is.string(options.tune) && is.inArray(options.tune, ['auto', 'iq', 'psnr', 'ssim'])) {
1301
+ if (this.options.heifLossless && options.tune === 'iq') {
1302
+ this.options.heifTune = 'ssim';
1303
+ } else {
1304
+ this.options.heifTune = options.tune;
1305
+ }
1306
+ } else {
1307
+ throw is.invalidParameterError('tune', 'one of: auto, iq, psnr, ssim', options.tune);
1308
+ }
1309
+ }
1191
1310
  } else {
1192
1311
  throw is.invalidParameterError('options', 'Object', options);
1193
1312
  }
@@ -1531,7 +1650,7 @@ function _pipeline (callback, stack) {
1531
1650
  // output=file/buffer
1532
1651
  if (this._isStreamInput()) {
1533
1652
  // output=file/buffer, input=stream
1534
- this.on('finish', () => {
1653
+ this._whenStreamInFinished(() => {
1535
1654
  this._flattenBufferIn();
1536
1655
  sharp.pipeline(this.options, (err, data, info) => {
1537
1656
  if (err) {
@@ -1556,7 +1675,7 @@ function _pipeline (callback, stack) {
1556
1675
  // output=stream
1557
1676
  if (this._isStreamInput()) {
1558
1677
  // output=stream, input=stream
1559
- this.once('finish', () => {
1678
+ this._whenStreamInFinished(() => {
1560
1679
  this._flattenBufferIn();
1561
1680
  sharp.pipeline(this.options, (err, data, info) => {
1562
1681
  if (err) {
@@ -1569,9 +1688,6 @@ function _pipeline (callback, stack) {
1569
1688
  this.on('end', () => this.emit('close'));
1570
1689
  });
1571
1690
  });
1572
- if (this.streamInFinished) {
1573
- this.emit('finish');
1574
- }
1575
1691
  } else {
1576
1692
  // output=stream, input=file/buffer
1577
1693
  sharp.pipeline(this.options, (err, data, info) => {
@@ -1591,7 +1707,7 @@ function _pipeline (callback, stack) {
1591
1707
  if (this._isStreamInput()) {
1592
1708
  // output=promise, input=stream
1593
1709
  return new Promise((resolve, reject) => {
1594
- this.once('finish', () => {
1710
+ this._whenStreamInFinished(() => {
1595
1711
  this._flattenBufferIn();
1596
1712
  sharp.pipeline(this.options, (err, data, info) => {
1597
1713
  if (err) {
@@ -1635,11 +1751,15 @@ module.exports = (Sharp) => {
1635
1751
  // Public
1636
1752
  toFile,
1637
1753
  toBuffer,
1754
+ toUint8Array,
1755
+ withDensity,
1638
1756
  keepExif,
1639
1757
  withExif,
1640
1758
  withExifMerge,
1641
1759
  keepIccProfile,
1642
1760
  withIccProfile,
1761
+ keepGainMap,
1762
+ withGainMap,
1643
1763
  keepXmp,
1644
1764
  withXmp,
1645
1765
  keepMetadata,