sharp 0.28.3 → 0.29.3
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 +2 -2
- package/binding.gyp +12 -9
- package/install/dll-copy.js +6 -6
- package/install/libvips.js +4 -8
- package/lib/channel.js +11 -7
- package/lib/colour.js +42 -1
- package/lib/constructor.js +18 -31
- package/lib/input.js +45 -3
- package/lib/is.js +19 -5
- package/lib/libvips.js +4 -19
- package/lib/operation.js +28 -5
- package/lib/output.js +147 -16
- package/lib/sharp.js +31 -0
- package/lib/utility.js +3 -2
- package/package.json +18 -15
- package/src/common.cc +67 -11
- package/src/common.h +25 -5
- package/src/libvips/cplusplus/VConnection.cpp +0 -26
- package/src/libvips/cplusplus/VImage.cpp +54 -16
- package/src/libvips/cplusplus/VInterpolate.cpp +0 -13
- package/src/libvips/cplusplus/vips-operators.cpp +185 -1
- package/src/metadata.cc +14 -0
- package/src/metadata.h +1 -0
- package/src/operations.cc +29 -3
- package/src/operations.h +13 -2
- package/src/pipeline.cc +103 -35
- package/src/pipeline.h +23 -3
- package/src/utilities.cc +1 -1
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,11 +13,17 @@ 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
|
|
|
19
25
|
const errMagickSave = new Error('GIF output requires libvips with support for ImageMagick');
|
|
26
|
+
const errJp2Save = new Error('JP2 output requires libvips with support for OpenJPEG');
|
|
20
27
|
|
|
21
28
|
/**
|
|
22
29
|
* Write output image data to a file.
|
|
@@ -28,6 +35,8 @@ const errMagickSave = new Error('GIF output requires libvips with support for Im
|
|
|
28
35
|
* By default all metadata will be removed, which includes EXIF-based orientation.
|
|
29
36
|
* See {@link withMetadata} for control over this.
|
|
30
37
|
*
|
|
38
|
+
* The caller is responsible for ensuring directory structures and permissions exist.
|
|
39
|
+
*
|
|
31
40
|
* A `Promise` is returned when `callback` is not provided.
|
|
32
41
|
*
|
|
33
42
|
* @example
|
|
@@ -52,7 +61,7 @@ function toFile (fileOut, callback) {
|
|
|
52
61
|
let err;
|
|
53
62
|
if (!is.string(fileOut)) {
|
|
54
63
|
err = new Error('Missing output file path');
|
|
55
|
-
} else if (this.options.input.file === fileOut) {
|
|
64
|
+
} else if (is.string(this.options.input.file) && path.resolve(this.options.input.file) === path.resolve(fileOut)) {
|
|
56
65
|
err = new Error('Cannot use same file for input and output');
|
|
57
66
|
} else if (this.options.formatOut === 'input' && fileOut.toLowerCase().endsWith('.gif') && !this.constructor.format.magick.output.file) {
|
|
58
67
|
err = errMagickSave;
|
|
@@ -403,7 +412,7 @@ function png (options) {
|
|
|
403
412
|
const colours = options.colours || options.colors;
|
|
404
413
|
if (is.defined(colours)) {
|
|
405
414
|
if (is.integer(colours) && is.inRange(colours, 2, 256)) {
|
|
406
|
-
this.options.
|
|
415
|
+
this.options.pngBitdepth = 1 << 31 - Math.clz32(Math.ceil(Math.log2(colours)));
|
|
407
416
|
} else {
|
|
408
417
|
throw is.invalidParameterError('colours', 'integer between 2 and 256', colours);
|
|
409
418
|
}
|
|
@@ -509,6 +518,84 @@ function gif (options) {
|
|
|
509
518
|
return this._updateFormatOut('gif', options);
|
|
510
519
|
}
|
|
511
520
|
|
|
521
|
+
/**
|
|
522
|
+
* Use these JP2 options for output image.
|
|
523
|
+
*
|
|
524
|
+
* Requires libvips compiled with support for OpenJPEG.
|
|
525
|
+
* The prebuilt binaries do not include this - see
|
|
526
|
+
* {@link https://sharp.pixelplumbing.com/install#custom-libvips installing a custom libvips}.
|
|
527
|
+
*
|
|
528
|
+
* @example
|
|
529
|
+
* // Convert any input to lossless JP2 output
|
|
530
|
+
* const data = await sharp(input)
|
|
531
|
+
* .jp2({ lossless: true })
|
|
532
|
+
* .toBuffer();
|
|
533
|
+
*
|
|
534
|
+
* @example
|
|
535
|
+
* // Convert any input to very high quality JP2 output
|
|
536
|
+
* const data = await sharp(input)
|
|
537
|
+
* .jp2({
|
|
538
|
+
* quality: 100,
|
|
539
|
+
* chromaSubsampling: '4:4:4'
|
|
540
|
+
* })
|
|
541
|
+
* .toBuffer();
|
|
542
|
+
*
|
|
543
|
+
* @since 0.29.1
|
|
544
|
+
*
|
|
545
|
+
* @param {Object} [options] - output options
|
|
546
|
+
* @param {number} [options.quality=80] - quality, integer 1-100
|
|
547
|
+
* @param {boolean} [options.lossless=false] - use lossless compression mode
|
|
548
|
+
* @param {number} [options.tileWidth=512] - horizontal tile size
|
|
549
|
+
* @param {number} [options.tileHeight=512] - vertical tile size
|
|
550
|
+
* @param {string} [options.chromaSubsampling='4:4:4'] - set to '4:2:0' to use chroma subsampling
|
|
551
|
+
* @returns {Sharp}
|
|
552
|
+
* @throws {Error} Invalid options
|
|
553
|
+
*/
|
|
554
|
+
/* istanbul ignore next */
|
|
555
|
+
function jp2 (options) {
|
|
556
|
+
if (!this.constructor.format.jp2k.output.buffer) {
|
|
557
|
+
throw errJp2Save;
|
|
558
|
+
}
|
|
559
|
+
if (is.object(options)) {
|
|
560
|
+
if (is.defined(options.quality)) {
|
|
561
|
+
if (is.integer(options.quality) && is.inRange(options.quality, 1, 100)) {
|
|
562
|
+
this.options.jp2Quality = options.quality;
|
|
563
|
+
} else {
|
|
564
|
+
throw is.invalidParameterError('quality', 'integer between 1 and 100', options.quality);
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
if (is.defined(options.lossless)) {
|
|
568
|
+
if (is.bool(options.lossless)) {
|
|
569
|
+
this.options.jp2Lossless = options.lossless;
|
|
570
|
+
} else {
|
|
571
|
+
throw is.invalidParameterError('lossless', 'boolean', options.lossless);
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
if (is.defined(options.tileWidth)) {
|
|
575
|
+
if (is.integer(options.tileWidth) && is.inRange(options.tileWidth, 1, 32768)) {
|
|
576
|
+
this.options.jp2TileWidth = options.tileWidth;
|
|
577
|
+
} else {
|
|
578
|
+
throw is.invalidParameterError('tileWidth', 'integer between 1 and 32768', options.tileWidth);
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
if (is.defined(options.tileHeight)) {
|
|
582
|
+
if (is.integer(options.tileHeight) && is.inRange(options.tileHeight, 1, 32768)) {
|
|
583
|
+
this.options.jp2TileHeight = options.tileHeight;
|
|
584
|
+
} else {
|
|
585
|
+
throw is.invalidParameterError('tileHeight', 'integer between 1 and 32768', options.tileHeight);
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
if (is.defined(options.chromaSubsampling)) {
|
|
589
|
+
if (is.string(options.chromaSubsampling) && is.inArray(options.chromaSubsampling, ['4:2:0', '4:4:4'])) {
|
|
590
|
+
this.options.heifChromaSubsampling = options.chromaSubsampling;
|
|
591
|
+
} else {
|
|
592
|
+
throw is.invalidParameterError('chromaSubsampling', 'one of: 4:2:0, 4:4:4', options.chromaSubsampling);
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
return this._updateFormatOut('jp2', options);
|
|
597
|
+
}
|
|
598
|
+
|
|
512
599
|
/**
|
|
513
600
|
* Set animation options if available.
|
|
514
601
|
* @private
|
|
@@ -550,6 +637,8 @@ function trySetAnimationOptions (source, target) {
|
|
|
550
637
|
/**
|
|
551
638
|
* Use these TIFF options for output image.
|
|
552
639
|
*
|
|
640
|
+
* The `density` can be set in pixels/inch via {@link withMetadata} instead of providing `xres` and `yres` in pixels/mm.
|
|
641
|
+
*
|
|
553
642
|
* @example
|
|
554
643
|
* // Convert SVG input to LZW-compressed, 1 bit per pixel TIFF output
|
|
555
644
|
* sharp('input.svg')
|
|
@@ -654,13 +743,15 @@ function tiff (options) {
|
|
|
654
743
|
* Whilst it is possible to create AVIF images smaller than 16x16 pixels,
|
|
655
744
|
* most web browsers do not display these properly.
|
|
656
745
|
*
|
|
746
|
+
* AVIF image sequences are not supported.
|
|
747
|
+
*
|
|
657
748
|
* @since 0.27.0
|
|
658
749
|
*
|
|
659
750
|
* @param {Object} [options] - output options
|
|
660
751
|
* @param {number} [options.quality=50] - quality, integer 1-100
|
|
661
752
|
* @param {boolean} [options.lossless=false] - use lossless compression
|
|
662
|
-
* @param {number} [options.speed=5] - CPU effort vs file size, 0 (slowest/smallest) to
|
|
663
|
-
* @param {string} [options.chromaSubsampling='4:
|
|
753
|
+
* @param {number} [options.speed=5] - CPU effort vs file size, 0 (slowest/smallest) to 9 (fastest/largest)
|
|
754
|
+
* @param {string} [options.chromaSubsampling='4:4:4'] - set to '4:2:0' to use chroma subsampling
|
|
664
755
|
* @returns {Sharp}
|
|
665
756
|
* @throws {Error} Invalid options
|
|
666
757
|
*/
|
|
@@ -680,8 +771,8 @@ function avif (options) {
|
|
|
680
771
|
* @param {number} [options.quality=50] - quality, integer 1-100
|
|
681
772
|
* @param {string} [options.compression='av1'] - compression format: av1, hevc
|
|
682
773
|
* @param {boolean} [options.lossless=false] - use lossless compression
|
|
683
|
-
* @param {number} [options.speed=5] - CPU effort vs file size, 0 (slowest/smallest) to
|
|
684
|
-
* @param {string} [options.chromaSubsampling='4:
|
|
774
|
+
* @param {number} [options.speed=5] - CPU effort vs file size, 0 (slowest/smallest) to 9 (fastest/largest)
|
|
775
|
+
* @param {string} [options.chromaSubsampling='4:4:4'] - set to '4:2:0' to use chroma subsampling
|
|
685
776
|
* @returns {Sharp}
|
|
686
777
|
* @throws {Error} Invalid options
|
|
687
778
|
*/
|
|
@@ -709,10 +800,10 @@ function heif (options) {
|
|
|
709
800
|
}
|
|
710
801
|
}
|
|
711
802
|
if (is.defined(options.speed)) {
|
|
712
|
-
if (is.integer(options.speed) && is.inRange(options.speed, 0,
|
|
803
|
+
if (is.integer(options.speed) && is.inRange(options.speed, 0, 9)) {
|
|
713
804
|
this.options.heifSpeed = options.speed;
|
|
714
805
|
} else {
|
|
715
|
-
throw is.invalidParameterError('speed', 'integer between 0 and
|
|
806
|
+
throw is.invalidParameterError('speed', 'integer between 0 and 9', options.speed);
|
|
716
807
|
}
|
|
717
808
|
}
|
|
718
809
|
if (is.defined(options.chromaSubsampling)) {
|
|
@@ -727,28 +818,41 @@ function heif (options) {
|
|
|
727
818
|
}
|
|
728
819
|
|
|
729
820
|
/**
|
|
730
|
-
* Force output to be raw, uncompressed
|
|
821
|
+
* Force output to be raw, uncompressed pixel data.
|
|
731
822
|
* Pixel ordering is left-to-right, top-to-bottom, without padding.
|
|
732
823
|
* Channel ordering will be RGB or RGBA for non-greyscale colourspaces.
|
|
733
824
|
*
|
|
734
825
|
* @example
|
|
735
|
-
* // Extract raw RGB pixel data from JPEG input
|
|
826
|
+
* // Extract raw, unsigned 8-bit RGB pixel data from JPEG input
|
|
736
827
|
* const { data, info } = await sharp('input.jpg')
|
|
737
828
|
* .raw()
|
|
738
829
|
* .toBuffer({ resolveWithObject: true });
|
|
739
830
|
*
|
|
740
831
|
* @example
|
|
741
|
-
* // Extract alpha channel as raw pixel data from PNG input
|
|
832
|
+
* // Extract alpha channel as raw, unsigned 16-bit pixel data from PNG input
|
|
742
833
|
* const data = await sharp('input.png')
|
|
743
834
|
* .ensureAlpha()
|
|
744
835
|
* .extractChannel(3)
|
|
745
836
|
* .toColourspace('b-w')
|
|
746
|
-
* .raw()
|
|
837
|
+
* .raw({ depth: 'ushort' })
|
|
747
838
|
* .toBuffer();
|
|
748
839
|
*
|
|
749
|
-
* @
|
|
840
|
+
* @param {Object} [options] - output options
|
|
841
|
+
* @param {string} [options.depth='uchar'] - bit depth, one of: char, uchar (default), short, ushort, int, uint, float, complex, double, dpcomplex
|
|
842
|
+
* @throws {Error} Invalid options
|
|
750
843
|
*/
|
|
751
|
-
function raw () {
|
|
844
|
+
function raw (options) {
|
|
845
|
+
if (is.object(options)) {
|
|
846
|
+
if (is.defined(options.depth)) {
|
|
847
|
+
if (is.string(options.depth) && is.inArray(options.depth,
|
|
848
|
+
['char', 'uchar', 'short', 'ushort', 'int', 'uint', 'float', 'complex', 'double', 'dpcomplex']
|
|
849
|
+
)) {
|
|
850
|
+
this.options.rawDepth = options.depth;
|
|
851
|
+
} else {
|
|
852
|
+
throw is.invalidParameterError('depth', 'one of: char, uchar, short, ushort, int, uint, float, complex, double, dpcomplex', options.depth);
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
}
|
|
752
856
|
return this._updateFormatOut('raw');
|
|
753
857
|
}
|
|
754
858
|
|
|
@@ -873,6 +977,31 @@ function tile (options) {
|
|
|
873
977
|
return this._updateFormatOut('dz');
|
|
874
978
|
}
|
|
875
979
|
|
|
980
|
+
/**
|
|
981
|
+
* Set a timeout for processing, in seconds.
|
|
982
|
+
* Use a value of zero to continue processing indefinitely, the default behaviour.
|
|
983
|
+
*
|
|
984
|
+
* The clock starts when libvips opens an input image for processing.
|
|
985
|
+
* Time spent waiting for a libuv thread to become available is not included.
|
|
986
|
+
*
|
|
987
|
+
* @since 0.29.2
|
|
988
|
+
*
|
|
989
|
+
* @param {Object} options
|
|
990
|
+
* @param {number} options.seconds - Number of seconds after which processing will be stopped
|
|
991
|
+
* @returns {Sharp}
|
|
992
|
+
*/
|
|
993
|
+
function timeout (options) {
|
|
994
|
+
if (!is.plainObject(options)) {
|
|
995
|
+
throw is.invalidParameterError('options', 'object', options);
|
|
996
|
+
}
|
|
997
|
+
if (is.integer(options.seconds) && is.inRange(options.seconds, 0, 3600)) {
|
|
998
|
+
this.options.timeoutSeconds = options.seconds;
|
|
999
|
+
} else {
|
|
1000
|
+
throw is.invalidParameterError('seconds', 'integer between 0 and 3600', options.seconds);
|
|
1001
|
+
}
|
|
1002
|
+
return this;
|
|
1003
|
+
}
|
|
1004
|
+
|
|
876
1005
|
/**
|
|
877
1006
|
* Update the output format unless options.force is false,
|
|
878
1007
|
* in which case revert to input format.
|
|
@@ -1018,6 +1147,7 @@ module.exports = function (Sharp) {
|
|
|
1018
1147
|
withMetadata,
|
|
1019
1148
|
toFormat,
|
|
1020
1149
|
jpeg,
|
|
1150
|
+
jp2,
|
|
1021
1151
|
png,
|
|
1022
1152
|
webp,
|
|
1023
1153
|
tiff,
|
|
@@ -1026,6 +1156,7 @@ module.exports = function (Sharp) {
|
|
|
1026
1156
|
gif,
|
|
1027
1157
|
raw,
|
|
1028
1158
|
tile,
|
|
1159
|
+
timeout,
|
|
1029
1160
|
// Private
|
|
1030
1161
|
_updateFormatOut,
|
|
1031
1162
|
_setBooleanOption,
|
package/lib/sharp.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const platformAndArch = require('./platform')();
|
|
4
|
+
|
|
5
|
+
/* istanbul ignore next */
|
|
6
|
+
try {
|
|
7
|
+
module.exports = require(`../build/Release/sharp-${platformAndArch}.node`);
|
|
8
|
+
} catch (err) {
|
|
9
|
+
// Bail early if bindings aren't available
|
|
10
|
+
const help = ['', 'Something went wrong installing the "sharp" module', '', err.message, '', 'Possible solutions:'];
|
|
11
|
+
if (/dylib/.test(err.message) && /Incompatible library version/.test(err.message)) {
|
|
12
|
+
help.push('- Update Homebrew: "brew update && brew upgrade vips"');
|
|
13
|
+
} else {
|
|
14
|
+
help.push(
|
|
15
|
+
'- Install with the --verbose flag and look for errors: "npm install --ignore-scripts=false --verbose sharp"',
|
|
16
|
+
`- Install for the current runtime: "npm install --platform=${process.platform} --arch=${process.arch} sharp"`
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
help.push(
|
|
20
|
+
'- Consult the installation documentation: https://sharp.pixelplumbing.com/install'
|
|
21
|
+
);
|
|
22
|
+
// Check loaded
|
|
23
|
+
if (process.platform === 'win32') {
|
|
24
|
+
const loadedModule = Object.keys(require.cache).find((i) => /[\\/]build[\\/]Release[\\/]sharp(.*)\.node$/.test(i));
|
|
25
|
+
if (loadedModule) {
|
|
26
|
+
const [, loadedPackage] = loadedModule.match(/node_modules[\\/]([^\\/]+)[\\/]/);
|
|
27
|
+
help.push(`- Ensure the version of sharp aligns with the ${loadedPackage} package: "npm ls sharp"`);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
throw new Error(help.join('\n'));
|
|
31
|
+
}
|
package/lib/utility.js
CHANGED
|
@@ -4,7 +4,8 @@ const events = require('events');
|
|
|
4
4
|
const detectLibc = require('detect-libc');
|
|
5
5
|
|
|
6
6
|
const is = require('./is');
|
|
7
|
-
const
|
|
7
|
+
const platformAndArch = require('./platform')();
|
|
8
|
+
const sharp = require('./sharp');
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* An Object containing nested boolean values representing the available input and output formats/methods.
|
|
@@ -45,7 +46,7 @@ let versions = {
|
|
|
45
46
|
vips: sharp.libvipsVersion()
|
|
46
47
|
};
|
|
47
48
|
try {
|
|
48
|
-
versions = require(`../vendor/${versions.vips}/versions.json`);
|
|
49
|
+
versions = require(`../vendor/${versions.vips}/${platformAndArch}/versions.json`);
|
|
49
50
|
} catch (err) {}
|
|
50
51
|
|
|
51
52
|
/**
|
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.29.3",
|
|
5
5
|
"author": "Lovell Fuller <npm@lovell.info>",
|
|
6
6
|
"homepage": "https://github.com/lovell/sharp",
|
|
7
7
|
"contributors": [
|
|
@@ -77,7 +77,9 @@
|
|
|
77
77
|
"alza54 <alza54@thiocod.in>",
|
|
78
78
|
"Jacob Smith <jacob@frende.me>",
|
|
79
79
|
"Michael Nutt <michael@nutt.im>",
|
|
80
|
-
"Brad Parham <baparham@gmail.com>"
|
|
80
|
+
"Brad Parham <baparham@gmail.com>",
|
|
81
|
+
"Taneli Vatanen <taneli.vatanen@gmail.com>",
|
|
82
|
+
"Joris Dugué <zaruike10@gmail.com>"
|
|
81
83
|
],
|
|
82
84
|
"scripts": {
|
|
83
85
|
"install": "(node install/libvips && node install/dll-copy && prebuild-install) || (node install/can-compile && node-gyp rebuild && node install/dll-copy)",
|
|
@@ -111,6 +113,7 @@
|
|
|
111
113
|
"tiff",
|
|
112
114
|
"gif",
|
|
113
115
|
"svg",
|
|
116
|
+
"jp2",
|
|
114
117
|
"dzi",
|
|
115
118
|
"image",
|
|
116
119
|
"resize",
|
|
@@ -121,45 +124,45 @@
|
|
|
121
124
|
"vips"
|
|
122
125
|
],
|
|
123
126
|
"dependencies": {
|
|
124
|
-
"color": "^
|
|
127
|
+
"color": "^4.0.1",
|
|
125
128
|
"detect-libc": "^1.0.3",
|
|
126
|
-
"node-addon-api": "^
|
|
127
|
-
"prebuild-install": "^
|
|
129
|
+
"node-addon-api": "^4.2.0",
|
|
130
|
+
"prebuild-install": "^7.0.0",
|
|
128
131
|
"semver": "^7.3.5",
|
|
129
|
-
"simple-get": "^
|
|
132
|
+
"simple-get": "^4.0.0",
|
|
130
133
|
"tar-fs": "^2.1.1",
|
|
131
134
|
"tunnel-agent": "^0.6.0"
|
|
132
135
|
},
|
|
133
136
|
"devDependencies": {
|
|
134
|
-
"async": "^3.2.
|
|
137
|
+
"async": "^3.2.2",
|
|
135
138
|
"cc": "^3.0.1",
|
|
136
139
|
"decompress-zip": "^0.3.3",
|
|
137
140
|
"documentation": "^13.2.5",
|
|
138
141
|
"exif-reader": "^1.0.3",
|
|
139
142
|
"icc": "^2.0.0",
|
|
140
143
|
"license-checker": "^25.0.1",
|
|
141
|
-
"mocha": "^
|
|
142
|
-
"mock-fs": "^
|
|
144
|
+
"mocha": "^9.1.3",
|
|
145
|
+
"mock-fs": "^5.1.2",
|
|
143
146
|
"nyc": "^15.1.0",
|
|
144
|
-
"prebuild": "^
|
|
147
|
+
"prebuild": "^11.0.0",
|
|
145
148
|
"rimraf": "^3.0.2",
|
|
146
|
-
"semistandard": "^16.0.
|
|
149
|
+
"semistandard": "^16.0.1"
|
|
147
150
|
},
|
|
148
151
|
"license": "Apache-2.0",
|
|
149
152
|
"config": {
|
|
150
|
-
"libvips": "8.
|
|
153
|
+
"libvips": "8.11.3",
|
|
151
154
|
"runtime": "napi",
|
|
152
|
-
"target":
|
|
155
|
+
"target": 5
|
|
153
156
|
},
|
|
154
157
|
"engines": {
|
|
155
|
-
"node": ">=
|
|
158
|
+
"node": ">=12.13.0"
|
|
156
159
|
},
|
|
157
160
|
"funding": {
|
|
158
161
|
"url": "https://opencollective.com/libvips"
|
|
159
162
|
},
|
|
160
163
|
"binary": {
|
|
161
164
|
"napi_versions": [
|
|
162
|
-
|
|
165
|
+
5
|
|
163
166
|
]
|
|
164
167
|
},
|
|
165
168
|
"semistandard": {
|
package/src/common.cc
CHANGED
|
@@ -92,6 +92,9 @@ namespace sharp {
|
|
|
92
92
|
}
|
|
93
93
|
// Raw pixel input
|
|
94
94
|
if (HasAttr(input, "rawChannels")) {
|
|
95
|
+
descriptor->rawDepth = static_cast<VipsBandFormat>(
|
|
96
|
+
vips_enum_from_nick(nullptr, VIPS_TYPE_BAND_FORMAT,
|
|
97
|
+
AttrAsStr(input, "rawDepth").data()));
|
|
95
98
|
descriptor->rawChannels = AttrAsUint32(input, "rawChannels");
|
|
96
99
|
descriptor->rawWidth = AttrAsUint32(input, "rawWidth");
|
|
97
100
|
descriptor->rawHeight = AttrAsUint32(input, "rawHeight");
|
|
@@ -154,6 +157,10 @@ namespace sharp {
|
|
|
154
157
|
bool IsGif(std::string const &str) {
|
|
155
158
|
return EndsWith(str, ".gif") || EndsWith(str, ".GIF");
|
|
156
159
|
}
|
|
160
|
+
bool IsJp2(std::string const &str) {
|
|
161
|
+
return EndsWith(str, ".jp2") || EndsWith(str, ".jpx") || EndsWith(str, ".j2k") || EndsWith(str, ".j2c")
|
|
162
|
+
|| EndsWith(str, ".JP2") || EndsWith(str, ".JPX") || EndsWith(str, ".J2K") || EndsWith(str, ".J2C");
|
|
163
|
+
}
|
|
157
164
|
bool IsTiff(std::string const &str) {
|
|
158
165
|
return EndsWith(str, ".tif") || EndsWith(str, ".tiff") || EndsWith(str, ".TIF") || EndsWith(str, ".TIFF");
|
|
159
166
|
}
|
|
@@ -187,6 +194,7 @@ namespace sharp {
|
|
|
187
194
|
case ImageType::WEBP: id = "webp"; break;
|
|
188
195
|
case ImageType::TIFF: id = "tiff"; break;
|
|
189
196
|
case ImageType::GIF: id = "gif"; break;
|
|
197
|
+
case ImageType::JP2: id = "jp2"; break;
|
|
190
198
|
case ImageType::SVG: id = "svg"; break;
|
|
191
199
|
case ImageType::HEIF: id = "heif"; break;
|
|
192
200
|
case ImageType::PDF: id = "pdf"; break;
|
|
@@ -223,6 +231,8 @@ namespace sharp {
|
|
|
223
231
|
{ "VipsForeignLoadGifBuffer", ImageType::GIF },
|
|
224
232
|
{ "VipsForeignLoadNsgifFile", ImageType::GIF },
|
|
225
233
|
{ "VipsForeignLoadNsgifBuffer", ImageType::GIF },
|
|
234
|
+
{ "VipsForeignLoadJp2kBuffer", ImageType::JP2 },
|
|
235
|
+
{ "VipsForeignLoadJp2kFile", ImageType::JP2 },
|
|
226
236
|
{ "VipsForeignLoadSvgFile", ImageType::SVG },
|
|
227
237
|
{ "VipsForeignLoadSvgBuffer", ImageType::SVG },
|
|
228
238
|
{ "VipsForeignLoadHeifFile", ImageType::HEIF },
|
|
@@ -231,6 +241,8 @@ namespace sharp {
|
|
|
231
241
|
{ "VipsForeignLoadPdfBuffer", ImageType::PDF },
|
|
232
242
|
{ "VipsForeignLoadMagickFile", ImageType::MAGICK },
|
|
233
243
|
{ "VipsForeignLoadMagickBuffer", ImageType::MAGICK },
|
|
244
|
+
{ "VipsForeignLoadMagick7File", ImageType::MAGICK },
|
|
245
|
+
{ "VipsForeignLoadMagick7Buffer", ImageType::MAGICK },
|
|
234
246
|
{ "VipsForeignLoadOpenslide", ImageType::OPENSLIDE },
|
|
235
247
|
{ "VipsForeignLoadPpmFile", ImageType::PPM },
|
|
236
248
|
{ "VipsForeignLoadFits", ImageType::FITS },
|
|
@@ -282,6 +294,7 @@ namespace sharp {
|
|
|
282
294
|
imageType == ImageType::WEBP ||
|
|
283
295
|
imageType == ImageType::MAGICK ||
|
|
284
296
|
imageType == ImageType::GIF ||
|
|
297
|
+
imageType == ImageType::JP2 ||
|
|
285
298
|
imageType == ImageType::TIFF ||
|
|
286
299
|
imageType == ImageType::HEIF ||
|
|
287
300
|
imageType == ImageType::PDF;
|
|
@@ -297,7 +310,7 @@ namespace sharp {
|
|
|
297
310
|
if (descriptor->rawChannels > 0) {
|
|
298
311
|
// Raw, uncompressed pixel data
|
|
299
312
|
image = VImage::new_from_memory(descriptor->buffer, descriptor->bufferLength,
|
|
300
|
-
descriptor->rawWidth, descriptor->rawHeight, descriptor->rawChannels,
|
|
313
|
+
descriptor->rawWidth, descriptor->rawHeight, descriptor->rawChannels, descriptor->rawDepth);
|
|
301
314
|
if (descriptor->rawChannels < 3) {
|
|
302
315
|
image.get_image()->Type = VIPS_INTERPRETATION_B_W;
|
|
303
316
|
} else {
|
|
@@ -505,6 +518,17 @@ namespace sharp {
|
|
|
505
518
|
return copy;
|
|
506
519
|
}
|
|
507
520
|
|
|
521
|
+
/*
|
|
522
|
+
Remove animation properties from image.
|
|
523
|
+
*/
|
|
524
|
+
VImage RemoveAnimationProperties(VImage image) {
|
|
525
|
+
VImage copy = image.copy();
|
|
526
|
+
copy.remove(VIPS_META_PAGE_HEIGHT);
|
|
527
|
+
copy.remove("delay");
|
|
528
|
+
copy.remove("loop");
|
|
529
|
+
return copy;
|
|
530
|
+
}
|
|
531
|
+
|
|
508
532
|
/*
|
|
509
533
|
Does this image have a non-default density?
|
|
510
534
|
*/
|
|
@@ -586,6 +610,33 @@ namespace sharp {
|
|
|
586
610
|
return warning;
|
|
587
611
|
}
|
|
588
612
|
|
|
613
|
+
/*
|
|
614
|
+
Attach an event listener for progress updates, used to detect timeout
|
|
615
|
+
*/
|
|
616
|
+
void SetTimeout(VImage image, int const seconds) {
|
|
617
|
+
if (seconds > 0) {
|
|
618
|
+
VipsImage *im = image.get_image();
|
|
619
|
+
if (im->progress_signal == NULL) {
|
|
620
|
+
int *timeout = VIPS_NEW(im, int);
|
|
621
|
+
*timeout = seconds;
|
|
622
|
+
g_signal_connect(im, "eval", G_CALLBACK(VipsProgressCallBack), timeout);
|
|
623
|
+
vips_image_set_progress(im, TRUE);
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
/*
|
|
629
|
+
Event listener for progress updates, used to detect timeout
|
|
630
|
+
*/
|
|
631
|
+
void VipsProgressCallBack(VipsImage *im, VipsProgress *progress, int *timeout) {
|
|
632
|
+
// printf("VipsProgressCallBack progress=%d run=%d timeout=%d\n", progress->percent, progress->run, *timeout);
|
|
633
|
+
if (*timeout > 0 && progress->run >= *timeout) {
|
|
634
|
+
vips_image_set_kill(im, TRUE);
|
|
635
|
+
vips_error("timeout", "%d%% complete", progress->percent);
|
|
636
|
+
*timeout = 0;
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
|
|
589
640
|
/*
|
|
590
641
|
Calculate the (left, top) coordinates of the output image
|
|
591
642
|
within the input image, applying the given gravity during an embed.
|
|
@@ -754,23 +805,27 @@ namespace sharp {
|
|
|
754
805
|
/*
|
|
755
806
|
Convert RGBA value to another colourspace
|
|
756
807
|
*/
|
|
757
|
-
std::vector<double> GetRgbaAsColourspace(std::vector<double> const rgba,
|
|
808
|
+
std::vector<double> GetRgbaAsColourspace(std::vector<double> const rgba,
|
|
809
|
+
VipsInterpretation const interpretation, bool premultiply) {
|
|
758
810
|
int const bands = static_cast<int>(rgba.size());
|
|
759
|
-
if (bands < 3
|
|
811
|
+
if (bands < 3) {
|
|
760
812
|
return rgba;
|
|
761
|
-
} else {
|
|
762
|
-
VImage pixel = VImage::new_matrix(1, 1);
|
|
763
|
-
pixel.set("bands", bands);
|
|
764
|
-
pixel = pixel.new_from_image(rgba);
|
|
765
|
-
pixel = pixel.colourspace(interpretation, VImage::option()->set("source_space", VIPS_INTERPRETATION_sRGB));
|
|
766
|
-
return pixel(0, 0);
|
|
767
813
|
}
|
|
814
|
+
VImage pixel = VImage::new_matrix(1, 1);
|
|
815
|
+
pixel.set("bands", bands);
|
|
816
|
+
pixel = pixel
|
|
817
|
+
.new_from_image(rgba)
|
|
818
|
+
.colourspace(interpretation, VImage::option()->set("source_space", VIPS_INTERPRETATION_sRGB));
|
|
819
|
+
if (premultiply) {
|
|
820
|
+
pixel = pixel.premultiply();
|
|
821
|
+
}
|
|
822
|
+
return pixel(0, 0);
|
|
768
823
|
}
|
|
769
824
|
|
|
770
825
|
/*
|
|
771
826
|
Apply the alpha channel to a given colour
|
|
772
827
|
*/
|
|
773
|
-
std::tuple<VImage, std::vector<double>> ApplyAlpha(VImage image, std::vector<double> colour) {
|
|
828
|
+
std::tuple<VImage, std::vector<double>> ApplyAlpha(VImage image, std::vector<double> colour, bool premultiply) {
|
|
774
829
|
// Scale up 8-bit values to match 16-bit input image
|
|
775
830
|
double const multiplier = sharp::Is16Bit(image.interpretation()) ? 256.0 : 1.0;
|
|
776
831
|
// Create alphaColour colour
|
|
@@ -794,7 +849,7 @@ namespace sharp {
|
|
|
794
849
|
alphaColour.push_back(colour[3] * multiplier);
|
|
795
850
|
}
|
|
796
851
|
// Ensure alphaColour colour uses correct colourspace
|
|
797
|
-
alphaColour = sharp::GetRgbaAsColourspace(alphaColour, image.interpretation());
|
|
852
|
+
alphaColour = sharp::GetRgbaAsColourspace(alphaColour, image.interpretation(), premultiply);
|
|
798
853
|
// Add non-transparent alpha channel, if required
|
|
799
854
|
if (colour[3] < 255.0 && !HasAlpha(image)) {
|
|
800
855
|
image = image.bandjoin(
|
|
@@ -824,4 +879,5 @@ namespace sharp {
|
|
|
824
879
|
}
|
|
825
880
|
return image;
|
|
826
881
|
}
|
|
882
|
+
|
|
827
883
|
} // namespace sharp
|
package/src/common.h
CHANGED
|
@@ -25,9 +25,9 @@
|
|
|
25
25
|
// Verify platform and compiler compatibility
|
|
26
26
|
|
|
27
27
|
#if (VIPS_MAJOR_VERSION < 8) || \
|
|
28
|
-
(VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION <
|
|
29
|
-
(VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION ==
|
|
30
|
-
#error "libvips version 8.
|
|
28
|
+
(VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION < 11) || \
|
|
29
|
+
(VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION == 11 && VIPS_MICRO_VERSION < 3)
|
|
30
|
+
#error "libvips version 8.11.3+ is required - please see https://sharp.pixelplumbing.com/install"
|
|
31
31
|
#endif
|
|
32
32
|
|
|
33
33
|
#if ((!defined(__clang__)) && defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 6)))
|
|
@@ -54,6 +54,7 @@ namespace sharp {
|
|
|
54
54
|
size_t bufferLength;
|
|
55
55
|
bool isBuffer;
|
|
56
56
|
double density;
|
|
57
|
+
VipsBandFormat rawDepth;
|
|
57
58
|
int rawChannels;
|
|
58
59
|
int rawWidth;
|
|
59
60
|
int rawHeight;
|
|
@@ -78,6 +79,7 @@ namespace sharp {
|
|
|
78
79
|
bufferLength(0),
|
|
79
80
|
isBuffer(FALSE),
|
|
80
81
|
density(72.0),
|
|
82
|
+
rawDepth(VIPS_FORMAT_UCHAR),
|
|
81
83
|
rawChannels(0),
|
|
82
84
|
rawWidth(0),
|
|
83
85
|
rawHeight(0),
|
|
@@ -114,6 +116,7 @@ namespace sharp {
|
|
|
114
116
|
JPEG,
|
|
115
117
|
PNG,
|
|
116
118
|
WEBP,
|
|
119
|
+
JP2,
|
|
117
120
|
TIFF,
|
|
118
121
|
GIF,
|
|
119
122
|
SVG,
|
|
@@ -140,6 +143,7 @@ namespace sharp {
|
|
|
140
143
|
bool IsJpeg(std::string const &str);
|
|
141
144
|
bool IsPng(std::string const &str);
|
|
142
145
|
bool IsWebp(std::string const &str);
|
|
146
|
+
bool IsJp2(std::string const &str);
|
|
143
147
|
bool IsGif(std::string const &str);
|
|
144
148
|
bool IsTiff(std::string const &str);
|
|
145
149
|
bool IsHeic(std::string const &str);
|
|
@@ -206,6 +210,11 @@ namespace sharp {
|
|
|
206
210
|
*/
|
|
207
211
|
VImage SetAnimationProperties(VImage image, int pageHeight, std::vector<int> delay, int loop);
|
|
208
212
|
|
|
213
|
+
/*
|
|
214
|
+
Remove animation properties from image.
|
|
215
|
+
*/
|
|
216
|
+
VImage RemoveAnimationProperties(VImage image);
|
|
217
|
+
|
|
209
218
|
/*
|
|
210
219
|
Does this image have a non-default density?
|
|
211
220
|
*/
|
|
@@ -241,6 +250,16 @@ namespace sharp {
|
|
|
241
250
|
*/
|
|
242
251
|
std::string VipsWarningPop();
|
|
243
252
|
|
|
253
|
+
/*
|
|
254
|
+
Attach an event listener for progress updates, used to detect timeout
|
|
255
|
+
*/
|
|
256
|
+
void SetTimeout(VImage image, int const timeoutSeconds);
|
|
257
|
+
|
|
258
|
+
/*
|
|
259
|
+
Event listener for progress updates, used to detect timeout
|
|
260
|
+
*/
|
|
261
|
+
void VipsProgressCallBack(VipsImage *image, VipsProgress *progress, int *timeoutSeconds);
|
|
262
|
+
|
|
244
263
|
/*
|
|
245
264
|
Calculate the (left, top) coordinates of the output image
|
|
246
265
|
within the input image, applying the given gravity during an embed.
|
|
@@ -286,12 +305,13 @@ namespace sharp {
|
|
|
286
305
|
/*
|
|
287
306
|
Convert RGBA value to another colourspace
|
|
288
307
|
*/
|
|
289
|
-
std::vector<double> GetRgbaAsColourspace(std::vector<double> const rgba,
|
|
308
|
+
std::vector<double> GetRgbaAsColourspace(std::vector<double> const rgba,
|
|
309
|
+
VipsInterpretation const interpretation, bool premultiply);
|
|
290
310
|
|
|
291
311
|
/*
|
|
292
312
|
Apply the alpha channel to a given colour
|
|
293
313
|
*/
|
|
294
|
-
std::tuple<VImage, std::vector<double>> ApplyAlpha(VImage image, std::vector<double> colour);
|
|
314
|
+
std::tuple<VImage, std::vector<double>> ApplyAlpha(VImage image, std::vector<double> colour, bool premultiply);
|
|
295
315
|
|
|
296
316
|
/*
|
|
297
317
|
Removes alpha channel, if any.
|