mirror of
https://github.com/lovell/sharp.git
synced 2026-02-04 21:56:18 +01:00
Compare commits
22 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fbe48d75dd | ||
|
|
20ba0f49dd | ||
|
|
c213e9878d | ||
|
|
9704ca4c18 | ||
|
|
49dce6219e | ||
|
|
260ff6c94f | ||
|
|
3ec281d104 | ||
|
|
c4c43d525b | ||
|
|
6c5cde363a | ||
|
|
d46b4d950f | ||
|
|
b369c4bb8a | ||
|
|
c3898487c4 | ||
|
|
ca3c5b400f | ||
|
|
97772b176c | ||
|
|
08a2965f1c | ||
|
|
76dcddfa3d | ||
|
|
79f476ae4d | ||
|
|
d406cb619c | ||
|
|
4f3890f1e4 | ||
|
|
7a9d58cc51 | ||
|
|
eef87da0e1 | ||
|
|
00e65f6f14 |
@@ -2,6 +2,7 @@ freebsd_instance:
|
|||||||
image_family: freebsd-13-0-snap
|
image_family: freebsd-13-0-snap
|
||||||
|
|
||||||
task:
|
task:
|
||||||
|
name: FreeBSD 13.0
|
||||||
env:
|
env:
|
||||||
IGNORE_OSVERSION: yes
|
IGNORE_OSVERSION: yes
|
||||||
prerequisites_script:
|
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.
|
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>`.
|
Please squash your changes into a single commit using a command like `git rebase -i upstream/<wip-branch>`.
|
||||||
|
|
||||||
### Add a new public method
|
### 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)?
|
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`?
|
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 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 "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 "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.*"
|
- 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"
|
install: sudo docker exec sharp sh -c "npm install --unsafe-perm"
|
||||||
script: sudo docker exec sharp sh -c "npm test"
|
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 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 "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 "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"
|
- 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"
|
install: sudo docker exec sharp sh -c "npm install --unsafe-perm"
|
||||||
script: sudo docker exec sharp sh -c "npm test"
|
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 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 "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 "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"
|
- 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"
|
install: sudo docker exec sharp sh -c "npm install --unsafe-perm"
|
||||||
script: sudo docker exec sharp sh -c "npm test"
|
script: sudo docker exec sharp sh -c "npm test"
|
||||||
|
|||||||
@@ -95,7 +95,7 @@
|
|||||||
'src/sharp.cc'
|
'src/sharp.cc'
|
||||||
],
|
],
|
||||||
'include_dirs': [
|
'include_dirs': [
|
||||||
'<!@(node -p "require(\'node-addon-api\').include")',
|
'<!(node -p "require(\'node-addon-api\').include_dir")',
|
||||||
],
|
],
|
||||||
'conditions': [
|
'conditions': [
|
||||||
['use_global_libvips == "true"', {
|
['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`)
|
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.
|
- `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`)
|
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.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.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.level` **[number][6]** level to extract from a multi-level input (OpenSlide), zero based. (optional, default `0`)
|
||||||
|
|||||||
@@ -372,6 +372,8 @@ Warning: multiple sharp instances concurrently producing tile output can expose
|
|||||||
- `options.skipBlanks` **[number][9]** threshold to skip tile generation, a value 0 - 255 for 8-bit images or 0 - 65535 for 16-bit images (optional, default `-1`)
|
- `options.skipBlanks` **[number][9]** threshold to skip tile generation, a value 0 - 255 for 8-bit images or 0 - 65535 for 16-bit images (optional, default `-1`)
|
||||||
- `options.container` **[string][2]** tile container, with value `fs` (filesystem) or `zip` (compressed file). (optional, default `'fs'`)
|
- `options.container` **[string][2]** tile container, with value `fs` (filesystem) or `zip` (compressed file). (optional, default `'fs'`)
|
||||||
- `options.layout` **[string][2]** filesystem layout, possible values are `dz`, `iiif`, `zoomify` or `google`. (optional, default `'dz'`)
|
- `options.layout` **[string][2]** filesystem layout, possible values are `dz`, `iiif`, `zoomify` or `google`. (optional, default `'dz'`)
|
||||||
|
- `options.centre` **[boolean][7]** centre image in tile. (optional, default `false`)
|
||||||
|
- `options.center` **[boolean][7]** alternative spelling of centre. (optional, default `false`)
|
||||||
|
|
||||||
### Examples
|
### Examples
|
||||||
|
|
||||||
|
|||||||
@@ -209,7 +209,8 @@ Returns **Sharp**
|
|||||||
Trim "boring" pixels from all edges that contain values similar to the top-left pixel.
|
Trim "boring" pixels from all edges that contain values similar to the top-left pixel.
|
||||||
Images consisting entirely of a single colour will calculate "boring" using the alpha channel, if any.
|
Images consisting entirely of a single colour will calculate "boring" using the alpha channel, if any.
|
||||||
|
|
||||||
The `info` response Object will contain `trimOffsetLeft` and `trimOffsetTop` properties.
|
The `info` response Object, obtained from callback of `.toFile()` or `.toBuffer()`,
|
||||||
|
will contain `trimOffsetLeft` and `trimOffsetTop` properties.
|
||||||
|
|
||||||
### Parameters
|
### Parameters
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,39 @@
|
|||||||
|
|
||||||
Requires libvips v8.10.0
|
Requires libvips v8.10.0
|
||||||
|
|
||||||
|
### v0.26.2 - 14th October 2020
|
||||||
|
|
||||||
|
* Add support for EXR input. Requires libvips compiled with OpenEXR.
|
||||||
|
[#698](https://github.com/lovell/sharp/issues/698)
|
||||||
|
|
||||||
|
* Ensure support for yarn v2.
|
||||||
|
[#2379](https://github.com/lovell/sharp/pull/2379)
|
||||||
|
[@jalovatt](https://github.com/jalovatt)
|
||||||
|
|
||||||
|
* Add centre/center option to tile-based output.
|
||||||
|
[#2397](https://github.com/lovell/sharp/pull/2397)
|
||||||
|
[@beig](https://github.com/beig)
|
||||||
|
|
||||||
|
### 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
|
### v0.26.0 - 25th August 2020
|
||||||
|
|
||||||
* Prebuilt libvips binaries are now statically-linked and Brotli-compressed, requiring Node.js 10.16.0+.
|
* Prebuilt libvips binaries are now statically-linked and Brotli-compressed, requiring Node.js 10.16.0+.
|
||||||
|
|||||||
@@ -197,3 +197,12 @@ GitHub: https://github.com/deftomat
|
|||||||
|
|
||||||
Name: Robert O'Rourke
|
Name: Robert O'Rourke
|
||||||
GitHub: https://github.com/roborourke
|
GitHub: https://github.com/roborourke
|
||||||
|
|
||||||
|
Name: Denis Soldatov
|
||||||
|
GitHub: https://github.com/derom
|
||||||
|
|
||||||
|
Name: Stefan Probst
|
||||||
|
GitHub: https://github.com/stefanprobst
|
||||||
|
|
||||||
|
Name: Thomas Beiganz
|
||||||
|
GitHub: https://github.com/beig
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; object-src 'none'; style-src 'unsafe-inline';
|
<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;
|
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;
|
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://cdn.jsdelivr.net/npm/docute@4/dist/docute.min.js
|
||||||
https://www.google-analytics.com/analytics.js;">
|
https://www.google-analytics.com/analytics.js;">
|
||||||
<link rel="icon" type="image/png" href="https://pixel.plumbing/px/32x32/sharp-logo.svg">
|
<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" 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="apple-touch-icon-precomposed" href="https://pixel.plumbing/px/57x57/sharp-logo.svg">
|
||||||
<link rel="author" href="/humans.txt" type="text/plain">
|
<link rel="author" href="/humans.txt" type="text/plain">
|
||||||
<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@v0.26.2/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="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://pixel.plumbing">
|
||||||
<link rel="dns-prefetch" href="https://www.google-analytics.com">
|
<link rel="dns-prefetch" href="https://www.google-analytics.com">
|
||||||
@@ -139,7 +139,7 @@
|
|||||||
docuteApiTitlePlugin,
|
docuteApiTitlePlugin,
|
||||||
docuteApiSearchPlugin
|
docuteApiSearchPlugin
|
||||||
],
|
],
|
||||||
sourcePath: 'https://cdn.jsdelivr.net/gh/lovell/sharp@v0.26.0/docs',
|
sourcePath: 'https://cdn.jsdelivr.net/gh/lovell/sharp@v0.26.2/docs',
|
||||||
nav: [
|
nav: [
|
||||||
{
|
{
|
||||||
title: 'Funding',
|
title: 'Funding',
|
||||||
|
|||||||
@@ -80,6 +80,12 @@ try {
|
|||||||
throw new Error(`Use with glibc ${detectLibc.version} requires manual installation of libvips >= ${minimumLibvipsVersion}`);
|
throw new Error(`Use with glibc ${detectLibc.version} requires manual installation of libvips >= ${minimumLibvipsVersion}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const supportedNodeVersion = process.env.npm_package_engines_node || require('../package.json').engines.node;
|
||||||
|
if (!semver.satisfies(process.versions.node, supportedNodeVersion)) {
|
||||||
|
throw new Error(`Expected Node.js version ${supportedNodeVersion} but found ${process.versions.node}`);
|
||||||
|
}
|
||||||
|
|
||||||
// Download to per-process temporary file
|
// Download to per-process temporary file
|
||||||
const tarFilename = ['libvips', minimumLibvipsVersion, platformAndArch].join('-') + '.tar.br';
|
const tarFilename = ['libvips', minimumLibvipsVersion, platformAndArch].join('-') + '.tar.br';
|
||||||
const tarPathCache = path.join(libvips.cachePath(), tarFilename);
|
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).
|
* 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.
|
* @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.
|
* 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.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.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 {number} [options.level=0] - level to extract from a multi-level input (OpenSlide), zero based.
|
||||||
@@ -238,6 +238,7 @@ const Sharp = function (input, options) {
|
|||||||
tileAngle: 0,
|
tileAngle: 0,
|
||||||
tileSkipBlanks: -1,
|
tileSkipBlanks: -1,
|
||||||
tileBackground: [255, 255, 255, 255],
|
tileBackground: [255, 255, 255, 255],
|
||||||
|
tileCentre: false,
|
||||||
linearA: 1,
|
linearA: 1,
|
||||||
linearB: 0,
|
linearB: 0,
|
||||||
// Function to notify of libvips warnings
|
// Function to notify of libvips warnings
|
||||||
|
|||||||
10
lib/input.js
10
lib/input.js
@@ -9,9 +9,9 @@ const sharp = require('../build/Release/sharp.node');
|
|||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
function _inputOptionsFromObject (obj) {
|
function _inputOptionsFromObject (obj) {
|
||||||
const { raw, density, limitInputPixels, sequentialRead, failOnError } = obj;
|
const { raw, density, limitInputPixels, sequentialRead, failOnError, animated, page, pages } = obj;
|
||||||
return [raw, density, limitInputPixels, sequentialRead, failOnError].some(is.defined)
|
return [raw, density, limitInputPixels, sequentialRead, failOnError, animated, page, pages].some(is.defined)
|
||||||
? { raw, density, limitInputPixels, sequentialRead, failOnError }
|
? { raw, density, limitInputPixels, sequentialRead, failOnError, animated, page, pages }
|
||||||
: undefined;
|
: undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,10 +57,10 @@ function _createInputDescriptor (input, inputOptions, containerOptions) {
|
|||||||
}
|
}
|
||||||
// Density
|
// Density
|
||||||
if (is.defined(inputOptions.density)) {
|
if (is.defined(inputOptions.density)) {
|
||||||
if (is.inRange(inputOptions.density, 1, 2400)) {
|
if (is.inRange(inputOptions.density, 1, 100000)) {
|
||||||
inputDescriptor.density = inputOptions.density;
|
inputDescriptor.density = inputOptions.density;
|
||||||
} else {
|
} else {
|
||||||
throw is.invalidParameterError('density', 'number between 1 and 2400', inputOptions.density);
|
throw is.invalidParameterError('density', 'number between 1 and 100000', inputOptions.density);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// limitInputPixels
|
// limitInputPixels
|
||||||
|
|||||||
@@ -658,6 +658,8 @@ function raw () {
|
|||||||
* @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
|
* @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
|
||||||
* @param {string} [options.container='fs'] tile container, with value `fs` (filesystem) or `zip` (compressed file).
|
* @param {string} [options.container='fs'] tile container, with value `fs` (filesystem) or `zip` (compressed file).
|
||||||
* @param {string} [options.layout='dz'] filesystem layout, possible values are `dz`, `iiif`, `zoomify` or `google`.
|
* @param {string} [options.layout='dz'] filesystem layout, possible values are `dz`, `iiif`, `zoomify` or `google`.
|
||||||
|
* @param {boolean} [options.centre=false] centre image in tile.
|
||||||
|
* @param {boolean} [options.center=false] alternative spelling of centre.
|
||||||
* @returns {Sharp}
|
* @returns {Sharp}
|
||||||
* @throws {Error} Invalid parameters
|
* @throws {Error} Invalid parameters
|
||||||
*/
|
*/
|
||||||
@@ -726,6 +728,11 @@ function tile (options) {
|
|||||||
} else if (is.defined(options.layout) && options.layout === 'google') {
|
} else if (is.defined(options.layout) && options.layout === 'google') {
|
||||||
this.options.tileSkipBlanks = 5;
|
this.options.tileSkipBlanks = 5;
|
||||||
}
|
}
|
||||||
|
// Center image in tile
|
||||||
|
const centre = is.bool(options.center) ? options.center : options.centre;
|
||||||
|
if (is.defined(centre)) {
|
||||||
|
this._setBooleanOption('tileCentre', centre);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Format
|
// Format
|
||||||
if (is.inArray(this.options.formatOut, ['jpeg', 'png', 'webp'])) {
|
if (is.inArray(this.options.formatOut, ['jpeg', 'png', 'webp'])) {
|
||||||
|
|||||||
@@ -386,7 +386,8 @@ function extract (options) {
|
|||||||
* Trim "boring" pixels from all edges that contain values similar to the top-left pixel.
|
* Trim "boring" pixels from all edges that contain values similar to the top-left pixel.
|
||||||
* Images consisting entirely of a single colour will calculate "boring" using the alpha channel, if any.
|
* Images consisting entirely of a single colour will calculate "boring" using the alpha channel, if any.
|
||||||
*
|
*
|
||||||
* The `info` response Object will contain `trimOffsetLeft` and `trimOffsetTop` properties.
|
* The `info` response Object, obtained from callback of `.toFile()` or `.toBuffer()`,
|
||||||
|
* will contain `trimOffsetLeft` and `trimOffsetTop` properties.
|
||||||
*
|
*
|
||||||
* @param {number} [threshold=10] the allowed difference from the top-left pixel, a number greater than zero.
|
* @param {number} [threshold=10] the allowed difference from the top-left pixel, a number greater than zero.
|
||||||
* @returns {Sharp}
|
* @returns {Sharp}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "sharp",
|
"name": "sharp",
|
||||||
"description": "High performance Node.js image processing, the fastest module to resize JPEG, PNG, WebP and TIFF images",
|
"description": "High performance Node.js image processing, the fastest module to resize JPEG, PNG, WebP and TIFF images",
|
||||||
"version": "0.26.0",
|
"version": "0.26.2",
|
||||||
"author": "Lovell Fuller <npm@lovell.info>",
|
"author": "Lovell Fuller <npm@lovell.info>",
|
||||||
"homepage": "https://github.com/lovell/sharp",
|
"homepage": "https://github.com/lovell/sharp",
|
||||||
"contributors": [
|
"contributors": [
|
||||||
@@ -114,7 +114,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"color": "^3.1.2",
|
"color": "^3.1.2",
|
||||||
"detect-libc": "^1.0.3",
|
"detect-libc": "^1.0.3",
|
||||||
"node-addon-api": "^3.0.0",
|
"node-addon-api": "^3.0.2",
|
||||||
"npmlog": "^4.1.2",
|
"npmlog": "^4.1.2",
|
||||||
"prebuild-install": "^5.3.5",
|
"prebuild-install": "^5.3.5",
|
||||||
"semver": "^7.3.2",
|
"semver": "^7.3.2",
|
||||||
|
|||||||
@@ -180,6 +180,7 @@ namespace sharp {
|
|||||||
case ImageType::OPENSLIDE: id = "openslide"; break;
|
case ImageType::OPENSLIDE: id = "openslide"; break;
|
||||||
case ImageType::PPM: id = "ppm"; break;
|
case ImageType::PPM: id = "ppm"; break;
|
||||||
case ImageType::FITS: id = "fits"; break;
|
case ImageType::FITS: id = "fits"; break;
|
||||||
|
case ImageType::EXR: id = "exr"; break;
|
||||||
case ImageType::VIPS: id = "vips"; break;
|
case ImageType::VIPS: id = "vips"; break;
|
||||||
case ImageType::RAW: id = "raw"; break;
|
case ImageType::RAW: id = "raw"; break;
|
||||||
case ImageType::UNKNOWN: id = "unknown"; break;
|
case ImageType::UNKNOWN: id = "unknown"; break;
|
||||||
@@ -210,6 +211,7 @@ namespace sharp {
|
|||||||
{ "openslideload", ImageType::OPENSLIDE },
|
{ "openslideload", ImageType::OPENSLIDE },
|
||||||
{ "ppmload", ImageType::PPM },
|
{ "ppmload", ImageType::PPM },
|
||||||
{ "fitsload", ImageType::FITS },
|
{ "fitsload", ImageType::FITS },
|
||||||
|
{ "openexrload", ImageType::EXR },
|
||||||
{ "vipsload", ImageType::VIPS },
|
{ "vipsload", ImageType::VIPS },
|
||||||
{ "rawload", ImageType::RAW }
|
{ "rawload", ImageType::RAW }
|
||||||
};
|
};
|
||||||
@@ -485,8 +487,8 @@ namespace sharp {
|
|||||||
Check the proposed format supports the current dimensions.
|
Check the proposed format supports the current dimensions.
|
||||||
*/
|
*/
|
||||||
void AssertImageTypeDimensions(VImage image, ImageType const imageType) {
|
void AssertImageTypeDimensions(VImage image, ImageType const imageType) {
|
||||||
const int height = image.get_typeof("pageHeight") == G_TYPE_INT
|
const int height = image.get_typeof(VIPS_META_PAGE_HEIGHT) == G_TYPE_INT
|
||||||
? image.get_int("pageHeight")
|
? image.get_int(VIPS_META_PAGE_HEIGHT)
|
||||||
: image.height();
|
: image.height();
|
||||||
if (imageType == ImageType::JPEG) {
|
if (imageType == ImageType::JPEG) {
|
||||||
if (image.width() > 65535 || height > 65535) {
|
if (image.width() > 65535 || height > 65535) {
|
||||||
|
|||||||
@@ -111,6 +111,7 @@ namespace sharp {
|
|||||||
OPENSLIDE,
|
OPENSLIDE,
|
||||||
PPM,
|
PPM,
|
||||||
FITS,
|
FITS,
|
||||||
|
EXR,
|
||||||
VIPS,
|
VIPS,
|
||||||
RAW,
|
RAW,
|
||||||
UNKNOWN,
|
UNKNOWN,
|
||||||
|
|||||||
@@ -782,6 +782,8 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|||||||
sharp::AssertImageTypeDimensions(image, sharp::ImageType::GIF);
|
sharp::AssertImageTypeDimensions(image, sharp::ImageType::GIF);
|
||||||
VipsArea *area = VIPS_AREA(image.magicksave_buffer(VImage::option()
|
VipsArea *area = VIPS_AREA(image.magicksave_buffer(VImage::option()
|
||||||
->set("strip", !baton->withMetadata)
|
->set("strip", !baton->withMetadata)
|
||||||
|
->set("optimize_gif_frames", TRUE)
|
||||||
|
->set("optimize_gif_transparency", TRUE)
|
||||||
->set("format", "gif")));
|
->set("format", "gif")));
|
||||||
baton->bufferOut = static_cast<char*>(area->data);
|
baton->bufferOut = static_cast<char*>(area->data);
|
||||||
baton->bufferOutLength = area->length;
|
baton->bufferOutLength = area->length;
|
||||||
@@ -925,6 +927,8 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|||||||
sharp::AssertImageTypeDimensions(image, sharp::ImageType::GIF);
|
sharp::AssertImageTypeDimensions(image, sharp::ImageType::GIF);
|
||||||
image.magicksave(const_cast<char*>(baton->fileOut.data()), VImage::option()
|
image.magicksave(const_cast<char*>(baton->fileOut.data()), VImage::option()
|
||||||
->set("strip", !baton->withMetadata)
|
->set("strip", !baton->withMetadata)
|
||||||
|
->set("optimize_gif_frames", TRUE)
|
||||||
|
->set("optimize_gif_transparency", TRUE)
|
||||||
->set("format", "gif"));
|
->set("format", "gif"));
|
||||||
baton->formatOut = "gif";
|
baton->formatOut = "gif";
|
||||||
} else if (baton->formatOut == "tiff" || (mightMatchInput && isTiff) ||
|
} else if (baton->formatOut == "tiff" || (mightMatchInput && isTiff) ||
|
||||||
@@ -1010,6 +1014,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|||||||
->set("suffix", const_cast<char*>(suffix.data()))
|
->set("suffix", const_cast<char*>(suffix.data()))
|
||||||
->set("angle", CalculateAngleRotation(baton->tileAngle))
|
->set("angle", CalculateAngleRotation(baton->tileAngle))
|
||||||
->set("background", baton->tileBackground)
|
->set("background", baton->tileBackground)
|
||||||
|
->set("centre", baton->tileCentre)
|
||||||
->set("skip_blanks", baton->tileSkipBlanks);
|
->set("skip_blanks", baton->tileSkipBlanks);
|
||||||
// libvips chooses a default depth based on layout. Instead of replicating that logic here by
|
// libvips chooses a default depth based on layout. Instead of replicating that logic here by
|
||||||
// not passing anything - libvips will handle choice
|
// not passing anything - libvips will handle choice
|
||||||
@@ -1399,6 +1404,7 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
|||||||
baton->tileDepth = static_cast<VipsForeignDzDepth>(
|
baton->tileDepth = static_cast<VipsForeignDzDepth>(
|
||||||
vips_enum_from_nick(nullptr, VIPS_TYPE_FOREIGN_DZ_DEPTH,
|
vips_enum_from_nick(nullptr, VIPS_TYPE_FOREIGN_DZ_DEPTH,
|
||||||
sharp::AttrAsStr(options, "tileDepth").data()));
|
sharp::AttrAsStr(options, "tileDepth").data()));
|
||||||
|
baton->tileCentre = sharp::AttrAsBool(options, "tileCentre");
|
||||||
|
|
||||||
// Force random access for certain operations
|
// Force random access for certain operations
|
||||||
if (baton->input->access == VIPS_ACCESS_SEQUENTIAL) {
|
if (baton->input->access == VIPS_ACCESS_SEQUENTIAL) {
|
||||||
|
|||||||
@@ -79,6 +79,7 @@ struct PipelineBaton {
|
|||||||
int cropOffsetLeft;
|
int cropOffsetLeft;
|
||||||
int cropOffsetTop;
|
int cropOffsetTop;
|
||||||
bool premultiplied;
|
bool premultiplied;
|
||||||
|
bool tileCentre;
|
||||||
std::string kernel;
|
std::string kernel;
|
||||||
bool fastShrinkOnLoad;
|
bool fastShrinkOnLoad;
|
||||||
double tintA;
|
double tintA;
|
||||||
|
|||||||
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
|
// Estimate entropy via histogram of greyscale value frequency
|
||||||
baton->entropy = std::abs(greyscale.hist_find().hist_entropy());
|
baton->entropy = std::abs(greyscale.hist_find().hist_entropy());
|
||||||
// Estimate sharpness via standard deviation of greyscale laplacian
|
// Estimate sharpness via standard deviation of greyscale laplacian
|
||||||
VImage laplacian = VImage::new_matrixv(3, 3,
|
if (image.width() > 1 || image.height() > 1) {
|
||||||
0.0, 1.0, 0.0,
|
VImage laplacian = VImage::new_matrixv(3, 3,
|
||||||
1.0, -4.0, 1.0,
|
0.0, 1.0, 0.0,
|
||||||
0.0, 1.0, 0.0);
|
1.0, -4.0, 1.0,
|
||||||
laplacian.set("scale", 9.0);
|
0.0, 1.0, 0.0);
|
||||||
baton->sharpness = greyscale.conv(laplacian).deviate();
|
laplacian.set("scale", 9.0);
|
||||||
|
baton->sharpness = greyscale.conv(laplacian).deviate();
|
||||||
|
}
|
||||||
// Most dominant sRGB colour via 4096-bin 3D histogram
|
// Most dominant sRGB colour via 4096-bin 3D histogram
|
||||||
vips::VImage hist = sharp::RemoveAlpha(image)
|
vips::VImage hist = sharp::RemoveAlpha(image)
|
||||||
.colourspace(VIPS_INTERPRETATION_sRGB)
|
.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 |
BIN
test/fixtures/expected/tile_centered.jpg
vendored
Normal file
BIN
test/fixtures/expected/tile_centered.jpg
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.0 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
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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'),
|
inputJPGBig: getPath('flowers.jpeg'),
|
||||||
|
|||||||
@@ -98,4 +98,36 @@ describe('GIF input', () => {
|
|||||||
sharp().gif({ delay: [65536] });
|
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) {
|
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 () {
|
sharp(Buffer.alloc(0)).toBuffer().then(function () {
|
||||||
assert(false);
|
assert(false);
|
||||||
done();
|
done();
|
||||||
@@ -647,7 +647,7 @@ describe('Input/output', function () {
|
|||||||
it('Invalid density: string', function () {
|
it('Invalid density: string', function () {
|
||||||
assert.throws(function () {
|
assert.throws(function () {
|
||||||
sharp({ density: 'zoinks' });
|
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 () {
|
it('Setting animated property updates pages property', function () {
|
||||||
assert.strictEqual(sharp({ animated: false }).options.input.pages, 1);
|
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) {
|
it('Stream in, Callback out', function (done) {
|
||||||
const readable = fs.createReadStream(fixtures.inputJpg);
|
const readable = fs.createReadStream(fixtures.inputJpg);
|
||||||
const pipeline = sharp().stats(function (err, stats) {
|
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) {
|
it('Convert SVG to PNG at 14.4DPI', function (done) {
|
||||||
sharp(fixtures.inputSvg, { density: 14.4 })
|
sharp(fixtures.inputSvg, { density: 14.4 })
|
||||||
.toFormat('png')
|
.toFormat('png')
|
||||||
|
|||||||
@@ -289,6 +289,14 @@ describe('Tile', function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('Invalid center parameter value fail', function () {
|
||||||
|
assert.throws(function () {
|
||||||
|
sharp().tile({
|
||||||
|
centre: 'true'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('Deep Zoom layout', function (done) {
|
it('Deep Zoom layout', function (done) {
|
||||||
const directory = fixtures.path('output.dzi_files');
|
const directory = fixtures.path('output.dzi_files');
|
||||||
rimraf(directory, function () {
|
rimraf(directory, function () {
|
||||||
@@ -765,6 +773,46 @@ describe('Tile', function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('Google layout with center image in tile', function (done) {
|
||||||
|
const directory = fixtures.path('output.google_center.dzi');
|
||||||
|
rimraf(directory, function () {
|
||||||
|
sharp(fixtures.inputJpg)
|
||||||
|
.tile({
|
||||||
|
center: true,
|
||||||
|
layout: 'google'
|
||||||
|
})
|
||||||
|
.toFile(directory, function (err, info) {
|
||||||
|
if (err) throw err;
|
||||||
|
assert.strictEqual('dz', info.format);
|
||||||
|
assert.strictEqual(2725, info.width);
|
||||||
|
assert.strictEqual(2225, info.height);
|
||||||
|
assert.strictEqual(3, info.channels);
|
||||||
|
assert.strictEqual('number', typeof info.size);
|
||||||
|
fixtures.assertSimilar(fixtures.expected('tile_centered.jpg'), fs.readFileSync(path.join(directory, '0', '0', '0.jpg')), done);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Google layout with center image in tile centre', function (done) {
|
||||||
|
const directory = fixtures.path('output.google_center.dzi');
|
||||||
|
rimraf(directory, function () {
|
||||||
|
sharp(fixtures.inputJpg)
|
||||||
|
.tile({
|
||||||
|
centre: true,
|
||||||
|
layout: 'google'
|
||||||
|
})
|
||||||
|
.toFile(directory, function (err, info) {
|
||||||
|
if (err) throw err;
|
||||||
|
assert.strictEqual('dz', info.format);
|
||||||
|
assert.strictEqual(2725, info.width);
|
||||||
|
assert.strictEqual(2225, info.height);
|
||||||
|
assert.strictEqual(3, info.channels);
|
||||||
|
assert.strictEqual('number', typeof info.size);
|
||||||
|
fixtures.assertSimilar(fixtures.expected('tile_centered.jpg'), fs.readFileSync(path.join(directory, '0', '0', '0.jpg')), done);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('IIIF layout', function (done) {
|
it('IIIF layout', function (done) {
|
||||||
const directory = fixtures.path('output.iiif.info');
|
const directory = fixtures.path('output.iiif.info');
|
||||||
rimraf(directory, function () {
|
rimraf(directory, function () {
|
||||||
|
|||||||
@@ -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';
|
'use strict';
|
||||||
|
|
||||||
|
const fs = require('fs');
|
||||||
const assert = require('assert');
|
const assert = require('assert');
|
||||||
|
|
||||||
const sharp = require('../../');
|
const sharp = require('../../');
|
||||||
@@ -184,4 +185,28 @@ describe('WebP', function () {
|
|||||||
|
|
||||||
assert.deepStrictEqual(updated.delay, expectedDelay);
|
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