sharp 0.32.1 → 0.32.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/binding.gyp +3 -1
- package/lib/composite.js +3 -3
- package/lib/constructor.js +3 -2
- package/lib/index.d.ts +2 -19
- package/lib/operation.js +12 -6
- package/lib/output.js +10 -2
- package/package.json +4 -4
- package/src/common.cc +13 -0
- package/src/common.h +5 -0
- package/src/pipeline.cc +38 -28
- package/src/pipeline.h +2 -0
package/binding.gyp
CHANGED
|
@@ -70,7 +70,9 @@
|
|
|
70
70
|
}, {
|
|
71
71
|
'target_name': 'sharp-<(platform_and_arch)',
|
|
72
72
|
'defines': [
|
|
73
|
-
'NAPI_VERSION=7'
|
|
73
|
+
'NAPI_VERSION=7',
|
|
74
|
+
'NODE_ADDON_API_DISABLE_DEPRECATED',
|
|
75
|
+
'NODE_API_SWALLOW_UNTHROWABLE_EXCEPTIONS'
|
|
74
76
|
],
|
|
75
77
|
'dependencies': [
|
|
76
78
|
'<!(node -p "require(\'node-addon-api\').gyp")',
|
package/lib/composite.js
CHANGED
|
@@ -46,7 +46,7 @@ const blend = {
|
|
|
46
46
|
* The images to composite must be the same size or smaller than the processed image.
|
|
47
47
|
* If both `top` and `left` options are provided, they take precedence over `gravity`.
|
|
48
48
|
*
|
|
49
|
-
* Any resize or
|
|
49
|
+
* Any resize, rotate or extract operations in the same processing pipeline
|
|
50
50
|
* will always be applied to the input image before composition.
|
|
51
51
|
*
|
|
52
52
|
* The `blend` option can be one of `clear`, `source`, `over`, `in`, `out`, `atop`,
|
|
@@ -108,14 +108,14 @@ const blend = {
|
|
|
108
108
|
* @param {string} [images[].input.text.align='left'] - text alignment (`'left'`, `'centre'`, `'center'`, `'right'`).
|
|
109
109
|
* @param {boolean} [images[].input.text.justify=false] - set this to true to apply justification to the text.
|
|
110
110
|
* @param {number} [images[].input.text.dpi=72] - the resolution (size) at which to render the text. Does not take effect if `height` is specified.
|
|
111
|
-
* @param {boolean} [images[].input.text.rgba=false] - set this to true to enable RGBA output. This is useful for colour emoji rendering, or support for
|
|
111
|
+
* @param {boolean} [images[].input.text.rgba=false] - set this to true to enable RGBA output. This is useful for colour emoji rendering, or support for Pango markup features like `<span foreground="red">Red!</span>`.
|
|
112
112
|
* @param {number} [images[].input.text.spacing=0] - text line height in points. Will use the font line height if none is specified.
|
|
113
113
|
* @param {String} [images[].blend='over'] - how to blend this image with the image below.
|
|
114
114
|
* @param {String} [images[].gravity='centre'] - gravity at which to place the overlay.
|
|
115
115
|
* @param {Number} [images[].top] - the pixel offset from the top edge.
|
|
116
116
|
* @param {Number} [images[].left] - the pixel offset from the left edge.
|
|
117
117
|
* @param {Boolean} [images[].tile=false] - set to true to repeat the overlay image across the entire image with the given `gravity`.
|
|
118
|
-
* @param {Boolean} [images[].premultiplied=false] - set to true to avoid
|
|
118
|
+
* @param {Boolean} [images[].premultiplied=false] - set to true to avoid premultiplying the image below. Equivalent to the `--premultiplied` vips option.
|
|
119
119
|
* @param {Number} [images[].density=72] - number representing the DPI for vector overlay image.
|
|
120
120
|
* @param {Object} [images[].raw] - describes overlay when using raw pixel data.
|
|
121
121
|
* @param {Number} [images[].raw.width]
|
package/lib/constructor.js
CHANGED
|
@@ -49,7 +49,7 @@ const debuglog = util.debuglog('sharp');
|
|
|
49
49
|
* readableStream.pipe(transformer).pipe(writableStream);
|
|
50
50
|
*
|
|
51
51
|
* @example
|
|
52
|
-
* // Create a blank 300x200 PNG image of semi-
|
|
52
|
+
* // Create a blank 300x200 PNG image of semi-translucent red pixels
|
|
53
53
|
* sharp({
|
|
54
54
|
* create: {
|
|
55
55
|
* width: 300,
|
|
@@ -122,7 +122,7 @@ const debuglog = util.debuglog('sharp');
|
|
|
122
122
|
* a String containing the filesystem path to an JPEG, PNG, WebP, AVIF, GIF, SVG or TIFF image file.
|
|
123
123
|
* JPEG, PNG, WebP, AVIF, GIF, SVG, TIFF or raw pixel image data can be streamed into the object when not present.
|
|
124
124
|
* @param {Object} [options] - if present, is an Object with optional attributes.
|
|
125
|
-
* @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),
|
|
125
|
+
* @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.
|
|
126
126
|
* @param {number|boolean} [options.limitInputPixels=268402689] - Do not process input images where the number of pixels
|
|
127
127
|
* (width x height) exceeds this limit. Assumes image dimensions contained in the input metadata can be trusted.
|
|
128
128
|
* An integral Number of pixels, zero or false to remove limit, true to use default limit of 268402689 (0x3FFF x 0x3FFF).
|
|
@@ -291,6 +291,7 @@ const Sharp = function (input, options) {
|
|
|
291
291
|
webpLossless: false,
|
|
292
292
|
webpNearLossless: false,
|
|
293
293
|
webpSmartSubsample: false,
|
|
294
|
+
webpPreset: 'default',
|
|
294
295
|
webpEffort: 4,
|
|
295
296
|
webpMinSize: false,
|
|
296
297
|
webpMixed: false,
|
package/lib/index.d.ts
CHANGED
|
@@ -1350,9 +1350,9 @@ declare namespace sharp {
|
|
|
1350
1350
|
grayscale?: boolean | undefined;
|
|
1351
1351
|
}
|
|
1352
1352
|
|
|
1353
|
-
interface OverlayOptions {
|
|
1353
|
+
interface OverlayOptions extends SharpOptions {
|
|
1354
1354
|
/** Buffer containing image data, String containing the path to an image file, or Create object */
|
|
1355
|
-
input?: string | Buffer | { create: Create } | { text: CreateText } | undefined;
|
|
1355
|
+
input?: string | Buffer | { create: Create } | { text: CreateText } | { raw: CreateRaw } | undefined;
|
|
1356
1356
|
/** how to blend this image with the image below. (optional, default `'over'`) */
|
|
1357
1357
|
blend?: Blend | undefined;
|
|
1358
1358
|
/** gravity at which to place the overlay. (optional, default 'centre') */
|
|
@@ -1363,25 +1363,8 @@ declare namespace sharp {
|
|
|
1363
1363
|
left?: number | undefined;
|
|
1364
1364
|
/** set to true to repeat the overlay image across the entire image with the given gravity. (optional, default false) */
|
|
1365
1365
|
tile?: boolean | undefined;
|
|
1366
|
-
/** number representing the DPI for vector overlay image. (optional, default 72) */
|
|
1367
|
-
density?: number | undefined;
|
|
1368
|
-
/** describes overlay when using raw pixel data. */
|
|
1369
|
-
raw?: Raw | undefined;
|
|
1370
1366
|
/** Set to true to avoid premultipling the image below. Equivalent to the --premultiplied vips option. */
|
|
1371
1367
|
premultiplied?: boolean | undefined;
|
|
1372
|
-
/** Set to true to read all frames/pages of an animated image. (optional, default false). */
|
|
1373
|
-
animated?: boolean | undefined;
|
|
1374
|
-
/**
|
|
1375
|
-
* When to abort processing of invalid pixel data, one of (in order of sensitivity):
|
|
1376
|
-
* 'none' (least), 'truncated', 'error' or 'warning' (most), highers level imply lower levels, invalid metadata will always abort. (optional, default 'warning')
|
|
1377
|
-
*/
|
|
1378
|
-
failOn?: FailOnOptions | undefined;
|
|
1379
|
-
/**
|
|
1380
|
-
* Do not process input images where the number of pixels (width x height) exceeds this limit.
|
|
1381
|
-
* Assumes image dimensions contained in the input metadata can be trusted.
|
|
1382
|
-
* An integral Number of pixels, zero or false to remove limit, true to use default limit of 268402689 (0x3FFF x 0x3FFF). (optional, default 268402689)
|
|
1383
|
-
*/
|
|
1384
|
-
limitInputPixels?: number | boolean | undefined;
|
|
1385
1368
|
}
|
|
1386
1369
|
|
|
1387
1370
|
interface TileOptions {
|
package/lib/operation.js
CHANGED
|
@@ -11,7 +11,7 @@ const is = require('./is');
|
|
|
11
11
|
* or auto-orient based on the EXIF `Orientation` tag.
|
|
12
12
|
*
|
|
13
13
|
* If an angle is provided, it is converted to a valid positive degree rotation.
|
|
14
|
-
* For example, `-450` will produce a
|
|
14
|
+
* For example, `-450` will produce a 270 degree rotation.
|
|
15
15
|
*
|
|
16
16
|
* When rotating by an angle other than a multiple of 90,
|
|
17
17
|
* the background colour can be provided with the `background` option.
|
|
@@ -80,9 +80,13 @@ function rotate (angle, options) {
|
|
|
80
80
|
}
|
|
81
81
|
|
|
82
82
|
/**
|
|
83
|
-
*
|
|
83
|
+
* Mirror the image vertically (up-down) about the x-axis.
|
|
84
|
+
* This always occurs before rotation, if any.
|
|
85
|
+
*
|
|
84
86
|
* The use of `flip` implies the removal of the EXIF `Orientation` tag, if any.
|
|
85
87
|
*
|
|
88
|
+
* This operation does not work correctly with multi-page images.
|
|
89
|
+
*
|
|
86
90
|
* @example
|
|
87
91
|
* const output = await sharp(input).flip().toBuffer();
|
|
88
92
|
*
|
|
@@ -95,7 +99,9 @@ function flip (flip) {
|
|
|
95
99
|
}
|
|
96
100
|
|
|
97
101
|
/**
|
|
98
|
-
*
|
|
102
|
+
* Mirror the image horizontally (left-right) about the y-axis.
|
|
103
|
+
* This always occurs before rotation, if any.
|
|
104
|
+
*
|
|
99
105
|
* The use of `flop` implies the removal of the EXIF `Orientation` tag, if any.
|
|
100
106
|
*
|
|
101
107
|
* @example
|
|
@@ -766,7 +772,7 @@ function linear (a, b) {
|
|
|
766
772
|
}
|
|
767
773
|
|
|
768
774
|
/**
|
|
769
|
-
*
|
|
775
|
+
* Recombine the image with the specified matrix.
|
|
770
776
|
*
|
|
771
777
|
* @since 0.21.1
|
|
772
778
|
*
|
|
@@ -779,7 +785,7 @@ function linear (a, b) {
|
|
|
779
785
|
* ])
|
|
780
786
|
* .raw()
|
|
781
787
|
* .toBuffer(function(err, data, info) {
|
|
782
|
-
* // data contains the raw pixel data after applying the
|
|
788
|
+
* // data contains the raw pixel data after applying the matrix
|
|
783
789
|
* // With this example input, a sepia filter has been applied
|
|
784
790
|
* });
|
|
785
791
|
*
|
|
@@ -836,7 +842,7 @@ function recomb (inputMatrix) {
|
|
|
836
842
|
* .toBuffer();
|
|
837
843
|
*
|
|
838
844
|
* @example
|
|
839
|
-
* //
|
|
845
|
+
* // decrease brightness and saturation while also hue-rotating by 90 degrees
|
|
840
846
|
* const output = await sharp(input)
|
|
841
847
|
* .modulate({
|
|
842
848
|
* brightness: 0.5,
|
package/lib/output.js
CHANGED
|
@@ -29,7 +29,7 @@ const formats = new Map([
|
|
|
29
29
|
['jxl', 'jxl']
|
|
30
30
|
]);
|
|
31
31
|
|
|
32
|
-
const jp2Regex = /\.jp[2x]|j2[kc]$/i;
|
|
32
|
+
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
|
|
|
@@ -75,7 +75,7 @@ function toFile (fileOut, callback) {
|
|
|
75
75
|
err = new Error('Missing output file path');
|
|
76
76
|
} else if (is.string(this.options.input.file) && path.resolve(this.options.input.file) === path.resolve(fileOut)) {
|
|
77
77
|
err = new Error('Cannot use same file for input and output');
|
|
78
|
-
} else if (jp2Regex.test(fileOut) && !this.constructor.format.jp2k.output.file) {
|
|
78
|
+
} else if (jp2Regex.test(path.extname(fileOut)) && !this.constructor.format.jp2k.output.file) {
|
|
79
79
|
err = errJp2Save();
|
|
80
80
|
}
|
|
81
81
|
if (err) {
|
|
@@ -483,6 +483,7 @@ function png (options) {
|
|
|
483
483
|
* @param {boolean} [options.lossless=false] - use lossless compression mode
|
|
484
484
|
* @param {boolean} [options.nearLossless=false] - use near_lossless compression mode
|
|
485
485
|
* @param {boolean} [options.smartSubsample=false] - use high quality chroma subsampling
|
|
486
|
+
* @param {string} [options.preset='default'] - named preset for preprocessing/filtering, one of: default, photo, picture, drawing, icon, text
|
|
486
487
|
* @param {number} [options.effort=4] - CPU effort, between 0 (fastest) and 6 (slowest)
|
|
487
488
|
* @param {number} [options.loop=0] - number of animation iterations, use 0 for infinite animation
|
|
488
489
|
* @param {number|number[]} [options.delay] - delay(s) between animation frames (in milliseconds)
|
|
@@ -517,6 +518,13 @@ function webp (options) {
|
|
|
517
518
|
if (is.defined(options.smartSubsample)) {
|
|
518
519
|
this._setBooleanOption('webpSmartSubsample', options.smartSubsample);
|
|
519
520
|
}
|
|
521
|
+
if (is.defined(options.preset)) {
|
|
522
|
+
if (is.string(options.preset) && is.inArray(options.preset, ['default', 'photo', 'picture', 'drawing', 'icon', 'text'])) {
|
|
523
|
+
this.options.webpPreset = options.preset;
|
|
524
|
+
} else {
|
|
525
|
+
throw is.invalidParameterError('preset', 'one of: default, photo, picture, drawing, icon, text', options.preset);
|
|
526
|
+
}
|
|
527
|
+
}
|
|
520
528
|
if (is.defined(options.effort)) {
|
|
521
529
|
if (is.integer(options.effort) && is.inRange(options.effort, 0, 6)) {
|
|
522
530
|
this.options.webpEffort = options.effort;
|
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.32.
|
|
4
|
+
"version": "0.32.3",
|
|
5
5
|
"author": "Lovell Fuller <npm@lovell.info>",
|
|
6
6
|
"homepage": "https://github.com/lovell/sharp",
|
|
7
7
|
"contributors": [
|
|
@@ -136,9 +136,9 @@
|
|
|
136
136
|
"detect-libc": "^2.0.1",
|
|
137
137
|
"node-addon-api": "^6.1.0",
|
|
138
138
|
"prebuild-install": "^7.1.1",
|
|
139
|
-
"semver": "^7.5.
|
|
139
|
+
"semver": "^7.5.4",
|
|
140
140
|
"simple-get": "^4.0.1",
|
|
141
|
-
"tar-fs": "^
|
|
141
|
+
"tar-fs": "^3.0.4",
|
|
142
142
|
"tunnel-agent": "^0.6.0"
|
|
143
143
|
},
|
|
144
144
|
"devDependencies": {
|
|
@@ -153,7 +153,7 @@
|
|
|
153
153
|
"mocha": "^10.2.0",
|
|
154
154
|
"mock-fs": "^5.2.0",
|
|
155
155
|
"nyc": "^15.1.0",
|
|
156
|
-
"prebuild": "
|
|
156
|
+
"prebuild": "lovell/prebuild#add-nodejs-20-drop-nodejs-10-and-12",
|
|
157
157
|
"semistandard": "^16.0.1",
|
|
158
158
|
"tsd": "^0.28.1"
|
|
159
159
|
},
|
package/src/common.cc
CHANGED
|
@@ -669,6 +669,10 @@ namespace sharp {
|
|
|
669
669
|
if (image.width() > 65535 || height > 65535) {
|
|
670
670
|
throw vips::VError("Processed image is too large for the GIF format");
|
|
671
671
|
}
|
|
672
|
+
} else if (imageType == ImageType::HEIF) {
|
|
673
|
+
if (image.width() > 16384 || height > 16384) {
|
|
674
|
+
throw vips::VError("Processed image is too large for the HEIF format");
|
|
675
|
+
}
|
|
672
676
|
}
|
|
673
677
|
}
|
|
674
678
|
|
|
@@ -1031,4 +1035,13 @@ namespace sharp {
|
|
|
1031
1035
|
return std::make_pair(hshrink, vshrink);
|
|
1032
1036
|
}
|
|
1033
1037
|
|
|
1038
|
+
/*
|
|
1039
|
+
Ensure decoding remains sequential.
|
|
1040
|
+
*/
|
|
1041
|
+
VImage StaySequential(VImage image, VipsAccess access, bool condition) {
|
|
1042
|
+
if (access == VIPS_ACCESS_SEQUENTIAL && condition) {
|
|
1043
|
+
return image.copy_memory();
|
|
1044
|
+
}
|
|
1045
|
+
return image;
|
|
1046
|
+
}
|
|
1034
1047
|
} // namespace sharp
|
package/src/common.h
CHANGED
|
@@ -370,6 +370,11 @@ namespace sharp {
|
|
|
370
370
|
std::pair<double, double> ResolveShrink(int width, int height, int targetWidth, int targetHeight,
|
|
371
371
|
Canvas canvas, bool swap, bool withoutEnlargement, bool withoutReduction);
|
|
372
372
|
|
|
373
|
+
/*
|
|
374
|
+
Ensure decoding remains sequential.
|
|
375
|
+
*/
|
|
376
|
+
VImage StaySequential(VImage image, VipsAccess access, bool condition = TRUE);
|
|
377
|
+
|
|
373
378
|
} // namespace sharp
|
|
374
379
|
|
|
375
380
|
#endif // SRC_COMMON_H_
|
package/src/pipeline.cc
CHANGED
|
@@ -56,6 +56,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
56
56
|
vips::VImage image;
|
|
57
57
|
sharp::ImageType inputImageType;
|
|
58
58
|
std::tie(image, inputImageType) = sharp::OpenInput(baton->input);
|
|
59
|
+
VipsAccess access = baton->input->access;
|
|
59
60
|
image = sharp::EnsureColourspace(image, baton->colourspaceInput);
|
|
60
61
|
|
|
61
62
|
int nPages = baton->input->pages;
|
|
@@ -90,6 +91,13 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
90
91
|
baton->rotationAngle != 0.0);
|
|
91
92
|
|
|
92
93
|
if (shouldRotateBefore) {
|
|
94
|
+
image = sharp::StaySequential(image, access,
|
|
95
|
+
rotation != VIPS_ANGLE_D0 ||
|
|
96
|
+
autoRotation != VIPS_ANGLE_D0 ||
|
|
97
|
+
autoFlip ||
|
|
98
|
+
baton->flip ||
|
|
99
|
+
baton->rotationAngle != 0.0);
|
|
100
|
+
|
|
93
101
|
if (autoRotation != VIPS_ANGLE_D0) {
|
|
94
102
|
image = image.rot(autoRotation);
|
|
95
103
|
autoRotation = VIPS_ANGLE_D0;
|
|
@@ -116,13 +124,14 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
116
124
|
MultiPageUnsupported(nPages, "Rotate");
|
|
117
125
|
std::vector<double> background;
|
|
118
126
|
std::tie(image, background) = sharp::ApplyAlpha(image, baton->rotationBackground, FALSE);
|
|
119
|
-
image = image.rotate(baton->rotationAngle, VImage::option()->set("background", background));
|
|
127
|
+
image = image.rotate(baton->rotationAngle, VImage::option()->set("background", background)).copy_memory();
|
|
120
128
|
}
|
|
121
129
|
}
|
|
122
130
|
|
|
123
131
|
// Trim
|
|
124
132
|
if (baton->trimThreshold > 0.0) {
|
|
125
133
|
MultiPageUnsupported(nPages, "Trim");
|
|
134
|
+
image = sharp::StaySequential(image, access);
|
|
126
135
|
image = sharp::Trim(image, baton->trimBackground, baton->trimThreshold);
|
|
127
136
|
baton->trimOffsetLeft = image.xoffset();
|
|
128
137
|
baton->trimOffsetTop = image.yoffset();
|
|
@@ -209,7 +218,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
209
218
|
// pdfload* and svgload*
|
|
210
219
|
if (jpegShrinkOnLoad > 1) {
|
|
211
220
|
vips::VOption *option = VImage::option()
|
|
212
|
-
->set("access",
|
|
221
|
+
->set("access", access)
|
|
213
222
|
->set("shrink", jpegShrinkOnLoad)
|
|
214
223
|
->set("unlimited", baton->input->unlimited)
|
|
215
224
|
->set("fail_on", baton->input->failOn);
|
|
@@ -224,7 +233,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
224
233
|
}
|
|
225
234
|
} else if (scale != 1.0) {
|
|
226
235
|
vips::VOption *option = VImage::option()
|
|
227
|
-
->set("access",
|
|
236
|
+
->set("access", access)
|
|
228
237
|
->set("scale", scale)
|
|
229
238
|
->set("fail_on", baton->input->failOn);
|
|
230
239
|
if (inputImageType == sharp::ImageType::WEBP) {
|
|
@@ -376,15 +385,20 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
376
385
|
->set("kernel", baton->kernel));
|
|
377
386
|
}
|
|
378
387
|
|
|
388
|
+
image = sharp::StaySequential(image, access,
|
|
389
|
+
autoRotation != VIPS_ANGLE_D0 ||
|
|
390
|
+
baton->flip ||
|
|
391
|
+
autoFlip ||
|
|
392
|
+
rotation != VIPS_ANGLE_D0);
|
|
379
393
|
// Auto-rotate post-extract
|
|
380
394
|
if (autoRotation != VIPS_ANGLE_D0) {
|
|
381
395
|
image = image.rot(autoRotation);
|
|
382
396
|
}
|
|
383
|
-
//
|
|
397
|
+
// Mirror vertically (up-down) about the x-axis
|
|
384
398
|
if (baton->flip || autoFlip) {
|
|
385
399
|
image = image.flip(VIPS_DIRECTION_VERTICAL);
|
|
386
400
|
}
|
|
387
|
-
//
|
|
401
|
+
// Mirror horizontally (left-right) about the y-axis
|
|
388
402
|
if (baton->flop || autoFlop) {
|
|
389
403
|
image = image.flip(VIPS_DIRECTION_HORIZONTAL);
|
|
390
404
|
}
|
|
@@ -399,6 +413,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
399
413
|
sharp::ImageType joinImageType = sharp::ImageType::UNKNOWN;
|
|
400
414
|
|
|
401
415
|
for (unsigned int i = 0; i < baton->joinChannelIn.size(); i++) {
|
|
416
|
+
baton->joinChannelIn[i]->access = access;
|
|
402
417
|
std::tie(joinImage, joinImageType) = sharp::OpenInput(baton->joinChannelIn[i]);
|
|
403
418
|
joinImage = sharp::EnsureColourspace(joinImage, baton->colourspaceInput);
|
|
404
419
|
image = image.bandjoin(joinImage);
|
|
@@ -467,13 +482,12 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
467
482
|
|
|
468
483
|
// Attention-based or Entropy-based crop
|
|
469
484
|
MultiPageUnsupported(nPages, "Resize strategy");
|
|
470
|
-
image =
|
|
471
|
-
->set("access", VIPS_ACCESS_RANDOM)
|
|
472
|
-
->set("threaded", TRUE));
|
|
473
|
-
|
|
485
|
+
image = sharp::StaySequential(image, access);
|
|
474
486
|
image = image.smartcrop(baton->width, baton->height, VImage::option()
|
|
475
487
|
->set("interesting", baton->position == 16 ? VIPS_INTERESTING_ENTROPY : VIPS_INTERESTING_ATTENTION)
|
|
488
|
+
#if (VIPS_MAJOR_VERSION >= 8 && VIPS_MINOR_VERSION >= 15)
|
|
476
489
|
->set("premultiplied", shouldPremultiplyAlpha)
|
|
490
|
+
#endif
|
|
477
491
|
->set("attention_x", &attention_x)
|
|
478
492
|
->set("attention_y", &attention_y));
|
|
479
493
|
baton->hasCropOffset = true;
|
|
@@ -489,6 +503,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
489
503
|
// Rotate post-extract non-90 angle
|
|
490
504
|
if (!baton->rotateBeforePreExtract && baton->rotationAngle != 0.0) {
|
|
491
505
|
MultiPageUnsupported(nPages, "Rotate");
|
|
506
|
+
image = sharp::StaySequential(image, access);
|
|
492
507
|
std::vector<double> background;
|
|
493
508
|
std::tie(image, background) = sharp::ApplyAlpha(image, baton->rotationBackground, shouldPremultiplyAlpha);
|
|
494
509
|
image = image.rotate(baton->rotationAngle, VImage::option()->set("background", background));
|
|
@@ -512,6 +527,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
512
527
|
// Affine transform
|
|
513
528
|
if (!baton->affineMatrix.empty()) {
|
|
514
529
|
MultiPageUnsupported(nPages, "Affine");
|
|
530
|
+
image = sharp::StaySequential(image, access);
|
|
515
531
|
std::vector<double> background;
|
|
516
532
|
std::tie(image, background) = sharp::ApplyAlpha(image, baton->affineBackground, shouldPremultiplyAlpha);
|
|
517
533
|
vips::VInterpolate interp = vips::VInterpolate::new_from_name(
|
|
@@ -608,6 +624,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
608
624
|
for (Composite *composite : baton->composite) {
|
|
609
625
|
VImage compositeImage;
|
|
610
626
|
sharp::ImageType compositeImageType = sharp::ImageType::UNKNOWN;
|
|
627
|
+
composite->input->access = access;
|
|
611
628
|
std::tie(compositeImage, compositeImageType) = sharp::OpenInput(composite->input);
|
|
612
629
|
compositeImage = sharp::EnsureColourspace(compositeImage, baton->colourspaceInput);
|
|
613
630
|
// Verify within current dimensions
|
|
@@ -694,11 +711,13 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
694
711
|
|
|
695
712
|
// Apply normalisation - stretch luminance to cover full dynamic range
|
|
696
713
|
if (baton->normalise) {
|
|
697
|
-
image = sharp::
|
|
714
|
+
image = sharp::StaySequential(image, access);
|
|
715
|
+
image = sharp::Normalise(image, baton->normaliseLower, baton->normaliseUpper);
|
|
698
716
|
}
|
|
699
717
|
|
|
700
718
|
// Apply contrast limiting adaptive histogram equalization (CLAHE)
|
|
701
719
|
if (baton->claheWidth != 0 && baton->claheHeight != 0) {
|
|
720
|
+
image = sharp::StaySequential(image, access);
|
|
702
721
|
image = sharp::Clahe(image, baton->claheWidth, baton->claheHeight, baton->claheMaxSlope);
|
|
703
722
|
}
|
|
704
723
|
|
|
@@ -706,6 +725,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
706
725
|
if (baton->boolean != nullptr) {
|
|
707
726
|
VImage booleanImage;
|
|
708
727
|
sharp::ImageType booleanImageType = sharp::ImageType::UNKNOWN;
|
|
728
|
+
baton->boolean->access = access;
|
|
709
729
|
std::tie(booleanImage, booleanImageType) = sharp::OpenInput(baton->boolean);
|
|
710
730
|
booleanImage = sharp::EnsureColourspace(booleanImage, baton->colourspaceInput);
|
|
711
731
|
image = sharp::Boolean(image, booleanImage, baton->booleanOp);
|
|
@@ -874,6 +894,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
874
894
|
->set("lossless", baton->webpLossless)
|
|
875
895
|
->set("near_lossless", baton->webpNearLossless)
|
|
876
896
|
->set("smart_subsample", baton->webpSmartSubsample)
|
|
897
|
+
->set("preset", baton->webpPreset)
|
|
877
898
|
->set("effort", baton->webpEffort)
|
|
878
899
|
->set("min_size", baton->webpMinSize)
|
|
879
900
|
->set("mixed", baton->webpMixed)
|
|
@@ -933,6 +954,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
933
954
|
} else if (baton->formatOut == "heif" ||
|
|
934
955
|
(baton->formatOut == "input" && inputImageType == sharp::ImageType::HEIF)) {
|
|
935
956
|
// Write HEIF to buffer
|
|
957
|
+
sharp::AssertImageTypeDimensions(image, sharp::ImageType::HEIF);
|
|
936
958
|
image = sharp::RemoveAnimationProperties(image).cast(VIPS_FORMAT_UCHAR);
|
|
937
959
|
VipsArea *area = reinterpret_cast<VipsArea*>(image.heifsave_buffer(VImage::option()
|
|
938
960
|
->set("strip", !baton->withMetadata)
|
|
@@ -954,6 +976,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
954
976
|
if (!sharp::HasAlpha(image)) {
|
|
955
977
|
baton->tileBackground.pop_back();
|
|
956
978
|
}
|
|
979
|
+
image = sharp::StaySequential(image, access, baton->tileAngle != 0);
|
|
957
980
|
vips::VOption *options = BuildOptionsDZ(baton);
|
|
958
981
|
VipsArea *area = reinterpret_cast<VipsArea*>(image.dzsave_buffer(options));
|
|
959
982
|
baton->bufferOut = static_cast<char*>(area->data);
|
|
@@ -1077,6 +1100,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
1077
1100
|
->set("lossless", baton->webpLossless)
|
|
1078
1101
|
->set("near_lossless", baton->webpNearLossless)
|
|
1079
1102
|
->set("smart_subsample", baton->webpSmartSubsample)
|
|
1103
|
+
->set("preset", baton->webpPreset)
|
|
1080
1104
|
->set("effort", baton->webpEffort)
|
|
1081
1105
|
->set("min_size", baton->webpMinSize)
|
|
1082
1106
|
->set("mixed", baton->webpMixed)
|
|
@@ -1122,6 +1146,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
1122
1146
|
} else if (baton->formatOut == "heif" || (mightMatchInput && isHeif) ||
|
|
1123
1147
|
(willMatchInput && inputImageType == sharp::ImageType::HEIF)) {
|
|
1124
1148
|
// Write HEIF to file
|
|
1149
|
+
sharp::AssertImageTypeDimensions(image, sharp::ImageType::HEIF);
|
|
1125
1150
|
image = sharp::RemoveAnimationProperties(image).cast(VIPS_FORMAT_UCHAR);
|
|
1126
1151
|
image.heifsave(const_cast<char*>(baton->fileOut.data()), VImage::option()
|
|
1127
1152
|
->set("strip", !baton->withMetadata)
|
|
@@ -1152,6 +1177,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
1152
1177
|
if (!sharp::HasAlpha(image)) {
|
|
1153
1178
|
baton->tileBackground.pop_back();
|
|
1154
1179
|
}
|
|
1180
|
+
image = sharp::StaySequential(image, access, baton->tileAngle != 0);
|
|
1155
1181
|
vips::VOption *options = BuildOptionsDZ(baton);
|
|
1156
1182
|
image.dzsave(const_cast<char*>(baton->fileOut.data()), options);
|
|
1157
1183
|
baton->formatOut = "dz";
|
|
@@ -1353,6 +1379,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
1353
1379
|
{"lossless", baton->webpLossless ? "TRUE" : "FALSE"},
|
|
1354
1380
|
{"near_lossless", baton->webpNearLossless ? "TRUE" : "FALSE"},
|
|
1355
1381
|
{"smart_subsample", baton->webpSmartSubsample ? "TRUE" : "FALSE"},
|
|
1382
|
+
{"preset", vips_enum_nick(VIPS_TYPE_FOREIGN_WEBP_PRESET, baton->webpPreset)},
|
|
1356
1383
|
{"min_size", baton->webpMinSize ? "TRUE" : "FALSE"},
|
|
1357
1384
|
{"mixed", baton->webpMixed ? "TRUE" : "FALSE"},
|
|
1358
1385
|
{"effort", std::to_string(baton->webpEffort)}
|
|
@@ -1605,6 +1632,7 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
|
|
1605
1632
|
baton->webpLossless = sharp::AttrAsBool(options, "webpLossless");
|
|
1606
1633
|
baton->webpNearLossless = sharp::AttrAsBool(options, "webpNearLossless");
|
|
1607
1634
|
baton->webpSmartSubsample = sharp::AttrAsBool(options, "webpSmartSubsample");
|
|
1635
|
+
baton->webpPreset = sharp::AttrAsEnum<VipsForeignWebpPreset>(options, "webpPreset", VIPS_TYPE_FOREIGN_WEBP_PRESET);
|
|
1608
1636
|
baton->webpEffort = sharp::AttrAsUint32(options, "webpEffort");
|
|
1609
1637
|
baton->webpMinSize = sharp::AttrAsBool(options, "webpMinSize");
|
|
1610
1638
|
baton->webpMixed = sharp::AttrAsBool(options, "webpMixed");
|
|
@@ -1664,24 +1692,6 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
|
|
1664
1692
|
baton->tileId = sharp::AttrAsStr(options, "tileId");
|
|
1665
1693
|
baton->tileBasename = sharp::AttrAsStr(options, "tileBasename");
|
|
1666
1694
|
|
|
1667
|
-
// Force random access for certain operations
|
|
1668
|
-
if (baton->input->access == VIPS_ACCESS_SEQUENTIAL) {
|
|
1669
|
-
if (
|
|
1670
|
-
baton->trimThreshold > 0.0 ||
|
|
1671
|
-
baton->normalise ||
|
|
1672
|
-
baton->position == 16 || baton->position == 17 ||
|
|
1673
|
-
baton->angle != 0 ||
|
|
1674
|
-
baton->rotationAngle != 0.0 ||
|
|
1675
|
-
baton->tileAngle != 0 ||
|
|
1676
|
-
baton->useExifOrientation ||
|
|
1677
|
-
baton->flip ||
|
|
1678
|
-
baton->claheWidth != 0 ||
|
|
1679
|
-
!baton->affineMatrix.empty()
|
|
1680
|
-
) {
|
|
1681
|
-
baton->input->access = VIPS_ACCESS_RANDOM;
|
|
1682
|
-
}
|
|
1683
|
-
}
|
|
1684
|
-
|
|
1685
1695
|
// Function to notify of libvips warnings
|
|
1686
1696
|
Napi::Function debuglog = options.Get("debuglog").As<Napi::Function>();
|
|
1687
1697
|
|
package/src/pipeline.h
CHANGED
|
@@ -153,6 +153,7 @@ struct PipelineBaton {
|
|
|
153
153
|
bool webpNearLossless;
|
|
154
154
|
bool webpLossless;
|
|
155
155
|
bool webpSmartSubsample;
|
|
156
|
+
VipsForeignWebpPreset webpPreset;
|
|
156
157
|
int webpEffort;
|
|
157
158
|
bool webpMinSize;
|
|
158
159
|
bool webpMixed;
|
|
@@ -318,6 +319,7 @@ struct PipelineBaton {
|
|
|
318
319
|
webpNearLossless(false),
|
|
319
320
|
webpLossless(false),
|
|
320
321
|
webpSmartSubsample(false),
|
|
322
|
+
webpPreset(VIPS_FOREIGN_WEBP_PRESET_DEFAULT),
|
|
321
323
|
webpEffort(4),
|
|
322
324
|
webpMinSize(false),
|
|
323
325
|
webpMixed(false),
|