sharp 0.23.0 → 0.23.4
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 +3 -2
- package/binding.gyp +16 -10
- package/docs/api-composite.md +1 -0
- package/docs/api-constructor.md +1 -1
- package/docs/api-input.md +1 -0
- package/docs/api-output.md +96 -84
- package/docs/api-resize.md +2 -0
- package/docs/changelog.md +58 -0
- package/docs/index.md +7 -2
- package/docs/install.md +11 -4
- package/docs/performance.md +12 -13
- package/install/libvips.js +12 -7
- package/lib/agent.js +5 -2
- package/lib/colour.js +16 -12
- package/lib/composite.js +11 -1
- package/lib/constructor.js +2 -1
- package/lib/input.js +5 -0
- package/lib/operation.js +1 -1
- package/lib/output.js +29 -9
- package/lib/platform.js +1 -0
- package/lib/resize.js +17 -8
- package/package.json +29 -18
- package/src/common.cc +20 -13
- package/src/common.h +7 -5
- package/src/metadata.cc +14 -0
- package/src/metadata.h +5 -1
- package/src/operations.cc +26 -5
- package/src/pipeline.cc +17 -6
- package/src/pipeline.h +5 -1
- package/src/utilities.cc +3 -2
package/install/libvips.js
CHANGED
|
@@ -19,6 +19,9 @@ const distBaseUrl = process.env.npm_config_sharp_dist_base_url || process.env.SH
|
|
|
19
19
|
|
|
20
20
|
const fail = function (err) {
|
|
21
21
|
npmLog.error('sharp', err.message);
|
|
22
|
+
if (err.code === 'EACCES') {
|
|
23
|
+
npmLog.info('sharp', 'Are you trying to install as a root or sudo user? Try again with the --unsafe-perm flag');
|
|
24
|
+
}
|
|
22
25
|
npmLog.info('sharp', 'Attempting to build from source via node-gyp but this may fail due to the above error');
|
|
23
26
|
npmLog.info('sharp', 'Please see https://sharp.pixelplumbing.com/page/install for required dependencies');
|
|
24
27
|
process.exit(1);
|
|
@@ -79,14 +82,16 @@ try {
|
|
|
79
82
|
npmLog.info('sharp', `Downloading ${url}`);
|
|
80
83
|
simpleGet({ url: url, agent: agent() }, function (err, response) {
|
|
81
84
|
if (err) {
|
|
82
|
-
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
|
|
85
|
+
fail(err);
|
|
86
|
+
} else if (response.statusCode === 404) {
|
|
87
|
+
fail(new Error(`Prebuilt libvips binaries are not yet available for ${platformAndArch}`));
|
|
88
|
+
} else if (response.statusCode !== 200) {
|
|
89
|
+
fail(new Error(`Status ${response.statusCode} ${response.statusMessage}`));
|
|
90
|
+
} else {
|
|
91
|
+
response
|
|
92
|
+
.on('error', fail)
|
|
93
|
+
.pipe(tmpFile);
|
|
86
94
|
}
|
|
87
|
-
response
|
|
88
|
-
.on('error', fail)
|
|
89
|
-
.pipe(tmpFile);
|
|
90
95
|
});
|
|
91
96
|
tmpFile
|
|
92
97
|
.on('error', fail)
|
package/lib/agent.js
CHANGED
|
@@ -20,15 +20,18 @@ function env (key) {
|
|
|
20
20
|
|
|
21
21
|
module.exports = function () {
|
|
22
22
|
try {
|
|
23
|
-
const proxy = url.
|
|
23
|
+
const proxy = new url.URL(proxies.map(env).find(is.string));
|
|
24
24
|
const tunnel = proxy.protocol === 'https:'
|
|
25
25
|
? tunnelAgent.httpsOverHttps
|
|
26
26
|
: tunnelAgent.httpsOverHttp;
|
|
27
|
+
const proxyAuth = proxy.username && proxy.password
|
|
28
|
+
? `${proxy.username}:${proxy.password}`
|
|
29
|
+
: null;
|
|
27
30
|
return tunnel({
|
|
28
31
|
proxy: {
|
|
29
32
|
port: Number(proxy.port),
|
|
30
33
|
host: proxy.hostname,
|
|
31
|
-
proxyAuth
|
|
34
|
+
proxyAuth
|
|
32
35
|
}
|
|
33
36
|
});
|
|
34
37
|
} catch (err) {
|
package/lib/colour.js
CHANGED
|
@@ -83,18 +83,22 @@ function toColorspace (colorspace) {
|
|
|
83
83
|
* Update a colour attribute of the this.options Object.
|
|
84
84
|
* @private
|
|
85
85
|
* @param {String} key
|
|
86
|
-
* @param {String|Object}
|
|
87
|
-
* @throws {Error} Invalid
|
|
86
|
+
* @param {String|Object} value
|
|
87
|
+
* @throws {Error} Invalid value
|
|
88
88
|
*/
|
|
89
|
-
function
|
|
90
|
-
if (is.
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
89
|
+
function _setBackgroundColourOption (key, value) {
|
|
90
|
+
if (is.defined(value)) {
|
|
91
|
+
if (is.object(value) || is.string(value)) {
|
|
92
|
+
const colour = color(value);
|
|
93
|
+
this.options[key] = [
|
|
94
|
+
colour.red(),
|
|
95
|
+
colour.green(),
|
|
96
|
+
colour.blue(),
|
|
97
|
+
Math.round(colour.alpha() * 255)
|
|
98
|
+
];
|
|
99
|
+
} else {
|
|
100
|
+
throw is.invalidParameterError('background', 'object or string', value);
|
|
101
|
+
}
|
|
98
102
|
}
|
|
99
103
|
}
|
|
100
104
|
|
|
@@ -111,7 +115,7 @@ module.exports = function (Sharp) {
|
|
|
111
115
|
toColourspace,
|
|
112
116
|
toColorspace,
|
|
113
117
|
// Private
|
|
114
|
-
|
|
118
|
+
_setBackgroundColourOption
|
|
115
119
|
});
|
|
116
120
|
// Class attributes
|
|
117
121
|
Sharp.colourspace = colourspace;
|
package/lib/composite.js
CHANGED
|
@@ -81,6 +81,7 @@ const blend = {
|
|
|
81
81
|
* @param {Number} [images[].top] - the pixel offset from the top edge.
|
|
82
82
|
* @param {Number} [images[].left] - the pixel offset from the left edge.
|
|
83
83
|
* @param {Boolean} [images[].tile=false] - set to true to repeat the overlay image across the entire image with the given `gravity`.
|
|
84
|
+
* @param {Boolean} [images[].premultiplied=false] - set to true to avoid premultipling the image below. Equivalent to the `--premultiplied` vips option.
|
|
84
85
|
* @param {Number} [images[].density=72] - number representing the DPI for vector overlay image.
|
|
85
86
|
* @param {Object} [images[].raw] - describes overlay when using raw pixel data.
|
|
86
87
|
* @param {Number} [images[].raw.width]
|
|
@@ -105,7 +106,8 @@ function composite (images) {
|
|
|
105
106
|
tile: false,
|
|
106
107
|
left: -1,
|
|
107
108
|
top: -1,
|
|
108
|
-
gravity: 0
|
|
109
|
+
gravity: 0,
|
|
110
|
+
premultiplied: false
|
|
109
111
|
};
|
|
110
112
|
if (is.defined(image.blend)) {
|
|
111
113
|
if (is.string(blend[image.blend])) {
|
|
@@ -147,6 +149,14 @@ function composite (images) {
|
|
|
147
149
|
throw is.invalidParameterError('gravity', 'valid gravity', image.gravity);
|
|
148
150
|
}
|
|
149
151
|
}
|
|
152
|
+
if (is.defined(image.premultiplied)) {
|
|
153
|
+
if (is.bool(image.premultiplied)) {
|
|
154
|
+
composite.premultiplied = image.premultiplied;
|
|
155
|
+
} else {
|
|
156
|
+
throw is.invalidParameterError('premultiplied', 'boolean', image.premultiplied);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
150
160
|
return composite;
|
|
151
161
|
});
|
|
152
162
|
return this;
|
package/lib/constructor.js
CHANGED
|
@@ -78,7 +78,7 @@ const debuglog = util.debuglog('sharp');
|
|
|
78
78
|
*
|
|
79
79
|
* @param {(Buffer|String)} [input] - if present, can be
|
|
80
80
|
* a Buffer containing JPEG, PNG, WebP, GIF, SVG, TIFF or raw pixel image data, or
|
|
81
|
-
* a String containing the path to an JPEG, PNG, WebP, GIF, SVG or TIFF image file.
|
|
81
|
+
* a String containing the filesystem path to an JPEG, PNG, WebP, GIF, SVG or TIFF image file.
|
|
82
82
|
* JPEG, PNG, WebP, GIF, SVG, TIFF or raw pixel image data can be streamed into the object when not present.
|
|
83
83
|
* @param {Object} [options] - if present, is an Object with optional attributes.
|
|
84
84
|
* @param {Boolean} [options.failOnError=true] - by default halt processing and raise an error when loading invalid images.
|
|
@@ -213,6 +213,7 @@ const Sharp = function (input, options) {
|
|
|
213
213
|
tileSize: 256,
|
|
214
214
|
tileOverlap: 0,
|
|
215
215
|
tileSkipBlanks: -1,
|
|
216
|
+
tileBackground: [255, 255, 255, 255],
|
|
216
217
|
linearA: 1,
|
|
217
218
|
linearB: 0,
|
|
218
219
|
// Function to notify of libvips warnings
|
package/lib/input.js
CHANGED
|
@@ -65,11 +65,15 @@ function _createInputDescriptor (input, inputOptions, containerOptions) {
|
|
|
65
65
|
if (is.defined(inputOptions.pages)) {
|
|
66
66
|
if (is.integer(inputOptions.pages) && is.inRange(inputOptions.pages, -1, 100000)) {
|
|
67
67
|
inputDescriptor.pages = inputOptions.pages;
|
|
68
|
+
} else {
|
|
69
|
+
throw is.invalidParameterError('pages', 'integer between -1 and 100000', inputOptions.pages);
|
|
68
70
|
}
|
|
69
71
|
}
|
|
70
72
|
if (is.defined(inputOptions.page)) {
|
|
71
73
|
if (is.integer(inputOptions.page) && is.inRange(inputOptions.page, 0, 100000)) {
|
|
72
74
|
inputDescriptor.page = inputOptions.page;
|
|
75
|
+
} else {
|
|
76
|
+
throw is.invalidParameterError('page', 'integer between 0 and 100000', inputOptions.page);
|
|
73
77
|
}
|
|
74
78
|
}
|
|
75
79
|
// Create new image
|
|
@@ -203,6 +207,7 @@ function clone () {
|
|
|
203
207
|
* - `icc`: Buffer containing raw [ICC](https://www.npmjs.com/package/icc) profile data, if present
|
|
204
208
|
* - `iptc`: Buffer containing raw IPTC data, if present
|
|
205
209
|
* - `xmp`: Buffer containing raw XMP data, if present
|
|
210
|
+
* - `tifftagPhotoshop`: Buffer containing raw TIFFTAG_PHOTOSHOP data, if present
|
|
206
211
|
*
|
|
207
212
|
* @example
|
|
208
213
|
* const image = sharp(inputJpg);
|
package/lib/operation.js
CHANGED
|
@@ -179,7 +179,7 @@ function blur (sigma) {
|
|
|
179
179
|
function flatten (options) {
|
|
180
180
|
this.options.flatten = is.bool(options) ? options : true;
|
|
181
181
|
if (is.object(options)) {
|
|
182
|
-
this.
|
|
182
|
+
this._setBackgroundColourOption('flattenBackground', options.background);
|
|
183
183
|
}
|
|
184
184
|
return this;
|
|
185
185
|
}
|
package/lib/output.js
CHANGED
|
@@ -10,6 +10,9 @@ const sharp = require('../build/Release/sharp.node');
|
|
|
10
10
|
* with JPEG, PNG, WebP, TIFF, DZI, and libvips' V format supported.
|
|
11
11
|
* Note that raw pixel data is only supported for buffer output.
|
|
12
12
|
*
|
|
13
|
+
* By default all metadata will be removed, which includes EXIF-based orientation.
|
|
14
|
+
* See {@link withMetadata} for control over this.
|
|
15
|
+
*
|
|
13
16
|
* A `Promise` is returned when `callback` is not provided.
|
|
14
17
|
*
|
|
15
18
|
* @example
|
|
@@ -57,7 +60,11 @@ function toFile (fileOut, callback) {
|
|
|
57
60
|
/**
|
|
58
61
|
* Write output to a Buffer.
|
|
59
62
|
* JPEG, PNG, WebP, TIFF and RAW output are supported.
|
|
60
|
-
*
|
|
63
|
+
*
|
|
64
|
+
* If no explicit format is set, the output format will match the input image, except GIF and SVG input which become PNG output.
|
|
65
|
+
*
|
|
66
|
+
* By default all metadata will be removed, which includes EXIF-based orientation.
|
|
67
|
+
* See {@link withMetadata} for control over this.
|
|
61
68
|
*
|
|
62
69
|
* `callback`, if present, gets three arguments `(err, data, info)` where:
|
|
63
70
|
* - `err` is an error, if any.
|
|
@@ -92,6 +99,8 @@ function toFile (fileOut, callback) {
|
|
|
92
99
|
function toBuffer (options, callback) {
|
|
93
100
|
if (is.object(options)) {
|
|
94
101
|
this._setBooleanOption('resolveWithObject', options.resolveWithObject);
|
|
102
|
+
} else if (this.options.resolveWithObject) {
|
|
103
|
+
this.options.resolveWithObject = false;
|
|
95
104
|
}
|
|
96
105
|
return this._pipeline(is.fn(options) ? options : callback);
|
|
97
106
|
}
|
|
@@ -487,6 +496,17 @@ function raw () {
|
|
|
487
496
|
return this._updateFormatOut('raw');
|
|
488
497
|
}
|
|
489
498
|
|
|
499
|
+
const formats = new Map([
|
|
500
|
+
['heic', 'heif'],
|
|
501
|
+
['heif', 'heif'],
|
|
502
|
+
['jpeg', 'jpeg'],
|
|
503
|
+
['jpg', 'jpeg'],
|
|
504
|
+
['png', 'png'],
|
|
505
|
+
['raw', 'raw'],
|
|
506
|
+
['tiff', 'tiff'],
|
|
507
|
+
['webp', 'webp']
|
|
508
|
+
]);
|
|
509
|
+
|
|
490
510
|
/**
|
|
491
511
|
* Force output to a given format.
|
|
492
512
|
*
|
|
@@ -502,14 +522,11 @@ function raw () {
|
|
|
502
522
|
* @throws {Error} unsupported format or options
|
|
503
523
|
*/
|
|
504
524
|
function toFormat (format, options) {
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
if (format === 'jpg') format = 'jpeg';
|
|
509
|
-
if (!is.inArray(format, ['jpeg', 'png', 'webp', 'tiff', 'raw'])) {
|
|
510
|
-
throw is.invalidParameterError('format', 'one of: jpeg, png, webp, tiff, raw', format);
|
|
525
|
+
const actualFormat = formats.get(is.object(format) && is.string(format.id) ? format.id : format);
|
|
526
|
+
if (!actualFormat) {
|
|
527
|
+
throw is.invalidParameterError('format', `one of: ${[...formats.keys()].join(', ')}`, format);
|
|
511
528
|
}
|
|
512
|
-
return this[
|
|
529
|
+
return this[actualFormat](options);
|
|
513
530
|
}
|
|
514
531
|
|
|
515
532
|
/**
|
|
@@ -534,6 +551,7 @@ function toFormat (format, options) {
|
|
|
534
551
|
* @param {Number} [options.size=256] tile size in pixels, a value between 1 and 8192.
|
|
535
552
|
* @param {Number} [options.overlap=0] tile overlap in pixels, a value between 0 and 8192.
|
|
536
553
|
* @param {Number} [options.angle=0] tile angle of rotation, must be a multiple of 90.
|
|
554
|
+
* @param {String|Object} [options.background={r: 255, g: 255, b: 255, alpha: 1}] - background colour, parsed by the [color](https://www.npmjs.org/package/color) module, defaults to white without transparency.
|
|
537
555
|
* @param {String} [options.depth] how deep to make the pyramid, possible values are `onepixel`, `onetile` or `one`, default based on layout.
|
|
538
556
|
* @param {Number} [options.skipBlanks=-1] threshold to skip tile generation, a value 0 - 255 for 8-bit images or 0 - 65535 for 16-bit images
|
|
539
557
|
* @param {String} [options.container='fs'] tile container, with value `fs` (filesystem) or `zip` (compressed file).
|
|
@@ -557,7 +575,7 @@ function tile (options) {
|
|
|
557
575
|
if (options.overlap > this.options.tileSize) {
|
|
558
576
|
throw is.invalidParameterError('overlap', `<= size (${this.options.tileSize})`, options.overlap);
|
|
559
577
|
}
|
|
560
|
-
this.options.tileOverlap =
|
|
578
|
+
this.options.tileOverlap = options.overlap;
|
|
561
579
|
} else {
|
|
562
580
|
throw is.invalidParameterError('overlap', 'integer between 0 and 8192', options.overlap);
|
|
563
581
|
}
|
|
@@ -586,6 +604,8 @@ function tile (options) {
|
|
|
586
604
|
throw is.invalidParameterError('angle', 'positive/negative multiple of 90', options.angle);
|
|
587
605
|
}
|
|
588
606
|
}
|
|
607
|
+
// Background colour
|
|
608
|
+
this._setBackgroundColourOption('tileBackground', options.background);
|
|
589
609
|
// Depth of tiles
|
|
590
610
|
if (is.defined(options.depth)) {
|
|
591
611
|
if (is.string(options.depth) && is.inArray(options.depth, ['onepixel', 'onetile', 'one'])) {
|
package/lib/platform.js
CHANGED
|
@@ -7,6 +7,7 @@ const env = process.env;
|
|
|
7
7
|
module.exports = function () {
|
|
8
8
|
const arch = env.npm_config_arch || process.arch;
|
|
9
9
|
const platform = env.npm_config_platform || process.platform;
|
|
10
|
+
/* istanbul ignore next */
|
|
10
11
|
const libc = (platform === 'linux' && detectLibc.isNonGlibcLinux) ? detectLibc.family : '';
|
|
11
12
|
|
|
12
13
|
const platformId = [`${platform}${libc}`];
|
package/lib/resize.js
CHANGED
|
@@ -210,12 +210,20 @@ function resize (width, height, options) {
|
|
|
210
210
|
}
|
|
211
211
|
if (is.object(options)) {
|
|
212
212
|
// Width
|
|
213
|
-
if (is.
|
|
214
|
-
|
|
213
|
+
if (is.defined(options.width)) {
|
|
214
|
+
if (is.integer(options.width) && options.width > 0) {
|
|
215
|
+
this.options.width = options.width;
|
|
216
|
+
} else {
|
|
217
|
+
throw is.invalidParameterError('width', 'positive integer', options.width);
|
|
218
|
+
}
|
|
215
219
|
}
|
|
216
220
|
// Height
|
|
217
|
-
if (is.
|
|
218
|
-
|
|
221
|
+
if (is.defined(options.height)) {
|
|
222
|
+
if (is.integer(options.height) && options.height > 0) {
|
|
223
|
+
this.options.height = options.height;
|
|
224
|
+
} else {
|
|
225
|
+
throw is.invalidParameterError('height', 'positive integer', options.height);
|
|
226
|
+
}
|
|
219
227
|
}
|
|
220
228
|
// Fit
|
|
221
229
|
if (is.defined(options.fit)) {
|
|
@@ -238,9 +246,7 @@ function resize (width, height, options) {
|
|
|
238
246
|
}
|
|
239
247
|
}
|
|
240
248
|
// Background
|
|
241
|
-
|
|
242
|
-
this._setColourOption('resizeBackground', options.background);
|
|
243
|
-
}
|
|
249
|
+
this._setBackgroundColourOption('resizeBackground', options.background);
|
|
244
250
|
// Kernel
|
|
245
251
|
if (is.defined(options.kernel)) {
|
|
246
252
|
if (is.string(kernel[options.kernel])) {
|
|
@@ -305,7 +311,7 @@ function extend (extend) {
|
|
|
305
311
|
this.options.extendBottom = extend.bottom;
|
|
306
312
|
this.options.extendLeft = extend.left;
|
|
307
313
|
this.options.extendRight = extend.right;
|
|
308
|
-
this.
|
|
314
|
+
this._setBackgroundColourOption('extendBackground', extend.background);
|
|
309
315
|
} else {
|
|
310
316
|
throw is.invalidParameterError('extend', 'integer or object', extend);
|
|
311
317
|
}
|
|
@@ -361,7 +367,10 @@ function extract (options) {
|
|
|
361
367
|
|
|
362
368
|
/**
|
|
363
369
|
* Trim "boring" pixels from all edges that contain values similar to the top-left pixel.
|
|
370
|
+
* Images consisting entirely of a single colour will calculate "boring" using the alpha channel, if any.
|
|
371
|
+
*
|
|
364
372
|
* The `info` response Object will contain `trimOffsetLeft` and `trimOffsetTop` properties.
|
|
373
|
+
*
|
|
365
374
|
* @param {Number} [threshold=10] the allowed difference from the top-left pixel, a number greater than zero.
|
|
366
375
|
* @returns {Sharp}
|
|
367
376
|
* @throws {Error} Invalid parameters
|
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 and TIFF images",
|
|
4
|
-
"version": "0.23.
|
|
4
|
+
"version": "0.23.4",
|
|
5
5
|
"author": "Lovell Fuller <npm@lovell.info>",
|
|
6
6
|
"homepage": "https://github.com/lovell/sharp",
|
|
7
7
|
"contributors": [
|
|
@@ -61,12 +61,15 @@
|
|
|
61
61
|
"Keith Belovay <keith@picthrive.com>",
|
|
62
62
|
"Michael B. Klein <mbklein@gmail.com>",
|
|
63
63
|
"Jordan Prudhomme <jordan@raboland.fr>",
|
|
64
|
-
"Ilya Ovdin <iovdin@gmail.com>"
|
|
64
|
+
"Ilya Ovdin <iovdin@gmail.com>",
|
|
65
|
+
"Andargor <andargor@yahoo.com>",
|
|
66
|
+
"Paul Neave <paul.neave@gmail.com>",
|
|
67
|
+
"Brendan Kennedy <brenwken@gmail.com>"
|
|
65
68
|
],
|
|
66
69
|
"scripts": {
|
|
67
70
|
"install": "(node install/libvips && node install/dll-copy && prebuild-install) || (node-gyp rebuild && node install/dll-copy)",
|
|
68
71
|
"clean": "rm -rf node_modules/ build/ vendor/ .nyc_output/ coverage/ test/fixtures/output.*",
|
|
69
|
-
"test": "semistandard &&
|
|
72
|
+
"test": "semistandard && cpplint && npm run test-unit && npm run test-licensing && prebuild-ci",
|
|
70
73
|
"test-unit": "nyc --reporter=lcov --branches=99 mocha --slow=5000 --timeout=60000 ./test/unit/*.js",
|
|
71
74
|
"test-licensing": "license-checker --production --summary --onlyAllow=\"Apache-2.0;BSD;ISC;MIT\"",
|
|
72
75
|
"test-coverage": "./test/coverage/report.sh",
|
|
@@ -74,6 +77,14 @@
|
|
|
74
77
|
"docs": "for m in constructor input resize composite operation colour channel output utility; do documentation build --shallow --format=md --markdown-toc=false lib/$m.js >docs/api-$m.md; done"
|
|
75
78
|
},
|
|
76
79
|
"main": "lib/index.js",
|
|
80
|
+
"files": [
|
|
81
|
+
"binding.gyp",
|
|
82
|
+
"docs/**",
|
|
83
|
+
"!docs/css/**",
|
|
84
|
+
"install/**",
|
|
85
|
+
"lib/**",
|
|
86
|
+
"src/**"
|
|
87
|
+
],
|
|
77
88
|
"repository": {
|
|
78
89
|
"type": "git",
|
|
79
90
|
"url": "git://github.com/lovell/sharp"
|
|
@@ -99,27 +110,27 @@
|
|
|
99
110
|
"detect-libc": "^1.0.3",
|
|
100
111
|
"nan": "^2.14.0",
|
|
101
112
|
"npmlog": "^4.1.2",
|
|
102
|
-
"prebuild-install": "^5.3.
|
|
113
|
+
"prebuild-install": "^5.3.3",
|
|
103
114
|
"semver": "^6.3.0",
|
|
104
|
-
"simple-get": "^3.0
|
|
105
|
-
"tar": "^
|
|
115
|
+
"simple-get": "^3.1.0",
|
|
116
|
+
"tar": "^5.0.5",
|
|
106
117
|
"tunnel-agent": "^0.6.0"
|
|
107
118
|
},
|
|
108
119
|
"devDependencies": {
|
|
109
120
|
"async": "^3.1.0",
|
|
110
|
-
"cc": "^
|
|
121
|
+
"cc": "^2.0.1",
|
|
111
122
|
"decompress-zip": "^0.3.2",
|
|
112
|
-
"documentation": "^12.
|
|
113
|
-
"exif-reader": "^1.0.
|
|
123
|
+
"documentation": "^12.1.4",
|
|
124
|
+
"exif-reader": "^1.0.3",
|
|
114
125
|
"icc": "^1.0.0",
|
|
115
126
|
"license-checker": "^25.0.1",
|
|
116
|
-
"mocha": "^6.2.
|
|
117
|
-
"mock-fs": "^4.10.
|
|
127
|
+
"mocha": "^6.2.2",
|
|
128
|
+
"mock-fs": "^4.10.4",
|
|
118
129
|
"nyc": "^14.1.1",
|
|
119
|
-
"prebuild": "^9.
|
|
130
|
+
"prebuild": "^9.1.1",
|
|
120
131
|
"prebuild-ci": "^3.1.0",
|
|
121
|
-
"rimraf": "^
|
|
122
|
-
"semistandard": "^
|
|
132
|
+
"rimraf": "^3.0.0",
|
|
133
|
+
"semistandard": "^14.2.0"
|
|
123
134
|
},
|
|
124
135
|
"license": "Apache-2.0",
|
|
125
136
|
"config": {
|
|
@@ -128,6 +139,9 @@
|
|
|
128
139
|
"engines": {
|
|
129
140
|
"node": ">=8.5.0"
|
|
130
141
|
},
|
|
142
|
+
"funding": {
|
|
143
|
+
"url": "https://opencollective.com/libvips"
|
|
144
|
+
},
|
|
131
145
|
"semistandard": {
|
|
132
146
|
"env": [
|
|
133
147
|
"mocha"
|
|
@@ -136,10 +150,7 @@
|
|
|
136
150
|
"cc": {
|
|
137
151
|
"linelength": "120",
|
|
138
152
|
"filter": [
|
|
139
|
-
"build/
|
|
140
|
-
"build/include",
|
|
141
|
-
"runtime/indentation_namespace",
|
|
142
|
-
"runtime/references"
|
|
153
|
+
"build/include"
|
|
143
154
|
]
|
|
144
155
|
}
|
|
145
156
|
}
|
package/src/common.cc
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
#include <string.h>
|
|
18
18
|
#include <vector>
|
|
19
19
|
#include <queue>
|
|
20
|
-
#include <mutex>
|
|
20
|
+
#include <mutex> // NOLINT(build/c++11)
|
|
21
21
|
|
|
22
22
|
#include <node.h>
|
|
23
23
|
#include <node_buffer.h>
|
|
@@ -58,6 +58,7 @@ namespace sharp {
|
|
|
58
58
|
v8::Local<v8::Object> buffer = AttrAs<v8::Object>(input, "buffer");
|
|
59
59
|
descriptor->bufferLength = node::Buffer::Length(buffer);
|
|
60
60
|
descriptor->buffer = node::Buffer::Data(buffer);
|
|
61
|
+
descriptor->isBuffer = TRUE;
|
|
61
62
|
buffersToPersist.push_back(buffer);
|
|
62
63
|
}
|
|
63
64
|
descriptor->failOnError = AttrTo<bool>(input, "failOnError");
|
|
@@ -147,7 +148,7 @@ namespace sharp {
|
|
|
147
148
|
case ImageType::OPENSLIDE: id = "openslide"; break;
|
|
148
149
|
case ImageType::PPM: id = "ppm"; break;
|
|
149
150
|
case ImageType::FITS: id = "fits"; break;
|
|
150
|
-
case ImageType::VIPS: id = "
|
|
151
|
+
case ImageType::VIPS: id = "vips"; break;
|
|
151
152
|
case ImageType::RAW: id = "raw"; break;
|
|
152
153
|
case ImageType::UNKNOWN: id = "unknown"; break;
|
|
153
154
|
case ImageType::MISSING: id = "missing"; break;
|
|
@@ -246,7 +247,7 @@ namespace sharp {
|
|
|
246
247
|
std::tuple<VImage, ImageType> OpenInput(InputDescriptor *descriptor, VipsAccess accessMethod) {
|
|
247
248
|
VImage image;
|
|
248
249
|
ImageType imageType;
|
|
249
|
-
if (descriptor->
|
|
250
|
+
if (descriptor->isBuffer) {
|
|
250
251
|
if (descriptor->rawChannels > 0) {
|
|
251
252
|
// Raw, uncompressed pixel data
|
|
252
253
|
image = VImage::new_from_memory(descriptor->buffer, descriptor->bufferLength,
|
|
@@ -277,7 +278,7 @@ namespace sharp {
|
|
|
277
278
|
}
|
|
278
279
|
image = VImage::new_from_buffer(descriptor->buffer, descriptor->bufferLength, nullptr, option);
|
|
279
280
|
if (imageType == ImageType::SVG || imageType == ImageType::PDF || imageType == ImageType::MAGICK) {
|
|
280
|
-
SetDensity(image, descriptor->density);
|
|
281
|
+
image = SetDensity(image, descriptor->density);
|
|
281
282
|
}
|
|
282
283
|
} catch (vips::VError const &err) {
|
|
283
284
|
throw vips::VError(std::string("Input buffer has corrupt header: ") + err.what());
|
|
@@ -323,7 +324,7 @@ namespace sharp {
|
|
|
323
324
|
}
|
|
324
325
|
image = VImage::new_from_file(descriptor->file.data(), option);
|
|
325
326
|
if (imageType == ImageType::SVG || imageType == ImageType::PDF || imageType == ImageType::MAGICK) {
|
|
326
|
-
SetDensity(image, descriptor->density);
|
|
327
|
+
image = SetDensity(image, descriptor->density);
|
|
327
328
|
}
|
|
328
329
|
} catch (vips::VError const &err) {
|
|
329
330
|
throw vips::VError(std::string("Input file has corrupt header: ") + err.what());
|
|
@@ -370,15 +371,19 @@ namespace sharp {
|
|
|
370
371
|
/*
|
|
371
372
|
Set EXIF Orientation of image.
|
|
372
373
|
*/
|
|
373
|
-
|
|
374
|
-
image.
|
|
374
|
+
VImage SetExifOrientation(VImage image, int const orientation) {
|
|
375
|
+
VImage copy = image.copy();
|
|
376
|
+
copy.set(VIPS_META_ORIENTATION, orientation);
|
|
377
|
+
return copy;
|
|
375
378
|
}
|
|
376
379
|
|
|
377
380
|
/*
|
|
378
381
|
Remove EXIF Orientation from image.
|
|
379
382
|
*/
|
|
380
|
-
|
|
381
|
-
|
|
383
|
+
VImage RemoveExifOrientation(VImage image) {
|
|
384
|
+
VImage copy = image.copy();
|
|
385
|
+
copy.remove(VIPS_META_ORIENTATION);
|
|
386
|
+
return copy;
|
|
382
387
|
}
|
|
383
388
|
|
|
384
389
|
/*
|
|
@@ -398,11 +403,13 @@ namespace sharp {
|
|
|
398
403
|
/*
|
|
399
404
|
Set pixels/mm resolution based on a pixels/inch density.
|
|
400
405
|
*/
|
|
401
|
-
|
|
406
|
+
VImage SetDensity(VImage image, const double density) {
|
|
402
407
|
const double pixelsPerMm = density / 25.4;
|
|
403
|
-
image.
|
|
404
|
-
|
|
405
|
-
|
|
408
|
+
VImage copy = image.copy();
|
|
409
|
+
copy.set("Xres", pixelsPerMm);
|
|
410
|
+
copy.set("Yres", pixelsPerMm);
|
|
411
|
+
copy.set(VIPS_META_RESOLUTION_UNIT, "in");
|
|
412
|
+
return copy;
|
|
406
413
|
}
|
|
407
414
|
|
|
408
415
|
/*
|
package/src/common.h
CHANGED
|
@@ -43,12 +43,13 @@ using vips::VImage;
|
|
|
43
43
|
|
|
44
44
|
namespace sharp {
|
|
45
45
|
|
|
46
|
-
struct InputDescriptor {
|
|
46
|
+
struct InputDescriptor { // NOLINT(runtime/indentation_namespace)
|
|
47
47
|
std::string name;
|
|
48
48
|
std::string file;
|
|
49
49
|
char *buffer;
|
|
50
50
|
bool failOnError;
|
|
51
51
|
size_t bufferLength;
|
|
52
|
+
bool isBuffer;
|
|
52
53
|
double density;
|
|
53
54
|
int rawChannels;
|
|
54
55
|
int rawWidth;
|
|
@@ -64,6 +65,7 @@ namespace sharp {
|
|
|
64
65
|
buffer(nullptr),
|
|
65
66
|
failOnError(TRUE),
|
|
66
67
|
bufferLength(0),
|
|
68
|
+
isBuffer(FALSE),
|
|
67
69
|
density(72.0),
|
|
68
70
|
rawChannels(0),
|
|
69
71
|
rawWidth(0),
|
|
@@ -92,7 +94,7 @@ namespace sharp {
|
|
|
92
94
|
|
|
93
95
|
// Create an InputDescriptor instance from a v8::Object describing an input image
|
|
94
96
|
InputDescriptor* CreateInputDescriptor(
|
|
95
|
-
v8::Local<v8::Object> input, std::vector<v8::Local<v8::Object>> &buffersToPersist);
|
|
97
|
+
v8::Local<v8::Object> input, std::vector<v8::Local<v8::Object>> &buffersToPersist); // NOLINT(runtime/references)
|
|
96
98
|
|
|
97
99
|
enum class ImageType {
|
|
98
100
|
JPEG,
|
|
@@ -175,12 +177,12 @@ namespace sharp {
|
|
|
175
177
|
/*
|
|
176
178
|
Set EXIF Orientation of image.
|
|
177
179
|
*/
|
|
178
|
-
|
|
180
|
+
VImage SetExifOrientation(VImage image, int const orientation);
|
|
179
181
|
|
|
180
182
|
/*
|
|
181
183
|
Remove EXIF Orientation from image.
|
|
182
184
|
*/
|
|
183
|
-
|
|
185
|
+
VImage RemoveExifOrientation(VImage image);
|
|
184
186
|
|
|
185
187
|
/*
|
|
186
188
|
Does this image have a non-default density?
|
|
@@ -195,7 +197,7 @@ namespace sharp {
|
|
|
195
197
|
/*
|
|
196
198
|
Set pixels/mm resolution based on a pixels/inch density.
|
|
197
199
|
*/
|
|
198
|
-
|
|
200
|
+
VImage SetDensity(VImage image, const double density);
|
|
199
201
|
|
|
200
202
|
/*
|
|
201
203
|
Check the proposed format supports the current dimensions.
|
package/src/metadata.cc
CHANGED
|
@@ -116,6 +116,14 @@ class MetadataWorker : public Nan::AsyncWorker {
|
|
|
116
116
|
memcpy(baton->xmp, xmp, xmpLength);
|
|
117
117
|
baton->xmpLength = xmpLength;
|
|
118
118
|
}
|
|
119
|
+
// TIFFTAG_PHOTOSHOP
|
|
120
|
+
if (image.get_typeof(VIPS_META_PHOTOSHOP_NAME) == VIPS_TYPE_BLOB) {
|
|
121
|
+
size_t tifftagPhotoshopLength;
|
|
122
|
+
void const *tifftagPhotoshop = image.get_blob(VIPS_META_PHOTOSHOP_NAME, &tifftagPhotoshopLength);
|
|
123
|
+
baton->tifftagPhotoshop = static_cast<char *>(g_malloc(tifftagPhotoshopLength));
|
|
124
|
+
memcpy(baton->tifftagPhotoshop, tifftagPhotoshop, tifftagPhotoshopLength);
|
|
125
|
+
baton->tifftagPhotoshopLength = tifftagPhotoshopLength;
|
|
126
|
+
}
|
|
119
127
|
}
|
|
120
128
|
|
|
121
129
|
// Clean up
|
|
@@ -189,6 +197,12 @@ class MetadataWorker : public Nan::AsyncWorker {
|
|
|
189
197
|
New("xmp").ToLocalChecked(),
|
|
190
198
|
Nan::NewBuffer(baton->xmp, baton->xmpLength, sharp::FreeCallback, nullptr).ToLocalChecked());
|
|
191
199
|
}
|
|
200
|
+
if (baton->tifftagPhotoshopLength > 0) {
|
|
201
|
+
Set(info,
|
|
202
|
+
New("tifftagPhotoshop").ToLocalChecked(),
|
|
203
|
+
Nan::NewBuffer(baton->tifftagPhotoshop, baton->tifftagPhotoshopLength, sharp::FreeCallback, nullptr)
|
|
204
|
+
.ToLocalChecked());
|
|
205
|
+
}
|
|
192
206
|
argv[1] = info;
|
|
193
207
|
}
|
|
194
208
|
|
package/src/metadata.h
CHANGED
|
@@ -48,6 +48,8 @@ struct MetadataBaton {
|
|
|
48
48
|
size_t iptcLength;
|
|
49
49
|
char *xmp;
|
|
50
50
|
size_t xmpLength;
|
|
51
|
+
char *tifftagPhotoshop;
|
|
52
|
+
size_t tifftagPhotoshopLength;
|
|
51
53
|
std::string err;
|
|
52
54
|
|
|
53
55
|
MetadataBaton():
|
|
@@ -71,7 +73,9 @@ struct MetadataBaton {
|
|
|
71
73
|
iptc(nullptr),
|
|
72
74
|
iptcLength(0),
|
|
73
75
|
xmp(nullptr),
|
|
74
|
-
xmpLength(0)
|
|
76
|
+
xmpLength(0),
|
|
77
|
+
tifftagPhotoshop(nullptr),
|
|
78
|
+
tifftagPhotoshopLength(0) {}
|
|
75
79
|
};
|
|
76
80
|
|
|
77
81
|
NAN_METHOD(metadata);
|