sharp 0.34.2 → 0.34.3-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/constructor.js +17 -6
- package/lib/index.d.ts +71 -8
- package/lib/input.js +113 -23
- package/lib/output.js +63 -0
- package/lib/resize.js +2 -0
- package/lib/utility.js +3 -9
- package/package.json +37 -42
- package/src/binding.gyp +5 -0
- package/src/common.cc +71 -53
- package/src/common.h +20 -15
- package/src/metadata.cc +4 -0
- package/src/pipeline.cc +21 -26
- package/src/pipeline.h +3 -0
- package/src/sharp.cc +4 -2
- package/src/utilities.cc +1 -1
package/lib/constructor.js
CHANGED
|
@@ -153,9 +153,6 @@ const debuglog = util.debuglog('sharp');
|
|
|
153
153
|
* @param {number} [options.ignoreIcc=false] - should the embedded ICC profile, if any, be ignored.
|
|
154
154
|
* @param {number} [options.pages=1] - Number of pages to extract for multi-page input (GIF, WebP, TIFF), use -1 for all pages.
|
|
155
155
|
* @param {number} [options.page=0] - Page number to start extracting from for multi-page input (GIF, WebP, TIFF), zero based.
|
|
156
|
-
* @param {number} [options.subifd=-1] - subIFD (Sub Image File Directory) to extract for OME-TIFF, defaults to main image.
|
|
157
|
-
* @param {number} [options.level=0] - level to extract from a multi-level input (OpenSlide), zero based.
|
|
158
|
-
* @param {string|Object} [options.pdfBackground] - Background colour to use when PDF is partially transparent. Parsed by the [color](https://www.npmjs.org/package/color) module to extract values for red, green, blue and alpha. Requires the use of a globally-installed libvips compiled with support for PDFium, Poppler, ImageMagick or GraphicsMagick.
|
|
159
156
|
* @param {boolean} [options.animated=false] - Set to `true` to read all frames/pages of an animated image (GIF, WebP, TIFF), equivalent of setting `pages` to `-1`.
|
|
160
157
|
* @param {Object} [options.raw] - describes raw pixel input image data. See `raw()` for pixel ordering.
|
|
161
158
|
* @param {number} [options.raw.width] - integral number of pixels wide.
|
|
@@ -163,15 +160,17 @@ const debuglog = util.debuglog('sharp');
|
|
|
163
160
|
* @param {number} [options.raw.channels] - integral number of channels, between 1 and 4.
|
|
164
161
|
* @param {boolean} [options.raw.premultiplied] - specifies that the raw input has already been premultiplied, set to `true`
|
|
165
162
|
* to avoid sharp premultiplying the image. (optional, default `false`)
|
|
163
|
+
* @param {number} [options.raw.pageHeight] - The pixel height of each page/frame for animated images, must be an integral factor of `raw.height`.
|
|
166
164
|
* @param {Object} [options.create] - describes a new image to be created.
|
|
167
165
|
* @param {number} [options.create.width] - integral number of pixels wide.
|
|
168
166
|
* @param {number} [options.create.height] - integral number of pixels high.
|
|
169
167
|
* @param {number} [options.create.channels] - integral number of channels, either 3 (RGB) or 4 (RGBA).
|
|
170
168
|
* @param {string|Object} [options.create.background] - parsed by the [color](https://www.npmjs.org/package/color) module to extract values for red, green, blue and alpha.
|
|
169
|
+
* @param {number} [options.create.pageHeight] - The pixel height of each page/frame for animated images, must be an integral factor of `create.height`.
|
|
171
170
|
* @param {Object} [options.create.noise] - describes a noise to be created.
|
|
172
171
|
* @param {string} [options.create.noise.type] - type of generated noise, currently only `gaussian` is supported.
|
|
173
|
-
* @param {number} [options.create.noise.mean] -
|
|
174
|
-
* @param {number} [options.create.noise.sigma] -
|
|
172
|
+
* @param {number} [options.create.noise.mean=128] - Mean value of pixels in the generated noise.
|
|
173
|
+
* @param {number} [options.create.noise.sigma=30] - Standard deviation of pixel values in the generated noise.
|
|
175
174
|
* @param {Object} [options.text] - describes a new text image to be created.
|
|
176
175
|
* @param {string} [options.text.text] - text to render as a UTF-8 string. It can contain Pango markup, for example `<i>Le</i>Monde`.
|
|
177
176
|
* @param {string} [options.text.font] - font name to render with.
|
|
@@ -191,7 +190,17 @@ const debuglog = util.debuglog('sharp');
|
|
|
191
190
|
* @param {string|Object} [options.join.background] - parsed by the [color](https://www.npmjs.org/package/color) module to extract values for red, green, blue and alpha.
|
|
192
191
|
* @param {string} [options.join.halign='left'] - horizontal alignment style for images joined horizontally (`'left'`, `'centre'`, `'center'`, `'right'`).
|
|
193
192
|
* @param {string} [options.join.valign='top'] - vertical alignment style for images joined vertically (`'top'`, `'centre'`, `'center'`, `'bottom'`).
|
|
194
|
-
*
|
|
193
|
+
* @param {Object} [options.tiff] - Describes TIFF specific options.
|
|
194
|
+
* @param {number} [options.tiff.subifd=-1] - Sub Image File Directory to extract for OME-TIFF, defaults to main image.
|
|
195
|
+
* @param {Object} [options.svg] - Describes SVG specific options.
|
|
196
|
+
* @param {string} [options.svg.stylesheet] - Custom CSS for SVG input, applied with a User Origin during the CSS cascade.
|
|
197
|
+
* @param {boolean} [options.svg.highBitdepth=false] - Set to `true` to render SVG input at 32-bits per channel (128-bit) instead of 8-bits per channel (32-bit) RGBA.
|
|
198
|
+
* @param {Object} [options.pdf] - Describes PDF specific options. Requires the use of a globally-installed libvips compiled with support for PDFium, Poppler, ImageMagick or GraphicsMagick.
|
|
199
|
+
* @param {string|Object} [options.pdf.background] - Background colour to use when PDF is partially transparent. Parsed by the [color](https://www.npmjs.org/package/color) module to extract values for red, green, blue and alpha.
|
|
200
|
+
* @param {Object} [options.openSlide] - Describes OpenSlide specific options. Requires the use of a globally-installed libvips compiled with support for OpenSlide.
|
|
201
|
+
* @param {number} [options.openSlide.level=0] - Level to extract from a multi-level input, zero based.
|
|
202
|
+
* @param {Object} [options.jp2] - Describes JPEG 2000 specific options. Requires the use of a globally-installed libvips compiled with support for OpenJPEG.
|
|
203
|
+
* @param {boolean} [options.jp2.oneshot=false] - Set to `true` to decode tiled JPEG 2000 images in a single operation, improving compatibility.
|
|
195
204
|
* @returns {Sharp}
|
|
196
205
|
* @throws {Error} Invalid parameters
|
|
197
206
|
*/
|
|
@@ -297,6 +306,7 @@ const Sharp = function (input, options) {
|
|
|
297
306
|
withIccProfile: '',
|
|
298
307
|
withExif: {},
|
|
299
308
|
withExifMerge: true,
|
|
309
|
+
withXmp: '',
|
|
300
310
|
resolveWithObject: false,
|
|
301
311
|
loop: -1,
|
|
302
312
|
delay: [],
|
|
@@ -337,6 +347,7 @@ const Sharp = function (input, options) {
|
|
|
337
347
|
gifDither: 1,
|
|
338
348
|
gifInterFrameMaxError: 0,
|
|
339
349
|
gifInterPaletteMaxError: 3,
|
|
350
|
+
gifKeepDuplicateFrames: false,
|
|
340
351
|
gifReuse: true,
|
|
341
352
|
gifProgressive: false,
|
|
342
353
|
tiffQuality: 80,
|
package/lib/index.d.ts
CHANGED
|
@@ -419,7 +419,7 @@ declare namespace sharp {
|
|
|
419
419
|
* @returns {Sharp}
|
|
420
420
|
*/
|
|
421
421
|
autoOrient(): Sharp
|
|
422
|
-
|
|
422
|
+
|
|
423
423
|
/**
|
|
424
424
|
* Flip the image about the vertical Y axis. This always occurs after rotation, if any.
|
|
425
425
|
* The use of flip implies the removal of the EXIF Orientation tag, if any.
|
|
@@ -730,6 +730,20 @@ declare namespace sharp {
|
|
|
730
730
|
*/
|
|
731
731
|
withIccProfile(icc: string, options?: WithIccProfileOptions): Sharp;
|
|
732
732
|
|
|
733
|
+
/**
|
|
734
|
+
* Keep all XMP metadata from the input image in the output image.
|
|
735
|
+
* @returns A sharp instance that can be used to chain operations
|
|
736
|
+
*/
|
|
737
|
+
keepXmp(): Sharp;
|
|
738
|
+
|
|
739
|
+
/**
|
|
740
|
+
* Set XMP metadata in the output image.
|
|
741
|
+
* @param {string} xmp - String containing XMP metadata to be embedded in the output image.
|
|
742
|
+
* @returns A sharp instance that can be used to chain operations
|
|
743
|
+
* @throws {Error} Invalid parameters
|
|
744
|
+
*/
|
|
745
|
+
withXmp(xmp: string): Sharp;
|
|
746
|
+
|
|
733
747
|
/**
|
|
734
748
|
* Include all metadata (EXIF, XMP, IPTC) from the input image in the output image.
|
|
735
749
|
* The default behaviour, when withMetadata is not used, is to strip all metadata and convert to the device-independent sRGB colour space.
|
|
@@ -1003,12 +1017,22 @@ declare namespace sharp {
|
|
|
1003
1017
|
pages?: number | undefined;
|
|
1004
1018
|
/** Page number to start extracting from for multi-page input (GIF, TIFF, PDF), zero based. (optional, default 0) */
|
|
1005
1019
|
page?: number | undefined;
|
|
1006
|
-
/**
|
|
1020
|
+
/** TIFF specific input options */
|
|
1021
|
+
tiff?: TiffInputOptions | undefined;
|
|
1022
|
+
/** SVG specific input options */
|
|
1023
|
+
svg?: SvgInputOptions | undefined;
|
|
1024
|
+
/** PDF specific input options */
|
|
1025
|
+
pdf?: PdfInputOptions | undefined;
|
|
1026
|
+
/** OpenSlide specific input options */
|
|
1027
|
+
openSlide?: OpenSlideInputOptions | undefined;
|
|
1028
|
+
/** JPEG 2000 specific input options */
|
|
1029
|
+
jp2?: Jp2InputOptions | undefined;
|
|
1030
|
+
/** Deprecated: use tiff.subifd instead */
|
|
1007
1031
|
subifd?: number | undefined;
|
|
1008
|
-
/**
|
|
1009
|
-
level?: number | undefined;
|
|
1010
|
-
/** Background colour to use when PDF is partially transparent. Requires the use of a globally-installed libvips compiled with support for PDFium, Poppler, ImageMagick or GraphicsMagick. */
|
|
1032
|
+
/** Deprecated: use pdf.background instead */
|
|
1011
1033
|
pdfBackground?: Colour | Color | undefined;
|
|
1034
|
+
/** Deprecated: use openSlide.level instead */
|
|
1035
|
+
level?: number | undefined;
|
|
1012
1036
|
/** Set to `true` to read all frames/pages of an animated image (equivalent of setting `pages` to `-1`). (optional, default false) */
|
|
1013
1037
|
animated?: boolean | undefined;
|
|
1014
1038
|
/** Describes raw pixel input image data. See raw() for pixel ordering. */
|
|
@@ -1051,6 +1075,8 @@ declare namespace sharp {
|
|
|
1051
1075
|
interface CreateRaw extends Raw {
|
|
1052
1076
|
/** Specifies that the raw input has already been premultiplied, set to true to avoid sharp premultiplying the image. (optional, default false) */
|
|
1053
1077
|
premultiplied?: boolean | undefined;
|
|
1078
|
+
/** The height of each page/frame for animated images, must be an integral factor of the overall image height. */
|
|
1079
|
+
pageHeight?: number | undefined;
|
|
1054
1080
|
}
|
|
1055
1081
|
|
|
1056
1082
|
type CreateChannels = 3 | 4;
|
|
@@ -1066,6 +1092,9 @@ declare namespace sharp {
|
|
|
1066
1092
|
background: Colour | Color;
|
|
1067
1093
|
/** Describes a noise to be created. */
|
|
1068
1094
|
noise?: Noise | undefined;
|
|
1095
|
+
/** The height of each page/frame for animated images, must be an integral factor of the overall image height. */
|
|
1096
|
+
pageHeight?: number | undefined;
|
|
1097
|
+
|
|
1069
1098
|
}
|
|
1070
1099
|
|
|
1071
1100
|
interface CreateText {
|
|
@@ -1114,6 +1143,33 @@ declare namespace sharp {
|
|
|
1114
1143
|
valign?: VerticalAlignment | undefined;
|
|
1115
1144
|
}
|
|
1116
1145
|
|
|
1146
|
+
interface TiffInputOptions {
|
|
1147
|
+
/** Sub Image File Directory to extract, defaults to main image. Use -1 for all subifds. */
|
|
1148
|
+
subifd?: number | undefined;
|
|
1149
|
+
}
|
|
1150
|
+
|
|
1151
|
+
interface SvgInputOptions {
|
|
1152
|
+
/** Custom CSS for SVG input, applied with a User Origin during the CSS cascade. */
|
|
1153
|
+
stylesheet?: string | undefined;
|
|
1154
|
+
/** Set to `true` to render SVG input at 32-bits per channel (128-bit) instead of 8-bits per channel (32-bit) RGBA. */
|
|
1155
|
+
highBitdepth?: boolean | undefined;
|
|
1156
|
+
}
|
|
1157
|
+
|
|
1158
|
+
interface PdfInputOptions {
|
|
1159
|
+
/** Background colour to use when PDF is partially transparent. Requires the use of a globally-installed libvips compiled with support for PDFium, Poppler, ImageMagick or GraphicsMagick. */
|
|
1160
|
+
background?: Colour | Color | undefined;
|
|
1161
|
+
}
|
|
1162
|
+
|
|
1163
|
+
interface OpenSlideInputOptions {
|
|
1164
|
+
/** Level to extract from a multi-level input, zero based. (optional, default 0) */
|
|
1165
|
+
level?: number | undefined;
|
|
1166
|
+
}
|
|
1167
|
+
|
|
1168
|
+
interface Jp2InputOptions {
|
|
1169
|
+
/** Set to `true` to load JPEG 2000 images using [oneshot mode](https://github.com/libvips/libvips/issues/4205) */
|
|
1170
|
+
oneshot?: boolean | undefined;
|
|
1171
|
+
}
|
|
1172
|
+
|
|
1117
1173
|
interface ExifDir {
|
|
1118
1174
|
[k: string]: string;
|
|
1119
1175
|
}
|
|
@@ -1198,6 +1254,8 @@ declare namespace sharp {
|
|
|
1198
1254
|
iptc?: Buffer | undefined;
|
|
1199
1255
|
/** Buffer containing raw XMP data, if present */
|
|
1200
1256
|
xmp?: Buffer | undefined;
|
|
1257
|
+
/** String containing XMP data, if valid UTF-8 */
|
|
1258
|
+
xmpAsString?: string | undefined;
|
|
1201
1259
|
/** Buffer containing raw TIFFTAG_PHOTOSHOP data, if present */
|
|
1202
1260
|
tifftagPhotoshop?: Buffer | undefined;
|
|
1203
1261
|
/** The encoder used to compress an HEIF file, `av1` (AVIF) or `hevc` (HEIC) */
|
|
@@ -1390,9 +1448,11 @@ declare namespace sharp {
|
|
|
1390
1448
|
/** Level of Floyd-Steinberg error diffusion, between 0 (least) and 1 (most) (optional, default 1.0) */
|
|
1391
1449
|
dither?: number | undefined;
|
|
1392
1450
|
/** Maximum inter-frame error for transparency, between 0 (lossless) and 32 (optional, default 0) */
|
|
1393
|
-
interFrameMaxError?: number;
|
|
1451
|
+
interFrameMaxError?: number | undefined;
|
|
1394
1452
|
/** Maximum inter-palette error for palette reuse, between 0 and 256 (optional, default 3) */
|
|
1395
|
-
interPaletteMaxError?: number;
|
|
1453
|
+
interPaletteMaxError?: number | undefined;
|
|
1454
|
+
/** Keep duplicate frames in the output instead of combining them (optional, default false) */
|
|
1455
|
+
keepDuplicateFrames?: boolean | undefined;
|
|
1396
1456
|
}
|
|
1397
1457
|
|
|
1398
1458
|
interface TiffOptions extends OutputOptions {
|
|
@@ -1510,7 +1570,7 @@ declare namespace sharp {
|
|
|
1510
1570
|
|
|
1511
1571
|
interface Noise {
|
|
1512
1572
|
/** type of generated noise, currently only gaussian is supported. */
|
|
1513
|
-
type
|
|
1573
|
+
type: 'gaussian';
|
|
1514
1574
|
/** mean of pixels in generated noise. */
|
|
1515
1575
|
mean?: number | undefined;
|
|
1516
1576
|
/** standard deviation of pixels in generated noise. */
|
|
@@ -1727,6 +1787,8 @@ declare namespace sharp {
|
|
|
1727
1787
|
mitchell: 'mitchell';
|
|
1728
1788
|
lanczos2: 'lanczos2';
|
|
1729
1789
|
lanczos3: 'lanczos3';
|
|
1790
|
+
mks2013: 'mks2013';
|
|
1791
|
+
mks2021: 'mks2021';
|
|
1730
1792
|
}
|
|
1731
1793
|
|
|
1732
1794
|
interface PresetEnum {
|
|
@@ -1844,6 +1906,7 @@ declare namespace sharp {
|
|
|
1844
1906
|
|
|
1845
1907
|
interface FormatEnum {
|
|
1846
1908
|
avif: AvailableFormatInfo;
|
|
1909
|
+
dcraw: AvailableFormatInfo;
|
|
1847
1910
|
dz: AvailableFormatInfo;
|
|
1848
1911
|
exr: AvailableFormatInfo;
|
|
1849
1912
|
fits: AvailableFormatInfo;
|
package/lib/input.js
CHANGED
|
@@ -22,14 +22,27 @@ const align = {
|
|
|
22
22
|
high: 'high'
|
|
23
23
|
};
|
|
24
24
|
|
|
25
|
+
const inputStreamParameters = [
|
|
26
|
+
// Limits and error handling
|
|
27
|
+
'failOn', 'limitInputPixels', 'unlimited',
|
|
28
|
+
// Format-generic
|
|
29
|
+
'animated', 'autoOrient', 'density', 'ignoreIcc', 'page', 'pages', 'sequentialRead',
|
|
30
|
+
// Format-specific
|
|
31
|
+
'jp2', 'openSlide', 'pdf', 'raw', 'svg', 'tiff',
|
|
32
|
+
// Deprecated
|
|
33
|
+
'failOnError', 'openSlideLevel', 'pdfBackground', 'tiffSubifd'
|
|
34
|
+
];
|
|
35
|
+
|
|
25
36
|
/**
|
|
26
37
|
* Extract input options, if any, from an object.
|
|
27
38
|
* @private
|
|
28
39
|
*/
|
|
29
40
|
function _inputOptionsFromObject (obj) {
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
|
|
41
|
+
const params = inputStreamParameters
|
|
42
|
+
.filter(p => is.defined(obj[p]))
|
|
43
|
+
.map(p => ([p, obj[p]]));
|
|
44
|
+
return params.length
|
|
45
|
+
? Object.fromEntries(params)
|
|
33
46
|
: undefined;
|
|
34
47
|
}
|
|
35
48
|
|
|
@@ -172,8 +185,6 @@ function _createInputDescriptor (input, inputOptions, containerOptions) {
|
|
|
172
185
|
inputDescriptor.rawWidth = inputOptions.raw.width;
|
|
173
186
|
inputDescriptor.rawHeight = inputOptions.raw.height;
|
|
174
187
|
inputDescriptor.rawChannels = inputOptions.raw.channels;
|
|
175
|
-
inputDescriptor.rawPremultiplied = !!inputOptions.raw.premultiplied;
|
|
176
|
-
|
|
177
188
|
switch (input.constructor) {
|
|
178
189
|
case Uint8Array:
|
|
179
190
|
case Uint8ClampedArray:
|
|
@@ -207,6 +218,25 @@ function _createInputDescriptor (input, inputOptions, containerOptions) {
|
|
|
207
218
|
} else {
|
|
208
219
|
throw new Error('Expected width, height and channels for raw pixel input');
|
|
209
220
|
}
|
|
221
|
+
inputDescriptor.rawPremultiplied = false;
|
|
222
|
+
if (is.defined(inputOptions.raw.premultiplied)) {
|
|
223
|
+
if (is.bool(inputOptions.raw.premultiplied)) {
|
|
224
|
+
inputDescriptor.rawPremultiplied = inputOptions.raw.premultiplied;
|
|
225
|
+
} else {
|
|
226
|
+
throw is.invalidParameterError('raw.premultiplied', 'boolean', inputOptions.raw.premultiplied);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
inputDescriptor.rawPageHeight = 0;
|
|
230
|
+
if (is.defined(inputOptions.raw.pageHeight)) {
|
|
231
|
+
if (is.integer(inputOptions.raw.pageHeight) && inputOptions.raw.pageHeight > 0 && inputOptions.raw.pageHeight <= inputOptions.raw.height) {
|
|
232
|
+
if (inputOptions.raw.height % inputOptions.raw.pageHeight !== 0) {
|
|
233
|
+
throw new Error(`Expected raw.height ${inputOptions.raw.height} to be a multiple of raw.pageHeight ${inputOptions.raw.pageHeight}`);
|
|
234
|
+
}
|
|
235
|
+
inputDescriptor.rawPageHeight = inputOptions.raw.pageHeight;
|
|
236
|
+
} else {
|
|
237
|
+
throw is.invalidParameterError('raw.pageHeight', 'positive integer', inputOptions.raw.pageHeight);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
210
240
|
}
|
|
211
241
|
// Multi-page input (GIF, TIFF, PDF)
|
|
212
242
|
if (is.defined(inputOptions.animated)) {
|
|
@@ -230,26 +260,68 @@ function _createInputDescriptor (input, inputOptions, containerOptions) {
|
|
|
230
260
|
throw is.invalidParameterError('page', 'integer between 0 and 100000', inputOptions.page);
|
|
231
261
|
}
|
|
232
262
|
}
|
|
233
|
-
//
|
|
234
|
-
if (is.defined(inputOptions.level)) {
|
|
263
|
+
// OpenSlide specific options
|
|
264
|
+
if (is.object(inputOptions.openSlide) && is.defined(inputOptions.openSlide.level)) {
|
|
265
|
+
if (is.integer(inputOptions.openSlide.level) && is.inRange(inputOptions.openSlide.level, 0, 256)) {
|
|
266
|
+
inputDescriptor.openSlideLevel = inputOptions.openSlide.level;
|
|
267
|
+
} else {
|
|
268
|
+
throw is.invalidParameterError('openSlide.level', 'integer between 0 and 256', inputOptions.openSlide.level);
|
|
269
|
+
}
|
|
270
|
+
} else if (is.defined(inputOptions.level)) {
|
|
271
|
+
// Deprecated
|
|
235
272
|
if (is.integer(inputOptions.level) && is.inRange(inputOptions.level, 0, 256)) {
|
|
236
|
-
inputDescriptor.
|
|
273
|
+
inputDescriptor.openSlideLevel = inputOptions.level;
|
|
237
274
|
} else {
|
|
238
275
|
throw is.invalidParameterError('level', 'integer between 0 and 256', inputOptions.level);
|
|
239
276
|
}
|
|
240
277
|
}
|
|
241
|
-
//
|
|
242
|
-
if (is.defined(inputOptions.subifd)) {
|
|
278
|
+
// TIFF specific options
|
|
279
|
+
if (is.object(inputOptions.tiff) && is.defined(inputOptions.tiff.subifd)) {
|
|
280
|
+
if (is.integer(inputOptions.tiff.subifd) && is.inRange(inputOptions.tiff.subifd, -1, 100000)) {
|
|
281
|
+
inputDescriptor.tiffSubifd = inputOptions.tiff.subifd;
|
|
282
|
+
} else {
|
|
283
|
+
throw is.invalidParameterError('tiff.subifd', 'integer between -1 and 100000', inputOptions.tiff.subifd);
|
|
284
|
+
}
|
|
285
|
+
} else if (is.defined(inputOptions.subifd)) {
|
|
286
|
+
// Deprecated
|
|
243
287
|
if (is.integer(inputOptions.subifd) && is.inRange(inputOptions.subifd, -1, 100000)) {
|
|
244
|
-
inputDescriptor.
|
|
288
|
+
inputDescriptor.tiffSubifd = inputOptions.subifd;
|
|
245
289
|
} else {
|
|
246
290
|
throw is.invalidParameterError('subifd', 'integer between -1 and 100000', inputOptions.subifd);
|
|
247
291
|
}
|
|
248
292
|
}
|
|
249
|
-
//
|
|
250
|
-
if (is.
|
|
293
|
+
// SVG specific options
|
|
294
|
+
if (is.object(inputOptions.svg)) {
|
|
295
|
+
if (is.defined(inputOptions.svg.stylesheet)) {
|
|
296
|
+
if (is.string(inputOptions.svg.stylesheet)) {
|
|
297
|
+
inputDescriptor.svgStylesheet = inputOptions.svg.stylesheet;
|
|
298
|
+
} else {
|
|
299
|
+
throw is.invalidParameterError('svg.stylesheet', 'string', inputOptions.svg.stylesheet);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
if (is.defined(inputOptions.svg.highBitdepth)) {
|
|
303
|
+
if (is.bool(inputOptions.svg.highBitdepth)) {
|
|
304
|
+
inputDescriptor.svgHighBitdepth = inputOptions.svg.highBitdepth;
|
|
305
|
+
} else {
|
|
306
|
+
throw is.invalidParameterError('svg.highBitdepth', 'boolean', inputOptions.svg.highBitdepth);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
// PDF specific options
|
|
311
|
+
if (is.object(inputOptions.pdf) && is.defined(inputOptions.pdf.background)) {
|
|
312
|
+
inputDescriptor.pdfBackground = this._getBackgroundColourOption(inputOptions.pdf.background);
|
|
313
|
+
} else if (is.defined(inputOptions.pdfBackground)) {
|
|
314
|
+
// Deprecated
|
|
251
315
|
inputDescriptor.pdfBackground = this._getBackgroundColourOption(inputOptions.pdfBackground);
|
|
252
316
|
}
|
|
317
|
+
// JPEG 2000 specific options
|
|
318
|
+
if (is.object(inputOptions.jp2) && is.defined(inputOptions.jp2.oneshot)) {
|
|
319
|
+
if (is.bool(inputOptions.jp2.oneshot)) {
|
|
320
|
+
inputDescriptor.jp2Oneshot = inputOptions.jp2.oneshot;
|
|
321
|
+
} else {
|
|
322
|
+
throw is.invalidParameterError('jp2.oneshot', 'boolean', inputOptions.jp2.oneshot);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
253
325
|
// Create new image
|
|
254
326
|
if (is.defined(inputOptions.create)) {
|
|
255
327
|
if (
|
|
@@ -261,27 +333,44 @@ function _createInputDescriptor (input, inputOptions, containerOptions) {
|
|
|
261
333
|
inputDescriptor.createWidth = inputOptions.create.width;
|
|
262
334
|
inputDescriptor.createHeight = inputOptions.create.height;
|
|
263
335
|
inputDescriptor.createChannels = inputOptions.create.channels;
|
|
336
|
+
inputDescriptor.createPageHeight = 0;
|
|
337
|
+
if (is.defined(inputOptions.create.pageHeight)) {
|
|
338
|
+
if (is.integer(inputOptions.create.pageHeight) && inputOptions.create.pageHeight > 0 && inputOptions.create.pageHeight <= inputOptions.create.height) {
|
|
339
|
+
if (inputOptions.create.height % inputOptions.create.pageHeight !== 0) {
|
|
340
|
+
throw new Error(`Expected create.height ${inputOptions.create.height} to be a multiple of create.pageHeight ${inputOptions.create.pageHeight}`);
|
|
341
|
+
}
|
|
342
|
+
inputDescriptor.createPageHeight = inputOptions.create.pageHeight;
|
|
343
|
+
} else {
|
|
344
|
+
throw is.invalidParameterError('create.pageHeight', 'positive integer', inputOptions.create.pageHeight);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
264
347
|
// Noise
|
|
265
348
|
if (is.defined(inputOptions.create.noise)) {
|
|
266
349
|
if (!is.object(inputOptions.create.noise)) {
|
|
267
350
|
throw new Error('Expected noise to be an object');
|
|
268
351
|
}
|
|
269
|
-
if (
|
|
352
|
+
if (inputOptions.create.noise.type !== 'gaussian') {
|
|
270
353
|
throw new Error('Only gaussian noise is supported at the moment');
|
|
271
354
|
}
|
|
355
|
+
inputDescriptor.createNoiseType = inputOptions.create.noise.type;
|
|
272
356
|
if (!is.inRange(inputOptions.create.channels, 1, 4)) {
|
|
273
357
|
throw is.invalidParameterError('create.channels', 'number between 1 and 4', inputOptions.create.channels);
|
|
274
358
|
}
|
|
275
|
-
inputDescriptor.
|
|
276
|
-
if (is.
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
359
|
+
inputDescriptor.createNoiseMean = 128;
|
|
360
|
+
if (is.defined(inputOptions.create.noise.mean)) {
|
|
361
|
+
if (is.number(inputOptions.create.noise.mean) && is.inRange(inputOptions.create.noise.mean, 0, 10000)) {
|
|
362
|
+
inputDescriptor.createNoiseMean = inputOptions.create.noise.mean;
|
|
363
|
+
} else {
|
|
364
|
+
throw is.invalidParameterError('create.noise.mean', 'number between 0 and 10000', inputOptions.create.noise.mean);
|
|
365
|
+
}
|
|
280
366
|
}
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
367
|
+
inputDescriptor.createNoiseSigma = 30;
|
|
368
|
+
if (is.defined(inputOptions.create.noise.sigma)) {
|
|
369
|
+
if (is.number(inputOptions.create.noise.sigma) && is.inRange(inputOptions.create.noise.sigma, 0, 10000)) {
|
|
370
|
+
inputDescriptor.createNoiseSigma = inputOptions.create.noise.sigma;
|
|
371
|
+
} else {
|
|
372
|
+
throw is.invalidParameterError('create.noise.sigma', 'number between 0 and 10000', inputOptions.create.noise.sigma);
|
|
373
|
+
}
|
|
285
374
|
}
|
|
286
375
|
} else if (is.defined(inputOptions.create.background)) {
|
|
287
376
|
if (!is.inRange(inputOptions.create.channels, 3, 4)) {
|
|
@@ -516,6 +605,7 @@ function _isStreamInput () {
|
|
|
516
605
|
* - `icc`: Buffer containing raw [ICC](https://www.npmjs.com/package/icc) profile data, if present
|
|
517
606
|
* - `iptc`: Buffer containing raw IPTC data, if present
|
|
518
607
|
* - `xmp`: Buffer containing raw XMP data, if present
|
|
608
|
+
* - `xmpAsString`: String containing XMP data, if valid UTF-8.
|
|
519
609
|
* - `tifftagPhotoshop`: Buffer containing raw TIFFTAG_PHOTOSHOP data, if present
|
|
520
610
|
* - `formatMagick`: String containing format for images loaded via *magick
|
|
521
611
|
* - `comments`: Array of keyword/text pairs representing PNG text blocks, if present.
|
package/lib/output.js
CHANGED
|
@@ -312,6 +312,59 @@ function withIccProfile (icc, options) {
|
|
|
312
312
|
return this;
|
|
313
313
|
}
|
|
314
314
|
|
|
315
|
+
/**
|
|
316
|
+
* Keep XMP metadata from the input image in the output image.
|
|
317
|
+
*
|
|
318
|
+
* @since 0.34.3
|
|
319
|
+
*
|
|
320
|
+
* @example
|
|
321
|
+
* const outputWithXmp = await sharp(inputWithXmp)
|
|
322
|
+
* .keepXmp()
|
|
323
|
+
* .toBuffer();
|
|
324
|
+
*
|
|
325
|
+
* @returns {Sharp}
|
|
326
|
+
*/
|
|
327
|
+
function keepXmp () {
|
|
328
|
+
this.options.keepMetadata |= 0b00010;
|
|
329
|
+
return this;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Set XMP metadata in the output image.
|
|
334
|
+
*
|
|
335
|
+
* Supported by PNG, JPEG, WebP, and TIFF output.
|
|
336
|
+
*
|
|
337
|
+
* @since 0.34.3
|
|
338
|
+
*
|
|
339
|
+
* @example
|
|
340
|
+
* const xmpString = `
|
|
341
|
+
* <?xml version="1.0"?>
|
|
342
|
+
* <x:xmpmeta xmlns:x="adobe:ns:meta/">
|
|
343
|
+
* <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
|
|
344
|
+
* <rdf:Description rdf:about="" xmlns:dc="http://purl.org/dc/elements/1.1/">
|
|
345
|
+
* <dc:creator><rdf:Seq><rdf:li>John Doe</rdf:li></rdf:Seq></dc:creator>
|
|
346
|
+
* </rdf:Description>
|
|
347
|
+
* </rdf:RDF>
|
|
348
|
+
* </x:xmpmeta>`;
|
|
349
|
+
*
|
|
350
|
+
* const data = await sharp(input)
|
|
351
|
+
* .withXmp(xmpString)
|
|
352
|
+
* .toBuffer();
|
|
353
|
+
*
|
|
354
|
+
* @param {string} xmp String containing XMP metadata to be embedded in the output image.
|
|
355
|
+
* @returns {Sharp}
|
|
356
|
+
* @throws {Error} Invalid parameters
|
|
357
|
+
*/
|
|
358
|
+
function withXmp (xmp) {
|
|
359
|
+
if (is.string(xmp) && xmp.length > 0) {
|
|
360
|
+
this.options.withXmp = xmp;
|
|
361
|
+
this.options.keepMetadata |= 0b00010;
|
|
362
|
+
} else {
|
|
363
|
+
throw is.invalidParameterError('xmp', 'non-empty string', xmp);
|
|
364
|
+
}
|
|
365
|
+
return this;
|
|
366
|
+
}
|
|
367
|
+
|
|
315
368
|
/**
|
|
316
369
|
* Keep all metadata (EXIF, ICC, XMP, IPTC) from the input image in the output image.
|
|
317
370
|
*
|
|
@@ -729,6 +782,7 @@ function webp (options) {
|
|
|
729
782
|
* @param {number} [options.dither=1.0] - level of Floyd-Steinberg error diffusion, between 0 (least) and 1 (most)
|
|
730
783
|
* @param {number} [options.interFrameMaxError=0] - maximum inter-frame error for transparency, between 0 (lossless) and 32
|
|
731
784
|
* @param {number} [options.interPaletteMaxError=3] - maximum inter-palette error for palette reuse, between 0 and 256
|
|
785
|
+
* @param {boolean} [options.keepDuplicateFrames=false] - keep duplicate frames in the output instead of combining them
|
|
732
786
|
* @param {number} [options.loop=0] - number of animation iterations, use 0 for infinite animation
|
|
733
787
|
* @param {number|number[]} [options.delay] - delay(s) between animation frames (in milliseconds)
|
|
734
788
|
* @param {boolean} [options.force=true] - force GIF output, otherwise attempt to use input format
|
|
@@ -779,6 +833,13 @@ function gif (options) {
|
|
|
779
833
|
throw is.invalidParameterError('interPaletteMaxError', 'number between 0.0 and 256.0', options.interPaletteMaxError);
|
|
780
834
|
}
|
|
781
835
|
}
|
|
836
|
+
if (is.defined(options.keepDuplicateFrames)) {
|
|
837
|
+
if (is.bool(options.keepDuplicateFrames)) {
|
|
838
|
+
this._setBooleanOption('gifKeepDuplicateFrames', options.keepDuplicateFrames);
|
|
839
|
+
} else {
|
|
840
|
+
throw is.invalidParameterError('keepDuplicateFrames', 'boolean', options.keepDuplicateFrames);
|
|
841
|
+
}
|
|
842
|
+
}
|
|
782
843
|
}
|
|
783
844
|
trySetAnimationOptions(options, this.options);
|
|
784
845
|
return this._updateFormatOut('gif', options);
|
|
@@ -1568,6 +1629,8 @@ module.exports = function (Sharp) {
|
|
|
1568
1629
|
withExifMerge,
|
|
1569
1630
|
keepIccProfile,
|
|
1570
1631
|
withIccProfile,
|
|
1632
|
+
keepXmp,
|
|
1633
|
+
withXmp,
|
|
1571
1634
|
keepMetadata,
|
|
1572
1635
|
withMetadata,
|
|
1573
1636
|
toFormat,
|
package/lib/resize.js
CHANGED
|
@@ -150,6 +150,8 @@ function isResizeExpected (options) {
|
|
|
150
150
|
* - `mitchell`: Use a [Mitchell-Netravali spline](https://www.cs.utexas.edu/~fussell/courses/cs384g-fall2013/lectures/mitchell/Mitchell.pdf).
|
|
151
151
|
* - `lanczos2`: Use a [Lanczos kernel](https://en.wikipedia.org/wiki/Lanczos_resampling#Lanczos_kernel) with `a=2`.
|
|
152
152
|
* - `lanczos3`: Use a Lanczos kernel with `a=3` (the default).
|
|
153
|
+
* - `mks2013`: Use a [Magic Kernel Sharp](https://johncostella.com/magic/mks.pdf) 2013 kernel, as adopted by Facebook.
|
|
154
|
+
* - `mks2021`: Use a Magic Kernel Sharp 2021 kernel, with more accurate (reduced) sharpening than the 2013 version.
|
|
153
155
|
*
|
|
154
156
|
* When upsampling, these kernels map to `nearest`, `linear` and `cubic` interpolators.
|
|
155
157
|
* Downsampling kernels without a matching upsampling interpolator map to `cubic`.
|
package/lib/utility.js
CHANGED
|
@@ -135,15 +135,9 @@ cache(true);
|
|
|
135
135
|
* e.g. libaom manages its own 4 threads when encoding AVIF images,
|
|
136
136
|
* and these are independent of the value set here.
|
|
137
137
|
*
|
|
138
|
-
*
|
|
139
|
-
*
|
|
140
|
-
*
|
|
141
|
-
*
|
|
142
|
-
* https://nodejs.org/api/cli.html#uv_threadpool_sizesize
|
|
143
|
-
*
|
|
144
|
-
* For example, by default, a machine with 8 CPU cores will process
|
|
145
|
-
* 4 images in parallel and use up to 8 threads per image,
|
|
146
|
-
* so there will be up to 32 concurrent threads.
|
|
138
|
+
* :::note
|
|
139
|
+
* Further {@link /performance|control over performance} is available.
|
|
140
|
+
* :::
|
|
147
141
|
*
|
|
148
142
|
* @example
|
|
149
143
|
* const threads = sharp.concurrency(); // 4
|
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.34.
|
|
4
|
+
"version": "0.34.3-rc.1",
|
|
5
5
|
"author": "Lovell Fuller <npm@lovell.info>",
|
|
6
6
|
"homepage": "https://sharp.pixelplumbing.com",
|
|
7
7
|
"contributors": [
|
|
@@ -92,7 +92,7 @@
|
|
|
92
92
|
"Don Denton <don@happycollision.com>"
|
|
93
93
|
],
|
|
94
94
|
"scripts": {
|
|
95
|
-
"install": "node install/check",
|
|
95
|
+
"install": "node install/check.js",
|
|
96
96
|
"clean": "rm -rf src/build/ .nyc_output/ coverage/ test/fixtures/output.*",
|
|
97
97
|
"test": "npm run test-lint && npm run test-unit && npm run test-licensing && npm run test-types",
|
|
98
98
|
"test-lint": "semistandard && cpplint",
|
|
@@ -100,8 +100,7 @@
|
|
|
100
100
|
"test-licensing": "license-checker --production --summary --onlyAllow=\"Apache-2.0;BSD;ISC;LGPL-3.0-or-later;MIT\"",
|
|
101
101
|
"test-leak": "./test/leak/leak.sh",
|
|
102
102
|
"test-types": "tsd",
|
|
103
|
-
"package-from-local-build": "node npm/from-local-build",
|
|
104
|
-
"package-from-github-release": "node npm/from-github-release",
|
|
103
|
+
"package-from-local-build": "node npm/from-local-build.js",
|
|
105
104
|
"docs-build": "node docs/build.mjs",
|
|
106
105
|
"docs-serve": "cd docs && npm start",
|
|
107
106
|
"docs-publish": "cd docs && npm run build && npx firebase-tools deploy --project pixelplumbing --only hosting:pixelplumbing-sharp"
|
|
@@ -142,49 +141,50 @@
|
|
|
142
141
|
"semver": "^7.7.2"
|
|
143
142
|
},
|
|
144
143
|
"optionalDependencies": {
|
|
145
|
-
"@img/sharp-darwin-arm64": "0.34.
|
|
146
|
-
"@img/sharp-darwin-x64": "0.34.
|
|
147
|
-
"@img/sharp-libvips-darwin-arm64": "1.
|
|
148
|
-
"@img/sharp-libvips-darwin-x64": "1.
|
|
149
|
-
"@img/sharp-libvips-linux-arm": "1.
|
|
150
|
-
"@img/sharp-libvips-linux-arm64": "1.
|
|
151
|
-
"@img/sharp-libvips-linux-ppc64": "1.
|
|
152
|
-
"@img/sharp-libvips-linux-s390x": "1.
|
|
153
|
-
"@img/sharp-libvips-linux-x64": "1.
|
|
154
|
-
"@img/sharp-libvips-linuxmusl-arm64": "1.
|
|
155
|
-
"@img/sharp-libvips-linuxmusl-x64": "1.
|
|
156
|
-
"@img/sharp-linux-arm": "0.34.
|
|
157
|
-
"@img/sharp-linux-arm64": "0.34.
|
|
158
|
-
"@img/sharp-linux-
|
|
159
|
-
"@img/sharp-linux-
|
|
160
|
-
"@img/sharp-
|
|
161
|
-
"@img/sharp-linuxmusl-
|
|
162
|
-
"@img/sharp-
|
|
163
|
-
"@img/sharp-
|
|
164
|
-
"@img/sharp-win32-
|
|
165
|
-
"@img/sharp-win32-
|
|
144
|
+
"@img/sharp-darwin-arm64": "0.34.3-rc.1",
|
|
145
|
+
"@img/sharp-darwin-x64": "0.34.3-rc.1",
|
|
146
|
+
"@img/sharp-libvips-darwin-arm64": "1.2.0",
|
|
147
|
+
"@img/sharp-libvips-darwin-x64": "1.2.0",
|
|
148
|
+
"@img/sharp-libvips-linux-arm": "1.2.0",
|
|
149
|
+
"@img/sharp-libvips-linux-arm64": "1.2.0",
|
|
150
|
+
"@img/sharp-libvips-linux-ppc64": "1.2.0",
|
|
151
|
+
"@img/sharp-libvips-linux-s390x": "1.2.0",
|
|
152
|
+
"@img/sharp-libvips-linux-x64": "1.2.0",
|
|
153
|
+
"@img/sharp-libvips-linuxmusl-arm64": "1.2.0",
|
|
154
|
+
"@img/sharp-libvips-linuxmusl-x64": "1.2.0",
|
|
155
|
+
"@img/sharp-linux-arm": "0.34.3-rc.1",
|
|
156
|
+
"@img/sharp-linux-arm64": "0.34.3-rc.1",
|
|
157
|
+
"@img/sharp-linux-ppc64": "0.34.3-rc.1",
|
|
158
|
+
"@img/sharp-linux-s390x": "0.34.3-rc.1",
|
|
159
|
+
"@img/sharp-linux-x64": "0.34.3-rc.1",
|
|
160
|
+
"@img/sharp-linuxmusl-arm64": "0.34.3-rc.1",
|
|
161
|
+
"@img/sharp-linuxmusl-x64": "0.34.3-rc.1",
|
|
162
|
+
"@img/sharp-wasm32": "0.34.3-rc.1",
|
|
163
|
+
"@img/sharp-win32-arm64": "0.34.3-rc.1",
|
|
164
|
+
"@img/sharp-win32-ia32": "0.34.3-rc.1",
|
|
165
|
+
"@img/sharp-win32-x64": "0.34.3-rc.1"
|
|
166
166
|
},
|
|
167
167
|
"devDependencies": {
|
|
168
|
-
"@emnapi/runtime": "^1.4.
|
|
169
|
-
"@img/sharp-libvips-dev": "1.
|
|
170
|
-
"@img/sharp-libvips-dev-wasm32": "1.
|
|
171
|
-
"@img/sharp-libvips-win32-arm64": "1.
|
|
172
|
-
"@img/sharp-libvips-win32-ia32": "1.
|
|
173
|
-
"@img/sharp-libvips-win32-x64": "1.
|
|
168
|
+
"@emnapi/runtime": "^1.4.4",
|
|
169
|
+
"@img/sharp-libvips-dev": "1.2.0",
|
|
170
|
+
"@img/sharp-libvips-dev-wasm32": "1.2.0",
|
|
171
|
+
"@img/sharp-libvips-win32-arm64": "1.2.0",
|
|
172
|
+
"@img/sharp-libvips-win32-ia32": "1.2.0",
|
|
173
|
+
"@img/sharp-libvips-win32-x64": "1.2.0",
|
|
174
174
|
"@types/node": "*",
|
|
175
175
|
"cc": "^3.0.1",
|
|
176
|
-
"emnapi": "^1.4.
|
|
176
|
+
"emnapi": "^1.4.4",
|
|
177
177
|
"exif-reader": "^2.0.2",
|
|
178
178
|
"extract-zip": "^2.0.1",
|
|
179
179
|
"icc": "^3.0.0",
|
|
180
180
|
"jsdoc-to-markdown": "^9.1.1",
|
|
181
181
|
"license-checker": "^25.0.1",
|
|
182
|
-
"mocha": "^11.
|
|
183
|
-
"node-addon-api": "^8.
|
|
182
|
+
"mocha": "^11.7.1",
|
|
183
|
+
"node-addon-api": "^8.4.0",
|
|
184
|
+
"node-gyp": "^11.2.0",
|
|
184
185
|
"nyc": "^17.1.0",
|
|
185
|
-
"prebuild": "^13.0.1",
|
|
186
186
|
"semistandard": "^17.0.0",
|
|
187
|
-
"tar-fs": "^3.0
|
|
187
|
+
"tar-fs": "^3.1.0",
|
|
188
188
|
"tsd": "^0.32.0"
|
|
189
189
|
},
|
|
190
190
|
"license": "Apache-2.0",
|
|
@@ -192,16 +192,11 @@
|
|
|
192
192
|
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
|
193
193
|
},
|
|
194
194
|
"config": {
|
|
195
|
-
"libvips": ">=8.
|
|
195
|
+
"libvips": ">=8.17.1"
|
|
196
196
|
},
|
|
197
197
|
"funding": {
|
|
198
198
|
"url": "https://opencollective.com/libvips"
|
|
199
199
|
},
|
|
200
|
-
"binary": {
|
|
201
|
-
"napi_versions": [
|
|
202
|
-
9
|
|
203
|
-
]
|
|
204
|
-
},
|
|
205
200
|
"semistandard": {
|
|
206
201
|
"env": [
|
|
207
202
|
"mocha"
|
package/src/binding.gyp
CHANGED
|
@@ -163,6 +163,8 @@
|
|
|
163
163
|
},
|
|
164
164
|
'xcode_settings': {
|
|
165
165
|
'OTHER_LDFLAGS': [
|
|
166
|
+
'-Wl,-s',
|
|
167
|
+
'-Wl,-dead_strip',
|
|
166
168
|
# Ensure runtime linking is relative to sharp.node
|
|
167
169
|
'-Wl,-rpath,\'@loader_path/../../sharp-libvips-<(platform_and_arch)/lib\'',
|
|
168
170
|
'-Wl,-rpath,\'@loader_path/../../../sharp-libvips-<(platform_and_arch)/<(sharp_libvips_version)/lib\'',
|
|
@@ -176,6 +178,9 @@
|
|
|
176
178
|
'defines': [
|
|
177
179
|
'_GLIBCXX_USE_CXX11_ABI=1'
|
|
178
180
|
],
|
|
181
|
+
'cflags_cc': [
|
|
182
|
+
'<!(node -p "require(\'detect-libc\').isNonGlibcLinuxSync() ? \'\' : \'-flto=auto\'")'
|
|
183
|
+
],
|
|
179
184
|
'link_settings': {
|
|
180
185
|
'libraries': [
|
|
181
186
|
'-l:libvips-cpp.so.<(vips_version)'
|
package/src/common.cc
CHANGED
|
@@ -93,6 +93,7 @@ namespace sharp {
|
|
|
93
93
|
descriptor->rawWidth = AttrAsUint32(input, "rawWidth");
|
|
94
94
|
descriptor->rawHeight = AttrAsUint32(input, "rawHeight");
|
|
95
95
|
descriptor->rawPremultiplied = AttrAsBool(input, "rawPremultiplied");
|
|
96
|
+
descriptor->rawPageHeight = AttrAsUint32(input, "rawPageHeight");
|
|
96
97
|
}
|
|
97
98
|
// Multi-page input (GIF, TIFF, PDF)
|
|
98
99
|
if (HasAttr(input, "pages")) {
|
|
@@ -101,23 +102,35 @@ namespace sharp {
|
|
|
101
102
|
if (HasAttr(input, "page")) {
|
|
102
103
|
descriptor->page = AttrAsUint32(input, "page");
|
|
103
104
|
}
|
|
105
|
+
// SVG
|
|
106
|
+
if (HasAttr(input, "svgStylesheet")) {
|
|
107
|
+
descriptor->svgStylesheet = AttrAsStr(input, "svgStylesheet");
|
|
108
|
+
}
|
|
109
|
+
if (HasAttr(input, "svgHighBitdepth")) {
|
|
110
|
+
descriptor->svgHighBitdepth = AttrAsBool(input, "svgHighBitdepth");
|
|
111
|
+
}
|
|
104
112
|
// Multi-level input (OpenSlide)
|
|
105
|
-
if (HasAttr(input, "
|
|
106
|
-
descriptor->
|
|
113
|
+
if (HasAttr(input, "openSlideLevel")) {
|
|
114
|
+
descriptor->openSlideLevel = AttrAsUint32(input, "openSlideLevel");
|
|
107
115
|
}
|
|
108
116
|
// subIFD (OME-TIFF)
|
|
109
117
|
if (HasAttr(input, "subifd")) {
|
|
110
|
-
descriptor->
|
|
118
|
+
descriptor->tiffSubifd = AttrAsInt32(input, "tiffSubifd");
|
|
111
119
|
}
|
|
112
120
|
// // PDF background color
|
|
113
121
|
if (HasAttr(input, "pdfBackground")) {
|
|
114
122
|
descriptor->pdfBackground = AttrAsVectorOfDouble(input, "pdfBackground");
|
|
115
123
|
}
|
|
124
|
+
// Use JPEG 2000 oneshot mode?
|
|
125
|
+
if (HasAttr(input, "jp2Oneshot")) {
|
|
126
|
+
descriptor->jp2Oneshot = AttrAsBool(input, "jp2Oneshot");
|
|
127
|
+
}
|
|
116
128
|
// Create new image
|
|
117
129
|
if (HasAttr(input, "createChannels")) {
|
|
118
130
|
descriptor->createChannels = AttrAsUint32(input, "createChannels");
|
|
119
131
|
descriptor->createWidth = AttrAsUint32(input, "createWidth");
|
|
120
132
|
descriptor->createHeight = AttrAsUint32(input, "createHeight");
|
|
133
|
+
descriptor->createPageHeight = AttrAsUint32(input, "createPageHeight");
|
|
121
134
|
if (HasAttr(input, "createNoiseType")) {
|
|
122
135
|
descriptor->createNoiseType = AttrAsStr(input, "createNoiseType");
|
|
123
136
|
descriptor->createNoiseMean = AttrAsDouble(input, "createNoiseMean");
|
|
@@ -271,6 +284,7 @@ namespace sharp {
|
|
|
271
284
|
case ImageType::EXR: id = "exr"; break;
|
|
272
285
|
case ImageType::JXL: id = "jxl"; break;
|
|
273
286
|
case ImageType::RAD: id = "rad"; break;
|
|
287
|
+
case ImageType::DCRAW: id = "dcraw"; break;
|
|
274
288
|
case ImageType::VIPS: id = "vips"; break;
|
|
275
289
|
case ImageType::RAW: id = "raw"; break;
|
|
276
290
|
case ImageType::UNKNOWN: id = "unknown"; break;
|
|
@@ -319,6 +333,8 @@ namespace sharp {
|
|
|
319
333
|
{ "VipsForeignLoadJxlBuffer", ImageType::JXL },
|
|
320
334
|
{ "VipsForeignLoadRadFile", ImageType::RAD },
|
|
321
335
|
{ "VipsForeignLoadRadBuffer", ImageType::RAD },
|
|
336
|
+
{ "VipsForeignLoadDcRawFile", ImageType::DCRAW },
|
|
337
|
+
{ "VipsForeignLoadDcRawBuffer", ImageType::DCRAW },
|
|
322
338
|
{ "VipsForeignLoadVips", ImageType::VIPS },
|
|
323
339
|
{ "VipsForeignLoadVipsFile", ImageType::VIPS },
|
|
324
340
|
{ "VipsForeignLoadRaw", ImageType::RAW }
|
|
@@ -383,6 +399,48 @@ namespace sharp {
|
|
|
383
399
|
imageType == ImageType::HEIF;
|
|
384
400
|
}
|
|
385
401
|
|
|
402
|
+
/*
|
|
403
|
+
Format-specific options builder
|
|
404
|
+
*/
|
|
405
|
+
vips::VOption* GetOptionsForImageType(ImageType imageType, InputDescriptor *descriptor) {
|
|
406
|
+
vips::VOption *option = VImage::option()
|
|
407
|
+
->set("access", descriptor->access)
|
|
408
|
+
->set("fail_on", descriptor->failOn);
|
|
409
|
+
if (descriptor->unlimited && ImageTypeSupportsUnlimited(imageType)) {
|
|
410
|
+
option->set("unlimited", true);
|
|
411
|
+
}
|
|
412
|
+
if (ImageTypeSupportsPage(imageType)) {
|
|
413
|
+
option->set("n", descriptor->pages);
|
|
414
|
+
option->set("page", descriptor->page);
|
|
415
|
+
}
|
|
416
|
+
switch (imageType) {
|
|
417
|
+
case ImageType::SVG:
|
|
418
|
+
option->set("dpi", descriptor->density)
|
|
419
|
+
->set("stylesheet", descriptor->svgStylesheet.data())
|
|
420
|
+
->set("high_bitdepth", descriptor->svgHighBitdepth);
|
|
421
|
+
break;
|
|
422
|
+
case ImageType::TIFF:
|
|
423
|
+
option->set("tiffSubifd", descriptor->tiffSubifd);
|
|
424
|
+
break;
|
|
425
|
+
case ImageType::PDF:
|
|
426
|
+
option->set("dpi", descriptor->density)
|
|
427
|
+
->set("background", descriptor->pdfBackground);
|
|
428
|
+
break;
|
|
429
|
+
case ImageType::OPENSLIDE:
|
|
430
|
+
option->set("openSlideLevel", descriptor->openSlideLevel);
|
|
431
|
+
break;
|
|
432
|
+
case ImageType::JP2:
|
|
433
|
+
option->set("oneshot", descriptor->jp2Oneshot);
|
|
434
|
+
break;
|
|
435
|
+
case ImageType::MAGICK:
|
|
436
|
+
option->set("density", std::to_string(descriptor->density).data());
|
|
437
|
+
break;
|
|
438
|
+
default:
|
|
439
|
+
break;
|
|
440
|
+
}
|
|
441
|
+
return option;
|
|
442
|
+
}
|
|
443
|
+
|
|
386
444
|
/*
|
|
387
445
|
Open an image from the given InputDescriptor (filesystem, compressed buffer, raw pixel data)
|
|
388
446
|
*/
|
|
@@ -400,6 +458,10 @@ namespace sharp {
|
|
|
400
458
|
} else {
|
|
401
459
|
image.get_image()->Type = is8bit ? VIPS_INTERPRETATION_sRGB : VIPS_INTERPRETATION_RGB16;
|
|
402
460
|
}
|
|
461
|
+
if (descriptor->rawPageHeight > 0) {
|
|
462
|
+
image.set(VIPS_META_PAGE_HEIGHT, descriptor->rawPageHeight);
|
|
463
|
+
image.set(VIPS_META_N_PAGES, static_cast<int>(descriptor->rawHeight / descriptor->rawPageHeight));
|
|
464
|
+
}
|
|
403
465
|
if (descriptor->rawPremultiplied) {
|
|
404
466
|
image = image.unpremultiply();
|
|
405
467
|
}
|
|
@@ -409,31 +471,7 @@ namespace sharp {
|
|
|
409
471
|
imageType = DetermineImageType(descriptor->buffer, descriptor->bufferLength);
|
|
410
472
|
if (imageType != ImageType::UNKNOWN) {
|
|
411
473
|
try {
|
|
412
|
-
vips::VOption *option =
|
|
413
|
-
->set("access", descriptor->access)
|
|
414
|
-
->set("fail_on", descriptor->failOn);
|
|
415
|
-
if (descriptor->unlimited && ImageTypeSupportsUnlimited(imageType)) {
|
|
416
|
-
option->set("unlimited", true);
|
|
417
|
-
}
|
|
418
|
-
if (imageType == ImageType::SVG || imageType == ImageType::PDF) {
|
|
419
|
-
option->set("dpi", descriptor->density);
|
|
420
|
-
}
|
|
421
|
-
if (imageType == ImageType::MAGICK) {
|
|
422
|
-
option->set("density", std::to_string(descriptor->density).data());
|
|
423
|
-
}
|
|
424
|
-
if (ImageTypeSupportsPage(imageType)) {
|
|
425
|
-
option->set("n", descriptor->pages);
|
|
426
|
-
option->set("page", descriptor->page);
|
|
427
|
-
}
|
|
428
|
-
if (imageType == ImageType::OPENSLIDE) {
|
|
429
|
-
option->set("level", descriptor->level);
|
|
430
|
-
}
|
|
431
|
-
if (imageType == ImageType::TIFF) {
|
|
432
|
-
option->set("subifd", descriptor->subifd);
|
|
433
|
-
}
|
|
434
|
-
if (imageType == ImageType::PDF) {
|
|
435
|
-
option->set("background", descriptor->pdfBackground);
|
|
436
|
-
}
|
|
474
|
+
vips::VOption *option = GetOptionsForImageType(imageType, descriptor);
|
|
437
475
|
image = VImage::new_from_buffer(descriptor->buffer, descriptor->bufferLength, nullptr, option);
|
|
438
476
|
if (imageType == ImageType::SVG || imageType == ImageType::PDF || imageType == ImageType::MAGICK) {
|
|
439
477
|
image = SetDensity(image, descriptor->density);
|
|
@@ -473,6 +511,10 @@ namespace sharp {
|
|
|
473
511
|
channels < 3 ? VIPS_INTERPRETATION_B_W : VIPS_INTERPRETATION_sRGB))
|
|
474
512
|
.new_from_image(background);
|
|
475
513
|
}
|
|
514
|
+
if (descriptor->createPageHeight > 0) {
|
|
515
|
+
image.set(VIPS_META_PAGE_HEIGHT, descriptor->createPageHeight);
|
|
516
|
+
image.set(VIPS_META_N_PAGES, static_cast<int>(descriptor->createHeight / descriptor->createPageHeight));
|
|
517
|
+
}
|
|
476
518
|
image = image.cast(VIPS_FORMAT_UCHAR);
|
|
477
519
|
imageType = ImageType::RAW;
|
|
478
520
|
} else if (descriptor->textValue.length() > 0) {
|
|
@@ -516,31 +558,7 @@ namespace sharp {
|
|
|
516
558
|
}
|
|
517
559
|
if (imageType != ImageType::UNKNOWN) {
|
|
518
560
|
try {
|
|
519
|
-
vips::VOption *option =
|
|
520
|
-
->set("access", descriptor->access)
|
|
521
|
-
->set("fail_on", descriptor->failOn);
|
|
522
|
-
if (descriptor->unlimited && ImageTypeSupportsUnlimited(imageType)) {
|
|
523
|
-
option->set("unlimited", true);
|
|
524
|
-
}
|
|
525
|
-
if (imageType == ImageType::SVG || imageType == ImageType::PDF) {
|
|
526
|
-
option->set("dpi", descriptor->density);
|
|
527
|
-
}
|
|
528
|
-
if (imageType == ImageType::MAGICK) {
|
|
529
|
-
option->set("density", std::to_string(descriptor->density).data());
|
|
530
|
-
}
|
|
531
|
-
if (ImageTypeSupportsPage(imageType)) {
|
|
532
|
-
option->set("n", descriptor->pages);
|
|
533
|
-
option->set("page", descriptor->page);
|
|
534
|
-
}
|
|
535
|
-
if (imageType == ImageType::OPENSLIDE) {
|
|
536
|
-
option->set("level", descriptor->level);
|
|
537
|
-
}
|
|
538
|
-
if (imageType == ImageType::TIFF) {
|
|
539
|
-
option->set("subifd", descriptor->subifd);
|
|
540
|
-
}
|
|
541
|
-
if (imageType == ImageType::PDF) {
|
|
542
|
-
option->set("background", descriptor->pdfBackground);
|
|
543
|
-
}
|
|
561
|
+
vips::VOption *option = GetOptionsForImageType(imageType, descriptor);
|
|
544
562
|
image = VImage::new_from_file(descriptor->file.data(), option);
|
|
545
563
|
if (imageType == ImageType::SVG || imageType == ImageType::PDF || imageType == ImageType::MAGICK) {
|
|
546
564
|
image = SetDensity(image, descriptor->density);
|
package/src/common.h
CHANGED
|
@@ -15,9 +15,9 @@
|
|
|
15
15
|
// Verify platform and compiler compatibility
|
|
16
16
|
|
|
17
17
|
#if (VIPS_MAJOR_VERSION < 8) || \
|
|
18
|
-
(VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION <
|
|
19
|
-
(VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION ==
|
|
20
|
-
#error "libvips version 8.
|
|
18
|
+
(VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION < 17) || \
|
|
19
|
+
(VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION == 17 && VIPS_MICRO_VERSION < 1)
|
|
20
|
+
#error "libvips version 8.17.1+ is required - please see https://sharp.pixelplumbing.com/install"
|
|
21
21
|
#endif
|
|
22
22
|
|
|
23
23
|
#if defined(__has_include)
|
|
@@ -48,13 +48,13 @@ namespace sharp {
|
|
|
48
48
|
int rawWidth;
|
|
49
49
|
int rawHeight;
|
|
50
50
|
bool rawPremultiplied;
|
|
51
|
+
int rawPageHeight;
|
|
51
52
|
int pages;
|
|
52
53
|
int page;
|
|
53
|
-
int level;
|
|
54
|
-
int subifd;
|
|
55
54
|
int createChannels;
|
|
56
55
|
int createWidth;
|
|
57
56
|
int createHeight;
|
|
57
|
+
int createPageHeight;
|
|
58
58
|
std::vector<double> createBackground;
|
|
59
59
|
std::string createNoiseType;
|
|
60
60
|
double createNoiseMean;
|
|
@@ -77,7 +77,12 @@ namespace sharp {
|
|
|
77
77
|
std::vector<double> joinBackground;
|
|
78
78
|
VipsAlign joinHalign;
|
|
79
79
|
VipsAlign joinValign;
|
|
80
|
+
std::string svgStylesheet;
|
|
81
|
+
bool svgHighBitdepth;
|
|
82
|
+
int tiffSubifd;
|
|
83
|
+
int openSlideLevel;
|
|
80
84
|
std::vector<double> pdfBackground;
|
|
85
|
+
bool jp2Oneshot;
|
|
81
86
|
|
|
82
87
|
InputDescriptor():
|
|
83
88
|
autoOrient(false),
|
|
@@ -95,13 +100,13 @@ namespace sharp {
|
|
|
95
100
|
rawWidth(0),
|
|
96
101
|
rawHeight(0),
|
|
97
102
|
rawPremultiplied(false),
|
|
103
|
+
rawPageHeight(0),
|
|
98
104
|
pages(1),
|
|
99
105
|
page(0),
|
|
100
|
-
level(0),
|
|
101
|
-
subifd(-1),
|
|
102
106
|
createChannels(0),
|
|
103
107
|
createWidth(0),
|
|
104
108
|
createHeight(0),
|
|
109
|
+
createPageHeight(0),
|
|
105
110
|
createBackground{ 0.0, 0.0, 0.0, 255.0 },
|
|
106
111
|
createNoiseMean(0.0),
|
|
107
112
|
createNoiseSigma(0.0),
|
|
@@ -120,7 +125,11 @@ namespace sharp {
|
|
|
120
125
|
joinBackground{ 0.0, 0.0, 0.0, 255.0 },
|
|
121
126
|
joinHalign(VIPS_ALIGN_LOW),
|
|
122
127
|
joinValign(VIPS_ALIGN_LOW),
|
|
123
|
-
|
|
128
|
+
svgHighBitdepth(false),
|
|
129
|
+
tiffSubifd(-1),
|
|
130
|
+
openSlideLevel(0),
|
|
131
|
+
pdfBackground{ 255.0, 255.0, 255.0, 255.0 },
|
|
132
|
+
jp2Oneshot(false) {}
|
|
124
133
|
};
|
|
125
134
|
|
|
126
135
|
// Convenience methods to access the attributes of a Napi::Object
|
|
@@ -160,6 +169,7 @@ namespace sharp {
|
|
|
160
169
|
EXR,
|
|
161
170
|
JXL,
|
|
162
171
|
RAD,
|
|
172
|
+
DCRAW,
|
|
163
173
|
VIPS,
|
|
164
174
|
RAW,
|
|
165
175
|
UNKNOWN,
|
|
@@ -216,14 +226,9 @@ namespace sharp {
|
|
|
216
226
|
ImageType DetermineImageType(char const *file);
|
|
217
227
|
|
|
218
228
|
/*
|
|
219
|
-
|
|
229
|
+
Format-specific options builder
|
|
220
230
|
*/
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
/*
|
|
224
|
-
Does this image type support removal of safety limits?
|
|
225
|
-
*/
|
|
226
|
-
bool ImageTypeSupportsUnlimited(ImageType imageType);
|
|
231
|
+
vips::VOption* GetOptionsForImageType(ImageType imageType, InputDescriptor *descriptor);
|
|
227
232
|
|
|
228
233
|
/*
|
|
229
234
|
Open an image from the given InputDescriptor (filesystem, compressed buffer, raw pixel data)
|
package/src/metadata.cc
CHANGED
|
@@ -262,6 +262,10 @@ class MetadataWorker : public Napi::AsyncWorker {
|
|
|
262
262
|
}
|
|
263
263
|
if (baton->xmpLength > 0) {
|
|
264
264
|
info.Set("xmp", Napi::Buffer<char>::NewOrCopy(env, baton->xmp, baton->xmpLength, sharp::FreeCallback));
|
|
265
|
+
if (g_utf8_validate(static_cast<char const *>(baton->xmp), baton->xmpLength, nullptr)) {
|
|
266
|
+
info.Set("xmpAsString",
|
|
267
|
+
Napi::String::New(env, static_cast<char const *>(baton->xmp), baton->xmpLength));
|
|
268
|
+
}
|
|
265
269
|
}
|
|
266
270
|
if (baton->tifftagPhotoshopLength > 0) {
|
|
267
271
|
info.Set("tifftagPhotoshop",
|
package/src/pipeline.cc
CHANGED
|
@@ -241,11 +241,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
241
241
|
// factor for jpegload*, a double scale factor for webpload*,
|
|
242
242
|
// pdfload* and svgload*
|
|
243
243
|
if (jpegShrinkOnLoad > 1) {
|
|
244
|
-
vips::VOption *option =
|
|
245
|
-
->set("access", access)
|
|
246
|
-
->set("shrink", jpegShrinkOnLoad)
|
|
247
|
-
->set("unlimited", baton->input->unlimited)
|
|
248
|
-
->set("fail_on", baton->input->failOn);
|
|
244
|
+
vips::VOption *option = GetOptionsForImageType(inputImageType, baton->input)->set("shrink", jpegShrinkOnLoad);
|
|
249
245
|
if (baton->input->buffer != nullptr) {
|
|
250
246
|
// Reload JPEG buffer
|
|
251
247
|
VipsBlob *blob = vips_blob_new(nullptr, baton->input->buffer, baton->input->bufferLength);
|
|
@@ -256,14 +252,8 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
256
252
|
image = VImage::jpegload(const_cast<char*>(baton->input->file.data()), option);
|
|
257
253
|
}
|
|
258
254
|
} else if (scale != 1.0) {
|
|
259
|
-
vips::VOption *option =
|
|
260
|
-
->set("access", access)
|
|
261
|
-
->set("scale", scale)
|
|
262
|
-
->set("fail_on", baton->input->failOn);
|
|
255
|
+
vips::VOption *option = GetOptionsForImageType(inputImageType, baton->input)->set("scale", scale);
|
|
263
256
|
if (inputImageType == sharp::ImageType::WEBP) {
|
|
264
|
-
option->set("n", baton->input->pages);
|
|
265
|
-
option->set("page", baton->input->page);
|
|
266
|
-
|
|
267
257
|
if (baton->input->buffer != nullptr) {
|
|
268
258
|
// Reload WebP buffer
|
|
269
259
|
VipsBlob *blob = vips_blob_new(nullptr, baton->input->buffer, baton->input->bufferLength);
|
|
@@ -274,9 +264,6 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
274
264
|
image = VImage::webpload(const_cast<char*>(baton->input->file.data()), option);
|
|
275
265
|
}
|
|
276
266
|
} else if (inputImageType == sharp::ImageType::SVG) {
|
|
277
|
-
option->set("unlimited", baton->input->unlimited);
|
|
278
|
-
option->set("dpi", baton->input->density);
|
|
279
|
-
|
|
280
267
|
if (baton->input->buffer != nullptr) {
|
|
281
268
|
// Reload SVG buffer
|
|
282
269
|
VipsBlob *blob = vips_blob_new(nullptr, baton->input->buffer, baton->input->bufferLength);
|
|
@@ -291,11 +278,6 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
291
278
|
throw vips::VError("Input SVG image will exceed 32767x32767 pixel limit when scaled");
|
|
292
279
|
}
|
|
293
280
|
} else if (inputImageType == sharp::ImageType::PDF) {
|
|
294
|
-
option->set("n", baton->input->pages);
|
|
295
|
-
option->set("page", baton->input->page);
|
|
296
|
-
option->set("dpi", baton->input->density);
|
|
297
|
-
option->set("background", baton->input->pdfBackground);
|
|
298
|
-
|
|
299
281
|
if (baton->input->buffer != nullptr) {
|
|
300
282
|
// Reload PDF buffer
|
|
301
283
|
VipsBlob *blob = vips_blob_new(nullptr, baton->input->buffer, baton->input->bufferLength);
|
|
@@ -305,7 +287,6 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
305
287
|
// Reload PDF file
|
|
306
288
|
image = VImage::pdfload(const_cast<char*>(baton->input->file.data()), option);
|
|
307
289
|
}
|
|
308
|
-
|
|
309
290
|
sharp::SetDensity(image, baton->input->density);
|
|
310
291
|
}
|
|
311
292
|
} else {
|
|
@@ -669,7 +650,6 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
669
650
|
sharp::ImageType compositeImageType = sharp::ImageType::UNKNOWN;
|
|
670
651
|
composite->input->access = access;
|
|
671
652
|
std::tie(compositeImage, compositeImageType) = sharp::OpenInput(composite->input);
|
|
672
|
-
compositeImage = sharp::EnsureColourspace(compositeImage, baton->colourspacePipeline);
|
|
673
653
|
|
|
674
654
|
if (composite->input->autoOrient) {
|
|
675
655
|
// Respect EXIF Orientation
|
|
@@ -734,8 +714,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
734
714
|
// gravity was used for extract_area, set it back to its default value of 0
|
|
735
715
|
composite->gravity = 0;
|
|
736
716
|
}
|
|
737
|
-
// Ensure image to composite is
|
|
738
|
-
compositeImage = compositeImage.colourspace(VIPS_INTERPRETATION_sRGB);
|
|
717
|
+
// Ensure image to composite is with unpremultiplied alpha
|
|
739
718
|
compositeImage = sharp::EnsureAlpha(compositeImage, 1);
|
|
740
719
|
if (composite->premultiplied) compositeImage = compositeImage.unpremultiply();
|
|
741
720
|
// Calculate position
|
|
@@ -760,7 +739,12 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
760
739
|
xs.push_back(left);
|
|
761
740
|
ys.push_back(top);
|
|
762
741
|
}
|
|
763
|
-
image = VImage::composite(images, modes, VImage::option()
|
|
742
|
+
image = VImage::composite(images, modes, VImage::option()
|
|
743
|
+
->set("compositing_space", baton->colourspacePipeline == VIPS_INTERPRETATION_LAST
|
|
744
|
+
? VIPS_INTERPRETATION_sRGB
|
|
745
|
+
: baton->colourspacePipeline)
|
|
746
|
+
->set("x", xs)
|
|
747
|
+
->set("y", ys));
|
|
764
748
|
image = sharp::RemoveGifPalette(image);
|
|
765
749
|
}
|
|
766
750
|
|
|
@@ -892,7 +876,12 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
892
876
|
image.set(s.first.data(), s.second.data());
|
|
893
877
|
}
|
|
894
878
|
}
|
|
895
|
-
|
|
879
|
+
// XMP buffer
|
|
880
|
+
if ((baton->keepMetadata & VIPS_FOREIGN_KEEP_XMP) && !baton->withXmp.empty()) {
|
|
881
|
+
image = image.copy();
|
|
882
|
+
image.set(VIPS_META_XMP_NAME, nullptr,
|
|
883
|
+
const_cast<void*>(static_cast<void const*>(baton->withXmp.c_str())), baton->withXmp.size());
|
|
884
|
+
}
|
|
896
885
|
// Number of channels used in output image
|
|
897
886
|
baton->channels = image.bands();
|
|
898
887
|
baton->width = image.width();
|
|
@@ -1003,6 +992,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
1003
992
|
->set("interlace", baton->gifProgressive)
|
|
1004
993
|
->set("interframe_maxerror", baton->gifInterFrameMaxError)
|
|
1005
994
|
->set("interpalette_maxerror", baton->gifInterPaletteMaxError)
|
|
995
|
+
->set("keep_duplicate_frames", baton->gifKeepDuplicateFrames)
|
|
1006
996
|
->set("dither", baton->gifDither)));
|
|
1007
997
|
baton->bufferOut = static_cast<char*>(area->data);
|
|
1008
998
|
baton->bufferOutLength = area->length;
|
|
@@ -1206,6 +1196,9 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|
|
1206
1196
|
->set("effort", baton->gifEffort)
|
|
1207
1197
|
->set("reuse", baton->gifReuse)
|
|
1208
1198
|
->set("interlace", baton->gifProgressive)
|
|
1199
|
+
->set("interframe_maxerror", baton->gifInterFrameMaxError)
|
|
1200
|
+
->set("interpalette_maxerror", baton->gifInterPaletteMaxError)
|
|
1201
|
+
->set("keep_duplicate_frames", baton->gifKeepDuplicateFrames)
|
|
1209
1202
|
->set("dither", baton->gifDither));
|
|
1210
1203
|
baton->formatOut = "gif";
|
|
1211
1204
|
} else if (baton->formatOut == "tiff" || (mightMatchInput && isTiff) ||
|
|
@@ -1718,6 +1711,7 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
|
|
1718
1711
|
}
|
|
1719
1712
|
}
|
|
1720
1713
|
baton->withExifMerge = sharp::AttrAsBool(options, "withExifMerge");
|
|
1714
|
+
baton->withXmp = sharp::AttrAsStr(options, "withXmp");
|
|
1721
1715
|
baton->timeoutSeconds = sharp::AttrAsUint32(options, "timeoutSeconds");
|
|
1722
1716
|
baton->loop = sharp::AttrAsUint32(options, "loop");
|
|
1723
1717
|
baton->delay = sharp::AttrAsInt32Vector(options, "delay");
|
|
@@ -1758,6 +1752,7 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
|
|
1758
1752
|
baton->gifDither = sharp::AttrAsDouble(options, "gifDither");
|
|
1759
1753
|
baton->gifInterFrameMaxError = sharp::AttrAsDouble(options, "gifInterFrameMaxError");
|
|
1760
1754
|
baton->gifInterPaletteMaxError = sharp::AttrAsDouble(options, "gifInterPaletteMaxError");
|
|
1755
|
+
baton->gifKeepDuplicateFrames = sharp::AttrAsBool(options, "gifKeepDuplicateFrames");
|
|
1761
1756
|
baton->gifReuse = sharp::AttrAsBool(options, "gifReuse");
|
|
1762
1757
|
baton->gifProgressive = sharp::AttrAsBool(options, "gifProgressive");
|
|
1763
1758
|
baton->tiffQuality = sharp::AttrAsUint32(options, "tiffQuality");
|
package/src/pipeline.h
CHANGED
|
@@ -169,6 +169,7 @@ struct PipelineBaton {
|
|
|
169
169
|
double gifDither;
|
|
170
170
|
double gifInterFrameMaxError;
|
|
171
171
|
double gifInterPaletteMaxError;
|
|
172
|
+
bool gifKeepDuplicateFrames;
|
|
172
173
|
bool gifReuse;
|
|
173
174
|
bool gifProgressive;
|
|
174
175
|
int tiffQuality;
|
|
@@ -201,6 +202,7 @@ struct PipelineBaton {
|
|
|
201
202
|
std::string withIccProfile;
|
|
202
203
|
std::unordered_map<std::string, std::string> withExif;
|
|
203
204
|
bool withExifMerge;
|
|
205
|
+
std::string withXmp;
|
|
204
206
|
int timeoutSeconds;
|
|
205
207
|
std::vector<double> convKernel;
|
|
206
208
|
int convKernelWidth;
|
|
@@ -342,6 +344,7 @@ struct PipelineBaton {
|
|
|
342
344
|
gifDither(1.0),
|
|
343
345
|
gifInterFrameMaxError(0.0),
|
|
344
346
|
gifInterPaletteMaxError(3.0),
|
|
347
|
+
gifKeepDuplicateFrames(false),
|
|
345
348
|
gifReuse(true),
|
|
346
349
|
gifProgressive(false),
|
|
347
350
|
tiffQuality(80),
|
package/src/sharp.cc
CHANGED
|
@@ -18,8 +18,10 @@ Napi::Object init(Napi::Env env, Napi::Object exports) {
|
|
|
18
18
|
vips_init("sharp");
|
|
19
19
|
});
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
static_cast<
|
|
21
|
+
for (auto domain : { "VIPS", "vips2tiff" }) {
|
|
22
|
+
g_log_set_handler(domain, static_cast<GLogLevelFlags>(G_LOG_LEVEL_WARNING),
|
|
23
|
+
static_cast<GLogFunc>(sharp::VipsWarningCallback), nullptr);
|
|
24
|
+
}
|
|
23
25
|
|
|
24
26
|
// Methods available to JavaScript
|
|
25
27
|
exports.Set("metadata", Napi::Function::New(env, metadata));
|
package/src/utilities.cc
CHANGED
|
@@ -119,7 +119,7 @@ Napi::Value format(const Napi::CallbackInfo& info) {
|
|
|
119
119
|
Napi::Object format = Napi::Object::New(env);
|
|
120
120
|
for (std::string const f : {
|
|
121
121
|
"jpeg", "png", "webp", "tiff", "magick", "openslide", "dz",
|
|
122
|
-
"ppm", "fits", "gif", "svg", "heif", "pdf", "vips", "jp2k", "jxl", "rad"
|
|
122
|
+
"ppm", "fits", "gif", "svg", "heif", "pdf", "vips", "jp2k", "jxl", "rad", "dcraw"
|
|
123
123
|
}) {
|
|
124
124
|
// Input
|
|
125
125
|
const VipsObjectClass *oc = vips_class_find("VipsOperation", (f + "load").c_str());
|