Compare commits

..

14 Commits

Author SHA1 Message Date
Lovell Fuller
866e9824d1 Release v0.26.0 2020-08-25 18:42:06 +01:00
Lovell Fuller
482e6078e2 Tests: Update leak suppressions for librsvg static data 2020-08-25 18:40:12 +01:00
Lovell Fuller
bc7ab296ef Tests: Update leak suppressions for static libs 2020-08-24 21:10:20 +01:00
Lovell Fuller
a5f4f53b56 Tests: remove no-longer-used conditional assertions 2020-08-23 20:11:23 +01:00
Lovell Fuller
b1227f526d Verify minimum libvips version at compile time 2020-08-23 20:10:27 +01:00
Lovell Fuller
78b42c8306 Docs: update performance test results 2020-08-23 16:48:46 +01:00
Lovell Fuller
4b6d45ab8e Prerelease v0.26.0-beta1 2020-08-23 15:56:25 +01:00
Lovell Fuller
7980341923 Upgrade libvips to v8.10.0 2020-08-23 15:36:03 +01:00
Lovell Fuller
3917efdebd Benchmarks: ensure PNG tests use consistent settings 2020-08-21 21:10:27 +01:00
Robert O'Rourke
eaecb7347b Add support to withMetadata for custom ICC profile #2271 2020-08-19 21:32:15 +01:00
Lovell Fuller
05ca7d3129 CI: further attempts to get Windows to play nicely 2020-08-18 20:53:18 +01:00
Lovell Fuller
4beae0de71 Add 'animated' constructor property as shortcut for 'pages'
Provides easier-to-understand API when handling animated images
2020-08-18 20:28:35 +01:00
Lovell Fuller
b711661784 CI: improve cross-platform (i.e. Windows) process spawning 2020-08-18 17:11:42 +01:00
Lovell Fuller
0c4a45b1f4 CI: workaround Appveyor ignoring v-prefixed tag names 2020-08-18 14:31:33 +01:00
23 changed files with 214 additions and 49 deletions

View File

@@ -29,6 +29,7 @@ Implements the [stream.Duplex][1] class.
- `options.pages` **[number][6]** number of pages to extract for multi-page input (GIF, TIFF, PDF), use -1 for all pages. (optional, default `1`)
- `options.page` **[number][6]** page number to start extracting from for multi-page input (GIF, TIFF, PDF), zero based. (optional, default `0`)
- `options.level` **[number][6]** level to extract from a multi-level input (OpenSlide), zero based. (optional, default `0`)
- `options.animated` **[boolean][5]** Set to `true` to read all frames/pages of an animated image (equivalent of setting `pages` to `-1`). (optional, default `false`)
- `options.raw` **[Object][4]?** describes raw pixel input image data. See `raw()` for pixel ordering.
- `options.raw.width` **[number][6]?**
- `options.raw.height` **[number][6]?**
@@ -78,6 +79,11 @@ sharp({
.then( ... );
```
```javascript
// Convert an animated GIF to an animated WebP
await sharp('in.gif', { animated: true }).toFile('out.webp');
```
- Throws **[Error][8]** Invalid parameters
Returns **[Sharp][9]**

View File

@@ -91,7 +91,8 @@ Returns **[Promise][5]<[Buffer][8]>** when no callback is provided
## withMetadata
Include all metadata (EXIF, XMP, IPTC) from the input image in the output image.
This will also convert to and add a web-friendly sRGB ICC profile.
This will also convert to and add a web-friendly sRGB ICC profile unless a custom
output profile is provided.
The default behaviour, when `withMetadata` is not used, is to convert to the device-independent
sRGB colour space and strip all metadata, including the removal of any ICC profile.
@@ -100,6 +101,7 @@ sRGB colour space and strip all metadata, including the removal of any ICC profi
- `options` **[Object][6]?**
- `options.orientation` **[number][9]?** value between 1 and 8, used to update the EXIF `Orientation` tag.
- `options.icc` **[string][2]?** filesystem path to output ICC profile, defaults to sRGB.
### Examples

View File

@@ -4,7 +4,7 @@
Requires libvips v8.10.0
### v0.26.0 - TBD
### v0.26.0 - 25th August 2020
* Prebuilt libvips binaries are now statically-linked and Brotli-compressed, requiring Node.js 10.16.0+.
@@ -27,6 +27,10 @@ Requires libvips v8.10.0
[#2259](https://github.com/lovell/sharp/pull/2259)
[@vouillon](https://github.com/vouillon)
* Add support to `withMetadata` for custom ICC profile.
[#2271](https://github.com/lovell/sharp/pull/2271)
[@roborourke](https://github.com/roborourke)
* Ensure prebuilt binaries for ARM default to v7 when using Electron.
[#2292](https://github.com/lovell/sharp/pull/2292)
[@diegodev3](https://github.com/diegodev3)

View File

@@ -194,3 +194,6 @@ GitHub: https://github.com/vouillon
Name: Tomáš Szabo
GitHub: https://github.com/deftomat
Name: Robert O'Rourke
GitHub: https://github.com/roborourke

View File

@@ -19,7 +19,7 @@
<link rel="apple-touch-icon-precomposed" sizes="72x72" href="https://pixel.plumbing/px/72x72/sharp-logo.svg">
<link rel="apple-touch-icon-precomposed" href="https://pixel.plumbing/px/57x57/sharp-logo.svg">
<link rel="author" href="/humans.txt" type="text/plain">
<link rel="preload" href="https://cdn.jsdelivr.net/gh/lovell/sharp@v0.25.4/docs/README.md" as="fetch" type="text/markdown" crossorigin>
<link rel="preload" href="https://cdn.jsdelivr.net/gh/lovell/sharp@v0.26.0/docs/README.md" as="fetch" type="text/markdown" crossorigin>
<link rel="preload" href="https://cdn.jsdelivr.net/gh/lovell/sharp@master/docs/image/sharp-logo.svg" as="image" type="image/svg+xml" crossorigin>
<link rel="dns-prefetch" href="https://pixel.plumbing">
<link rel="dns-prefetch" href="https://www.google-analytics.com">
@@ -139,7 +139,7 @@
docuteApiTitlePlugin,
docuteApiSearchPlugin
],
sourcePath: 'https://cdn.jsdelivr.net/gh/lovell/sharp@v0.25.4/docs',
sourcePath: 'https://cdn.jsdelivr.net/gh/lovell/sharp@v0.26.0/docs',
nav: [
{
title: 'Funding',

View File

@@ -4,11 +4,11 @@ A test to benchmark the performance of this module relative to alternatives.
## The contenders
* [jimp](https://www.npmjs.com/package/jimp) v0.9.3 - Image processing in pure JavaScript. Provides bicubic interpolation.
* [mapnik](https://www.npmjs.org/package/mapnik) v4.3.1 - Whilst primarily a map renderer, Mapnik contains bitmap image utilities.
* [jimp](https://www.npmjs.com/package/jimp) v0.16.0 - Image processing in pure JavaScript. Provides bicubic interpolation.
* [mapnik](https://www.npmjs.org/package/mapnik) v4.5.2 - Whilst primarily a map renderer, Mapnik contains bitmap image utilities.
* [imagemagick](https://www.npmjs.com/package/imagemagick) v0.1.3 - Supports filesystem only and "*has been unmaintained for a long time*".
* [gm](https://www.npmjs.com/package/gm) v1.23.1 - Fully featured wrapper around GraphicsMagick's `gm` command line utility.
* sharp v0.24.0 / libvips v8.9.0 - Caching within libvips disabled to ensure a fair comparison.
* sharp v0.26.0 / libvips v8.10.0 - Caching within libvips disabled to ensure a fair comparison.
## The task
@@ -18,25 +18,25 @@ then compress to JPEG at a "quality" setting of 80.
## Test environment
* AWS EC2 eu-west-1 [c5.large](https://aws.amazon.com/ec2/instance-types/c5/) (2x Xeon Platinum 8124M CPU @ 3.00GHz)
* Ubuntu 18.04 (hvm-ssd/ubuntu-bionic-18.04-amd64-server-20180912 ami-00035f41c82244dab)
* Node.js v12.14.1
* AWS EC2 eu-west-1 [c5d.large](https://aws.amazon.com/ec2/instance-types/c5/) (2x Xeon Platinum 8124M CPU @ 3.00GHz)
* Ubuntu 20.04 (ami-0f1d11c92a9467c07)
* Node.js v14.8.0
## Results
| Module | Input | Output | Ops/sec | Speed-up |
| :----------------- | :----- | :----- | ------: | -------: |
| jimp | buffer | buffer | 0.72 | 1.0 |
| mapnik | buffer | buffer | 3.02 | 4.2 |
| gm | buffer | buffer | 3.90 | 5.4 |
| gm | file | file | 3.94 | 5.5 |
| imagemagick | file | file | 4.30 | 6.0 |
| sharp | stream | stream | 23.65 | 32.8 |
| sharp | file | file | 24.66 | 34.3 |
| sharp | buffer | buffer | 25.14 | 34.9 |
| jimp | buffer | buffer | 0.75 | 1.0 |
| mapnik | buffer | buffer | 3.00 | 4.0 |
| gm | buffer | buffer | 4.12 | 5.5 |
| gm | file | file | 4.13 | 5.5 |
| imagemagick | file | file | 4.30 | 5.7 |
| sharp | stream | stream | 22.37 | 29.8 |
| sharp | file | file | 23.40 | 31.2 |
| sharp | buffer | buffer | 24.01 | 32.0 |
Greater libvips performance can be expected with caching enabled (default)
and using 8+ core machines, especially those with larger L1/L2 CPU caches.
and using 4+ core machines, especially those with larger L1/L2 CPU caches.
The I/O limits of the relevant (de)compression library will generally determine maximum throughput.

View File

@@ -1,9 +1,12 @@
'use strict';
const { execFileSync } = require('child_process');
const { spawnSync } = require('child_process');
const { prebuild_upload: hasToken, APPVEYOR_REPO_TAG_NAME, TRAVIS_TAG } = process.env;
if (hasToken && (APPVEYOR_REPO_TAG_NAME || TRAVIS_TAG)) {
execFileSync('prebuild', ['--runtime', 'napi', '--target', '3'], { stdio: 'inherit' });
spawnSync('node',
['./node_modules/prebuild/bin.js', '--runtime', 'napi', '--target', '3'],
{ shell: true, stdio: 'inherit' }
);
}

View File

@@ -86,6 +86,10 @@ const debuglog = util.debuglog('sharp');
* .toBuffer()
* .then( ... );
*
* @example
* // Convert an animated GIF to an animated WebP
* await sharp('in.gif', { animated: true }).toFile('out.webp');
*
* @param {(Buffer|string)} [input] - if present, can be
* a Buffer containing JPEG, PNG, WebP, GIF, SVG, TIFF or raw pixel image data, or
* a String containing the filesystem path to an JPEG, PNG, WebP, GIF, SVG or TIFF image file.
@@ -102,6 +106,7 @@ const debuglog = util.debuglog('sharp');
* @param {number} [options.pages=1] - number of pages to extract for multi-page input (GIF, TIFF, PDF), use -1 for all pages.
* @param {number} [options.page=0] - page number to start extracting from for multi-page input (GIF, TIFF, PDF), zero based.
* @param {number} [options.level=0] - level to extract from a multi-level input (OpenSlide), zero based.
* @param {boolean} [options.animated=false] - Set to `true` to read all frames/pages of an animated image (equivalent of setting `pages` to `-1`).
* @param {Object} [options.raw] - describes raw pixel input image data. See `raw()` for pixel ordering.
* @param {number} [options.raw.width]
* @param {number} [options.raw.height]
@@ -187,6 +192,7 @@ const Sharp = function (input, options) {
streamOut: false,
withMetadata: false,
withMetadataOrientation: -1,
withMetadataIcc: '',
resolveWithObject: false,
// output format
jpegQuality: 80,

View File

@@ -99,6 +99,13 @@ function _createInputDescriptor (input, inputOptions, containerOptions) {
}
}
// Multi-page input (GIF, TIFF, PDF)
if (is.defined(inputOptions.animated)) {
if (is.bool(inputOptions.animated)) {
inputDescriptor.pages = inputOptions.animated ? -1 : 1;
} else {
throw is.invalidParameterError('animated', 'boolean', inputOptions.animated);
}
}
if (is.defined(inputOptions.pages)) {
if (is.integer(inputOptions.pages) && is.inRange(inputOptions.pages, -1, 100000)) {
inputDescriptor.pages = inputOptions.pages;

View File

@@ -119,7 +119,8 @@ function toBuffer (options, callback) {
/**
* Include all metadata (EXIF, XMP, IPTC) from the input image in the output image.
* This will also convert to and add a web-friendly sRGB ICC profile.
* This will also convert to and add a web-friendly sRGB ICC profile unless a custom
* output profile is provided.
*
* The default behaviour, when `withMetadata` is not used, is to convert to the device-independent
* sRGB colour space and strip all metadata, including the removal of any ICC profile.
@@ -132,6 +133,7 @@ function toBuffer (options, callback) {
*
* @param {Object} [options]
* @param {number} [options.orientation] value between 1 and 8, used to update the EXIF `Orientation` tag.
* @param {string} [options.icc] filesystem path to output ICC profile, defaults to sRGB.
* @returns {Sharp}
* @throws {Error} Invalid parameters
*/
@@ -145,6 +147,13 @@ function withMetadata (options) {
throw is.invalidParameterError('orientation', 'integer between 1 and 8', options.orientation);
}
}
if (is.defined(options.icc)) {
if (is.string(options.icc)) {
this.options.withMetadataIcc = options.icc;
} else {
throw is.invalidParameterError('icc', 'string filesystem path to ICC profile', options.icc);
}
}
}
return this;
}
@@ -399,6 +408,7 @@ function webp (options) {
* @returns {Sharp}
* @throws {Error} Invalid options
*/
/* istanbul ignore next */
function gif (options) {
if (!this.constructor.format.magick.output.buffer) {
throw new Error('The gif operation requires libvips to have been installed with support for ImageMagick');

View File

@@ -1,7 +1,7 @@
{
"name": "sharp",
"description": "High performance Node.js image processing, the fastest module to resize JPEG, PNG, WebP and TIFF images",
"version": "0.26.0-alpha2",
"version": "0.26.0",
"author": "Lovell Fuller <npm@lovell.info>",
"homepage": "https://github.com/lovell/sharp",
"contributors": [
@@ -68,7 +68,8 @@
"Brychan Bennett-Odlum <git@brychan.io>",
"Edward Silverton <e.silverton@gmail.com>",
"Roman Malieiev <aromaleev@gmail.com>",
"Tomas Szabo <tomas.szabo@deftomat.com>"
"Tomas Szabo <tomas.szabo@deftomat.com>",
"Robert O'Rourke <robert@o-rourke.org>"
],
"scripts": {
"install": "(node install/libvips && node install/dll-copy && prebuild-install) || (node-gyp rebuild && node install/dll-copy)",
@@ -130,15 +131,15 @@
"icc": "^2.0.0",
"license-checker": "^25.0.1",
"mocha": "^8.1.1",
"mock-fs": "^4.12.0",
"mock-fs": "^4.13.0",
"nyc": "^15.1.0",
"prebuild": "^10.0.0",
"prebuild": "^10.0.1",
"rimraf": "^3.0.2",
"semistandard": "^14.2.3"
},
"license": "Apache-2.0",
"config": {
"libvips": "8.10.0-rc4",
"libvips": "8.10.0",
"runtime": "napi",
"target": 3
},

View File

@@ -24,8 +24,8 @@
// Verify platform and compiler compatibility
#if (VIPS_MAJOR_VERSION < 8 || (VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION < 9))
#error "libvips version 8.9.2+ is required - please see https://sharp.pixelplumbing.com/install"
#if (VIPS_MAJOR_VERSION < 8 || (VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION < 10))
#error "libvips version 8.10.0+ is required - please see https://sharp.pixelplumbing.com/install"
#endif
#if ((!defined(__clang__)) && defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 6)))

View File

@@ -684,6 +684,15 @@ class PipelineWorker : public Napi::AsyncWorker {
}
}
// Apply output ICC profile
if (!baton->withMetadataIcc.empty()) {
image = image.icc_transform(
const_cast<char*>(baton->withMetadataIcc.data()),
VImage::option()
->set("input_profile", "srgb")
->set("intent", VIPS_INTENT_PERCEPTUAL));
}
// Override EXIF Orientation tag
if (baton->withMetadata && baton->withMetadataOrientation != -1) {
image = sharp::SetExifOrientation(image, baton->withMetadataOrientation);
@@ -1319,6 +1328,7 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
baton->fileOut = sharp::AttrAsStr(options, "fileOut");
baton->withMetadata = sharp::AttrAsBool(options, "withMetadata");
baton->withMetadataOrientation = sharp::AttrAsUint32(options, "withMetadataOrientation");
baton->withMetadataIcc = sharp::AttrAsStr(options, "withMetadataIcc");
// Format-specific
baton->jpegQuality = sharp::AttrAsUint32(options, "jpegQuality");
baton->jpegProgressive = sharp::AttrAsBool(options, "jpegProgressive");

View File

@@ -155,6 +155,7 @@ struct PipelineBaton {
std::string err;
bool withMetadata;
int withMetadataOrientation;
std::string withMetadataIcc;
std::unique_ptr<double[]> convKernel;
int convKernelWidth;
int convKernelHeight;

View File

@@ -12,12 +12,12 @@
"benchmark": "^2.1.4",
"gm": "^1.23.1",
"imagemagick": "^0.1.3",
"jimp": "^0.9.3",
"mapnik": "^4.3.1",
"jimp": "^0.16.0",
"mapnik": "^4.5.2",
"semver": "^7.1.1"
},
"license": "Apache-2.0",
"engines": {
"node": ">=8.5.0"
"node": ">=10.16.0"
}
}

View File

@@ -564,8 +564,9 @@ async.series({
},
// PNG
png: function (callback) {
const inputPngBuffer = fs.readFileSync(fixtures.inputPng);
const inputPngBuffer = fs.readFileSync(fixtures.inputPngAlphaPremultiplicationLarge);
const pngSuite = new Benchmark.Suite('png');
const minSamples = 64;
// jimp
pngSuite.add('jimp-buffer-buffer', {
defer: true,
@@ -576,6 +577,8 @@ async.series({
} else {
image
.resize(width, height)
.deflateLevel(6)
.filterType(0)
.getBuffer(jimp.MIME_PNG, function (err) {
if (err) {
throw err;
@@ -589,12 +592,14 @@ async.series({
}).add('jimp-file-file', {
defer: true,
fn: function (deferred) {
jimp.read(fixtures.inputPng, function (err, image) {
jimp.read(fixtures.inputPngAlphaPremultiplicationLarge, function (err, image) {
if (err) {
throw err;
} else {
image
.resize(width, height)
.deflateLevel(6)
.filterType(0)
.write(fixtures.outputPng, function (err) {
if (err) {
throw err;
@@ -610,7 +615,7 @@ async.series({
pngSuite.add('mapnik-file-file', {
defer: true,
fn: function (deferred) {
mapnik.Image.open(fixtures.inputPng, function (err, img) {
mapnik.Image.open(fixtures.inputPngAlphaPremultiplicationLarge, function (err, img) {
if (err) throw err;
img.premultiply(function (err, img) {
if (err) throw err;
@@ -657,11 +662,15 @@ async.series({
defer: true,
fn: function (deferred) {
imagemagick.resize({
srcPath: fixtures.inputPng,
srcPath: fixtures.inputPngAlphaPremultiplicationLarge,
dstPath: fixtures.outputPng,
width: width,
height: height,
filter: 'Lanczos'
filter: 'Lanczos',
customArgs: [
'-define', 'PNG:compression-level=6',
'-define', 'PNG:compression-filter=0'
]
}, function (err) {
if (err) {
throw err;
@@ -675,9 +684,11 @@ async.series({
pngSuite.add('gm-file-file', {
defer: true,
fn: function (deferred) {
gm(fixtures.inputPng)
gm(fixtures.inputPngAlphaPremultiplicationLarge)
.filter('Lanczos')
.resize(width, height)
.define('PNG:compression-level=6')
.define('PNG:compression-filter=0')
.write(fixtures.outputPng, function (err) {
if (err) {
throw err;
@@ -689,9 +700,11 @@ async.series({
}).add('gm-file-buffer', {
defer: true,
fn: function (deferred) {
gm(fixtures.inputPng)
gm(fixtures.inputPngAlphaPremultiplicationLarge)
.filter('Lanczos')
.resize(width, height)
.define('PNG:compression-level=6')
.define('PNG:compression-filter=0')
.toBuffer(function (err, buffer) {
if (err) {
throw err;
@@ -705,9 +718,11 @@ async.series({
// sharp
pngSuite.add('sharp-buffer-file', {
defer: true,
minSamples,
fn: function (deferred) {
sharp(inputPngBuffer)
.resize(width, height)
.png({ compressionLevel: 6 })
.toFile(fixtures.outputPng, function (err) {
if (err) {
throw err;
@@ -718,9 +733,11 @@ async.series({
}
}).add('sharp-buffer-buffer', {
defer: true,
minSamples,
fn: function (deferred) {
sharp(inputPngBuffer)
.resize(width, height)
.png({ compressionLevel: 6 })
.toBuffer(function (err, buffer) {
if (err) {
throw err;
@@ -732,9 +749,11 @@ async.series({
}
}).add('sharp-file-file', {
defer: true,
minSamples,
fn: function (deferred) {
sharp(fixtures.inputPng)
sharp(fixtures.inputPngAlphaPremultiplicationLarge)
.resize(width, height)
.png({ compressionLevel: 6 })
.toFile(fixtures.outputPng, function (err) {
if (err) {
throw err;
@@ -745,9 +764,11 @@ async.series({
}
}).add('sharp-file-buffer', {
defer: true,
minSamples,
fn: function (deferred) {
sharp(fixtures.inputPng)
sharp(fixtures.inputPngAlphaPremultiplicationLarge)
.resize(width, height)
.png({ compressionLevel: 6 })
.toBuffer(function (err, buffer) {
if (err) {
throw err;
@@ -759,10 +780,11 @@ async.series({
}
}).add('sharp-progressive', {
defer: true,
minSamples,
fn: function (deferred) {
sharp(inputPngBuffer)
.resize(width, height)
.png({ progressive: true })
.png({ compressionLevel: 6, progressive: true })
.toBuffer(function (err, buffer) {
if (err) {
throw err;
@@ -774,10 +796,27 @@ async.series({
}
}).add('sharp-adaptiveFiltering', {
defer: true,
minSamples,
fn: function (deferred) {
sharp(inputPngBuffer)
.resize(width, height)
.png({ adaptiveFiltering: true })
.png({ adaptiveFiltering: true, compressionLevel: 6 })
.toBuffer(function (err, buffer) {
if (err) {
throw err;
} else {
assert.notStrictEqual(null, buffer);
deferred.resolve();
}
});
}
}).add('sharp-compressionLevel=9', {
defer: true,
minSamples,
fn: function (deferred) {
sharp(inputPngBuffer)
.resize(width, height)
.png({ compressionLevel: 9 })
.toBuffer(function (err, buffer) {
if (err) {
throw err;

BIN
test/fixtures/expected/hilutite.jpg vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

BIN
test/fixtures/expected/icc-cmyk.jpg vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 MiB

BIN
test/fixtures/hilutite.icm vendored Normal file

Binary file not shown.

View File

@@ -39,6 +39,16 @@
Memcheck:Cond
obj:*/libjpeg.so*
}
{
value_jpeg_obj_static
Memcheck:Value8
obj:*/libvips.so*
}
{
cond_jpeg_obj_static
Memcheck:Cond
obj:*/libvips.so*
}
{
param_jpeg_jpeg_finish_compress
Memcheck:Param
@@ -304,6 +314,16 @@
...
fun:vips__init
}
{
leak_rsvg_static_data
Memcheck:Leak
match-leak-kinds: definite
fun:malloc
...
fun:rsvg_rust_handle_new_from_stream_sync
...
fun:vips_object_build
}
# libuv warnings
{
@@ -418,6 +438,13 @@
...
fun:_ZN4node17CreateEnvironmentEPN2v87IsolateEP9uv_loop_sNS0_5LocalINS0_7ContextEEEiPKPKciSB_
}
{
leak_nodejs_CreateEnvironment_IsolateData
Memcheck:Leak
match-leak-kinds: possible
...
fun:_ZN4node17CreateEnvironmentEPNS_11IsolateDataEN2v85LocalINS2_7ContextEEERKSt6vectorISsSaISsEESA_NS_16EnvironmentFlags5FlagsENS_8ThreadIdESt10unique_ptrINS_21InspectorParentHandleESt14default_deleteISF_EE
}
{
leak_nodejs_Environment_Start
Memcheck:Leak

View File

@@ -649,6 +649,15 @@ describe('Input/output', function () {
sharp({ density: 'zoinks' });
}, /Expected number between 1 and 2400 for density but received zoinks of type string/);
});
it('Setting animated property updates pages property', function () {
assert.strictEqual(sharp({ animated: false }).options.input.pages, 1);
assert.strictEqual(sharp({ animated: true }).options.input.pages, -1);
});
it('Invalid animated property throws', function () {
assert.throws(function () {
sharp({ animated: -1 });
}, /Expected boolean for animated but received -1 of type number/);
});
it('Invalid page property throws', function () {
assert.throws(function () {
sharp({ page: -1 });

View File

@@ -501,6 +501,42 @@ describe('Image metadata', function () {
});
});
it('Apply CMYK output ICC profile', function (done) {
const output = fixtures.path('output.icc-cmyk.jpg');
sharp(fixtures.inputJpg)
.withMetadata({ icc: 'cmyk' })
.toFile(output, function (err, info) {
if (err) throw err;
sharp(output).metadata(function (err, metadata) {
if (err) throw err;
assert.strictEqual(true, metadata.hasProfile);
assert.strictEqual('cmyk', metadata.space);
assert.strictEqual(4, metadata.channels);
// ICC
assert.strictEqual('object', typeof metadata.icc);
assert.strictEqual(true, metadata.icc instanceof Buffer);
const profile = icc.parse(metadata.icc);
assert.strictEqual('object', typeof profile);
assert.strictEqual('CMYK', profile.colorSpace);
assert.strictEqual('Relative', profile.intent);
assert.strictEqual('Printer', profile.deviceClass);
});
fixtures.assertSimilar(output, fixtures.path('expected/icc-cmyk.jpg'), { threshold: 0 }, done);
});
});
it('Apply custom output ICC profile', function (done) {
const output = fixtures.path('output.hilutite.jpg');
sharp(fixtures.inputJpg)
.withMetadata({ icc: fixtures.path('hilutite.icm') })
.toFile(output, function (err, info) {
if (err) throw err;
fixtures.assertMaxColourDistance(output, fixtures.path('expected/hilutite.jpg'), 0);
fixtures.assertMaxColourDistance(output, fixtures.inputJpg, 16.5);
done();
});
});
it('Include metadata in output, enabled via empty object', () =>
sharp(fixtures.inputJpgWithExif)
.withMetadata({})
@@ -675,5 +711,10 @@ describe('Image metadata', function () {
sharp().withMetadata({ orientation: 9 });
});
});
it('Non string icc', function () {
assert.throws(function () {
sharp().withMetadata({ icc: true });
});
});
});
});

View File

@@ -161,9 +161,7 @@ describe('TIFF', function () {
.then(() => sharp(fixtures.outputTiff)
.metadata()
.then(({ density }) => {
assert.strictEqual(true,
density === 2540 || // libvips <= 8.8.2
density === 25400); // libvips >= 8.8.3
assert.strictEqual(25400, density);
return promisify(rimraf)(fixtures.outputTiff);
})
)
@@ -179,9 +177,7 @@ describe('TIFF', function () {
.then(data => sharp(data)
.metadata()
.then(({ density }) => {
assert.strictEqual(true,
density === 2540 || // libvips <= 8.8.2
density === 25400); // libvips >= 8.8.3
assert.strictEqual(25400, density);
})
)
);