@revizly/sharp 0.34.1-revizly8 → 0.34.4-revizly1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/lib/channel.js +2 -0
- package/lib/constructor.js +19 -7
- package/lib/index.d.ts +115 -20
- package/lib/input.js +113 -23
- package/lib/libvips.js +2 -2
- package/lib/output.js +66 -0
- package/lib/resize.js +10 -5
- package/lib/utility.js +3 -9
- package/package.json +20 -25
- package/src/binding.gyp +7 -4
- package/src/common.cc +76 -68
- package/src/common.h +20 -21
- package/src/metadata.cc +4 -0
- package/src/pipeline.cc +60 -69
- package/src/pipeline.h +5 -1
- package/src/stats.cc +1 -1
- package/src/utilities.cc +1 -1
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);
|
|
@@ -1019,6 +1080,9 @@ function tiff (options) {
|
|
|
1019
1080
|
* AVIF image sequences are not supported.
|
|
1020
1081
|
* Prebuilt binaries support a bitdepth of 8 only.
|
|
1021
1082
|
*
|
|
1083
|
+
* This feature is experimental on the Windows ARM64 platform
|
|
1084
|
+
* and requires a CPU with ARM64v8.4 or later.
|
|
1085
|
+
*
|
|
1022
1086
|
* @example
|
|
1023
1087
|
* const data = await sharp(input)
|
|
1024
1088
|
* .avif({ effort: 2 })
|
|
@@ -1565,6 +1629,8 @@ module.exports = function (Sharp) {
|
|
|
1565
1629
|
withExifMerge,
|
|
1566
1630
|
keepIccProfile,
|
|
1567
1631
|
withIccProfile,
|
|
1632
|
+
keepXmp,
|
|
1633
|
+
withXmp,
|
|
1568
1634
|
keepMetadata,
|
|
1569
1635
|
withMetadata,
|
|
1570
1636
|
toFormat,
|
package/lib/resize.js
CHANGED
|
@@ -107,7 +107,7 @@ const mapFitToCanvas = {
|
|
|
107
107
|
* @private
|
|
108
108
|
*/
|
|
109
109
|
function isRotationExpected (options) {
|
|
110
|
-
return (options.angle % 360) !== 0 || options.
|
|
110
|
+
return (options.angle % 360) !== 0 || options.rotationAngle !== 0;
|
|
111
111
|
}
|
|
112
112
|
|
|
113
113
|
/**
|
|
@@ -129,7 +129,7 @@ function isResizeExpected (options) {
|
|
|
129
129
|
*
|
|
130
130
|
* Some of these values are based on the [object-fit](https://developer.mozilla.org/en-US/docs/Web/CSS/object-fit) CSS property.
|
|
131
131
|
*
|
|
132
|
-
* <img alt="Examples of various values for the fit property when resizing" width="100%" style="aspect-ratio: 998/243" src="
|
|
132
|
+
* <img alt="Examples of various values for the fit property when resizing" width="100%" style="aspect-ratio: 998/243" src="/api-resize-fit.svg">
|
|
133
133
|
*
|
|
134
134
|
* When using a **fit** of `cover` or `contain`, the default **position** is `centre`. Other options are:
|
|
135
135
|
* - `sharp.position`: `top`, `right top`, `right`, `right bottom`, `bottom`, `left bottom`, `left`, `left top`.
|
|
@@ -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`.
|
|
@@ -341,7 +343,7 @@ function resize (widthOrOptions, height, options) {
|
|
|
341
343
|
}
|
|
342
344
|
}
|
|
343
345
|
if (isRotationExpected(this.options) && isResizeExpected(this.options)) {
|
|
344
|
-
this.options.
|
|
346
|
+
this.options.rotateBefore = true;
|
|
345
347
|
}
|
|
346
348
|
return this;
|
|
347
349
|
}
|
|
@@ -488,9 +490,12 @@ function extract (options) {
|
|
|
488
490
|
// Ensure existing rotation occurs before pre-resize extraction
|
|
489
491
|
if (isRotationExpected(this.options) && !isResizeExpected(this.options)) {
|
|
490
492
|
if (this.options.widthPre === -1 || this.options.widthPost === -1) {
|
|
491
|
-
this.options.
|
|
493
|
+
this.options.rotateBefore = true;
|
|
492
494
|
}
|
|
493
495
|
}
|
|
496
|
+
if (this.options.input.autoOrient) {
|
|
497
|
+
this.options.orientBefore = true;
|
|
498
|
+
}
|
|
494
499
|
return this;
|
|
495
500
|
}
|
|
496
501
|
|
|
@@ -564,7 +569,7 @@ function trim (options) {
|
|
|
564
569
|
}
|
|
565
570
|
}
|
|
566
571
|
if (isRotationExpected(this.options)) {
|
|
567
|
-
this.options.
|
|
572
|
+
this.options.rotateBefore = true;
|
|
568
573
|
}
|
|
569
574
|
return this;
|
|
570
575
|
}
|
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": "@revizly/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.4-revizly1",
|
|
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,8 @@
|
|
|
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-
|
|
103
|
+
"package-from-local-build": "node npm/from-local-build.js",
|
|
104
|
+
"package-release-notes": "node npm/release-notes.js",
|
|
105
105
|
"docs-build": "node docs/build.mjs",
|
|
106
106
|
"docs-serve": "cd docs && npm start",
|
|
107
107
|
"docs-publish": "cd docs && npm run build && npx firebase-tools deploy --project pixelplumbing --only hosting:pixelplumbing-sharp"
|
|
@@ -138,49 +138,44 @@
|
|
|
138
138
|
],
|
|
139
139
|
"dependencies": {
|
|
140
140
|
"color": "^4.2.3",
|
|
141
|
-
"detect-libc": "^2.0.
|
|
142
|
-
"semver": "^7.7.
|
|
141
|
+
"detect-libc": "^2.0.4",
|
|
142
|
+
"semver": "^7.7.2"
|
|
143
143
|
},
|
|
144
144
|
"optionalDependencies": {
|
|
145
|
-
"@revizly/sharp-libvips-linux-arm64": "1.0.
|
|
146
|
-
"@revizly/sharp-libvips-linux-x64": "1.0.
|
|
147
|
-
"@revizly/sharp-linux-arm64": "0.34.1-
|
|
148
|
-
"@revizly/sharp-linux-x64": "0.34.1-
|
|
145
|
+
"@revizly/sharp-libvips-linux-arm64": "1.0.21",
|
|
146
|
+
"@revizly/sharp-libvips-linux-x64": "1.0.21",
|
|
147
|
+
"@revizly/sharp-linux-arm64": "0.34.1-revizly12",
|
|
148
|
+
"@revizly/sharp-linux-x64": "0.34.1-revizly12"
|
|
149
149
|
},
|
|
150
150
|
"devDependencies": {
|
|
151
|
-
"@emnapi/runtime": "^1.4.
|
|
152
|
-
"@revizly/sharp-libvips-dev": "1.0.
|
|
151
|
+
"@emnapi/runtime": "^1.4.5",
|
|
152
|
+
"@revizly/sharp-libvips-dev": "1.0.21",
|
|
153
153
|
"@types/node": "*",
|
|
154
154
|
"cc": "^3.0.1",
|
|
155
|
-
"emnapi": "^1.4.
|
|
155
|
+
"emnapi": "^1.4.5",
|
|
156
156
|
"exif-reader": "^2.0.2",
|
|
157
157
|
"extract-zip": "^2.0.1",
|
|
158
158
|
"icc": "^3.0.0",
|
|
159
|
-
"jsdoc-to-markdown": "^9.1.
|
|
159
|
+
"jsdoc-to-markdown": "^9.1.2",
|
|
160
160
|
"license-checker": "^25.0.1",
|
|
161
|
-
"mocha": "^11.1
|
|
162
|
-
"node-addon-api": "^8.
|
|
161
|
+
"mocha": "^11.7.1",
|
|
162
|
+
"node-addon-api": "^8.5.0",
|
|
163
|
+
"node-gyp": "^11.4.1",
|
|
163
164
|
"nyc": "^17.1.0",
|
|
164
|
-
"prebuild": "^13.0.1",
|
|
165
165
|
"semistandard": "^17.0.0",
|
|
166
|
-
"tar-fs": "^3.0
|
|
167
|
-
"tsd": "^0.
|
|
166
|
+
"tar-fs": "^3.1.0",
|
|
167
|
+
"tsd": "^0.33.0"
|
|
168
168
|
},
|
|
169
169
|
"license": "Apache-2.0",
|
|
170
170
|
"engines": {
|
|
171
171
|
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
|
172
172
|
},
|
|
173
173
|
"config": {
|
|
174
|
-
"libvips": ">=8.
|
|
174
|
+
"libvips": ">=8.17.1"
|
|
175
175
|
},
|
|
176
176
|
"funding": {
|
|
177
177
|
"url": "https://opencollective.com/libvips"
|
|
178
178
|
},
|
|
179
|
-
"binary": {
|
|
180
|
-
"napi_versions": [
|
|
181
|
-
9
|
|
182
|
-
]
|
|
183
|
-
},
|
|
184
179
|
"semistandard": {
|
|
185
180
|
"env": [
|
|
186
181
|
"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)'
|
|
@@ -203,11 +208,9 @@
|
|
|
203
208
|
'-Oz',
|
|
204
209
|
'-sALLOW_MEMORY_GROWTH',
|
|
205
210
|
'-sENVIRONMENT=node',
|
|
206
|
-
'-sEXPORTED_FUNCTIONS=
|
|
211
|
+
'-sEXPORTED_FUNCTIONS=emnapiInit,_vips_shutdown,_uv_library_shutdown',
|
|
207
212
|
'-sNODERAWFS',
|
|
208
|
-
'-
|
|
209
|
-
'-sWASM_ASYNC_COMPILATION=0',
|
|
210
|
-
'-sWASM_BIGINT'
|
|
213
|
+
'-sWASM_ASYNC_COMPILATION=0'
|
|
211
214
|
],
|
|
212
215
|
'libraries': [
|
|
213
216
|
'<!@(PKG_CONFIG_PATH="<!(node -p "require(\'@revizly/sharp-libvips-dev-wasm32/lib\')")/pkgconfig" pkg-config --static --libs vips-cpp)'
|
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);
|
|
@@ -951,14 +969,6 @@ namespace sharp {
|
|
|
951
969
|
return interpretation == VIPS_INTERPRETATION_RGB16 || interpretation == VIPS_INTERPRETATION_GREY16;
|
|
952
970
|
}
|
|
953
971
|
|
|
954
|
-
/*
|
|
955
|
-
Return the image alpha maximum. Useful for combining alpha bands. scRGB
|
|
956
|
-
images are 0 - 1 for image data, but the alpha is 0 - 255.
|
|
957
|
-
*/
|
|
958
|
-
double MaximumImageAlpha(VipsInterpretation const interpretation) {
|
|
959
|
-
return Is16Bit(interpretation) ? 65535.0 : 255.0;
|
|
960
|
-
}
|
|
961
|
-
|
|
962
972
|
/*
|
|
963
973
|
Convert RGBA value to another colourspace
|
|
964
974
|
*/
|
|
@@ -1001,16 +1011,16 @@ namespace sharp {
|
|
|
1001
1011
|
0.0722 * colour[2])
|
|
1002
1012
|
};
|
|
1003
1013
|
}
|
|
1004
|
-
// Add alpha channel to alphaColour colour
|
|
1014
|
+
// Add alpha channel(s) to alphaColour colour
|
|
1005
1015
|
if (colour[3] < 255.0 || image.has_alpha()) {
|
|
1006
|
-
|
|
1016
|
+
int extraBands = image.bands() > 4 ? image.bands() - 3 : 1;
|
|
1017
|
+
alphaColour.insert(alphaColour.end(), extraBands, colour[3] * multiplier);
|
|
1007
1018
|
}
|
|
1008
1019
|
// Ensure alphaColour colour uses correct colourspace
|
|
1009
1020
|
alphaColour = sharp::GetRgbaAsColourspace(alphaColour, image.interpretation(), premultiply);
|
|
1010
1021
|
// Add non-transparent alpha channel, if required
|
|
1011
1022
|
if (colour[3] < 255.0 && !image.has_alpha()) {
|
|
1012
|
-
image = image.
|
|
1013
|
-
VImage::new_matrix(image.width(), image.height()).new_from_image(255 * multiplier).cast(image.format()));
|
|
1023
|
+
image = image.bandjoin_const({ 255 * multiplier });
|
|
1014
1024
|
}
|
|
1015
1025
|
return std::make_tuple(image, alphaColour);
|
|
1016
1026
|
}
|
|
@@ -1030,9 +1040,7 @@ namespace sharp {
|
|
|
1030
1040
|
*/
|
|
1031
1041
|
VImage EnsureAlpha(VImage image, double const value) {
|
|
1032
1042
|
if (!image.has_alpha()) {
|
|
1033
|
-
|
|
1034
|
-
alpha.push_back(value * sharp::MaximumImageAlpha(image.interpretation()));
|
|
1035
|
-
image = image.bandjoin_const(alpha);
|
|
1043
|
+
image = image.bandjoin_const({ value * vips_interpretation_max_alpha(image.interpretation()) });
|
|
1036
1044
|
}
|
|
1037
1045
|
return image;
|
|
1038
1046
|
}
|
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)
|
|
@@ -357,12 +362,6 @@ namespace sharp {
|
|
|
357
362
|
*/
|
|
358
363
|
bool Is16Bit(VipsInterpretation const interpretation);
|
|
359
364
|
|
|
360
|
-
/*
|
|
361
|
-
Return the image alpha maximum. Useful for combining alpha bands. scRGB
|
|
362
|
-
images are 0 - 1 for image data, but the alpha is 0 - 255.
|
|
363
|
-
*/
|
|
364
|
-
double MaximumImageAlpha(VipsInterpretation const interpretation);
|
|
365
|
-
|
|
366
365
|
/*
|
|
367
366
|
Convert RGBA value to another colourspace
|
|
368
367
|
*/
|
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",
|