sharp 0.33.4-rc.0 → 0.33.5-rc.0
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/install/check.js +2 -2
- package/lib/constructor.js +2 -0
- package/lib/index.d.ts +22 -3
- package/lib/input.js +1 -0
- package/lib/libvips.js +10 -8
- package/lib/operation.js +55 -18
- package/lib/output.js +2 -0
- package/lib/sharp.js +2 -2
- package/lib/utility.js +7 -0
- package/package.json +38 -35
- package/src/binding.gyp +1 -1
- package/src/common.h +2 -2
- package/src/metadata.cc +33 -0
- package/src/metadata.h +3 -0
- package/src/operations.cc +20 -16
- package/src/operations.h +3 -3
- package/src/pipeline.cc +19 -6
- package/src/pipeline.h +8 -2
package/install/check.js
CHANGED
|
@@ -18,7 +18,7 @@ try {
|
|
|
18
18
|
}
|
|
19
19
|
try {
|
|
20
20
|
const gyp = require('node-gyp');
|
|
21
|
-
log(`Found node-gyp
|
|
21
|
+
log(`Found node-gyp ${gyp().version}`);
|
|
22
22
|
} catch (err) {
|
|
23
23
|
log('Please add node-gyp to your dependencies');
|
|
24
24
|
return;
|
|
@@ -30,7 +30,7 @@ try {
|
|
|
30
30
|
}
|
|
31
31
|
};
|
|
32
32
|
|
|
33
|
-
if (useGlobalLibvips()) {
|
|
33
|
+
if (useGlobalLibvips(log)) {
|
|
34
34
|
buildFromSource(`Detected globally-installed libvips v${globalLibvipsVersion()}`);
|
|
35
35
|
} else if (process.env.npm_config_build_from_source) {
|
|
36
36
|
buildFromSource('Detected --build-from-source flag');
|
package/lib/constructor.js
CHANGED
package/lib/index.d.ts
CHANGED
|
@@ -464,7 +464,7 @@ declare namespace sharp {
|
|
|
464
464
|
* @throws {Error} Invalid parameters
|
|
465
465
|
* @returns A sharp instance that can be used to chain operations
|
|
466
466
|
*/
|
|
467
|
-
blur(sigma?: number | boolean): Sharp;
|
|
467
|
+
blur(sigma?: number | boolean | BlurOptions): Sharp;
|
|
468
468
|
|
|
469
469
|
/**
|
|
470
470
|
* Merge alpha transparency channel, if any, with background.
|
|
@@ -571,11 +571,11 @@ declare namespace sharp {
|
|
|
571
571
|
|
|
572
572
|
/**
|
|
573
573
|
* Recomb the image with the specified matrix.
|
|
574
|
-
* @param inputMatrix 3x3 Recombination matrix
|
|
574
|
+
* @param inputMatrix 3x3 Recombination matrix or 4x4 Recombination matrix
|
|
575
575
|
* @throws {Error} Invalid parameters
|
|
576
576
|
* @returns A sharp instance that can be used to chain operations
|
|
577
577
|
*/
|
|
578
|
-
recomb(inputMatrix: Matrix3x3): Sharp;
|
|
578
|
+
recomb(inputMatrix: Matrix3x3 | Matrix4x4): Sharp;
|
|
579
579
|
|
|
580
580
|
/**
|
|
581
581
|
* Transforms the image using brightness, saturation, hue rotation and lightness.
|
|
@@ -1108,6 +1108,8 @@ declare namespace sharp {
|
|
|
1108
1108
|
resolutionUnit?: 'inch' | 'cm' | undefined;
|
|
1109
1109
|
/** String containing format for images loaded via *magick */
|
|
1110
1110
|
formatMagick?: string | undefined;
|
|
1111
|
+
/** Array of keyword/text pairs representing PNG text blocks, if present. */
|
|
1112
|
+
comments?: CommentsMetadata[] | undefined;
|
|
1111
1113
|
}
|
|
1112
1114
|
|
|
1113
1115
|
interface LevelMetadata {
|
|
@@ -1115,6 +1117,11 @@ declare namespace sharp {
|
|
|
1115
1117
|
height: number;
|
|
1116
1118
|
}
|
|
1117
1119
|
|
|
1120
|
+
interface CommentsMetadata {
|
|
1121
|
+
keyword: string;
|
|
1122
|
+
text: string;
|
|
1123
|
+
}
|
|
1124
|
+
|
|
1118
1125
|
interface Stats {
|
|
1119
1126
|
/** Array of channel statistics for each channel in the image. */
|
|
1120
1127
|
channels: ChannelStats[];
|
|
@@ -1335,6 +1342,17 @@ declare namespace sharp {
|
|
|
1335
1342
|
background?: Color | undefined;
|
|
1336
1343
|
}
|
|
1337
1344
|
|
|
1345
|
+
type Precision = 'integer' | 'float' | 'approximate';
|
|
1346
|
+
|
|
1347
|
+
interface BlurOptions {
|
|
1348
|
+
/** A value between 0.3 and 1000 representing the sigma of the Gaussian mask, where `sigma = 1 + radius / 2` */
|
|
1349
|
+
sigma: number;
|
|
1350
|
+
/** A value between 0.001 and 1. A smaller value will generate a larger, more accurate mask. */
|
|
1351
|
+
minAmplitude?: number;
|
|
1352
|
+
/** How accurate the operation should be, one of: integer, float, approximate. (optional, default "integer") */
|
|
1353
|
+
precision?: Precision | undefined;
|
|
1354
|
+
}
|
|
1355
|
+
|
|
1338
1356
|
interface FlattenOptions {
|
|
1339
1357
|
/** background colour, parsed by the color module, defaults to black. (optional, default {r:0,g:0,b:0}) */
|
|
1340
1358
|
background?: Color | undefined;
|
|
@@ -1730,6 +1748,7 @@ declare namespace sharp {
|
|
|
1730
1748
|
|
|
1731
1749
|
type Matrix2x2 = [[number, number], [number, number]];
|
|
1732
1750
|
type Matrix3x3 = [[number, number, number], [number, number, number], [number, number, number]];
|
|
1751
|
+
type Matrix4x4 = [[number, number, number, number], [number, number, number, number], [number, number, number, number], [number, number, number, number]];
|
|
1733
1752
|
}
|
|
1734
1753
|
|
|
1735
1754
|
export = sharp;
|
package/lib/input.js
CHANGED
|
@@ -450,6 +450,7 @@ function _isStreamInput () {
|
|
|
450
450
|
* - `xmp`: Buffer containing raw XMP data, if present
|
|
451
451
|
* - `tifftagPhotoshop`: Buffer containing raw TIFFTAG_PHOTOSHOP data, if present
|
|
452
452
|
* - `formatMagick`: String containing format for images loaded via *magick
|
|
453
|
+
* - `comments`: Array of keyword/text pairs representing PNG text blocks, if present.
|
|
453
454
|
*
|
|
454
455
|
* @example
|
|
455
456
|
* const metadata = await sharp(input).metadata();
|
package/lib/libvips.js
CHANGED
|
@@ -10,10 +10,10 @@ const semverGreaterThanOrEqualTo = require('semver/functions/gte');
|
|
|
10
10
|
const semverSatisfies = require('semver/functions/satisfies');
|
|
11
11
|
const detectLibc = require('detect-libc');
|
|
12
12
|
|
|
13
|
-
const { engines, optionalDependencies } = require('../package.json');
|
|
13
|
+
const { config, engines, optionalDependencies } = require('../package.json');
|
|
14
14
|
|
|
15
15
|
const minimumLibvipsVersionLabelled = process.env.npm_package_config_libvips || /* istanbul ignore next */
|
|
16
|
-
|
|
16
|
+
config.libvips;
|
|
17
17
|
const minimumLibvipsVersion = semverCoerce(minimumLibvipsVersionLabelled).version;
|
|
18
18
|
|
|
19
19
|
const prebuiltPlatforms = [
|
|
@@ -162,21 +162,23 @@ const pkgConfigPath = () => {
|
|
|
162
162
|
}
|
|
163
163
|
};
|
|
164
164
|
|
|
165
|
-
const skipSearch = (status, reason) => {
|
|
166
|
-
|
|
165
|
+
const skipSearch = (status, reason, logger) => {
|
|
166
|
+
if (logger) {
|
|
167
|
+
logger(`Detected ${reason}, skipping search for globally-installed libvips`);
|
|
168
|
+
}
|
|
167
169
|
return status;
|
|
168
170
|
};
|
|
169
171
|
|
|
170
|
-
const useGlobalLibvips = () => {
|
|
172
|
+
const useGlobalLibvips = (logger) => {
|
|
171
173
|
if (Boolean(process.env.SHARP_IGNORE_GLOBAL_LIBVIPS) === true) {
|
|
172
|
-
return skipSearch(false, 'SHARP_IGNORE_GLOBAL_LIBVIPS');
|
|
174
|
+
return skipSearch(false, 'SHARP_IGNORE_GLOBAL_LIBVIPS', logger);
|
|
173
175
|
}
|
|
174
176
|
if (Boolean(process.env.SHARP_FORCE_GLOBAL_LIBVIPS) === true) {
|
|
175
|
-
return skipSearch(true, 'SHARP_FORCE_GLOBAL_LIBVIPS');
|
|
177
|
+
return skipSearch(true, 'SHARP_FORCE_GLOBAL_LIBVIPS', logger);
|
|
176
178
|
}
|
|
177
179
|
/* istanbul ignore next */
|
|
178
180
|
if (isRosetta()) {
|
|
179
|
-
return skipSearch(false, 'Rosetta');
|
|
181
|
+
return skipSearch(false, 'Rosetta', logger);
|
|
180
182
|
}
|
|
181
183
|
const globalVipsVersion = globalLibvipsVersion();
|
|
182
184
|
return !!globalVipsVersion && /* istanbul ignore next */
|
package/lib/operation.js
CHANGED
|
@@ -6,6 +6,17 @@
|
|
|
6
6
|
const color = require('color');
|
|
7
7
|
const is = require('./is');
|
|
8
8
|
|
|
9
|
+
/**
|
|
10
|
+
* How accurate an operation should be.
|
|
11
|
+
* @member
|
|
12
|
+
* @private
|
|
13
|
+
*/
|
|
14
|
+
const vipsPrecision = {
|
|
15
|
+
integer: 'integer',
|
|
16
|
+
float: 'float',
|
|
17
|
+
approximate: 'approximate'
|
|
18
|
+
};
|
|
19
|
+
|
|
9
20
|
/**
|
|
10
21
|
* Rotate the output image by either an explicit angle
|
|
11
22
|
* or auto-orient based on the EXIF `Orientation` tag.
|
|
@@ -367,23 +378,51 @@ function median (size) {
|
|
|
367
378
|
* .blur(5)
|
|
368
379
|
* .toBuffer();
|
|
369
380
|
*
|
|
370
|
-
* @param {number} [
|
|
381
|
+
* @param {Object|number|Boolean} [options]
|
|
382
|
+
* @param {number} [options.sigma] a value between 0.3 and 1000 representing the sigma of the Gaussian mask, where `sigma = 1 + radius / 2`.
|
|
383
|
+
* @param {string} [options.precision='integer'] How accurate the operation should be, one of: integer, float, approximate.
|
|
384
|
+
* @param {number} [options.minAmplitude=0.2] A value between 0.001 and 1. A smaller value will generate a larger, more accurate mask.
|
|
371
385
|
* @returns {Sharp}
|
|
372
386
|
* @throws {Error} Invalid parameters
|
|
373
387
|
*/
|
|
374
|
-
function blur (
|
|
375
|
-
|
|
388
|
+
function blur (options) {
|
|
389
|
+
let sigma;
|
|
390
|
+
if (is.number(options)) {
|
|
391
|
+
sigma = options;
|
|
392
|
+
} else if (is.plainObject(options)) {
|
|
393
|
+
if (!is.number(options.sigma)) {
|
|
394
|
+
throw is.invalidParameterError('options.sigma', 'number between 0.3 and 1000', sigma);
|
|
395
|
+
}
|
|
396
|
+
sigma = options.sigma;
|
|
397
|
+
if ('precision' in options) {
|
|
398
|
+
if (is.string(vipsPrecision[options.precision])) {
|
|
399
|
+
this.options.precision = vipsPrecision[options.precision];
|
|
400
|
+
} else {
|
|
401
|
+
throw is.invalidParameterError('precision', 'one of: integer, float, approximate', options.precision);
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
if ('minAmplitude' in options) {
|
|
405
|
+
if (is.number(options.minAmplitude) && is.inRange(options.minAmplitude, 0.001, 1)) {
|
|
406
|
+
this.options.minAmpl = options.minAmplitude;
|
|
407
|
+
} else {
|
|
408
|
+
throw is.invalidParameterError('minAmplitude', 'number between 0.001 and 1', options.minAmplitude);
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
if (!is.defined(options)) {
|
|
376
414
|
// No arguments: default to mild blur
|
|
377
415
|
this.options.blurSigma = -1;
|
|
378
|
-
} else if (is.bool(
|
|
416
|
+
} else if (is.bool(options)) {
|
|
379
417
|
// Boolean argument: apply mild blur?
|
|
380
|
-
this.options.blurSigma =
|
|
418
|
+
this.options.blurSigma = options ? -1 : 0;
|
|
381
419
|
} else if (is.number(sigma) && is.inRange(sigma, 0.3, 1000)) {
|
|
382
420
|
// Numeric argument: specific sigma
|
|
383
421
|
this.options.blurSigma = sigma;
|
|
384
422
|
} else {
|
|
385
423
|
throw is.invalidParameterError('sigma', 'number between 0.3 and 1000', sigma);
|
|
386
424
|
}
|
|
425
|
+
|
|
387
426
|
return this;
|
|
388
427
|
}
|
|
389
428
|
|
|
@@ -787,24 +826,22 @@ function linear (a, b) {
|
|
|
787
826
|
* // With this example input, a sepia filter has been applied
|
|
788
827
|
* });
|
|
789
828
|
*
|
|
790
|
-
* @param {Array<Array<number>>} inputMatrix - 3x3 Recombination matrix
|
|
829
|
+
* @param {Array<Array<number>>} inputMatrix - 3x3 or 4x4 Recombination matrix
|
|
791
830
|
* @returns {Sharp}
|
|
792
831
|
* @throws {Error} Invalid parameters
|
|
793
832
|
*/
|
|
794
833
|
function recomb (inputMatrix) {
|
|
795
|
-
if (!Array.isArray(inputMatrix)
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
834
|
+
if (!Array.isArray(inputMatrix)) {
|
|
835
|
+
throw is.invalidParameterError('inputMatrix', 'array', inputMatrix);
|
|
836
|
+
}
|
|
837
|
+
if (inputMatrix.length !== 3 && inputMatrix.length !== 4) {
|
|
838
|
+
throw is.invalidParameterError('inputMatrix', '3x3 or 4x4 array', inputMatrix.length);
|
|
839
|
+
}
|
|
840
|
+
const recombMatrix = inputMatrix.flat().map(Number);
|
|
841
|
+
if (recombMatrix.length !== 9 && recombMatrix.length !== 16) {
|
|
842
|
+
throw is.invalidParameterError('inputMatrix', 'cardinality of 9 or 16', recombMatrix.length);
|
|
802
843
|
}
|
|
803
|
-
this.options.recombMatrix =
|
|
804
|
-
inputMatrix[0][0], inputMatrix[0][1], inputMatrix[0][2],
|
|
805
|
-
inputMatrix[1][0], inputMatrix[1][1], inputMatrix[1][2],
|
|
806
|
-
inputMatrix[2][0], inputMatrix[2][1], inputMatrix[2][2]
|
|
807
|
-
].map(Number);
|
|
844
|
+
this.options.recombMatrix = recombMatrix;
|
|
808
845
|
return this;
|
|
809
846
|
}
|
|
810
847
|
|
package/lib/output.js
CHANGED
|
@@ -65,6 +65,7 @@ const bitdepthFromColourCount = (colours) => 1 << 31 - Math.clz32(Math.ceil(Math
|
|
|
65
65
|
* `channels` and `premultiplied` (indicating if premultiplication was used).
|
|
66
66
|
* When using a crop strategy also contains `cropOffsetLeft` and `cropOffsetTop`.
|
|
67
67
|
* When using the attention crop strategy also contains `attentionX` and `attentionY`, the focal point of the cropped region.
|
|
68
|
+
* Animated output will also contain `pageHeight` and `pages`.
|
|
68
69
|
* May also contain `textAutofitDpi` (dpi the font was rendered at) if image was created from text.
|
|
69
70
|
* @returns {Promise<Object>} - when no callback is provided
|
|
70
71
|
* @throws {Error} Invalid parameters
|
|
@@ -109,6 +110,7 @@ function toFile (fileOut, callback) {
|
|
|
109
110
|
* - `info` contains the output image `format`, `size` (bytes), `width`, `height`,
|
|
110
111
|
* `channels` and `premultiplied` (indicating if premultiplication was used).
|
|
111
112
|
* When using a crop strategy also contains `cropOffsetLeft` and `cropOffsetTop`.
|
|
113
|
+
* Animated output will also contain `pageHeight` and `pages`.
|
|
112
114
|
* May also contain `textAutofitDpi` (dpi the font was rendered at) if image was created from text.
|
|
113
115
|
*
|
|
114
116
|
* A `Promise` is returned when `callback` is not provided.
|
package/lib/sharp.js
CHANGED
|
@@ -73,9 +73,9 @@ if (sharp) {
|
|
|
73
73
|
}
|
|
74
74
|
if (isLinux && /(symbol not found|CXXABI_)/i.test(messages)) {
|
|
75
75
|
try {
|
|
76
|
-
const {
|
|
76
|
+
const { config } = require(`@img/sharp-libvips-${runtimePlatform}/package`);
|
|
77
77
|
const libcFound = `${familySync()} ${versionSync()}`;
|
|
78
|
-
const libcRequires = `${
|
|
78
|
+
const libcRequires = `${config.musl ? 'musl' : 'glibc'} ${config.musl || config.glibc}`;
|
|
79
79
|
help.push(
|
|
80
80
|
'- Update your OS:',
|
|
81
81
|
` Found ${libcFound}`,
|
package/lib/utility.js
CHANGED
|
@@ -75,6 +75,13 @@ if (!libvipsVersion.isGlobal) {
|
|
|
75
75
|
}
|
|
76
76
|
versions.sharp = require('../package.json').version;
|
|
77
77
|
|
|
78
|
+
/* istanbul ignore next */
|
|
79
|
+
if (versions.heif && format.heif) {
|
|
80
|
+
// Prebuilt binaries provide AV1
|
|
81
|
+
format.heif.input.fileSuffix = ['.avif'];
|
|
82
|
+
format.heif.output.alias = ['avif'];
|
|
83
|
+
}
|
|
84
|
+
|
|
78
85
|
/**
|
|
79
86
|
* Gets or, when options are provided, sets the limits of _libvips'_ operation cache.
|
|
80
87
|
* Existing entries in the cache will be trimmed after any change in limits.
|
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, GIF, AVIF and TIFF images",
|
|
4
|
-
"version": "0.33.
|
|
4
|
+
"version": "0.33.5-rc.0",
|
|
5
5
|
"author": "Lovell Fuller <npm@lovell.info>",
|
|
6
6
|
"homepage": "https://sharp.pixelplumbing.com",
|
|
7
7
|
"contributors": [
|
|
@@ -88,7 +88,8 @@
|
|
|
88
88
|
"Mart Jansink <m.jansink@gmail.com>",
|
|
89
89
|
"Lachlan Newman <lachnewman007@gmail.com>",
|
|
90
90
|
"Dennis Beatty <dennis@dcbeatty.com>",
|
|
91
|
-
"Ingvar Stepanyan <me@rreverser.com>"
|
|
91
|
+
"Ingvar Stepanyan <me@rreverser.com>",
|
|
92
|
+
"Don Denton <don@happycollision.com>"
|
|
92
93
|
],
|
|
93
94
|
"scripts": {
|
|
94
95
|
"install": "node install/check",
|
|
@@ -138,56 +139,58 @@
|
|
|
138
139
|
"dependencies": {
|
|
139
140
|
"color": "^4.2.3",
|
|
140
141
|
"detect-libc": "^2.0.3",
|
|
141
|
-
"semver": "^7.6.
|
|
142
|
+
"semver": "^7.6.3"
|
|
142
143
|
},
|
|
143
144
|
"optionalDependencies": {
|
|
144
|
-
"@img/sharp-darwin-arm64": "0.33.
|
|
145
|
-
"@img/sharp-darwin-x64": "0.33.
|
|
146
|
-
"@img/sharp-libvips-darwin-arm64": "1.0.
|
|
147
|
-
"@img/sharp-libvips-darwin-x64": "1.0.
|
|
148
|
-
"@img/sharp-libvips-linux-arm": "1.0.
|
|
149
|
-
"@img/sharp-libvips-linux-arm64": "1.0.
|
|
150
|
-
"@img/sharp-libvips-linux-s390x": "1.0.
|
|
151
|
-
"@img/sharp-libvips-linux-x64": "1.0.
|
|
152
|
-
"@img/sharp-libvips-linuxmusl-arm64": "1.0.
|
|
153
|
-
"@img/sharp-libvips-linuxmusl-x64": "1.0.
|
|
154
|
-
"@img/sharp-linux-arm": "0.33.
|
|
155
|
-
"@img/sharp-linux-arm64": "0.33.
|
|
156
|
-
"@img/sharp-linux-s390x": "0.33.
|
|
157
|
-
"@img/sharp-linux-x64": "0.33.
|
|
158
|
-
"@img/sharp-linuxmusl-arm64": "0.33.
|
|
159
|
-
"@img/sharp-linuxmusl-x64": "0.33.
|
|
160
|
-
"@img/sharp-wasm32": "0.33.
|
|
161
|
-
"@img/sharp-win32-ia32": "0.33.
|
|
162
|
-
"@img/sharp-win32-x64": "0.33.
|
|
145
|
+
"@img/sharp-darwin-arm64": "0.33.5-rc.0",
|
|
146
|
+
"@img/sharp-darwin-x64": "0.33.5-rc.0",
|
|
147
|
+
"@img/sharp-libvips-darwin-arm64": "1.0.4",
|
|
148
|
+
"@img/sharp-libvips-darwin-x64": "1.0.4",
|
|
149
|
+
"@img/sharp-libvips-linux-arm": "1.0.5",
|
|
150
|
+
"@img/sharp-libvips-linux-arm64": "1.0.4",
|
|
151
|
+
"@img/sharp-libvips-linux-s390x": "1.0.4",
|
|
152
|
+
"@img/sharp-libvips-linux-x64": "1.0.4",
|
|
153
|
+
"@img/sharp-libvips-linuxmusl-arm64": "1.0.4",
|
|
154
|
+
"@img/sharp-libvips-linuxmusl-x64": "1.0.4",
|
|
155
|
+
"@img/sharp-linux-arm": "0.33.5-rc.0",
|
|
156
|
+
"@img/sharp-linux-arm64": "0.33.5-rc.0",
|
|
157
|
+
"@img/sharp-linux-s390x": "0.33.5-rc.0",
|
|
158
|
+
"@img/sharp-linux-x64": "0.33.5-rc.0",
|
|
159
|
+
"@img/sharp-linuxmusl-arm64": "0.33.5-rc.0",
|
|
160
|
+
"@img/sharp-linuxmusl-x64": "0.33.5-rc.0",
|
|
161
|
+
"@img/sharp-wasm32": "0.33.5-rc.0",
|
|
162
|
+
"@img/sharp-win32-ia32": "0.33.5-rc.0",
|
|
163
|
+
"@img/sharp-win32-x64": "0.33.5-rc.0"
|
|
163
164
|
},
|
|
164
165
|
"devDependencies": {
|
|
165
|
-
"@emnapi/runtime": "^1.
|
|
166
|
-
"@img/sharp-libvips-dev": "1.0.
|
|
167
|
-
"@img/sharp-libvips-dev-wasm32": "1.0.
|
|
168
|
-
"@img/sharp-libvips-win32-ia32": "1.0.
|
|
169
|
-
"@img/sharp-libvips-win32-x64": "1.0.
|
|
166
|
+
"@emnapi/runtime": "^1.2.0",
|
|
167
|
+
"@img/sharp-libvips-dev": "1.0.4",
|
|
168
|
+
"@img/sharp-libvips-dev-wasm32": "1.0.5",
|
|
169
|
+
"@img/sharp-libvips-win32-ia32": "1.0.4",
|
|
170
|
+
"@img/sharp-libvips-win32-x64": "1.0.4",
|
|
170
171
|
"@types/node": "*",
|
|
171
172
|
"async": "^3.2.5",
|
|
172
173
|
"cc": "^3.0.1",
|
|
173
|
-
"emnapi": "^1.
|
|
174
|
+
"emnapi": "^1.2.0",
|
|
174
175
|
"exif-reader": "^2.0.1",
|
|
175
176
|
"extract-zip": "^2.0.1",
|
|
176
177
|
"icc": "^3.0.0",
|
|
177
|
-
"jsdoc-to-markdown": "^8.0.
|
|
178
|
+
"jsdoc-to-markdown": "^8.0.3",
|
|
178
179
|
"license-checker": "^25.0.1",
|
|
179
|
-
"mocha": "^10.
|
|
180
|
-
"node-addon-api": "^8.
|
|
181
|
-
"nyc": "^
|
|
180
|
+
"mocha": "^10.7.3",
|
|
181
|
+
"node-addon-api": "^8.1.0",
|
|
182
|
+
"nyc": "^17.0.0",
|
|
182
183
|
"prebuild": "^13.0.1",
|
|
183
184
|
"semistandard": "^17.0.0",
|
|
184
185
|
"tar-fs": "^3.0.6",
|
|
185
|
-
"tsd": "^0.31.
|
|
186
|
+
"tsd": "^0.31.1"
|
|
186
187
|
},
|
|
187
188
|
"license": "Apache-2.0",
|
|
188
189
|
"engines": {
|
|
189
|
-
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
|
190
|
-
|
|
190
|
+
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
|
191
|
+
},
|
|
192
|
+
"config": {
|
|
193
|
+
"libvips": ">=8.15.3"
|
|
191
194
|
},
|
|
192
195
|
"funding": {
|
|
193
196
|
"url": "https://opencollective.com/libvips"
|
package/src/binding.gyp
CHANGED
|
@@ -192,7 +192,7 @@
|
|
|
192
192
|
'-Oz',
|
|
193
193
|
'-sALLOW_MEMORY_GROWTH',
|
|
194
194
|
'-sENVIRONMENT=node',
|
|
195
|
-
'-sEXPORTED_FUNCTIONS=["_vips_shutdown", "_uv_library_shutdown"]',
|
|
195
|
+
'-sEXPORTED_FUNCTIONS=["emnapiInit", "_vips_shutdown", "_uv_library_shutdown"]',
|
|
196
196
|
'-sNODERAWFS',
|
|
197
197
|
'-sTEXTDECODER=0',
|
|
198
198
|
'-sWASM_ASYNC_COMPILATION=0',
|
package/src/common.h
CHANGED
|
@@ -16,8 +16,8 @@
|
|
|
16
16
|
|
|
17
17
|
#if (VIPS_MAJOR_VERSION < 8) || \
|
|
18
18
|
(VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION < 15) || \
|
|
19
|
-
(VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION == 15 && VIPS_MICRO_VERSION <
|
|
20
|
-
#error "libvips version 8.15.
|
|
19
|
+
(VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION == 15 && VIPS_MICRO_VERSION < 3)
|
|
20
|
+
#error "libvips version 8.15.3+ is required - please see https://sharp.pixelplumbing.com/install"
|
|
21
21
|
#endif
|
|
22
22
|
|
|
23
23
|
#if ((!defined(__clang__)) && defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 6)))
|
package/src/metadata.cc
CHANGED
|
@@ -10,6 +10,8 @@
|
|
|
10
10
|
#include "common.h"
|
|
11
11
|
#include "metadata.h"
|
|
12
12
|
|
|
13
|
+
static void* readPNGComment(VipsImage *image, const char *field, GValue *value, void *p);
|
|
14
|
+
|
|
13
15
|
class MetadataWorker : public Napi::AsyncWorker {
|
|
14
16
|
public:
|
|
15
17
|
MetadataWorker(Napi::Function callback, MetadataBaton *baton, Napi::Function debuglog) :
|
|
@@ -131,6 +133,8 @@ class MetadataWorker : public Napi::AsyncWorker {
|
|
|
131
133
|
memcpy(baton->tifftagPhotoshop, tifftagPhotoshop, tifftagPhotoshopLength);
|
|
132
134
|
baton->tifftagPhotoshopLength = tifftagPhotoshopLength;
|
|
133
135
|
}
|
|
136
|
+
// PNG comments
|
|
137
|
+
vips_image_map(image.get_image(), readPNGComment, &baton->comments);
|
|
134
138
|
}
|
|
135
139
|
|
|
136
140
|
// Clean up
|
|
@@ -246,6 +250,17 @@ class MetadataWorker : public Napi::AsyncWorker {
|
|
|
246
250
|
Napi::Buffer<char>::NewOrCopy(env, baton->tifftagPhotoshop,
|
|
247
251
|
baton->tifftagPhotoshopLength, sharp::FreeCallback));
|
|
248
252
|
}
|
|
253
|
+
if (baton->comments.size() > 0) {
|
|
254
|
+
int i = 0;
|
|
255
|
+
Napi::Array comments = Napi::Array::New(env, baton->comments.size());
|
|
256
|
+
for (auto &c : baton->comments) {
|
|
257
|
+
Napi::Object comment = Napi::Object::New(env);
|
|
258
|
+
comment.Set("keyword", c.first);
|
|
259
|
+
comment.Set("text", c.second);
|
|
260
|
+
comments.Set(i++, comment);
|
|
261
|
+
}
|
|
262
|
+
info.Set("comments", comments);
|
|
263
|
+
}
|
|
249
264
|
Callback().Call(Receiver().Value(), { env.Null(), info });
|
|
250
265
|
} else {
|
|
251
266
|
Callback().Call(Receiver().Value(), { Napi::Error::New(env, sharp::TrimEnd(baton->err)).Value() });
|
|
@@ -285,3 +300,21 @@ Napi::Value metadata(const Napi::CallbackInfo& info) {
|
|
|
285
300
|
|
|
286
301
|
return info.Env().Undefined();
|
|
287
302
|
}
|
|
303
|
+
|
|
304
|
+
const char *PNG_COMMENT_START = "png-comment-";
|
|
305
|
+
const int PNG_COMMENT_START_LEN = strlen(PNG_COMMENT_START);
|
|
306
|
+
|
|
307
|
+
static void* readPNGComment(VipsImage *image, const char *field, GValue *value, void *p) {
|
|
308
|
+
MetadataComments *comments = static_cast<MetadataComments *>(p);
|
|
309
|
+
|
|
310
|
+
if (vips_isprefix(PNG_COMMENT_START, field)) {
|
|
311
|
+
const char *keyword = strchr(field + PNG_COMMENT_START_LEN, '-');
|
|
312
|
+
const char *str;
|
|
313
|
+
if (keyword != NULL && !vips_image_get_string(image, field, &str)) {
|
|
314
|
+
keyword++; // Skip the hyphen
|
|
315
|
+
comments->push_back(std::make_pair(keyword, str));
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
return NULL;
|
|
320
|
+
}
|
package/src/metadata.h
CHANGED
|
@@ -9,6 +9,8 @@
|
|
|
9
9
|
|
|
10
10
|
#include "./common.h"
|
|
11
11
|
|
|
12
|
+
typedef std::vector<std::pair<std::string, std::string>> MetadataComments;
|
|
13
|
+
|
|
12
14
|
struct MetadataBaton {
|
|
13
15
|
// Input
|
|
14
16
|
sharp::InputDescriptor *input;
|
|
@@ -47,6 +49,7 @@ struct MetadataBaton {
|
|
|
47
49
|
size_t xmpLength;
|
|
48
50
|
char *tifftagPhotoshop;
|
|
49
51
|
size_t tifftagPhotoshopLength;
|
|
52
|
+
MetadataComments comments;
|
|
50
53
|
std::string err;
|
|
51
54
|
|
|
52
55
|
MetadataBaton():
|
package/src/operations.cc
CHANGED
|
@@ -144,7 +144,7 @@ namespace sharp {
|
|
|
144
144
|
/*
|
|
145
145
|
* Gaussian blur. Use sigma of -1.0 for fast blur.
|
|
146
146
|
*/
|
|
147
|
-
VImage Blur(VImage image, double const sigma) {
|
|
147
|
+
VImage Blur(VImage image, double const sigma, VipsPrecision precision, double const minAmpl) {
|
|
148
148
|
if (sigma == -1.0) {
|
|
149
149
|
// Fast, mild blur - averages neighbouring pixels
|
|
150
150
|
VImage blur = VImage::new_matrixv(3, 3,
|
|
@@ -155,7 +155,9 @@ namespace sharp {
|
|
|
155
155
|
return image.conv(blur);
|
|
156
156
|
} else {
|
|
157
157
|
// Slower, accurate Gaussian blur
|
|
158
|
-
return StaySequential(image).gaussblur(sigma)
|
|
158
|
+
return StaySequential(image).gaussblur(sigma, VImage::option()
|
|
159
|
+
->set("precision", precision)
|
|
160
|
+
->set("min_ampl", minAmpl));
|
|
159
161
|
}
|
|
160
162
|
}
|
|
161
163
|
|
|
@@ -164,10 +166,10 @@ namespace sharp {
|
|
|
164
166
|
*/
|
|
165
167
|
VImage Convolve(VImage image, int const width, int const height,
|
|
166
168
|
double const scale, double const offset,
|
|
167
|
-
std::
|
|
169
|
+
std::vector<double> const &kernel_v
|
|
168
170
|
) {
|
|
169
171
|
VImage kernel = VImage::new_from_memory(
|
|
170
|
-
kernel_v.
|
|
172
|
+
static_cast<void*>(const_cast<double*>(kernel_v.data())),
|
|
171
173
|
width * height * sizeof(double),
|
|
172
174
|
width,
|
|
173
175
|
height,
|
|
@@ -183,19 +185,21 @@ namespace sharp {
|
|
|
183
185
|
* Recomb with a Matrix of the given bands/channel size.
|
|
184
186
|
* Eg. RGB will be a 3x3 matrix.
|
|
185
187
|
*/
|
|
186
|
-
VImage Recomb(VImage image, std::
|
|
187
|
-
double
|
|
188
|
+
VImage Recomb(VImage image, std::vector<double> const& matrix) {
|
|
189
|
+
double* m = const_cast<double*>(matrix.data());
|
|
188
190
|
image = image.colourspace(VIPS_INTERPRETATION_sRGB);
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
191
|
+
if (matrix.size() == 9) {
|
|
192
|
+
return image
|
|
193
|
+
.recomb(image.bands() == 3
|
|
194
|
+
? VImage::new_matrix(3, 3, m, 9)
|
|
195
|
+
: VImage::new_matrixv(4, 4,
|
|
196
|
+
m[0], m[1], m[2], 0.0,
|
|
197
|
+
m[3], m[4], m[5], 0.0,
|
|
198
|
+
m[6], m[7], m[8], 0.0,
|
|
199
|
+
0.0, 0.0, 0.0, 1.0));
|
|
200
|
+
} else {
|
|
201
|
+
return image.recomb(VImage::new_matrix(4, 4, m, 16));
|
|
202
|
+
}
|
|
199
203
|
}
|
|
200
204
|
|
|
201
205
|
VImage Modulate(VImage image, double const brightness, double const saturation,
|
package/src/operations.h
CHANGED
|
@@ -47,13 +47,13 @@ namespace sharp {
|
|
|
47
47
|
/*
|
|
48
48
|
* Gaussian blur. Use sigma of -1.0 for fast blur.
|
|
49
49
|
*/
|
|
50
|
-
VImage Blur(VImage image, double const sigma);
|
|
50
|
+
VImage Blur(VImage image, double const sigma, VipsPrecision precision, double const minAmpl);
|
|
51
51
|
|
|
52
52
|
/*
|
|
53
53
|
* Convolution with a kernel.
|
|
54
54
|
*/
|
|
55
55
|
VImage Convolve(VImage image, int const width, int const height,
|
|
56
|
-
double const scale, double const offset, std::
|
|
56
|
+
double const scale, double const offset, std::vector<double> const &kernel_v);
|
|
57
57
|
|
|
58
58
|
/*
|
|
59
59
|
* Sharpen flat and jagged areas. Use sigma of -1.0 for fast sharpen.
|
|
@@ -95,7 +95,7 @@ namespace sharp {
|
|
|
95
95
|
* Recomb with a Matrix of the given bands/channel size.
|
|
96
96
|
* Eg. RGB will be a 3x3 matrix.
|
|
97
97
|
*/
|
|
98
|
-
VImage Recomb(VImage image, std::
|
|
98
|
+
VImage Recomb(VImage image, std::vector<double> const &matrix);
|
|
99
99
|
|
|
100
100
|
/*
|
|
101
101
|
* Modulate brightness, saturation, hue and lightness
|
package/src/pipeline.cc
CHANGED
|
@@ -325,6 +325,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
325
325
|
if ((baton->keepMetadata & VIPS_FOREIGN_KEEP_ICC) && baton->withIccProfile.empty()) {
|
|
326
326
|
// Cache input profile for use with output
|
|
327
327
|
inputProfile = sharp::GetProfile(image);
|
|
328
|
+
baton->input->ignoreIcc = true;
|
|
328
329
|
}
|
|
329
330
|
char const *processingProfile = image.interpretation() == VIPS_INTERPRETATION_RGB16 ? "p3" : "srgb";
|
|
330
331
|
if (
|
|
@@ -592,7 +593,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
592
593
|
|
|
593
594
|
// Blur
|
|
594
595
|
if (shouldBlur) {
|
|
595
|
-
image = sharp::Blur(image, baton->blurSigma);
|
|
596
|
+
image = sharp::Blur(image, baton->blurSigma, baton->precision, baton->minAmpl);
|
|
596
597
|
}
|
|
597
598
|
|
|
598
599
|
// Unflatten the image
|
|
@@ -609,7 +610,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
609
610
|
}
|
|
610
611
|
|
|
611
612
|
// Recomb
|
|
612
|
-
if (baton->recombMatrix
|
|
613
|
+
if (!baton->recombMatrix.empty()) {
|
|
613
614
|
image = sharp::Recomb(image, baton->recombMatrix);
|
|
614
615
|
}
|
|
615
616
|
|
|
@@ -849,6 +850,11 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
849
850
|
image = sharp::SetAnimationProperties(
|
|
850
851
|
image, nPages, targetPageHeight, baton->delay, baton->loop);
|
|
851
852
|
|
|
853
|
+
if (image.get_typeof(VIPS_META_PAGE_HEIGHT) == G_TYPE_INT) {
|
|
854
|
+
baton->pageHeightOut = image.get_int(VIPS_META_PAGE_HEIGHT);
|
|
855
|
+
baton->pagesOut = image.get_int(VIPS_META_N_PAGES);
|
|
856
|
+
}
|
|
857
|
+
|
|
852
858
|
// Output
|
|
853
859
|
sharp::SetTimeout(image, baton->timeoutSeconds);
|
|
854
860
|
if (baton->fileOut.empty()) {
|
|
@@ -1284,6 +1290,10 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
1284
1290
|
if (baton->input->textAutofitDpi) {
|
|
1285
1291
|
info.Set("textAutofitDpi", static_cast<uint32_t>(baton->input->textAutofitDpi));
|
|
1286
1292
|
}
|
|
1293
|
+
if (baton->pageHeightOut) {
|
|
1294
|
+
info.Set("pageHeight", static_cast<int32_t>(baton->pageHeightOut));
|
|
1295
|
+
info.Set("pages", static_cast<int32_t>(baton->pagesOut));
|
|
1296
|
+
}
|
|
1287
1297
|
|
|
1288
1298
|
if (baton->bufferOutLength > 0) {
|
|
1289
1299
|
// Add buffer size to info
|
|
@@ -1532,6 +1542,8 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
|
|
1532
1542
|
baton->negate = sharp::AttrAsBool(options, "negate");
|
|
1533
1543
|
baton->negateAlpha = sharp::AttrAsBool(options, "negateAlpha");
|
|
1534
1544
|
baton->blurSigma = sharp::AttrAsDouble(options, "blurSigma");
|
|
1545
|
+
baton->precision = sharp::AttrAsEnum<VipsPrecision>(options, "precision", VIPS_TYPE_PRECISION);
|
|
1546
|
+
baton->minAmpl = sharp::AttrAsDouble(options, "minAmpl");
|
|
1535
1547
|
baton->brightness = sharp::AttrAsDouble(options, "brightness");
|
|
1536
1548
|
baton->saturation = sharp::AttrAsDouble(options, "saturation");
|
|
1537
1549
|
baton->hue = sharp::AttrAsInt32(options, "hue");
|
|
@@ -1597,17 +1609,18 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
|
|
1597
1609
|
baton->convKernelScale = sharp::AttrAsDouble(kernel, "scale");
|
|
1598
1610
|
baton->convKernelOffset = sharp::AttrAsDouble(kernel, "offset");
|
|
1599
1611
|
size_t const kernelSize = static_cast<size_t>(baton->convKernelWidth * baton->convKernelHeight);
|
|
1600
|
-
baton->convKernel
|
|
1612
|
+
baton->convKernel.resize(kernelSize);
|
|
1601
1613
|
Napi::Array kdata = kernel.Get("kernel").As<Napi::Array>();
|
|
1602
1614
|
for (unsigned int i = 0; i < kernelSize; i++) {
|
|
1603
1615
|
baton->convKernel[i] = sharp::AttrAsDouble(kdata, i);
|
|
1604
1616
|
}
|
|
1605
1617
|
}
|
|
1606
1618
|
if (options.Has("recombMatrix")) {
|
|
1607
|
-
baton->recombMatrix = std::unique_ptr<double[]>(new double[9]);
|
|
1608
1619
|
Napi::Array recombMatrix = options.Get("recombMatrix").As<Napi::Array>();
|
|
1609
|
-
|
|
1610
|
-
|
|
1620
|
+
unsigned int matrixElements = recombMatrix.Length();
|
|
1621
|
+
baton->recombMatrix.resize(matrixElements);
|
|
1622
|
+
for (unsigned int i = 0; i < matrixElements; i++) {
|
|
1623
|
+
baton->recombMatrix[i] = sharp::AttrAsDouble(recombMatrix, i);
|
|
1611
1624
|
}
|
|
1612
1625
|
}
|
|
1613
1626
|
baton->colourspacePipeline = sharp::AttrAsEnum<VipsInterpretation>(
|
package/src/pipeline.h
CHANGED
|
@@ -43,6 +43,8 @@ struct PipelineBaton {
|
|
|
43
43
|
std::string fileOut;
|
|
44
44
|
void *bufferOut;
|
|
45
45
|
size_t bufferOutLength;
|
|
46
|
+
int pageHeightOut;
|
|
47
|
+
int pagesOut;
|
|
46
48
|
std::vector<Composite *> composite;
|
|
47
49
|
std::vector<sharp::InputDescriptor *> joinChannelIn;
|
|
48
50
|
int topOffsetPre;
|
|
@@ -76,6 +78,8 @@ struct PipelineBaton {
|
|
|
76
78
|
bool negate;
|
|
77
79
|
bool negateAlpha;
|
|
78
80
|
double blurSigma;
|
|
81
|
+
VipsPrecision precision;
|
|
82
|
+
double minAmpl;
|
|
79
83
|
double brightness;
|
|
80
84
|
double saturation;
|
|
81
85
|
int hue;
|
|
@@ -195,7 +199,7 @@ struct PipelineBaton {
|
|
|
195
199
|
std::unordered_map<std::string, std::string> withExif;
|
|
196
200
|
bool withExifMerge;
|
|
197
201
|
int timeoutSeconds;
|
|
198
|
-
std::
|
|
202
|
+
std::vector<double> convKernel;
|
|
199
203
|
int convKernelWidth;
|
|
200
204
|
int convKernelHeight;
|
|
201
205
|
double convKernelScale;
|
|
@@ -221,11 +225,13 @@ struct PipelineBaton {
|
|
|
221
225
|
VipsForeignDzDepth tileDepth;
|
|
222
226
|
std::string tileId;
|
|
223
227
|
std::string tileBasename;
|
|
224
|
-
std::
|
|
228
|
+
std::vector<double> recombMatrix;
|
|
225
229
|
|
|
226
230
|
PipelineBaton():
|
|
227
231
|
input(nullptr),
|
|
228
232
|
bufferOutLength(0),
|
|
233
|
+
pageHeightOut(0),
|
|
234
|
+
pagesOut(0),
|
|
229
235
|
topOffsetPre(-1),
|
|
230
236
|
topOffsetPost(-1),
|
|
231
237
|
channels(0),
|