mirror of
https://github.com/lovell/sharp.git
synced 2026-02-04 13:46:19 +01:00
Compare commits
21 Commits
v0.26.0-be
...
v0.26.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c4c43d525b | ||
|
|
6c5cde363a | ||
|
|
d46b4d950f | ||
|
|
b369c4bb8a | ||
|
|
c3898487c4 | ||
|
|
ca3c5b400f | ||
|
|
97772b176c | ||
|
|
08a2965f1c | ||
|
|
76dcddfa3d | ||
|
|
79f476ae4d | ||
|
|
d406cb619c | ||
|
|
4f3890f1e4 | ||
|
|
7a9d58cc51 | ||
|
|
eef87da0e1 | ||
|
|
00e65f6f14 | ||
|
|
866e9824d1 | ||
|
|
482e6078e2 | ||
|
|
bc7ab296ef | ||
|
|
a5f4f53b56 | ||
|
|
b1227f526d | ||
|
|
78b42c8306 |
@@ -2,6 +2,7 @@ freebsd_instance:
|
||||
image_family: freebsd-13-0-snap
|
||||
|
||||
task:
|
||||
name: FreeBSD 13.0
|
||||
env:
|
||||
IGNORE_OSVERSION: yes
|
||||
prerequisites_script:
|
||||
|
||||
4
.github/CONTRIBUTING.md
vendored
4
.github/CONTRIBUTING.md
vendored
@@ -42,10 +42,6 @@ You deserve to add your details to the [list of contributors](https://github.com
|
||||
|
||||
Any change that modifies the existing public API should be added to the relevant work-in-progress branch for inclusion in the next major release.
|
||||
|
||||
| Release | WIP branch |
|
||||
| ------: | :--------- |
|
||||
| v0.26.0 | zoom |
|
||||
|
||||
Please squash your changes into a single commit using a command like `git rebase -i upstream/<wip-branch>`.
|
||||
|
||||
### Add a new public method
|
||||
|
||||
2
.github/ISSUE_TEMPLATE/installation.md
vendored
2
.github/ISSUE_TEMPLATE/installation.md
vendored
@@ -7,7 +7,7 @@ labels: installation
|
||||
|
||||
Did you see the [documentation relating to installation](https://sharp.pixelplumbing.com/install)?
|
||||
|
||||
Have you ensured the platform and version of Node.js used for `npm install` is the same as the platform and version of Node.js used at runtime?
|
||||
Have you ensured the architecture and platform of Node.js used for `npm install` is the same as the architecture and platform of Node.js used at runtime?
|
||||
|
||||
Are you using the latest version? Is the version currently in use as reported by `npm ls sharp` the same as the latest version as reported by `npm view sharp dist-tags.latest`?
|
||||
|
||||
|
||||
@@ -72,7 +72,7 @@ jobs:
|
||||
- sudo docker run -dit --name sharp --env CI --env TRAVIS_TAG --env prebuild_upload --volume "${PWD}:/mnt/sharp" --workdir /mnt/sharp arm64v8/debian:bullseye
|
||||
- sudo docker exec sharp sh -c "apt-get update && apt-get install -y build-essential git python2 curl"
|
||||
- sudo docker exec sharp sh -c "curl -s https://deb.nodesource.com/gpgkey/nodesource.gpg.key | apt-key add -"
|
||||
- sudo docker exec sharp sh -c "echo 'deb https://deb.nodesource.com/node_10.x buster main' >/etc/apt/sources.list.d/nodesource.list"
|
||||
- sudo docker exec sharp sh -c "echo 'deb https://deb.nodesource.com/node_10.x sid main' >/etc/apt/sources.list.d/nodesource.list"
|
||||
- sudo docker exec sharp sh -c "apt-get update && apt-get install -y nodejs=10.*"
|
||||
install: sudo docker exec sharp sh -c "npm install --unsafe-perm"
|
||||
script: sudo docker exec sharp sh -c "npm test"
|
||||
@@ -86,7 +86,7 @@ jobs:
|
||||
- sudo docker run -dit --name sharp --env CI --volume "${PWD}:/mnt/sharp" --workdir /mnt/sharp arm64v8/debian:bullseye
|
||||
- sudo docker exec sharp sh -c "apt-get update && apt-get install -y build-essential git python2 curl"
|
||||
- sudo docker exec sharp sh -c "curl -s https://deb.nodesource.com/gpgkey/nodesource.gpg.key | apt-key add -"
|
||||
- sudo docker exec sharp sh -c "echo 'deb https://deb.nodesource.com/node_12.x buster main' >/etc/apt/sources.list.d/nodesource.list"
|
||||
- sudo docker exec sharp sh -c "echo 'deb https://deb.nodesource.com/node_12.x sid main' >/etc/apt/sources.list.d/nodesource.list"
|
||||
- sudo docker exec sharp sh -c "apt-get update && apt-get install -y nodejs"
|
||||
install: sudo docker exec sharp sh -c "npm install --unsafe-perm"
|
||||
script: sudo docker exec sharp sh -c "npm test"
|
||||
@@ -100,7 +100,7 @@ jobs:
|
||||
- sudo docker run -dit --name sharp --env CI --volume "${PWD}:/mnt/sharp" --workdir /mnt/sharp arm64v8/debian:bullseye
|
||||
- sudo docker exec sharp sh -c "apt-get update && apt-get install -y build-essential git python2 curl"
|
||||
- sudo docker exec sharp sh -c "curl -s https://deb.nodesource.com/gpgkey/nodesource.gpg.key | apt-key add -"
|
||||
- sudo docker exec sharp sh -c "echo 'deb https://deb.nodesource.com/node_14.x buster main' >/etc/apt/sources.list.d/nodesource.list"
|
||||
- sudo docker exec sharp sh -c "echo 'deb https://deb.nodesource.com/node_14.x sid main' >/etc/apt/sources.list.d/nodesource.list"
|
||||
- sudo docker exec sharp sh -c "apt-get update && apt-get install -y nodejs"
|
||||
install: sudo docker exec sharp sh -c "npm install --unsafe-perm"
|
||||
script: sudo docker exec sharp sh -c "npm test"
|
||||
|
||||
@@ -95,7 +95,7 @@
|
||||
'src/sharp.cc'
|
||||
],
|
||||
'include_dirs': [
|
||||
'<!@(node -p "require(\'node-addon-api\').include")',
|
||||
'<!(node -p "require(\'node-addon-api\').include_dir")',
|
||||
],
|
||||
'conditions': [
|
||||
['use_global_libvips == "true"', {
|
||||
|
||||
@@ -25,7 +25,7 @@ Implements the [stream.Duplex][1] class.
|
||||
An integral Number of pixels, zero or false to remove limit, true to use default limit of 268402689 (0x3FFF x 0x3FFF). (optional, default `268402689`)
|
||||
- `options.sequentialRead` **[boolean][5]** Set this to `true` to use sequential rather than random access where possible.
|
||||
This can reduce memory usage and might improve performance on some systems. (optional, default `false`)
|
||||
- `options.density` **[number][6]** number representing the DPI for vector images. (optional, default `72`)
|
||||
- `options.density` **[number][6]** number representing the DPI for vector images in the range 1 to 100000. (optional, default `72`)
|
||||
- `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`)
|
||||
|
||||
@@ -4,7 +4,27 @@
|
||||
|
||||
Requires libvips v8.10.0
|
||||
|
||||
### v0.26.0 - TBD
|
||||
### v0.26.1 - 20th September 2020
|
||||
|
||||
* Ensure correct pageHeight when verifying multi-page image dimensions.
|
||||
[#2343](https://github.com/lovell/sharp/pull/2343)
|
||||
[@derom](https://github.com/derom)
|
||||
|
||||
* Allow input density range up to 100000 DPI.
|
||||
[#2348](https://github.com/lovell/sharp/pull/2348)
|
||||
[@stefanprobst](https://github.com/stefanprobst)
|
||||
|
||||
* Ensure animation-related properties can be set for Stream-based input.
|
||||
[#2369](https://github.com/lovell/sharp/pull/2369)
|
||||
[@AcrylicShrimp](https://github.com/AcrylicShrimp)
|
||||
|
||||
* Ensure `stats` can be calculated for 1x1 input.
|
||||
[#2372](https://github.com/lovell/sharp/issues/2372)
|
||||
|
||||
* Ensure animated GIF output is optimised.
|
||||
[#2376](https://github.com/lovell/sharp/issues/2376)
|
||||
|
||||
### v0.26.0 - 25th August 2020
|
||||
|
||||
* Prebuilt libvips binaries are now statically-linked and Brotli-compressed, requiring Node.js 10.16.0+.
|
||||
|
||||
|
||||
@@ -197,3 +197,9 @@ GitHub: https://github.com/deftomat
|
||||
|
||||
Name: Robert O'Rourke
|
||||
GitHub: https://github.com/roborourke
|
||||
|
||||
Name: Denis Soldatov
|
||||
GitHub: https://github.com/derom
|
||||
|
||||
Name: Stefan Probst
|
||||
GitHub: https://github.com/stefanprobst
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; object-src 'none'; style-src 'unsafe-inline';
|
||||
img-src 'unsafe-inline' data: https://pixel.plumbing/px/ https://cdn.jsdelivr.net/gh/lovell/ https://www.google-analytics.com;
|
||||
connect-src 'self' https://cdn.jsdelivr.net/gh/lovell/ https://www.google-analytics.com;
|
||||
script-src 'sha256-iXDHv+t2aGdJcmEvwHfqmGH4SrOSx+P8rCF6+WLLwXA=' 'unsafe-eval'
|
||||
script-src 'unsafe-inline' 'unsafe-eval'
|
||||
https://cdn.jsdelivr.net/npm/docute@4/dist/docute.min.js
|
||||
https://www.google-analytics.com/analytics.js;">
|
||||
<link rel="icon" type="image/png" href="https://pixel.plumbing/px/32x32/sharp-logo.svg">
|
||||
@@ -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.1/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.1/docs',
|
||||
nav: [
|
||||
{
|
||||
title: 'Funding',
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -80,6 +80,9 @@ try {
|
||||
throw new Error(`Use with glibc ${detectLibc.version} requires manual installation of libvips >= ${minimumLibvipsVersion}`);
|
||||
}
|
||||
}
|
||||
if (!semver.satisfies(process.versions.node, process.env.npm_package_engines_node)) {
|
||||
throw new Error(`Expected Node.js version ${process.env.npm_package_engines_node} but found ${process.versions.node}`);
|
||||
}
|
||||
// Download to per-process temporary file
|
||||
const tarFilename = ['libvips', minimumLibvipsVersion, platformAndArch].join('-') + '.tar.br';
|
||||
const tarPathCache = path.join(libvips.cachePath(), tarFilename);
|
||||
|
||||
@@ -102,7 +102,7 @@ const debuglog = util.debuglog('sharp');
|
||||
* An integral Number of pixels, zero or false to remove limit, true to use default limit of 268402689 (0x3FFF x 0x3FFF).
|
||||
* @param {boolean} [options.sequentialRead=false] - Set this to `true` to use sequential rather than random access where possible.
|
||||
* This can reduce memory usage and might improve performance on some systems.
|
||||
* @param {number} [options.density=72] - number representing the DPI for vector images.
|
||||
* @param {number} [options.density=72] - number representing the DPI for vector images in the range 1 to 100000.
|
||||
* @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.
|
||||
|
||||
10
lib/input.js
10
lib/input.js
@@ -9,9 +9,9 @@ const sharp = require('../build/Release/sharp.node');
|
||||
* @private
|
||||
*/
|
||||
function _inputOptionsFromObject (obj) {
|
||||
const { raw, density, limitInputPixels, sequentialRead, failOnError } = obj;
|
||||
return [raw, density, limitInputPixels, sequentialRead, failOnError].some(is.defined)
|
||||
? { raw, density, limitInputPixels, sequentialRead, failOnError }
|
||||
const { raw, density, limitInputPixels, sequentialRead, failOnError, animated, page, pages } = obj;
|
||||
return [raw, density, limitInputPixels, sequentialRead, failOnError, animated, page, pages].some(is.defined)
|
||||
? { raw, density, limitInputPixels, sequentialRead, failOnError, animated, page, pages }
|
||||
: undefined;
|
||||
}
|
||||
|
||||
@@ -57,10 +57,10 @@ function _createInputDescriptor (input, inputOptions, containerOptions) {
|
||||
}
|
||||
// Density
|
||||
if (is.defined(inputOptions.density)) {
|
||||
if (is.inRange(inputOptions.density, 1, 2400)) {
|
||||
if (is.inRange(inputOptions.density, 1, 100000)) {
|
||||
inputDescriptor.density = inputOptions.density;
|
||||
} else {
|
||||
throw is.invalidParameterError('density', 'number between 1 and 2400', inputOptions.density);
|
||||
throw is.invalidParameterError('density', 'number between 1 and 100000', inputOptions.density);
|
||||
}
|
||||
}
|
||||
// limitInputPixels
|
||||
|
||||
@@ -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-beta1",
|
||||
"version": "0.26.1",
|
||||
"author": "Lovell Fuller <npm@lovell.info>",
|
||||
"homepage": "https://github.com/lovell/sharp",
|
||||
"contributors": [
|
||||
@@ -114,7 +114,7 @@
|
||||
"dependencies": {
|
||||
"color": "^3.1.2",
|
||||
"detect-libc": "^1.0.3",
|
||||
"node-addon-api": "^3.0.0",
|
||||
"node-addon-api": "^3.0.2",
|
||||
"npmlog": "^4.1.2",
|
||||
"prebuild-install": "^5.3.5",
|
||||
"semver": "^7.3.2",
|
||||
|
||||
@@ -485,8 +485,8 @@ namespace sharp {
|
||||
Check the proposed format supports the current dimensions.
|
||||
*/
|
||||
void AssertImageTypeDimensions(VImage image, ImageType const imageType) {
|
||||
const int height = image.get_typeof("pageHeight") == G_TYPE_INT
|
||||
? image.get_int("pageHeight")
|
||||
const int height = image.get_typeof(VIPS_META_PAGE_HEIGHT) == G_TYPE_INT
|
||||
? image.get_int(VIPS_META_PAGE_HEIGHT)
|
||||
: image.height();
|
||||
if (imageType == ImageType::JPEG) {
|
||||
if (image.width() > 65535 || height > 65535) {
|
||||
|
||||
@@ -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)))
|
||||
|
||||
@@ -782,6 +782,8 @@ class PipelineWorker : public Napi::AsyncWorker {
|
||||
sharp::AssertImageTypeDimensions(image, sharp::ImageType::GIF);
|
||||
VipsArea *area = VIPS_AREA(image.magicksave_buffer(VImage::option()
|
||||
->set("strip", !baton->withMetadata)
|
||||
->set("optimize_gif_frames", TRUE)
|
||||
->set("optimize_gif_transparency", TRUE)
|
||||
->set("format", "gif")));
|
||||
baton->bufferOut = static_cast<char*>(area->data);
|
||||
baton->bufferOutLength = area->length;
|
||||
@@ -925,6 +927,8 @@ class PipelineWorker : public Napi::AsyncWorker {
|
||||
sharp::AssertImageTypeDimensions(image, sharp::ImageType::GIF);
|
||||
image.magicksave(const_cast<char*>(baton->fileOut.data()), VImage::option()
|
||||
->set("strip", !baton->withMetadata)
|
||||
->set("optimize_gif_frames", TRUE)
|
||||
->set("optimize_gif_transparency", TRUE)
|
||||
->set("format", "gif"));
|
||||
baton->formatOut = "gif";
|
||||
} else if (baton->formatOut == "tiff" || (mightMatchInput && isTiff) ||
|
||||
|
||||
14
src/stats.cc
14
src/stats.cc
@@ -80,12 +80,14 @@ class StatsWorker : public Napi::AsyncWorker {
|
||||
// Estimate entropy via histogram of greyscale value frequency
|
||||
baton->entropy = std::abs(greyscale.hist_find().hist_entropy());
|
||||
// Estimate sharpness via standard deviation of greyscale laplacian
|
||||
VImage laplacian = VImage::new_matrixv(3, 3,
|
||||
0.0, 1.0, 0.0,
|
||||
1.0, -4.0, 1.0,
|
||||
0.0, 1.0, 0.0);
|
||||
laplacian.set("scale", 9.0);
|
||||
baton->sharpness = greyscale.conv(laplacian).deviate();
|
||||
if (image.width() > 1 || image.height() > 1) {
|
||||
VImage laplacian = VImage::new_matrixv(3, 3,
|
||||
0.0, 1.0, 0.0,
|
||||
1.0, -4.0, 1.0,
|
||||
0.0, 1.0, 0.0);
|
||||
laplacian.set("scale", 9.0);
|
||||
baton->sharpness = greyscale.conv(laplacian).deviate();
|
||||
}
|
||||
// Most dominant sRGB colour via 4096-bin 3D histogram
|
||||
vips::VImage hist = sharp::RemoveAlpha(image)
|
||||
.colourspace(VIPS_INTERPRETATION_sRGB)
|
||||
|
||||
BIN
test/fixtures/big-height.webp
vendored
Normal file
BIN
test/fixtures/big-height.webp
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.1 KiB |
3
test/fixtures/circle.svg
vendored
Normal file
3
test/fixtures/circle.svg
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 8 8">
|
||||
<circle r="3.75" cx="4" cy="4" fill="deeppink" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 122 B |
BIN
test/fixtures/expected/circle.png
vendored
Normal file
BIN
test/fixtures/expected/circle.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 22 KiB |
2
test/fixtures/index.js
vendored
2
test/fixtures/index.js
vendored
@@ -95,6 +95,7 @@ module.exports = {
|
||||
inputWebPWithTransparency: getPath('5_webp_a.webp'), // http://www.gstatic.com/webp/gallery3/5_webp_a.webp
|
||||
inputWebPAnimated: getPath('rotating-squares.webp'), // http://www.gstatic.com/webp/gallery3/5_webp_a.webp
|
||||
inputWebPAnimatedLoop3: getPath('animated-loop-3.webp'), // http://www.gstatic.com/webp/gallery3/5_webp_a.webp
|
||||
inputWebPAnimatedBigHeight: getPath('big-height.webp'),
|
||||
inputTiff: getPath('G31D.TIF'), // http://www.fileformat.info/format/tiff/sample/e6c9a6e5253348f4aef6d17b534360ab/index.htm
|
||||
inputTiffMultipage: getPath('G31D_MULTI.TIF'), // gm convert G31D.TIF -resize 50% G31D_2.TIF ; tiffcp G31D.TIF G31D_2.TIF G31D_MULTI.TIF
|
||||
inputTiffCielab: getPath('cielab-dagams.tiff'), // https://github.com/lovell/sharp/issues/646
|
||||
@@ -106,6 +107,7 @@ module.exports = {
|
||||
inputGifAnimated: getPath('rotating-squares.gif'), // CC0 https://loading.io/spinner/blocks/-rotating-squares-preloader-gif
|
||||
inputGifAnimatedLoop3: getPath('animated-loop-3.gif'), // CC-BY-SA-4.0 Petrus3743 https://commons.wikimedia.org/wiki/File:01-Goldener_Schnitt_Formel-Animation.gif
|
||||
inputSvg: getPath('check.svg'), // http://dev.w3.org/SVG/tools/svgweb/samples/svg-files/check.svg
|
||||
inputSvgSmallViewBox: getPath('circle.svg'),
|
||||
inputSvgWithEmbeddedImages: getPath('struct-image-04-t.svg'), // https://dev.w3.org/SVG/profiles/1.2T/test/svg/struct-image-04-t.svg
|
||||
|
||||
inputJPGBig: getPath('flowers.jpeg'),
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -98,4 +98,36 @@ describe('GIF input', () => {
|
||||
sharp().gif({ delay: [65536] });
|
||||
});
|
||||
});
|
||||
|
||||
it('should work with streams when only animated is set', function (done) {
|
||||
if (sharp.format.magick.output.buffer) {
|
||||
fs.createReadStream(fixtures.inputGifAnimated)
|
||||
.pipe(sharp({ animated: true }))
|
||||
.gif()
|
||||
.toBuffer(function (err, data, info) {
|
||||
if (err) throw err;
|
||||
assert.strictEqual(true, data.length > 0);
|
||||
assert.strictEqual('gif', info.format);
|
||||
fixtures.assertSimilar(fixtures.inputGifAnimated, data, done);
|
||||
});
|
||||
} else {
|
||||
done();
|
||||
}
|
||||
});
|
||||
|
||||
it('should work with streams when only pages is set', function (done) {
|
||||
if (sharp.format.magick.output.buffer) {
|
||||
fs.createReadStream(fixtures.inputGifAnimated)
|
||||
.pipe(sharp({ pages: -1 }))
|
||||
.gif()
|
||||
.toBuffer(function (err, data, info) {
|
||||
if (err) throw err;
|
||||
assert.strictEqual(true, data.length > 0);
|
||||
assert.strictEqual('gif', info.format);
|
||||
fixtures.assertSimilar(fixtures.inputGifAnimated, data, done);
|
||||
});
|
||||
} else {
|
||||
done();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -302,7 +302,7 @@ describe('Input/output', function () {
|
||||
});
|
||||
|
||||
it('Fail when input is empty Buffer', function (done) {
|
||||
if (sharp.format.magick.input.buffer) return this.skip(); // can be removed with libvips 8.10.0+
|
||||
if (sharp.format.magick.input.buffer) return this.skip(); // can be removed with libvips 8.10.1+
|
||||
sharp(Buffer.alloc(0)).toBuffer().then(function () {
|
||||
assert(false);
|
||||
done();
|
||||
@@ -647,7 +647,7 @@ describe('Input/output', function () {
|
||||
it('Invalid density: string', function () {
|
||||
assert.throws(function () {
|
||||
sharp({ density: 'zoinks' });
|
||||
}, /Expected number between 1 and 2400 for density but received zoinks of type string/);
|
||||
}, /Expected number between 1 and 100000 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);
|
||||
|
||||
@@ -462,6 +462,19 @@ describe('Image Stats', function () {
|
||||
})
|
||||
);
|
||||
|
||||
it('Entropy and sharpness of 1x1 input are zero', async () => {
|
||||
const { entropy, sharpness } = await sharp({
|
||||
create: {
|
||||
width: 1,
|
||||
height: 1,
|
||||
channels: 3,
|
||||
background: 'red'
|
||||
}
|
||||
}).stats();
|
||||
assert.strictEqual(entropy, 0);
|
||||
assert.strictEqual(sharpness, 0);
|
||||
});
|
||||
|
||||
it('Stream in, Callback out', function (done) {
|
||||
const readable = fs.createReadStream(fixtures.inputJpg);
|
||||
const pipeline = sharp().stats(function (err, stats) {
|
||||
|
||||
@@ -48,6 +48,31 @@ describe('SVG input', function () {
|
||||
});
|
||||
});
|
||||
|
||||
it('Convert SVG to PNG at DPI larger than 2400', function (done) {
|
||||
const size = 1024;
|
||||
sharp(fixtures.inputSvgSmallViewBox).metadata(function (err, metadata) {
|
||||
if (err) throw err;
|
||||
const density = (size / Math.max(metadata.width, metadata.height)) * metadata.density;
|
||||
sharp(fixtures.inputSvgSmallViewBox, { density })
|
||||
.resize(size)
|
||||
.toFormat('png')
|
||||
.toBuffer(function (err, data, info) {
|
||||
if (err) throw err;
|
||||
assert.strictEqual('png', info.format);
|
||||
assert.strictEqual(size, info.width);
|
||||
assert.strictEqual(size, info.height);
|
||||
fixtures.assertSimilar(fixtures.expected('circle.png'), data, function (err) {
|
||||
if (err) throw err;
|
||||
sharp(data).metadata(function (err, info) {
|
||||
if (err) throw err;
|
||||
assert.strictEqual(9216, info.density);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('Convert SVG to PNG at 14.4DPI', function (done) {
|
||||
sharp(fixtures.inputSvg, { density: 14.4 })
|
||||
.toFormat('png')
|
||||
|
||||
@@ -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);
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
@@ -16,4 +16,12 @@ describe('toBuffer', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('correctly process animated webp with height > 16383', (done) => {
|
||||
const image = sharp(fixtures.inputWebPAnimatedBigHeight, { animated: true });
|
||||
image.toBuffer().then((buff) => {
|
||||
assert.strictEqual(Buffer.isBuffer(buff), true);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
'use strict';
|
||||
|
||||
const fs = require('fs');
|
||||
const assert = require('assert');
|
||||
|
||||
const sharp = require('../../');
|
||||
@@ -184,4 +185,28 @@ describe('WebP', function () {
|
||||
|
||||
assert.deepStrictEqual(updated.delay, expectedDelay);
|
||||
});
|
||||
|
||||
it('should work with streams when only animated is set', function (done) {
|
||||
fs.createReadStream(fixtures.inputWebPAnimated)
|
||||
.pipe(sharp({ animated: true }))
|
||||
.webp({ lossless: true })
|
||||
.toBuffer(function (err, data, info) {
|
||||
if (err) throw err;
|
||||
assert.strictEqual(true, data.length > 0);
|
||||
assert.strictEqual('webp', info.format);
|
||||
fixtures.assertSimilar(fixtures.inputWebPAnimated, data, done);
|
||||
});
|
||||
});
|
||||
|
||||
it('should work with streams when only pages is set', function (done) {
|
||||
fs.createReadStream(fixtures.inputWebPAnimated)
|
||||
.pipe(sharp({ pages: -1 }))
|
||||
.webp({ lossless: true })
|
||||
.toBuffer(function (err, data, info) {
|
||||
if (err) throw err;
|
||||
assert.strictEqual(true, data.length > 0);
|
||||
assert.strictEqual('webp', info.format);
|
||||
fixtures.assertSimilar(fixtures.inputWebPAnimated, data, done);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user