mirror of
https://github.com/lovell/sharp.git
synced 2026-02-04 13:46:19 +01:00
Compare commits
58 Commits
v0.33.1-rc
...
v0.33.3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
55466f122c | ||
|
|
ede8217ab3 | ||
|
|
2689fb4e65 | ||
|
|
eaf31a59e5 | ||
|
|
aa1bbcb5c1 | ||
|
|
3c26080c39 | ||
|
|
dc07fd4e9c | ||
|
|
7bc74feb11 | ||
|
|
c5f318ed4d | ||
|
|
8fbb1cd154 | ||
|
|
88aee8a887 | ||
|
|
0f77b18078 | ||
|
|
3eeaee71c0 | ||
|
|
045d54e2e6 | ||
|
|
75fedf1b75 | ||
|
|
debdacb726 | ||
|
|
1c8ae67ed2 | ||
|
|
0eb57698ec | ||
|
|
bc95531f2d | ||
|
|
60f4048d6c | ||
|
|
fb70fbb09f | ||
|
|
fc439bedf1 | ||
|
|
26d0b7147d | ||
|
|
af6aa8a690 | ||
|
|
bd4f1abba2 | ||
|
|
d2656a3679 | ||
|
|
a3b45ceccc | ||
|
|
0dcc7d50a8 | ||
|
|
bcb22af034 | ||
|
|
d04dc62666 | ||
|
|
c30d355f97 | ||
|
|
49cb148b38 | ||
|
|
3bc31a8b20 | ||
|
|
c28523e70e | ||
|
|
278f393f74 | ||
|
|
cbf68c1395 | ||
|
|
45e8071599 | ||
|
|
b96389d975 | ||
|
|
a77ac6ae25 | ||
|
|
9bcf399b4c | ||
|
|
4aacee8055 | ||
|
|
0b18aeff62 | ||
|
|
bed1c2ac18 | ||
|
|
8cd832656b | ||
|
|
0499f59e71 | ||
|
|
1fa59bf9b3 | ||
|
|
db40ee6912 | ||
|
|
02b98b8e1b | ||
|
|
31fef216e4 | ||
|
|
77ab5d7a51 | ||
|
|
cd5cf7ce2d | ||
|
|
39cb9d9a6c | ||
|
|
4919bc5134 | ||
|
|
a4e64eb01f | ||
|
|
328b18df88 | ||
|
|
5e7bf32e5e | ||
|
|
04403f4e5f | ||
|
|
420e0822b4 |
@@ -24,7 +24,7 @@ jobs:
|
||||
linux-arm64-glibc-node-18:
|
||||
resource_class: arm.medium
|
||||
machine:
|
||||
image: ubuntu-2004:current
|
||||
image: ubuntu-2204:current
|
||||
steps:
|
||||
- checkout
|
||||
- run: |
|
||||
@@ -46,7 +46,7 @@ jobs:
|
||||
linux-arm64-glibc-node-20:
|
||||
resource_class: arm.medium
|
||||
machine:
|
||||
image: ubuntu-2004:current
|
||||
image: ubuntu-2204:current
|
||||
steps:
|
||||
- checkout
|
||||
- run: |
|
||||
@@ -69,7 +69,7 @@ jobs:
|
||||
linux-arm64-musl-node-18:
|
||||
resource_class: arm.medium
|
||||
machine:
|
||||
image: ubuntu-2004:current
|
||||
image: ubuntu-2204:current
|
||||
steps:
|
||||
- checkout
|
||||
- run: |
|
||||
@@ -87,7 +87,7 @@ jobs:
|
||||
linux-arm64-musl-node-20:
|
||||
resource_class: arm.medium
|
||||
machine:
|
||||
image: ubuntu-2004:current
|
||||
image: ubuntu-2204:current
|
||||
steps:
|
||||
- checkout
|
||||
- run: |
|
||||
|
||||
2
.github/CONTRIBUTING.md
vendored
2
.github/CONTRIBUTING.md
vendored
@@ -63,7 +63,7 @@ By way of example, the `background()` method present in v0.20.0 was deprecated i
|
||||
|
||||
## Documentation
|
||||
|
||||
The public API is documented with [JSDoc](http://usejsdoc.org/) annotated comments.
|
||||
The public API is documented with [JSDoc](https://jsdoc.app/) annotated comments.
|
||||
|
||||
These can be converted to Markdown by running:
|
||||
```sh
|
||||
|
||||
15
.github/ISSUE_TEMPLATE/installation.md
vendored
15
.github/ISSUE_TEMPLATE/installation.md
vendored
@@ -24,7 +24,8 @@ You must confirm both of these before continuing.
|
||||
|
||||
If you cannot confirm this, please upgrade to the latest version and try again before opening an issue.
|
||||
|
||||
If you are using another package which depends on a version of `sharp` that is not the latest, please open an issue against that package instead.
|
||||
If you are using another package which depends on a version of `sharp` that is not the latest,
|
||||
please open an issue against that package instead.
|
||||
|
||||
### Are you using a supported runtime?
|
||||
|
||||
@@ -43,15 +44,17 @@ and try again before opening an issue.
|
||||
<!-- Please place an [x] in the relevant box to confirm. -->
|
||||
|
||||
- [ ] I am using npm >= 9.6.5 with `--include=optional`
|
||||
- [ ] I am using yarn >= 3.2.0 and I am not using the "Plug'n'Play" linker
|
||||
- [ ] I am using yarn >= 3.2.0
|
||||
- [ ] I am using pnpm >= 7.1.0 with `--no-optional=false`
|
||||
- [ ] I am using Deno
|
||||
- [ ] I am using Bun
|
||||
|
||||
If you cannot confirm any of these,
|
||||
please upgrade to the latest version of your chosen package manager
|
||||
and ensure you are allowing the installation of optional or multi-platform dependencies
|
||||
before opening an issue.
|
||||
If you cannot confirm any of these, please upgrade to the latest version of your chosen package manager
|
||||
and ensure you are allowing the installation of optional or multi-platform dependencies before opening an issue.
|
||||
|
||||
### What is the complete error message, including the full stack trace?
|
||||
|
||||
<!-- Please provide the error message and stack trace here. -->
|
||||
|
||||
### What is the complete output of running `npm install --verbose --foreground-scripts sharp` in an empty directory?
|
||||
|
||||
|
||||
91
.github/workflows/ci.yml
vendored
91
.github/workflows/ci.yml
vendored
@@ -16,12 +16,14 @@ jobs:
|
||||
include:
|
||||
- os: ubuntu-22.04
|
||||
container: rockylinux:8
|
||||
nodejs_arch: x64
|
||||
nodejs_version: "^18.17.0"
|
||||
nodejs_version_major: 18
|
||||
platform: linux-x64
|
||||
prebuild: true
|
||||
- os: ubuntu-22.04
|
||||
container: rockylinux:8
|
||||
nodejs_arch: x64
|
||||
nodejs_version: "^20.3.0"
|
||||
nodejs_version_major: 20
|
||||
platform: linux-x64
|
||||
@@ -45,9 +47,20 @@ jobs:
|
||||
nodejs_version: "^20.3.0"
|
||||
nodejs_version_major: 20
|
||||
platform: darwin-x64
|
||||
- os: macos-14
|
||||
nodejs_arch: arm64
|
||||
nodejs_version: "^18.17.0"
|
||||
nodejs_version_major: 18
|
||||
platform: darwin-arm64
|
||||
prebuild: true
|
||||
- os: macos-14
|
||||
nodejs_arch: arm64
|
||||
nodejs_version: "^20.3.0"
|
||||
nodejs_version_major: 20
|
||||
platform: darwin-arm64
|
||||
- os: windows-2019
|
||||
nodejs_arch: x86
|
||||
nodejs_version: "^18.17.0"
|
||||
nodejs_version: "18.18.2" # pinned to avoid 18.19.0 and npm 10
|
||||
nodejs_version_major: 18
|
||||
platform: win32-ia32
|
||||
prebuild: true
|
||||
@@ -68,19 +81,9 @@ jobs:
|
||||
nodejs_version_major: 20
|
||||
platform: win32-x64
|
||||
steps:
|
||||
- name: Dependencies (Linux glibc)
|
||||
if: contains(matrix.container, 'centos')
|
||||
run: |
|
||||
yum install -y https://rpm.nodesource.com/pub_${{ matrix.nodejs_version_major }}.x/nodistro/repo/nodesource-release-nodistro-1.noarch.rpm
|
||||
yum install -y https://packages.endpointdev.com/rhel/7/os/x86_64/endpoint-repo.x86_64.rpm
|
||||
yum install -y centos-release-scl
|
||||
yum install -y devtoolset-11-gcc-c++ make git python3 nodejs fontconfig google-noto-sans-fonts
|
||||
echo "/opt/rh/devtoolset-11/root/usr/bin" >> $GITHUB_PATH
|
||||
- name: Dependencies (Rocky Linux glibc)
|
||||
if: contains(matrix.container, 'rockylinux')
|
||||
run: |
|
||||
dnf install -y https://rpm.nodesource.com/pub_${{ matrix.nodejs_version_major }}.x/nodistro/repo/nodesource-release-nodistro-1.noarch.rpm
|
||||
dnf install -y --setopt=nodesource-nodejs.module_hotfixes=1 nodejs
|
||||
dnf install -y gcc-toolset-11-gcc-c++ make git python3 fontconfig google-noto-sans-fonts
|
||||
echo "/opt/rh/gcc-toolset-11/root/usr/bin" >> $GITHUB_PATH
|
||||
- name: Dependencies (Linux musl)
|
||||
@@ -88,12 +91,12 @@ jobs:
|
||||
run: apk add build-base git python3 font-noto --update-cache
|
||||
- name: Dependencies (Python 3.11 - macOS, Windows)
|
||||
if: contains(matrix.os, 'macos') || contains(matrix.os, 'windows')
|
||||
uses: actions/setup-python@v4
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.11'
|
||||
- name: Dependencies (Node.js - macOS, Windows)
|
||||
if: contains(matrix.os, 'macos') || contains(matrix.os, 'windows')
|
||||
uses: actions/setup-node@v3
|
||||
python-version: "3.12"
|
||||
- name: Dependencies (Node.js)
|
||||
if: "!contains(matrix.platform, 'linuxmusl')"
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ matrix.nodejs_version }}
|
||||
architecture: ${{ matrix.nodejs_arch }}
|
||||
@@ -166,18 +169,25 @@ jobs:
|
||||
contents: write
|
||||
name: wasm32 - prebuild
|
||||
runs-on: ubuntu-22.04
|
||||
container: "emscripten/emsdk:3.1.48"
|
||||
container: "emscripten/emsdk:3.1.56"
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- name: Dependencies
|
||||
run: apt-get update && apt-get install -y pkg-config
|
||||
- name: Dependencies (Node.js)
|
||||
uses: actions/setup-node@v3
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "20"
|
||||
- name: Install
|
||||
run: emmake npm install --build-from-source
|
||||
- name: Verify emscripten versions match
|
||||
run: |
|
||||
EMSCRIPTEN_VERSION_LIBVIPS=$(node -p "require('@img/sharp-libvips-dev-wasm32/versions').emscripten")
|
||||
EMSCRIPTEN_VERSION_SHARP=$(emcc -dumpversion)
|
||||
echo "libvips built with emscripten $EMSCRIPTEN_VERSION_LIBVIPS"
|
||||
echo "sharp built with emscripten $EMSCRIPTEN_VERSION_SHARP"
|
||||
test "$EMSCRIPTEN_VERSION_LIBVIPS" = "$EMSCRIPTEN_VERSION_SHARP"
|
||||
- name: Test
|
||||
run: emmake npm test
|
||||
- name: Test packaging
|
||||
@@ -194,48 +204,3 @@ jobs:
|
||||
npm_config_nodedir: emscripten
|
||||
prebuild_upload: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: cd src && ln -s ../package.json && emmake npx prebuild --platform=emscripten --arch=wasm32 --strip=0
|
||||
macstadium-runner:
|
||||
permissions:
|
||||
contents: write
|
||||
name: ${{ matrix.platform }} - Node.js ${{ matrix.nodejs_version_major }} ${{ matrix.prebuild && '- prebuild' }}
|
||||
runs-on: macos-m1
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- nodejs_arch: x64
|
||||
nodejs_version: "^18.17.0"
|
||||
nodejs_version_major: 18
|
||||
platform: darwin-x64
|
||||
- nodejs_arch: arm64
|
||||
nodejs_version: "^18.17.0"
|
||||
nodejs_version_major: 18
|
||||
platform: darwin-arm64
|
||||
prebuild: true
|
||||
defaults:
|
||||
run:
|
||||
shell: /usr/bin/arch -arch arm64e /bin/bash -l {0}
|
||||
steps:
|
||||
- name: Dependencies (Node.js)
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: ${{ matrix.nodejs_version }}
|
||||
architecture: ${{ matrix.nodejs_arch }}
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- name: Install
|
||||
run: npm install --build-from-source
|
||||
- name: Test
|
||||
run: npm test
|
||||
- name: Test packaging
|
||||
run: |
|
||||
npm run package-from-local-build
|
||||
npm pkg set "optionalDependencies.@img/sharp-${{ matrix.platform }}=file:./npm/${{ matrix.platform }}"
|
||||
npm run clean
|
||||
npm install --ignore-scripts
|
||||
npm test
|
||||
- name: Prebuild
|
||||
if: matrix.prebuild && startsWith(github.ref, 'refs/tags/')
|
||||
env:
|
||||
prebuild_upload: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: cd src && ln -s ../package.json && npx prebuild
|
||||
|
||||
26
.github/workflows/npm.yml
vendored
26
.github/workflows/npm.yml
vendored
@@ -27,6 +27,10 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
runtime: node
|
||||
package-manager: yarn
|
||||
- name: linux-x64-node-yarn-pnp
|
||||
runs-on: ubuntu-22.04
|
||||
runtime: node
|
||||
package-manager: yarn-pnp
|
||||
- name: linux-x64-deno
|
||||
runs-on: ubuntu-22.04
|
||||
runtime: deno
|
||||
@@ -46,6 +50,10 @@ jobs:
|
||||
runs-on: macos-11
|
||||
runtime: node
|
||||
package-manager: yarn
|
||||
- name: darwin-x64-node-yarn-pnp
|
||||
runs-on: macos-11
|
||||
runtime: node
|
||||
package-manager: yarn-pnp
|
||||
- name: darwin-x64-deno
|
||||
runs-on: macos-11
|
||||
runtime: deno
|
||||
@@ -65,6 +73,10 @@ jobs:
|
||||
runs-on: windows-2019
|
||||
runtime: node
|
||||
package-manager: yarn
|
||||
- name: win32-x64-node-yarn-pnp
|
||||
runs-on: windows-2019
|
||||
runtime: node
|
||||
package-manager: yarn-pnp
|
||||
- name: win32-x64-deno
|
||||
runs-on: windows-2019
|
||||
runtime: deno
|
||||
@@ -72,7 +84,7 @@ jobs:
|
||||
steps:
|
||||
- name: Install Node.js
|
||||
if: ${{ matrix.runtime == 'node' }}
|
||||
uses: actions/setup-node@v3
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
- name: Install pnpm
|
||||
@@ -115,35 +127,37 @@ jobs:
|
||||
contents: |
|
||||
import { deepStrictEqual } from 'node:assert';
|
||||
import sharp from 'sharp';
|
||||
deepStrictEqual(['.jpg', '.jpeg', '.jpe'], sharp.format.jpeg.input.fileSuffix);
|
||||
deepStrictEqual(['.jpg', '.jpeg', '.jpe', '.jfif'], sharp.format.jpeg.input.fileSuffix);
|
||||
|
||||
- name: Run with Node.js + npm
|
||||
if: ${{ matrix.runtime == 'node' && matrix.package-manager == 'npm' }}
|
||||
if: ${{ matrix.package-manager == 'npm' }}
|
||||
run: |
|
||||
npm install --ignore-scripts
|
||||
node release.mjs
|
||||
|
||||
- name: Run with Node.js + pnpm
|
||||
if: ${{ matrix.runtime == 'node' && matrix.package-manager == 'pnpm' }}
|
||||
if: ${{ matrix.package-manager == 'pnpm' }}
|
||||
run: |
|
||||
pnpm install --ignore-scripts
|
||||
node release.mjs
|
||||
|
||||
- name: Run with Node.js + yarn
|
||||
if: ${{ matrix.runtime == 'node' && matrix.package-manager == 'yarn' }}
|
||||
if: ${{ matrix.package-manager == 'yarn' }}
|
||||
run: |
|
||||
corepack enable
|
||||
yarn set version stable
|
||||
yarn config set enableImmutableInstalls false
|
||||
yarn config set enableScripts false
|
||||
yarn config set nodeLinker node-modules
|
||||
yarn install
|
||||
node release.mjs
|
||||
|
||||
- name: Run with Node.js + yarn pnp
|
||||
if: ${{ matrix.runtime == 'node' && matrix.package-manager == 'yarn' }}
|
||||
if: ${{ matrix.package-manager == 'yarn-pnp' }}
|
||||
run: |
|
||||
corepack enable
|
||||
yarn set version stable
|
||||
yarn config set enableImmutableInstalls false
|
||||
yarn config set enableScripts false
|
||||
yarn config set nodeLinker pnp
|
||||
yarn install
|
||||
|
||||
@@ -8,7 +8,7 @@ smaller, web-friendly JPEG, PNG, WebP, GIF and AVIF images of varying dimensions
|
||||
|
||||
It can be used with all JavaScript runtimes
|
||||
that provide support for Node-API v9, including
|
||||
Node.js >= 18.17.0, Deno and Bun.
|
||||
Node.js (^18.17.0 or >= 20.3.0), Deno and Bun.
|
||||
|
||||
Resizing an image is typically 4x-5x faster than using the
|
||||
quickest ImageMagick and GraphicsMagick settings
|
||||
|
||||
@@ -66,7 +66,7 @@ where the overall height is the `pageHeight` multiplied by the number of `pages`
|
||||
| [options.text.dpi] | <code>number</code> | <code>72</code> | the resolution (size) at which to render the text. Does not take effect if `height` is specified. |
|
||||
| [options.text.rgba] | <code>boolean</code> | <code>false</code> | set this to true to enable RGBA output. This is useful for colour emoji rendering, or support for pango markup features like `<span foreground="red">Red!</span>`. |
|
||||
| [options.text.spacing] | <code>number</code> | <code>0</code> | text line height in points. Will use the font line height if none is specified. |
|
||||
| [options.text.wrap] | <code>string</code> | <code>"'word'"</code> | word wrapping style when width is provided, one of: 'word', 'char', 'charWord' (prefer char, fallback to word) or 'none'. |
|
||||
| [options.text.wrap] | <code>string</code> | <code>"'word'"</code> | word wrapping style when width is provided, one of: 'word', 'char', 'word-char' (prefer word, fallback to char) or 'none'. |
|
||||
|
||||
**Example**
|
||||
```js
|
||||
@@ -79,14 +79,16 @@ sharp('input.jpg')
|
||||
```
|
||||
**Example**
|
||||
```js
|
||||
// Read image data from readableStream,
|
||||
// Read image data from remote URL,
|
||||
// resize to 300 pixels wide,
|
||||
// emit an 'info' event with calculated dimensions
|
||||
// and finally write image data to writableStream
|
||||
var transformer = sharp()
|
||||
const { body } = fetch('https://...');
|
||||
const readableStream = Readable.fromWeb(body);
|
||||
const transformer = sharp()
|
||||
.resize(300)
|
||||
.on('info', function(info) {
|
||||
console.log('Image height is ' + info.height);
|
||||
.on('info', ({ height }) => {
|
||||
console.log(`Image height is ${height}`);
|
||||
});
|
||||
readableStream.pipe(transformer).pipe(writableStream);
|
||||
```
|
||||
|
||||
@@ -18,6 +18,8 @@ The use of `rotate` without an angle will remove the EXIF `Orientation` tag, if
|
||||
Only one rotation can occur per pipeline.
|
||||
Previous calls to `rotate` in the same pipeline will be ignored.
|
||||
|
||||
Multi-page images can only be rotated by 180 degrees.
|
||||
|
||||
Method order is important when rotating, resizing and/or extracting regions,
|
||||
for example `.rotate(x).extract(y)` will produce a different result to `.extract(y).rotate(x)`.
|
||||
|
||||
|
||||
@@ -367,10 +367,14 @@ const data = await sharp(input)
|
||||
|
||||
Use these PNG options for output image.
|
||||
|
||||
By default, PNG output is full colour at 8 or 16 bits per pixel.
|
||||
By default, PNG output is full colour at 8 bits per pixel.
|
||||
|
||||
Indexed PNG input at 1, 2 or 4 bits per pixel is converted to 8 bits per pixel.
|
||||
Set `palette` to `true` for slower, indexed PNG output.
|
||||
|
||||
For 16 bits per pixel output, convert to `rgb16` via
|
||||
[toColourspace](/api-colour#tocolourspace).
|
||||
|
||||
|
||||
**Throws**:
|
||||
|
||||
@@ -405,6 +409,14 @@ const data = await sharp(input)
|
||||
.png({ palette: true })
|
||||
.toBuffer();
|
||||
```
|
||||
**Example**
|
||||
```js
|
||||
// Output 16 bits per pixel RGB(A)
|
||||
const data = await sharp(input)
|
||||
.toColourspace('rgb16')
|
||||
.png()
|
||||
.toBuffer();
|
||||
```
|
||||
|
||||
|
||||
## webp
|
||||
@@ -605,6 +617,7 @@ sharp('input.svg')
|
||||
Use these AVIF options for output image.
|
||||
|
||||
AVIF image sequences are not supported.
|
||||
Prebuilt binaries support a bitdepth of 8 only.
|
||||
|
||||
|
||||
**Throws**:
|
||||
@@ -620,6 +633,7 @@ AVIF image sequences are not supported.
|
||||
| [options.lossless] | <code>boolean</code> | <code>false</code> | use lossless compression |
|
||||
| [options.effort] | <code>number</code> | <code>4</code> | CPU effort, between 0 (fastest) and 9 (slowest) |
|
||||
| [options.chromaSubsampling] | <code>string</code> | <code>"'4:4:4'"</code> | set to '4:2:0' to use chroma subsampling |
|
||||
| [options.bitdepth] | <code>number</code> | <code>8</code> | set bitdepth to 8, 10 or 12 bit |
|
||||
|
||||
**Example**
|
||||
```js
|
||||
@@ -658,6 +672,7 @@ globally-installed libvips compiled with support for libheif, libde265 and x265.
|
||||
| [options.lossless] | <code>boolean</code> | <code>false</code> | use lossless compression |
|
||||
| [options.effort] | <code>number</code> | <code>4</code> | CPU effort, between 0 (fastest) and 9 (slowest) |
|
||||
| [options.chromaSubsampling] | <code>string</code> | <code>"'4:4:4'"</code> | set to '4:2:0' to use chroma subsampling |
|
||||
| [options.bitdepth] | <code>number</code> | <code>8</code> | set bitdepth to 8, 10 or 12 bit |
|
||||
|
||||
**Example**
|
||||
```js
|
||||
@@ -763,7 +778,7 @@ The prebuilt binaries do not include this - see
|
||||
| [options.angle] | <code>number</code> | <code>0</code> | tile angle of rotation, must be a multiple of 90. |
|
||||
| [options.background] | <code>string</code> \| <code>Object</code> | <code>"{r: 255, g: 255, b: 255, alpha: 1}"</code> | background colour, parsed by the [color](https://www.npmjs.org/package/color) module, defaults to white without transparency. |
|
||||
| [options.depth] | <code>string</code> | | how deep to make the pyramid, possible values are `onepixel`, `onetile` or `one`, default based on layout. |
|
||||
| [options.skipBlanks] | <code>number</code> | <code>-1</code> | threshold to skip tile generation, a value 0 - 255 for 8-bit images or 0 - 65535 for 16-bit images |
|
||||
| [options.skipBlanks] | <code>number</code> | <code>-1</code> | Threshold to skip tile generation. Range is 0-255 for 8-bit images, 0-65535 for 16-bit images. Default is 5 for `google` layout, -1 (no skip) otherwise. |
|
||||
| [options.container] | <code>string</code> | <code>"'fs'"</code> | tile container, with value `fs` (filesystem) or `zip` (compressed file). |
|
||||
| [options.layout] | <code>string</code> | <code>"'dz'"</code> | filesystem layout, possible values are `dz`, `iiif`, `iiif3`, `zoomify` or `google`. |
|
||||
| [options.centre] | <code>boolean</code> | <code>false</code> | centre image in tile. |
|
||||
|
||||
@@ -2,9 +2,42 @@
|
||||
|
||||
## v0.33 - *gauge*
|
||||
|
||||
Requires libvips v8.15.0
|
||||
Requires libvips v8.15.2
|
||||
|
||||
### v0.33.1 - TBD
|
||||
### v0.33.3 - 23rd March 2024
|
||||
|
||||
* Upgrade to libvips v8.15.2 for upstream bug fixes.
|
||||
|
||||
* Ensure `keepIccProfile` retains P3 and CMYK input profiles.
|
||||
[#3906](https://github.com/lovell/sharp/issues/3906)
|
||||
[#4008](https://github.com/lovell/sharp/issues/4008)
|
||||
|
||||
* Ensure `text.wrap` property can accept `word-char` as value.
|
||||
[#4028](https://github.com/lovell/sharp/pull/4028)
|
||||
[@yolopunk](https://github.com/yolopunk)
|
||||
|
||||
* Ensure `clone` takes a deep copy of existing options.
|
||||
[#4029](https://github.com/lovell/sharp/issues/4029)
|
||||
|
||||
* Add `bitdepth` option to `heif` output (prebuilt binaries support 8-bit only).
|
||||
[#4036](https://github.com/lovell/sharp/pull/4036)
|
||||
[@mertalev](https://github.com/mertalev)
|
||||
|
||||
### v0.33.2 - 12th January 2024
|
||||
|
||||
* Upgrade to libvips v8.15.1 for upstream bug fixes.
|
||||
|
||||
* TypeScript: add definition for `keepMetadata`.
|
||||
[#3914](https://github.com/lovell/sharp/pull/3914)
|
||||
[@abhi0498](https://github.com/abhi0498)
|
||||
|
||||
* Ensure `extend` operation stays sequential when copying (regression in 0.32.0).
|
||||
[#3928](https://github.com/lovell/sharp/issues/3928)
|
||||
|
||||
* Improve error handling for unsupported multi-page rotation.
|
||||
[#3940](https://github.com/lovell/sharp/issues/3940)
|
||||
|
||||
### v0.33.1 - 17th December 2023
|
||||
|
||||
* Add support for Yarn Plug'n'Play filesystem layout.
|
||||
[#3888](https://github.com/lovell/sharp/issues/3888)
|
||||
@@ -18,7 +51,7 @@ Requires libvips v8.15.0
|
||||
|
||||
### v0.33.0 - 29th November 2023
|
||||
|
||||
* Drop support for Node.js 14 and 16, now requires Node.js >= 18.17.0
|
||||
* Drop support for Node.js 14 and 16, now requires Node.js ^18.17.0 or >= 20.3.0
|
||||
|
||||
* Prebuilt binaries distributed via npm registry and installed via package manager.
|
||||
|
||||
|
||||
@@ -284,3 +284,9 @@ GitHub: https://github.com/RReverser
|
||||
|
||||
Name: Tamás András Horváth
|
||||
GitHub: https://github.com/icetee
|
||||
|
||||
Name: Aaron Che
|
||||
GitHub: https://github.com/yolopunk
|
||||
|
||||
Name: Mert Alev
|
||||
GitHub: https://github.com/mertalev
|
||||
|
||||
@@ -35,7 +35,7 @@ deno run --allow-ffi ...
|
||||
|
||||
## Prerequisites
|
||||
|
||||
* Node-API v9 compatible runtime e.g. Node.js >= 18.17.0
|
||||
* Node-API v9 compatible runtime e.g. Node.js ^18.17.0 or >=20.3.0.
|
||||
|
||||
## Prebuilt binaries
|
||||
|
||||
@@ -61,7 +61,7 @@ for the current OS platform and CPU architecture, where available.
|
||||
Some package managers support multiple platforms and architectures
|
||||
within the same installation tree and/or using the same lockfile.
|
||||
|
||||
### npm
|
||||
### npm v10+
|
||||
|
||||
> ⚠️ **npm `package-lock.json` files can cause installation problems due to [npm bug #4828](https://github.com/npm/cli/issues/4828)**
|
||||
|
||||
@@ -79,11 +79,11 @@ npm install --cpu=x64 --os=linux sharp
|
||||
npm install --cpu=x64 --os=linux --libc=musl sharp
|
||||
```
|
||||
|
||||
### yarn
|
||||
### yarn v3+
|
||||
|
||||
Use the [supportedArchitectures](https://yarnpkg.com/configuration/yarnrc#supportedArchitectures) configuration.
|
||||
|
||||
### pnpm
|
||||
### pnpm v8+
|
||||
|
||||
Use the [supportedArchitectures](https://pnpm.io/package_json#pnpmsupportedarchitectures) configuration.
|
||||
|
||||
@@ -109,8 +109,8 @@ This module will be compiled from source at `npm install` time when:
|
||||
Building from source requires:
|
||||
|
||||
* C++11 compiler
|
||||
* [node-addon-api](https://www.npmjs.com/package/node-addon-api)
|
||||
* [node-gyp](https://github.com/nodejs/node-gyp#installation) and its dependencies
|
||||
* [node-addon-api](https://www.npmjs.com/package/node-addon-api) version 7+
|
||||
* [node-gyp](https://github.com/nodejs/node-gyp#installation) version 9+ and its dependencies
|
||||
|
||||
There is an install-time check for these dependencies.
|
||||
If `node-addon-api` or `node-gyp` cannot be found, try adding them via:
|
||||
@@ -173,25 +173,11 @@ must include binaries for either the linux-x64 or linux-arm64 platforms
|
||||
depending on the chosen architecture.
|
||||
|
||||
When building your deployment package on a machine that differs from the target architecture,
|
||||
you will need to install either `@img/sharp-linux-x64` or `@img/sharp-linux-arm64` package.
|
||||
see the [cross-platform](#cross-platform) section to help decide which package manager is appropriate
|
||||
and how to configure it.
|
||||
|
||||
```sh
|
||||
npm install --os=linux --cpu=x64 sharp
|
||||
```
|
||||
|
||||
```sh
|
||||
npm install --os=linux --cpu=arm64 sharp
|
||||
```
|
||||
|
||||
When using npm 9 or earlier, this can be achieved using the following:
|
||||
|
||||
```sh
|
||||
npm install --force @img/sharp-linux-x64
|
||||
```
|
||||
|
||||
```sh
|
||||
npm install --force @img/sharp-linux-arm64
|
||||
```
|
||||
Some package managers use symbolic links
|
||||
but AWS Lambda does not support these within deployment packages.
|
||||
|
||||
To get the best performance select the largest memory available.
|
||||
A 1536 MB function provides ~12x more CPU time than a 128 MB function.
|
||||
@@ -245,6 +231,44 @@ custom:
|
||||
- npm install --os=linux --cpu=x64 sharp
|
||||
```
|
||||
|
||||
### electron
|
||||
|
||||
Ensure `sharp` is unpacked from the ASAR archive file using the
|
||||
[asarUnpack](https://www.electron.build/configuration/configuration.html)
|
||||
option.
|
||||
|
||||
```json
|
||||
{
|
||||
"build": {
|
||||
"asar": true,
|
||||
"asarUnpack": [
|
||||
"**/node_modules/sharp/**/*",
|
||||
"**/node_modules/@img/**/*"
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### vite
|
||||
|
||||
Ensure `sharp` is excluded from bundling via the
|
||||
[build.rollupOptions](https://vitejs.dev/config/build-options.html)
|
||||
configuration.
|
||||
|
||||
```js
|
||||
import { defineConfig } from 'vite';
|
||||
|
||||
export default defineConfig({
|
||||
build: {
|
||||
rollupOptions: {
|
||||
external: [
|
||||
"sharp"
|
||||
]
|
||||
}
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
## TypeScript
|
||||
|
||||
TypeScript definitions are published as part of
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -90,7 +90,7 @@ function pipelineColourspace (colourspace) {
|
||||
if (!is.string(colourspace)) {
|
||||
throw is.invalidParameterError('colourspace', 'string', colourspace);
|
||||
}
|
||||
this.options.colourspaceInput = colourspace;
|
||||
this.options.colourspacePipeline = colourspace;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@@ -40,14 +40,16 @@ const debuglog = util.debuglog('sharp');
|
||||
* });
|
||||
*
|
||||
* @example
|
||||
* // Read image data from readableStream,
|
||||
* // Read image data from remote URL,
|
||||
* // resize to 300 pixels wide,
|
||||
* // emit an 'info' event with calculated dimensions
|
||||
* // and finally write image data to writableStream
|
||||
* var transformer = sharp()
|
||||
* const { body } = fetch('https://...');
|
||||
* const readableStream = Readable.fromWeb(body);
|
||||
* const transformer = sharp()
|
||||
* .resize(300)
|
||||
* .on('info', function(info) {
|
||||
* console.log('Image height is ' + info.height);
|
||||
* .on('info', ({ height }) => {
|
||||
* console.log(`Image height is ${height}`);
|
||||
* });
|
||||
* readableStream.pipe(transformer).pipe(writableStream);
|
||||
*
|
||||
@@ -164,7 +166,7 @@ const debuglog = util.debuglog('sharp');
|
||||
* @param {number} [options.text.dpi=72] - the resolution (size) at which to render the text. Does not take effect if `height` is specified.
|
||||
* @param {boolean} [options.text.rgba=false] - set this to true to enable RGBA output. This is useful for colour emoji rendering, or support for pango markup features like `<span foreground="red">Red!</span>`.
|
||||
* @param {number} [options.text.spacing=0] - text line height in points. Will use the font line height if none is specified.
|
||||
* @param {string} [options.text.wrap='word'] - word wrapping style when width is provided, one of: 'word', 'char', 'charWord' (prefer char, fallback to word) or 'none'.
|
||||
* @param {string} [options.text.wrap='word'] - word wrapping style when width is provided, one of: 'word', 'char', 'word-char' (prefer word, fallback to char) or 'none'.
|
||||
* @returns {Sharp}
|
||||
* @throws {Error} Invalid parameters
|
||||
*/
|
||||
@@ -255,7 +257,7 @@ const Sharp = function (input, options) {
|
||||
removeAlpha: false,
|
||||
ensureAlpha: -1,
|
||||
colourspace: 'srgb',
|
||||
colourspaceInput: 'last',
|
||||
colourspacePipeline: 'last',
|
||||
composite: [],
|
||||
// output
|
||||
fileOut: '',
|
||||
@@ -323,6 +325,7 @@ const Sharp = function (input, options) {
|
||||
heifCompression: 'av1',
|
||||
heifEffort: 4,
|
||||
heifChromaSubsampling: '4:4:4',
|
||||
heifBitdepth: 8,
|
||||
jxlDistance: 1,
|
||||
jxlDecodingTier: 0,
|
||||
jxlEffort: 7,
|
||||
@@ -423,13 +426,16 @@ Object.setPrototypeOf(Sharp, stream.Duplex);
|
||||
function clone () {
|
||||
// Clone existing options
|
||||
const clone = this.constructor.call();
|
||||
clone.options = Object.assign({}, this.options);
|
||||
const { debuglog, queueListener, ...options } = this.options;
|
||||
clone.options = structuredClone(options);
|
||||
clone.options.debuglog = debuglog;
|
||||
clone.options.queueListener = queueListener;
|
||||
// Pass 'finish' event to clone for Stream-based input
|
||||
if (this._isStreamInput()) {
|
||||
this.on('finish', () => {
|
||||
// Clone inherits input data
|
||||
this._flattenBufferIn();
|
||||
clone.options.bufferIn = this.options.bufferIn;
|
||||
clone.options.input.buffer = this.options.input.buffer;
|
||||
clone.emit('finish');
|
||||
});
|
||||
}
|
||||
|
||||
14
lib/index.d.ts
vendored
14
lib/index.d.ts
vendored
@@ -341,6 +341,12 @@ declare namespace sharp {
|
||||
*/
|
||||
metadata(): Promise<Metadata>;
|
||||
|
||||
/**
|
||||
* Keep all metadata (EXIF, ICC, XMP, IPTC) from the input image in the output image.
|
||||
* @returns A sharp instance that can be used to chain operations
|
||||
*/
|
||||
keepMetadata(): Sharp;
|
||||
|
||||
/**
|
||||
* Access to pixel-derived image statistics for every channel in the image.
|
||||
* @returns A sharp instance that can be used to chain operations
|
||||
@@ -1011,7 +1017,7 @@ declare namespace sharp {
|
||||
rgba?: boolean;
|
||||
/** Text line height in points. Will use the font line height if none is specified. (optional, default `0`) */
|
||||
spacing?: number;
|
||||
/** Word wrapping style when width is provided, one of: 'word', 'char', 'charWord' (prefer char, fallback to word) or 'none' */
|
||||
/** Word wrapping style when width is provided, one of: 'word', 'char', 'word-char' (prefer word, fallback to char) or 'none' */
|
||||
wrap?: TextWrap;
|
||||
}
|
||||
|
||||
@@ -1238,6 +1244,8 @@ declare namespace sharp {
|
||||
effort?: number | undefined;
|
||||
/** set to '4:2:0' to use chroma subsampling, requires libvips v8.11.0 (optional, default '4:4:4') */
|
||||
chromaSubsampling?: string | undefined;
|
||||
/** Set bitdepth to 8, 10 or 12 bit (optional, default 8) */
|
||||
bitdepth?: 8 | 10 | 12 | undefined;
|
||||
}
|
||||
|
||||
interface HeifOptions extends OutputOptions {
|
||||
@@ -1251,6 +1259,8 @@ declare namespace sharp {
|
||||
effort?: number | undefined;
|
||||
/** set to '4:2:0' to use chroma subsampling (optional, default '4:4:4') */
|
||||
chromaSubsampling?: string | undefined;
|
||||
/** Set bitdepth to 8, 10 or 12 bit (optional, default 8) */
|
||||
bitdepth?: 8 | 10 | 12 | undefined;
|
||||
}
|
||||
|
||||
interface GifOptions extends OutputOptions, AnimationOptions {
|
||||
@@ -1607,7 +1617,7 @@ declare namespace sharp {
|
||||
|
||||
type TextAlign = 'left' | 'centre' | 'center' | 'right';
|
||||
|
||||
type TextWrap = 'word' | 'char' | 'charWord' | 'none';
|
||||
type TextWrap = 'word' | 'char' | 'word-char' | 'none';
|
||||
|
||||
type TileContainer = 'fs' | 'zip';
|
||||
|
||||
|
||||
@@ -345,10 +345,10 @@ function _createInputDescriptor (input, inputOptions, containerOptions) {
|
||||
}
|
||||
}
|
||||
if (is.defined(inputOptions.text.wrap)) {
|
||||
if (is.string(inputOptions.text.wrap) && is.inArray(inputOptions.text.wrap, ['word', 'char', 'wordChar', 'none'])) {
|
||||
if (is.string(inputOptions.text.wrap) && is.inArray(inputOptions.text.wrap, ['word', 'char', 'word-char', 'none'])) {
|
||||
inputDescriptor.textWrap = inputOptions.text.wrap;
|
||||
} else {
|
||||
throw is.invalidParameterError('text.wrap', 'one of: word, char, wordChar, none', inputOptions.text.wrap);
|
||||
throw is.invalidParameterError('text.wrap', 'one of: word, char, word-char, none', inputOptions.text.wrap);
|
||||
}
|
||||
}
|
||||
delete inputDescriptor.buffer;
|
||||
|
||||
@@ -7,6 +7,7 @@ const { spawnSync } = require('node:child_process');
|
||||
const { createHash } = require('node:crypto');
|
||||
const semverCoerce = require('semver/functions/coerce');
|
||||
const semverGreaterThanOrEqualTo = require('semver/functions/gte');
|
||||
const semverSatisfies = require('semver/functions/satisfies');
|
||||
const detectLibc = require('detect-libc');
|
||||
|
||||
const { engines, optionalDependencies } = require('../package.json');
|
||||
@@ -83,6 +84,15 @@ const buildSharpLibvipsLibDir = () => {
|
||||
return '';
|
||||
};
|
||||
|
||||
const isUnsupportedNodeRuntime = () => {
|
||||
/* istanbul ignore next */
|
||||
if (process.release?.name === 'node' && process.versions) {
|
||||
if (!semverSatisfies(process.versions.node, engines.node)) {
|
||||
return { found: process.versions.node, expected: engines.node };
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/* istanbul ignore next */
|
||||
const isEmscripten = () => {
|
||||
const { CC } = process.env;
|
||||
@@ -174,6 +184,7 @@ module.exports = {
|
||||
buildSharpLibvipsIncludeDir,
|
||||
buildSharpLibvipsCPlusPlusDir,
|
||||
buildSharpLibvipsLibDir,
|
||||
isUnsupportedNodeRuntime,
|
||||
runtimePlatformArch,
|
||||
log,
|
||||
yarnLocator,
|
||||
|
||||
@@ -24,6 +24,8 @@ const is = require('./is');
|
||||
* Only one rotation can occur per pipeline.
|
||||
* Previous calls to `rotate` in the same pipeline will be ignored.
|
||||
*
|
||||
* Multi-page images can only be rotated by 180 degrees.
|
||||
*
|
||||
* Method order is important when rotating, resizing and/or extracting regions,
|
||||
* for example `.rotate(x).extract(y)` will produce a different result to `.extract(y).rotate(x)`.
|
||||
*
|
||||
|
||||
@@ -504,10 +504,14 @@ function jpeg (options) {
|
||||
/**
|
||||
* Use these PNG options for output image.
|
||||
*
|
||||
* By default, PNG output is full colour at 8 or 16 bits per pixel.
|
||||
* By default, PNG output is full colour at 8 bits per pixel.
|
||||
*
|
||||
* Indexed PNG input at 1, 2 or 4 bits per pixel is converted to 8 bits per pixel.
|
||||
* Set `palette` to `true` for slower, indexed PNG output.
|
||||
*
|
||||
* For 16 bits per pixel output, convert to `rgb16` via
|
||||
* {@link /api-colour#tocolourspace|toColourspace}.
|
||||
*
|
||||
* @example
|
||||
* // Convert any input to full colour PNG output
|
||||
* const data = await sharp(input)
|
||||
@@ -520,6 +524,13 @@ function jpeg (options) {
|
||||
* .png({ palette: true })
|
||||
* .toBuffer();
|
||||
*
|
||||
* @example
|
||||
* // Output 16 bits per pixel RGB(A)
|
||||
* const data = await sharp(input)
|
||||
* .toColourspace('rgb16')
|
||||
* .png()
|
||||
* .toBuffer();
|
||||
*
|
||||
* @param {Object} [options]
|
||||
* @param {boolean} [options.progressive=false] - use progressive (interlace) scan
|
||||
* @param {number} [options.compressionLevel=6] - zlib compression level, 0 (fastest, largest) to 9 (slowest, smallest)
|
||||
@@ -1000,6 +1011,7 @@ function tiff (options) {
|
||||
* Use these AVIF options for output image.
|
||||
*
|
||||
* AVIF image sequences are not supported.
|
||||
* Prebuilt binaries support a bitdepth of 8 only.
|
||||
*
|
||||
* @example
|
||||
* const data = await sharp(input)
|
||||
@@ -1018,6 +1030,7 @@ function tiff (options) {
|
||||
* @param {boolean} [options.lossless=false] - use lossless compression
|
||||
* @param {number} [options.effort=4] - CPU effort, between 0 (fastest) and 9 (slowest)
|
||||
* @param {string} [options.chromaSubsampling='4:4:4'] - set to '4:2:0' to use chroma subsampling
|
||||
* @param {number} [options.bitdepth=8] - set bitdepth to 8, 10 or 12 bit
|
||||
* @returns {Sharp}
|
||||
* @throws {Error} Invalid options
|
||||
*/
|
||||
@@ -1044,6 +1057,7 @@ function avif (options) {
|
||||
* @param {boolean} [options.lossless=false] - use lossless compression
|
||||
* @param {number} [options.effort=4] - CPU effort, between 0 (fastest) and 9 (slowest)
|
||||
* @param {string} [options.chromaSubsampling='4:4:4'] - set to '4:2:0' to use chroma subsampling
|
||||
* @param {number} [options.bitdepth=8] - set bitdepth to 8, 10 or 12 bit
|
||||
* @returns {Sharp}
|
||||
* @throws {Error} Invalid options
|
||||
*/
|
||||
@@ -1082,6 +1096,16 @@ function heif (options) {
|
||||
throw is.invalidParameterError('chromaSubsampling', 'one of: 4:2:0, 4:4:4', options.chromaSubsampling);
|
||||
}
|
||||
}
|
||||
if (is.defined(options.bitdepth)) {
|
||||
if (is.integer(options.bitdepth) && is.inArray(options.bitdepth, [8, 10, 12])) {
|
||||
if (options.bitdepth !== 8 && this.constructor.versions.heif) {
|
||||
throw is.invalidParameterError('bitdepth when using prebuilt binaries', 8, options.bitdepth);
|
||||
}
|
||||
this.options.heifBitdepth = options.bitdepth;
|
||||
} else {
|
||||
throw is.invalidParameterError('bitdepth', '8, 10 or 12', options.bitdepth);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw is.invalidParameterError('options', 'Object', options);
|
||||
}
|
||||
@@ -1233,7 +1257,7 @@ function raw (options) {
|
||||
* @param {number} [options.angle=0] tile angle of rotation, must be a multiple of 90.
|
||||
* @param {string|Object} [options.background={r: 255, g: 255, b: 255, alpha: 1}] - background colour, parsed by the [color](https://www.npmjs.org/package/color) module, defaults to white without transparency.
|
||||
* @param {string} [options.depth] how deep to make the pyramid, possible values are `onepixel`, `onetile` or `one`, default based on layout.
|
||||
* @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. Range is 0-255 for 8-bit images, 0-65535 for 16-bit images. Default is 5 for `google` layout, -1 (no skip) otherwise.
|
||||
* @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`, `iiif3`, `zoomify` or `google`.
|
||||
* @param {boolean} [options.centre=false] centre image in tile.
|
||||
|
||||
17
lib/sharp.js
17
lib/sharp.js
@@ -7,7 +7,7 @@
|
||||
|
||||
const { familySync, versionSync } = require('detect-libc');
|
||||
|
||||
const { runtimePlatformArch, prebuiltPlatforms, minimumLibvipsVersion } = require('./libvips');
|
||||
const { runtimePlatformArch, isUnsupportedNodeRuntime, prebuiltPlatforms, minimumLibvipsVersion } = require('./libvips');
|
||||
const runtimePlatform = runtimePlatformArch();
|
||||
|
||||
const paths = [
|
||||
@@ -44,8 +44,16 @@ if (sharp) {
|
||||
const messages = errors.map(err => err.message).join(' ');
|
||||
help.push('Possible solutions:');
|
||||
// Common error messages
|
||||
if (prebuiltPlatforms.includes(runtimePlatform)) {
|
||||
if (isUnsupportedNodeRuntime()) {
|
||||
const { found, expected } = isUnsupportedNodeRuntime();
|
||||
help.push(
|
||||
'- Please upgrade Node.js:',
|
||||
` Found ${found}`,
|
||||
` Requires ${expected}`
|
||||
);
|
||||
} else if (prebuiltPlatforms.includes(runtimePlatform)) {
|
||||
const [os, cpu] = runtimePlatform.split('-');
|
||||
const libc = os.endsWith('musl') ? ' --libc=musl' : '';
|
||||
help.push(
|
||||
'- Ensure optional dependencies can be installed:',
|
||||
' npm install --include=optional sharp',
|
||||
@@ -53,15 +61,14 @@ if (sharp) {
|
||||
'- Ensure your package manager supports multi-platform installation:',
|
||||
' See https://sharp.pixelplumbing.com/install#cross-platform',
|
||||
'- Add platform-specific dependencies:',
|
||||
` npm install --os=${os} --cpu=${cpu} sharp`,
|
||||
` npm install --force @img/sharp-${runtimePlatform}`
|
||||
` npm install --os=${os.replace('musl', '')}${libc} --cpu=${cpu} sharp`
|
||||
);
|
||||
} else {
|
||||
help.push(
|
||||
`- Manually install libvips >= ${minimumLibvipsVersion}`,
|
||||
'- Add experimental WebAssembly-based dependencies:',
|
||||
' npm install --cpu=wasm32 sharp',
|
||||
' npm install --force @img/sharp-wasm32'
|
||||
' npm install @img/sharp-wasm32'
|
||||
);
|
||||
}
|
||||
if (isLinux && /(symbol not found|CXXABI_)/i.test(messages)) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@img/sharp-darwin-arm64",
|
||||
"version": "0.33.1-rc.1",
|
||||
"version": "0.33.3",
|
||||
"description": "Prebuilt sharp for use with macOS 64-bit ARM",
|
||||
"author": "Lovell Fuller <npm@lovell.info>",
|
||||
"homepage": "https://sharp.pixelplumbing.com",
|
||||
@@ -15,7 +15,7 @@
|
||||
},
|
||||
"preferUnplugged": true,
|
||||
"optionalDependencies": {
|
||||
"@img/sharp-libvips-darwin-arm64": "1.0.0"
|
||||
"@img/sharp-libvips-darwin-arm64": "1.0.2"
|
||||
},
|
||||
"files": [
|
||||
"lib"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@img/sharp-darwin-x64",
|
||||
"version": "0.33.1-rc.1",
|
||||
"version": "0.33.3",
|
||||
"description": "Prebuilt sharp for use with macOS x64",
|
||||
"author": "Lovell Fuller <npm@lovell.info>",
|
||||
"homepage": "https://sharp.pixelplumbing.com",
|
||||
@@ -15,7 +15,7 @@
|
||||
},
|
||||
"preferUnplugged": true,
|
||||
"optionalDependencies": {
|
||||
"@img/sharp-libvips-darwin-x64": "1.0.0"
|
||||
"@img/sharp-libvips-darwin-x64": "1.0.2"
|
||||
},
|
||||
"files": [
|
||||
"lib"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@img/sharp-linux-arm",
|
||||
"version": "0.33.1-rc.1",
|
||||
"version": "0.33.3",
|
||||
"description": "Prebuilt sharp for use with Linux (glibc) ARM (32-bit)",
|
||||
"author": "Lovell Fuller <npm@lovell.info>",
|
||||
"homepage": "https://sharp.pixelplumbing.com",
|
||||
@@ -15,7 +15,7 @@
|
||||
},
|
||||
"preferUnplugged": true,
|
||||
"optionalDependencies": {
|
||||
"@img/sharp-libvips-linux-arm": "1.0.0"
|
||||
"@img/sharp-libvips-linux-arm": "1.0.2"
|
||||
},
|
||||
"files": [
|
||||
"lib"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@img/sharp-linux-arm64",
|
||||
"version": "0.33.1-rc.1",
|
||||
"version": "0.33.3",
|
||||
"description": "Prebuilt sharp for use with Linux (glibc) 64-bit ARM",
|
||||
"author": "Lovell Fuller <npm@lovell.info>",
|
||||
"homepage": "https://sharp.pixelplumbing.com",
|
||||
@@ -15,7 +15,7 @@
|
||||
},
|
||||
"preferUnplugged": true,
|
||||
"optionalDependencies": {
|
||||
"@img/sharp-libvips-linux-arm64": "1.0.0"
|
||||
"@img/sharp-libvips-linux-arm64": "1.0.2"
|
||||
},
|
||||
"files": [
|
||||
"lib"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@img/sharp-linux-s390x",
|
||||
"version": "0.33.1-rc.1",
|
||||
"version": "0.33.3",
|
||||
"description": "Prebuilt sharp for use with Linux (glibc) s390x",
|
||||
"author": "Lovell Fuller <npm@lovell.info>",
|
||||
"homepage": "https://sharp.pixelplumbing.com",
|
||||
@@ -15,7 +15,7 @@
|
||||
},
|
||||
"preferUnplugged": true,
|
||||
"optionalDependencies": {
|
||||
"@img/sharp-libvips-linux-s390x": "1.0.0"
|
||||
"@img/sharp-libvips-linux-s390x": "1.0.2"
|
||||
},
|
||||
"files": [
|
||||
"lib"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@img/sharp-linux-x64",
|
||||
"version": "0.33.1-rc.1",
|
||||
"version": "0.33.3",
|
||||
"description": "Prebuilt sharp for use with Linux (glibc) x64",
|
||||
"author": "Lovell Fuller <npm@lovell.info>",
|
||||
"homepage": "https://sharp.pixelplumbing.com",
|
||||
@@ -15,7 +15,7 @@
|
||||
},
|
||||
"preferUnplugged": true,
|
||||
"optionalDependencies": {
|
||||
"@img/sharp-libvips-linux-x64": "1.0.0"
|
||||
"@img/sharp-libvips-linux-x64": "1.0.2"
|
||||
},
|
||||
"files": [
|
||||
"lib"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@img/sharp-linuxmusl-arm64",
|
||||
"version": "0.33.1-rc.1",
|
||||
"version": "0.33.3",
|
||||
"description": "Prebuilt sharp for use with Linux (musl) 64-bit ARM",
|
||||
"author": "Lovell Fuller <npm@lovell.info>",
|
||||
"homepage": "https://sharp.pixelplumbing.com",
|
||||
@@ -15,7 +15,7 @@
|
||||
},
|
||||
"preferUnplugged": true,
|
||||
"optionalDependencies": {
|
||||
"@img/sharp-libvips-linuxmusl-arm64": "1.0.0"
|
||||
"@img/sharp-libvips-linuxmusl-arm64": "1.0.2"
|
||||
},
|
||||
"files": [
|
||||
"lib"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@img/sharp-linuxmusl-x64",
|
||||
"version": "0.33.1-rc.1",
|
||||
"version": "0.33.3",
|
||||
"description": "Prebuilt sharp for use with Linux (musl) x64",
|
||||
"author": "Lovell Fuller <npm@lovell.info>",
|
||||
"homepage": "https://sharp.pixelplumbing.com",
|
||||
@@ -15,7 +15,7 @@
|
||||
},
|
||||
"preferUnplugged": true,
|
||||
"optionalDependencies": {
|
||||
"@img/sharp-libvips-linuxmusl-x64": "1.0.0"
|
||||
"@img/sharp-libvips-linuxmusl-x64": "1.0.2"
|
||||
},
|
||||
"files": [
|
||||
"lib"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@img/sharp",
|
||||
"version": "0.33.1-rc.1",
|
||||
"version": "0.33.3",
|
||||
"private": "true",
|
||||
"workspaces": [
|
||||
"darwin-arm64",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@img/sharp-wasm32",
|
||||
"version": "0.33.1-rc.1",
|
||||
"version": "0.33.3",
|
||||
"description": "Prebuilt sharp for use with wasm32",
|
||||
"author": "Lovell Fuller <npm@lovell.info>",
|
||||
"homepage": "https://sharp.pixelplumbing.com",
|
||||
@@ -34,7 +34,7 @@
|
||||
"pnpm": ">=7.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@emnapi/runtime": "^0.44.0"
|
||||
"@emnapi/runtime": "^1.1.0"
|
||||
},
|
||||
"cpu": [
|
||||
"wasm32"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@img/sharp-win32-ia32",
|
||||
"version": "0.33.1-rc.1",
|
||||
"version": "0.33.3",
|
||||
"description": "Prebuilt sharp for use with Windows x86 (32-bit)",
|
||||
"author": "Lovell Fuller <npm@lovell.info>",
|
||||
"homepage": "https://sharp.pixelplumbing.com",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@img/sharp-win32-x64",
|
||||
"version": "0.33.1-rc.1",
|
||||
"version": "0.33.3",
|
||||
"description": "Prebuilt sharp for use with Windows x64",
|
||||
"author": "Lovell Fuller <npm@lovell.info>",
|
||||
"homepage": "https://sharp.pixelplumbing.com",
|
||||
|
||||
74
package.json
74
package.json
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"name": "sharp",
|
||||
"description": "High performance Node.js image processing, the fastest module to resize JPEG, PNG, WebP, GIF, AVIF and TIFF images",
|
||||
"version": "0.33.1-rc.1",
|
||||
"version": "0.33.3",
|
||||
"author": "Lovell Fuller <npm@lovell.info>",
|
||||
"homepage": "https://github.com/lovell/sharp",
|
||||
"homepage": "https://sharp.pixelplumbing.com",
|
||||
"contributors": [
|
||||
"Pierre Inglebert <pierre.inglebert@gmail.com>",
|
||||
"Jonathan Ong <jonathanrichardong@gmail.com>",
|
||||
@@ -137,57 +137,57 @@
|
||||
],
|
||||
"dependencies": {
|
||||
"color": "^4.2.3",
|
||||
"detect-libc": "^2.0.2",
|
||||
"semver": "^7.5.4"
|
||||
"detect-libc": "^2.0.3",
|
||||
"semver": "^7.6.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@img/sharp-darwin-arm64": "0.33.1-rc.1",
|
||||
"@img/sharp-darwin-x64": "0.33.1-rc.1",
|
||||
"@img/sharp-libvips-darwin-arm64": "1.0.0",
|
||||
"@img/sharp-libvips-darwin-x64": "1.0.0",
|
||||
"@img/sharp-libvips-linux-arm": "1.0.0",
|
||||
"@img/sharp-libvips-linux-arm64": "1.0.0",
|
||||
"@img/sharp-libvips-linux-s390x": "1.0.0",
|
||||
"@img/sharp-libvips-linux-x64": "1.0.0",
|
||||
"@img/sharp-libvips-linuxmusl-arm64": "1.0.0",
|
||||
"@img/sharp-libvips-linuxmusl-x64": "1.0.0",
|
||||
"@img/sharp-linux-arm": "0.33.1-rc.1",
|
||||
"@img/sharp-linux-arm64": "0.33.1-rc.1",
|
||||
"@img/sharp-linux-s390x": "0.33.1-rc.1",
|
||||
"@img/sharp-linux-x64": "0.33.1-rc.1",
|
||||
"@img/sharp-linuxmusl-arm64": "0.33.1-rc.1",
|
||||
"@img/sharp-linuxmusl-x64": "0.33.1-rc.1",
|
||||
"@img/sharp-wasm32": "0.33.1-rc.1",
|
||||
"@img/sharp-win32-ia32": "0.33.1-rc.1",
|
||||
"@img/sharp-win32-x64": "0.33.1-rc.1"
|
||||
"@img/sharp-darwin-arm64": "0.33.3",
|
||||
"@img/sharp-darwin-x64": "0.33.3",
|
||||
"@img/sharp-libvips-darwin-arm64": "1.0.2",
|
||||
"@img/sharp-libvips-darwin-x64": "1.0.2",
|
||||
"@img/sharp-libvips-linux-arm": "1.0.2",
|
||||
"@img/sharp-libvips-linux-arm64": "1.0.2",
|
||||
"@img/sharp-libvips-linux-s390x": "1.0.2",
|
||||
"@img/sharp-libvips-linux-x64": "1.0.2",
|
||||
"@img/sharp-libvips-linuxmusl-arm64": "1.0.2",
|
||||
"@img/sharp-libvips-linuxmusl-x64": "1.0.2",
|
||||
"@img/sharp-linux-arm": "0.33.3",
|
||||
"@img/sharp-linux-arm64": "0.33.3",
|
||||
"@img/sharp-linux-s390x": "0.33.3",
|
||||
"@img/sharp-linux-x64": "0.33.3",
|
||||
"@img/sharp-linuxmusl-arm64": "0.33.3",
|
||||
"@img/sharp-linuxmusl-x64": "0.33.3",
|
||||
"@img/sharp-wasm32": "0.33.3",
|
||||
"@img/sharp-win32-ia32": "0.33.3",
|
||||
"@img/sharp-win32-x64": "0.33.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@emnapi/runtime": "^0.44.0",
|
||||
"@img/sharp-libvips-dev": "1.0.0",
|
||||
"@img/sharp-libvips-dev-wasm32": "1.0.0",
|
||||
"@img/sharp-libvips-win32-ia32": "1.0.0",
|
||||
"@img/sharp-libvips-win32-x64": "1.0.0",
|
||||
"@emnapi/runtime": "^1.1.0",
|
||||
"@img/sharp-libvips-dev": "1.0.2",
|
||||
"@img/sharp-libvips-dev-wasm32": "1.0.3",
|
||||
"@img/sharp-libvips-win32-ia32": "1.0.2",
|
||||
"@img/sharp-libvips-win32-x64": "1.0.2",
|
||||
"@types/node": "*",
|
||||
"async": "^3.2.5",
|
||||
"cc": "^3.0.1",
|
||||
"emnapi": "^0.44.0",
|
||||
"exif-reader": "^2.0.0",
|
||||
"emnapi": "^1.1.0",
|
||||
"exif-reader": "^2.0.1",
|
||||
"extract-zip": "^2.0.1",
|
||||
"icc": "^3.0.0",
|
||||
"jsdoc-to-markdown": "^8.0.0",
|
||||
"jsdoc-to-markdown": "^8.0.1",
|
||||
"license-checker": "^25.0.1",
|
||||
"mocha": "^10.2.0",
|
||||
"node-addon-api": "^7.0.0",
|
||||
"mocha": "^10.3.0",
|
||||
"node-addon-api": "^8.0.0",
|
||||
"nyc": "^15.1.0",
|
||||
"prebuild": "^12.1.0",
|
||||
"prebuild": "^13.0.0",
|
||||
"semistandard": "^17.0.0",
|
||||
"tar-fs": "^3.0.4",
|
||||
"tsd": "^0.29.0"
|
||||
"tar-fs": "^3.0.5",
|
||||
"tsd": "^0.30.7"
|
||||
},
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0",
|
||||
"libvips": ">=8.15.0"
|
||||
"libvips": ">=8.15.2"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
|
||||
#if (VIPS_MAJOR_VERSION < 8) || \
|
||||
(VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION < 15) || \
|
||||
(VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION == 15 && VIPS_MICRO_VERSION < 0)
|
||||
#error "libvips version 8.15.0+ is required - please see https://sharp.pixelplumbing.com/install"
|
||||
(VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION == 15 && VIPS_MICRO_VERSION < 2)
|
||||
#error "libvips version 8.15.2+ is required - please see https://sharp.pixelplumbing.com/install"
|
||||
#endif
|
||||
|
||||
#if ((!defined(__clang__)) && defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 6)))
|
||||
|
||||
@@ -54,7 +54,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
||||
sharp::ImageType inputImageType;
|
||||
std::tie(image, inputImageType) = sharp::OpenInput(baton->input);
|
||||
VipsAccess access = baton->input->access;
|
||||
image = sharp::EnsureColourspace(image, baton->colourspaceInput);
|
||||
image = sharp::EnsureColourspace(image, baton->colourspacePipeline);
|
||||
|
||||
int nPages = baton->input->pages;
|
||||
if (nPages == -1) {
|
||||
@@ -96,6 +96,9 @@ class PipelineWorker : public Napi::AsyncWorker {
|
||||
baton->rotationAngle != 0.0);
|
||||
|
||||
if (autoRotation != VIPS_ANGLE_D0) {
|
||||
if (autoRotation != VIPS_ANGLE_D180) {
|
||||
MultiPageUnsupported(nPages, "Rotate");
|
||||
}
|
||||
image = image.rot(autoRotation);
|
||||
autoRotation = VIPS_ANGLE_D0;
|
||||
}
|
||||
@@ -114,6 +117,9 @@ class PipelineWorker : public Napi::AsyncWorker {
|
||||
baton->flop = FALSE;
|
||||
}
|
||||
if (rotation != VIPS_ANGLE_D0) {
|
||||
if (rotation != VIPS_ANGLE_D180) {
|
||||
MultiPageUnsupported(nPages, "Rotate");
|
||||
}
|
||||
image = image.rot(rotation);
|
||||
rotation = VIPS_ANGLE_D0;
|
||||
}
|
||||
@@ -183,7 +189,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
||||
// - input colourspace is not specified;
|
||||
bool const shouldPreShrink = (targetResizeWidth > 0 || targetResizeHeight > 0) &&
|
||||
baton->gamma == 0 && baton->topOffsetPre == -1 && baton->trimThreshold < 0.0 &&
|
||||
baton->colourspaceInput == VIPS_INTERPRETATION_LAST && !shouldRotateBefore;
|
||||
baton->colourspacePipeline == VIPS_INTERPRETATION_LAST && !shouldRotateBefore;
|
||||
|
||||
if (shouldPreShrink) {
|
||||
// The common part of the shrink: the bit by which both axes must be shrunk
|
||||
@@ -325,6 +331,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
||||
sharp::HasProfile(image) &&
|
||||
image.interpretation() != VIPS_INTERPRETATION_LABS &&
|
||||
image.interpretation() != VIPS_INTERPRETATION_GREY16 &&
|
||||
baton->colourspacePipeline != VIPS_INTERPRETATION_CMYK &&
|
||||
!baton->input->ignoreIcc
|
||||
) {
|
||||
// Convert to sRGB/P3 using embedded profile
|
||||
@@ -338,7 +345,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
||||
}
|
||||
} else if (
|
||||
image.interpretation() == VIPS_INTERPRETATION_CMYK &&
|
||||
baton->colourspaceInput != VIPS_INTERPRETATION_CMYK
|
||||
baton->colourspacePipeline != VIPS_INTERPRETATION_CMYK
|
||||
) {
|
||||
image = image.icc_transform(processingProfile, VImage::option()
|
||||
->set("input_profile", "cmyk")
|
||||
@@ -397,6 +404,9 @@ class PipelineWorker : public Napi::AsyncWorker {
|
||||
rotation != VIPS_ANGLE_D0);
|
||||
// Auto-rotate post-extract
|
||||
if (autoRotation != VIPS_ANGLE_D0) {
|
||||
if (autoRotation != VIPS_ANGLE_D180) {
|
||||
MultiPageUnsupported(nPages, "Rotate");
|
||||
}
|
||||
image = image.rot(autoRotation);
|
||||
}
|
||||
// Mirror vertically (up-down) about the x-axis
|
||||
@@ -409,6 +419,9 @@ class PipelineWorker : public Napi::AsyncWorker {
|
||||
}
|
||||
// Rotate post-extract 90-angle
|
||||
if (rotation != VIPS_ANGLE_D0) {
|
||||
if (rotation != VIPS_ANGLE_D180) {
|
||||
MultiPageUnsupported(nPages, "Rotate");
|
||||
}
|
||||
image = image.rot(rotation);
|
||||
}
|
||||
|
||||
@@ -420,7 +433,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
||||
for (unsigned int i = 0; i < baton->joinChannelIn.size(); i++) {
|
||||
baton->joinChannelIn[i]->access = access;
|
||||
std::tie(joinImage, joinImageType) = sharp::OpenInput(baton->joinChannelIn[i]);
|
||||
joinImage = sharp::EnsureColourspace(joinImage, baton->colourspaceInput);
|
||||
joinImage = sharp::EnsureColourspace(joinImage, baton->colourspacePipeline);
|
||||
image = image.bandjoin(joinImage);
|
||||
}
|
||||
image = image.copy(VImage::option()->set("interpretation", baton->colourspace));
|
||||
@@ -561,6 +574,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
||||
VImage::option()->set("extend", baton->extendWith)->set("background", background));
|
||||
} else {
|
||||
std::vector<double> ignoredBackground(1);
|
||||
image = sharp::StaySequential(image, baton->input->access);
|
||||
image = nPages > 1
|
||||
? sharp::EmbedMultiPage(image,
|
||||
baton->extendLeft, baton->extendTop, baton->width, baton->height,
|
||||
@@ -629,7 +643,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
||||
sharp::ImageType compositeImageType = sharp::ImageType::UNKNOWN;
|
||||
composite->input->access = access;
|
||||
std::tie(compositeImage, compositeImageType) = sharp::OpenInput(composite->input);
|
||||
compositeImage = sharp::EnsureColourspace(compositeImage, baton->colourspaceInput);
|
||||
compositeImage = sharp::EnsureColourspace(compositeImage, baton->colourspacePipeline);
|
||||
// Verify within current dimensions
|
||||
if (compositeImage.width() > image.width() || compositeImage.height() > image.height()) {
|
||||
throw vips::VError("Image to composite must have same dimensions or smaller");
|
||||
@@ -730,7 +744,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
||||
sharp::ImageType booleanImageType = sharp::ImageType::UNKNOWN;
|
||||
baton->boolean->access = access;
|
||||
std::tie(booleanImage, booleanImageType) = sharp::OpenInput(baton->boolean);
|
||||
booleanImage = sharp::EnsureColourspace(booleanImage, baton->colourspaceInput);
|
||||
booleanImage = sharp::EnsureColourspace(booleanImage, baton->colourspacePipeline);
|
||||
image = sharp::Boolean(image, booleanImage, baton->booleanOp);
|
||||
image = sharp::RemoveGifPalette(image);
|
||||
}
|
||||
@@ -763,9 +777,9 @@ class PipelineWorker : public Napi::AsyncWorker {
|
||||
// Convert colourspace, pass the current known interpretation so libvips doesn't have to guess
|
||||
image = image.colourspace(baton->colourspace, VImage::option()->set("source_space", image.interpretation()));
|
||||
// Transform colours from embedded profile to output profile
|
||||
if ((baton->keepMetadata & VIPS_FOREIGN_KEEP_ICC) &&
|
||||
if ((baton->keepMetadata & VIPS_FOREIGN_KEEP_ICC) && baton->colourspacePipeline != VIPS_INTERPRETATION_CMYK &&
|
||||
baton->withIccProfile.empty() && sharp::HasProfile(image)) {
|
||||
image = image.icc_transform("srgb", VImage::option()
|
||||
image = image.icc_transform(processingProfile, VImage::option()
|
||||
->set("embedded", TRUE)
|
||||
->set("depth", sharp::Is16Bit(image.interpretation()) ? 16 : 8)
|
||||
->set("intent", VIPS_INTENT_PERCEPTUAL));
|
||||
@@ -975,7 +989,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
||||
->set("Q", baton->heifQuality)
|
||||
->set("compression", baton->heifCompression)
|
||||
->set("effort", baton->heifEffort)
|
||||
->set("bitdepth", 8)
|
||||
->set("bitdepth", baton->heifBitdepth)
|
||||
->set("subsample_mode", baton->heifChromaSubsampling == "4:4:4"
|
||||
? VIPS_FOREIGN_SUBSAMPLE_OFF : VIPS_FOREIGN_SUBSAMPLE_ON)
|
||||
->set("lossless", baton->heifLossless)));
|
||||
@@ -1168,7 +1182,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
||||
->set("Q", baton->heifQuality)
|
||||
->set("compression", baton->heifCompression)
|
||||
->set("effort", baton->heifEffort)
|
||||
->set("bitdepth", 8)
|
||||
->set("bitdepth", baton->heifBitdepth)
|
||||
->set("subsample_mode", baton->heifChromaSubsampling == "4:4:4"
|
||||
? VIPS_FOREIGN_SUBSAMPLE_OFF : VIPS_FOREIGN_SUBSAMPLE_ON)
|
||||
->set("lossless", baton->heifLossless));
|
||||
@@ -1594,10 +1608,10 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
||||
baton->recombMatrix[i] = sharp::AttrAsDouble(recombMatrix, i);
|
||||
}
|
||||
}
|
||||
baton->colourspaceInput = sharp::AttrAsEnum<VipsInterpretation>(
|
||||
options, "colourspaceInput", VIPS_TYPE_INTERPRETATION);
|
||||
if (baton->colourspaceInput == VIPS_INTERPRETATION_ERROR) {
|
||||
baton->colourspaceInput = VIPS_INTERPRETATION_LAST;
|
||||
baton->colourspacePipeline = sharp::AttrAsEnum<VipsInterpretation>(
|
||||
options, "colourspacePipeline", VIPS_TYPE_INTERPRETATION);
|
||||
if (baton->colourspacePipeline == VIPS_INTERPRETATION_ERROR) {
|
||||
baton->colourspacePipeline = VIPS_INTERPRETATION_LAST;
|
||||
}
|
||||
baton->colourspace = sharp::AttrAsEnum<VipsInterpretation>(options, "colourspace", VIPS_TYPE_INTERPRETATION);
|
||||
if (baton->colourspace == VIPS_INTERPRETATION_ERROR) {
|
||||
@@ -1682,6 +1696,7 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
||||
options, "heifCompression", VIPS_TYPE_FOREIGN_HEIF_COMPRESSION);
|
||||
baton->heifEffort = sharp::AttrAsUint32(options, "heifEffort");
|
||||
baton->heifChromaSubsampling = sharp::AttrAsStr(options, "heifChromaSubsampling");
|
||||
baton->heifBitdepth = sharp::AttrAsUint32(options, "heifBitdepth");
|
||||
baton->jxlDistance = sharp::AttrAsDouble(options, "jxlDistance");
|
||||
baton->jxlDecodingTier = sharp::AttrAsUint32(options, "jxlDecodingTier");
|
||||
baton->jxlEffort = sharp::AttrAsUint32(options, "jxlEffort");
|
||||
|
||||
@@ -181,6 +181,7 @@ struct PipelineBaton {
|
||||
int heifEffort;
|
||||
std::string heifChromaSubsampling;
|
||||
bool heifLossless;
|
||||
int heifBitdepth;
|
||||
double jxlDistance;
|
||||
int jxlDecodingTier;
|
||||
int jxlEffort;
|
||||
@@ -205,7 +206,7 @@ struct PipelineBaton {
|
||||
int extractChannel;
|
||||
bool removeAlpha;
|
||||
double ensureAlpha;
|
||||
VipsInterpretation colourspaceInput;
|
||||
VipsInterpretation colourspacePipeline;
|
||||
VipsInterpretation colourspace;
|
||||
std::vector<int> delay;
|
||||
int loop;
|
||||
@@ -349,6 +350,7 @@ struct PipelineBaton {
|
||||
heifEffort(4),
|
||||
heifChromaSubsampling("4:4:4"),
|
||||
heifLossless(false),
|
||||
heifBitdepth(8),
|
||||
jxlDistance(1.0),
|
||||
jxlDecodingTier(0),
|
||||
jxlEffort(7),
|
||||
@@ -369,7 +371,7 @@ struct PipelineBaton {
|
||||
extractChannel(-1),
|
||||
removeAlpha(false),
|
||||
ensureAlpha(-1.0),
|
||||
colourspaceInput(VIPS_INTERPRETATION_LAST),
|
||||
colourspacePipeline(VIPS_INTERPRETATION_LAST),
|
||||
colourspace(VIPS_INTERPRETATION_LAST),
|
||||
loop(-1),
|
||||
tileSize(256),
|
||||
|
||||
@@ -44,6 +44,12 @@ sharp('input.png')
|
||||
// sharpened, with metadata, 90% quality WebP image data. Phew!
|
||||
});
|
||||
|
||||
sharp('input.png')
|
||||
.keepMetadata()
|
||||
.toFile('output.png', (err, info) => {
|
||||
// output.png is an image containing input.png along with all metadata(EXIF, ICC, XMP, IPTC) from input.png
|
||||
})
|
||||
|
||||
sharp('input.jpg')
|
||||
.resize(300, 200)
|
||||
.toFile('output.jpg', (err: Error) => {
|
||||
@@ -404,7 +410,7 @@ sharp({
|
||||
|
||||
// Taken from API documentation at
|
||||
// https://sharp.pixelplumbing.com/api-operation#clahe
|
||||
// introducted
|
||||
// introduced
|
||||
sharp('input.jpg').clahe({ width: 10, height: 10 }).toFile('output.jpg');
|
||||
|
||||
sharp('input.jpg').clahe({ width: 10, height: 10, maxSlope: 5 }).toFile('outfile.jpg');
|
||||
@@ -589,7 +595,7 @@ sharp({
|
||||
rgba: true,
|
||||
justify: true,
|
||||
spacing: 10,
|
||||
wrap: 'charWord',
|
||||
wrap: 'word-char',
|
||||
},
|
||||
})
|
||||
.png()
|
||||
|
||||
@@ -144,4 +144,10 @@ describe('AVIF', () => {
|
||||
/Processed image is too large for the HEIF format/
|
||||
)
|
||||
);
|
||||
|
||||
it('Invalid bitdepth value throws error', async () => {
|
||||
assert.rejects(
|
||||
() => sharp().avif({ bitdepth: 11 }),
|
||||
/Error: Expected 8, 10 or 12 for bitdepth but received 11 of type number/);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -77,4 +77,26 @@ describe('Clone', function () {
|
||||
assert.strictEqual(0, original.listenerCount('finish'));
|
||||
assert.strictEqual(0, clone.listenerCount('finish'));
|
||||
});
|
||||
|
||||
it('Ensure deep clone of properties, including arrays', async () => {
|
||||
const alpha = await sharp({
|
||||
create: { width: 320, height: 240, channels: 3, background: 'red' }
|
||||
}).toColourspace('b-w').png().toBuffer();
|
||||
|
||||
const original = sharp();
|
||||
const joiner = original.clone().joinChannel(alpha);
|
||||
const negater = original.clone().negate();
|
||||
|
||||
fs.createReadStream(fixtures.inputJpg320x240).pipe(original);
|
||||
const joined = await joiner.png({ effort: 1 }).toBuffer();
|
||||
const negated = await negater.png({ effort: 1 }).toBuffer();
|
||||
|
||||
const joinedMetadata = await sharp(joined).metadata();
|
||||
assert.strictEqual(joinedMetadata.channels, 4);
|
||||
assert.strictEqual(joinedMetadata.hasAlpha, true);
|
||||
|
||||
const negatedMetadata = await sharp(negated).metadata();
|
||||
assert.strictEqual(negatedMetadata.channels, 3);
|
||||
assert.strictEqual(negatedMetadata.hasAlpha, false);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -451,7 +451,7 @@ describe('composite', () => {
|
||||
assert.strictEqual(info.height, 40);
|
||||
});
|
||||
|
||||
it('Ensure implict unpremultiply after resize but before composite', async () => {
|
||||
it('Ensure implicit unpremultiply after resize but before composite', async () => {
|
||||
const [r, g, b, a] = await sharp({
|
||||
create: {
|
||||
width: 1, height: 1, channels: 4, background: 'saddlebrown'
|
||||
|
||||
@@ -73,6 +73,20 @@ describe('Extend', function () {
|
||||
});
|
||||
});
|
||||
|
||||
it('extend top with mirroring uses ordered read', async () => {
|
||||
const data = await sharp(fixtures.inputJpg)
|
||||
.extend({
|
||||
extendWith: 'mirror',
|
||||
top: 1
|
||||
})
|
||||
.png({ compressionLevel: 0 })
|
||||
.toBuffer();
|
||||
|
||||
const { width, height } = await sharp(data).metadata();
|
||||
assert.strictEqual(2725, width);
|
||||
assert.strictEqual(2226, height);
|
||||
});
|
||||
|
||||
it(`extend sides unequally with RGBA (${extendWith})`, function (done) {
|
||||
sharp(fixtures.inputPngWithTransparency16bit)
|
||||
.resize(120)
|
||||
|
||||
@@ -78,4 +78,21 @@ describe('HEIF', () => {
|
||||
sharp().heif({ compression: 'av1', chromaSubsampling: '4:4:4' });
|
||||
});
|
||||
});
|
||||
it('valid bitdepth value does not throw an error', () => {
|
||||
const { heif } = sharp.versions;
|
||||
delete sharp.versions.heif;
|
||||
assert.doesNotThrow(() => {
|
||||
sharp().heif({ compression: 'av1', bitdepth: 12 });
|
||||
});
|
||||
sharp.versions.heif = '1.2.3';
|
||||
assert.throws(() => {
|
||||
sharp().heif({ compression: 'av1', bitdepth: 10 });
|
||||
}, /Error: Expected 8 for bitdepth when using prebuilt binaries but received 10 of type number/);
|
||||
sharp.versions.heif = heif;
|
||||
});
|
||||
it('invalid bitdepth value should throw an error', () => {
|
||||
assert.throws(() => {
|
||||
sharp().heif({ compression: 'av1', bitdepth: 11 });
|
||||
}, /Error: Expected 8, 10 or 12 for bitdepth but received 11 of type number/);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -123,6 +123,9 @@ describe('libvips binaries', function () {
|
||||
const [, arch] = libvips.runtimePlatformArch().split('-');
|
||||
assert.strict(['arm', 'arm64', 'ia32', 'x64'].includes(arch));
|
||||
});
|
||||
it('isUnsupportedNodeRuntime', () => {
|
||||
assert.strictEqual(libvips.isUnsupportedNodeRuntime(), undefined);
|
||||
});
|
||||
});
|
||||
|
||||
describe('logger', function () {
|
||||
@@ -159,7 +162,7 @@ describe('libvips binaries', function () {
|
||||
process.env.npm_config_arch = 's390x';
|
||||
process.env.npm_config_libc = '';
|
||||
const locatorHash = libvips.yarnLocator();
|
||||
assert.strictEqual(locatorHash, '86cc8ee6e4');
|
||||
assert.strictEqual(locatorHash, '45978c229d');
|
||||
delete process.env.npm_config_platform;
|
||||
delete process.env.npm_config_arch;
|
||||
delete process.env.npm_config_libc;
|
||||
|
||||
@@ -576,6 +576,19 @@ describe('Image metadata', function () {
|
||||
assert.strictEqual(description, 'Generic RGB Profile');
|
||||
});
|
||||
|
||||
it('keep existing CMYK ICC profile', async () => {
|
||||
const data = await sharp(fixtures.inputJpgWithCmykProfile)
|
||||
.pipelineColourspace('cmyk')
|
||||
.toColourspace('cmyk')
|
||||
.keepIccProfile()
|
||||
.toBuffer();
|
||||
|
||||
const metadata = await sharp(data).metadata();
|
||||
assert.strictEqual(metadata.channels, 4);
|
||||
const { description } = icc.parse(metadata.icc);
|
||||
assert.strictEqual(description, 'U.S. Web Coated (SWOP) v2');
|
||||
});
|
||||
|
||||
it('transform to ICC profile and attach', async () => {
|
||||
const data = await sharp({ create })
|
||||
.png()
|
||||
|
||||
@@ -353,6 +353,21 @@ describe('Rotation', function () {
|
||||
)
|
||||
);
|
||||
|
||||
it('Animated image rotate 180', () =>
|
||||
assert.doesNotReject(() => sharp(fixtures.inputGifAnimated, { animated: true })
|
||||
.rotate(180)
|
||||
.toBuffer()
|
||||
)
|
||||
);
|
||||
|
||||
it('Animated image rotate non-180 rejects', () =>
|
||||
assert.rejects(() => sharp(fixtures.inputGifAnimated, { animated: true })
|
||||
.rotate(90)
|
||||
.toBuffer(),
|
||||
/Rotate is not supported for multi-page images/
|
||||
)
|
||||
);
|
||||
|
||||
it('Multiple rotate emits warning', () => {
|
||||
let warningMessage = '';
|
||||
const s = sharp();
|
||||
|
||||
@@ -319,21 +319,21 @@ describe('Text to image', function () {
|
||||
|
||||
it('valid wrap throws', () => {
|
||||
assert.doesNotThrow(() => sharp({ text: { text: 'text', wrap: 'none' } }));
|
||||
assert.doesNotThrow(() => sharp({ text: { text: 'text', wrap: 'wordChar' } }));
|
||||
assert.doesNotThrow(() => sharp({ text: { text: 'text', wrap: 'word-char' } }));
|
||||
});
|
||||
|
||||
it('invalid wrap throws', () => {
|
||||
assert.throws(
|
||||
() => sharp({ text: { text: 'text', wrap: 1 } }),
|
||||
/Expected one of: word, char, wordChar, none for text\.wrap but received 1 of type number/
|
||||
/Expected one of: word, char, word-char, none for text\.wrap but received 1 of type number/
|
||||
);
|
||||
assert.throws(
|
||||
() => sharp({ text: { text: 'text', wrap: false } }),
|
||||
/Expected one of: word, char, wordChar, none for text\.wrap but received false of type boolean/
|
||||
/Expected one of: word, char, word-char, none for text\.wrap but received false of type boolean/
|
||||
);
|
||||
assert.throws(
|
||||
() => sharp({ text: { text: 'text', wrap: 'invalid' } }),
|
||||
/Expected one of: word, char, wordChar, none for text\.wrap but received invalid of type string/
|
||||
/Expected one of: word, char, word-char, none for text\.wrap but received invalid of type string/
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -134,7 +134,7 @@ describe('Utilities', function () {
|
||||
});
|
||||
});
|
||||
it('input fileSuffix', function () {
|
||||
assert.deepStrictEqual(['.jpg', '.jpeg', '.jpe'], sharp.format.jpeg.input.fileSuffix);
|
||||
assert.deepStrictEqual(['.jpg', '.jpeg', '.jpe', '.jfif'], sharp.format.jpeg.input.fileSuffix);
|
||||
});
|
||||
it('output alias', function () {
|
||||
assert.deepStrictEqual(['jpe', 'jpg'], sharp.format.jpeg.output.alias);
|
||||
|
||||
Reference in New Issue
Block a user