mirror of
https://github.com/lovell/sharp.git
synced 2026-02-04 05:36:18 +01:00
Compare commits
24 Commits
main
...
17d4a684df
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
17d4a684df | ||
|
|
ed6b7384d0 | ||
|
|
ef77388a73 | ||
|
|
66764b359b | ||
|
|
8561f0da1d | ||
|
|
0468c1be9f | ||
|
|
4b1680c312 | ||
|
|
2346722c0d | ||
|
|
a5e726002c | ||
|
|
d161e45e06 | ||
|
|
006d37b2d0 | ||
|
|
0d872bd13a | ||
|
|
1cf4b7f04d | ||
|
|
e50c0c2e04 | ||
|
|
3278a9a913 | ||
|
|
1b2f79335d | ||
|
|
937167933b | ||
|
|
dbcb7e60bd | ||
|
|
e1bad5470e | ||
|
|
1a2c1c8833 | ||
|
|
aaeded2b67 | ||
|
|
f6cdd36559 | ||
|
|
283c7d3f0c | ||
|
|
34c39fa194 |
18
.cirrus.yml
18
.cirrus.yml
@@ -1,18 +0,0 @@
|
|||||||
freebsd_instance:
|
|
||||||
image_family: freebsd-16-0-snap
|
|
||||||
|
|
||||||
task:
|
|
||||||
name: FreeBSD
|
|
||||||
env:
|
|
||||||
IGNORE_OSVERSION: yes
|
|
||||||
skip_notifications: true
|
|
||||||
prerequisites_script:
|
|
||||||
- pkg update -f
|
|
||||||
- pkg upgrade -y
|
|
||||||
- pkg install -y devel/git devel/pkgconf graphics/vips www/node22 www/npm
|
|
||||||
- pkg-config --modversion vips-cpp
|
|
||||||
install_script:
|
|
||||||
- npm install
|
|
||||||
- npm run build
|
|
||||||
test_script:
|
|
||||||
- node --test test/unit/io.js
|
|
||||||
2
.github/ISSUE_TEMPLATE/installation.md
vendored
2
.github/ISSUE_TEMPLATE/installation.md
vendored
@@ -31,7 +31,7 @@ please open an issue against that package instead.
|
|||||||
|
|
||||||
<!-- Please place an [x] in the relevant box to confirm. -->
|
<!-- Please place an [x] in the relevant box to confirm. -->
|
||||||
|
|
||||||
- [ ] I am using Node.js with a version that satisfies `^18.17.0 || ^20.3.0 || >=21.0.0`
|
- [ ] I am using Node.js with a version that satisfies `>=20.9.0`
|
||||||
- [ ] I am using Deno
|
- [ ] I am using Deno
|
||||||
- [ ] I am using Bun
|
- [ ] I am using Bun
|
||||||
|
|
||||||
|
|||||||
171
.github/workflows/ci.yml
vendored
171
.github/workflows/ci.yml
vendored
@@ -9,8 +9,8 @@ jobs:
|
|||||||
contents: read
|
contents: read
|
||||||
runs-on: ubuntu-24.04
|
runs-on: ubuntu-24.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v6
|
||||||
- uses: actions/setup-node@v5
|
- uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
node-version: "24"
|
node-version: "24"
|
||||||
- run: npm install --ignore-scripts
|
- run: npm install --ignore-scripts
|
||||||
@@ -31,123 +31,124 @@ jobs:
|
|||||||
- os: ubuntu-24.04
|
- os: ubuntu-24.04
|
||||||
container: rockylinux:8
|
container: rockylinux:8
|
||||||
nodejs_arch: x64
|
nodejs_arch: x64
|
||||||
nodejs_version: "^18.17.0"
|
nodejs_version: "^20.9.0"
|
||||||
nodejs_version_major: 18
|
nodejs_version_major: 20
|
||||||
platform: linux-x64
|
platform: linux-x64
|
||||||
package: true
|
package: true
|
||||||
- os: ubuntu-24.04
|
- os: ubuntu-24.04
|
||||||
container: rockylinux:8
|
container: rockylinux:8
|
||||||
nodejs_arch: x64
|
nodejs_arch: x64
|
||||||
nodejs_version: "^20.3.0"
|
nodejs_version: "^22"
|
||||||
nodejs_version_major: 20
|
|
||||||
platform: linux-x64
|
|
||||||
- os: ubuntu-24.04
|
|
||||||
container: rockylinux:8
|
|
||||||
nodejs_arch: x64
|
|
||||||
nodejs_version: "^22.9.0"
|
|
||||||
nodejs_version_major: 22
|
nodejs_version_major: 22
|
||||||
platform: linux-x64
|
platform: linux-x64
|
||||||
- os: ubuntu-24.04
|
- os: ubuntu-24.04
|
||||||
container: node:18-alpine3.17
|
container: rockylinux:8
|
||||||
nodejs_version_major: 18
|
nodejs_arch: x64
|
||||||
platform: linuxmusl-x64
|
nodejs_version: "^24"
|
||||||
package: true
|
nodejs_version_major: 24
|
||||||
|
platform: linux-x64
|
||||||
- os: ubuntu-24.04
|
- os: ubuntu-24.04
|
||||||
container: node:20-alpine3.18
|
container: node:20-alpine3.18
|
||||||
nodejs_version_major: 20
|
nodejs_version_major: 20
|
||||||
platform: linuxmusl-x64
|
platform: linuxmusl-x64
|
||||||
|
package: true
|
||||||
- os: ubuntu-24.04
|
- os: ubuntu-24.04
|
||||||
container: node:22-alpine3.20
|
container: node:22-alpine3.20
|
||||||
nodejs_version_major: 22
|
nodejs_version_major: 22
|
||||||
platform: linuxmusl-x64
|
platform: linuxmusl-x64
|
||||||
|
- os: ubuntu-24.04
|
||||||
|
container: node:24-alpine3.22
|
||||||
|
nodejs_version_major: 24
|
||||||
|
platform: linuxmusl-x64
|
||||||
- os: ubuntu-24.04-arm
|
- os: ubuntu-24.04-arm
|
||||||
container: arm64v8/rockylinux:8
|
container: arm64v8/rockylinux:8
|
||||||
nodejs_arch: arm64
|
nodejs_arch: arm64
|
||||||
nodejs_version: "^18.17.0"
|
nodejs_version: "^20.9.0"
|
||||||
nodejs_version_major: 18
|
nodejs_version_major: 20
|
||||||
platform: linux-arm64
|
platform: linux-arm64
|
||||||
package: true
|
package: true
|
||||||
- os: ubuntu-24.04-arm
|
- os: ubuntu-24.04-arm
|
||||||
container: arm64v8/rockylinux:8
|
container: arm64v8/rockylinux:8
|
||||||
nodejs_arch: arm64
|
nodejs_arch: arm64
|
||||||
nodejs_version: "^20.3.0"
|
nodejs_version: "^22"
|
||||||
nodejs_version_major: 20
|
nodejs_version_major: 22
|
||||||
|
platform: linux-arm64
|
||||||
|
- os: ubuntu-24.04-arm
|
||||||
|
container: arm64v8/rockylinux:8
|
||||||
|
nodejs_arch: arm64
|
||||||
|
nodejs_version: "^24"
|
||||||
|
nodejs_version_major: 24
|
||||||
platform: linux-arm64
|
platform: linux-arm64
|
||||||
- os: macos-15-intel
|
- os: macos-15-intel
|
||||||
nodejs_arch: x64
|
nodejs_arch: x64
|
||||||
nodejs_version: "^18.17.0"
|
nodejs_version: "^20.9.0"
|
||||||
nodejs_version_major: 18
|
nodejs_version_major: 20
|
||||||
platform: darwin-x64
|
platform: darwin-x64
|
||||||
package: true
|
package: true
|
||||||
- os: macos-15-intel
|
- os: macos-15-intel
|
||||||
nodejs_arch: x64
|
nodejs_arch: x64
|
||||||
nodejs_version: "^20.3.0"
|
nodejs_version: "^22"
|
||||||
nodejs_version_major: 20
|
nodejs_version_major: 22
|
||||||
platform: darwin-x64
|
platform: darwin-x64
|
||||||
- os: macos-15-intel
|
- os: macos-15-intel
|
||||||
nodejs_arch: x64
|
nodejs_arch: x64
|
||||||
nodejs_version: "^22.9.0"
|
nodejs_version: "^24"
|
||||||
nodejs_version_major: 22
|
nodejs_version_major: 24
|
||||||
platform: darwin-x64
|
platform: darwin-x64
|
||||||
- os: macos-15
|
- os: macos-15
|
||||||
nodejs_arch: arm64
|
nodejs_arch: arm64
|
||||||
nodejs_version: "^18.17.0"
|
nodejs_version: "^20.9.0"
|
||||||
nodejs_version_major: 18
|
nodejs_version_major: 20
|
||||||
platform: darwin-arm64
|
platform: darwin-arm64
|
||||||
package: true
|
package: true
|
||||||
- os: macos-15
|
- os: macos-15
|
||||||
nodejs_arch: arm64
|
nodejs_arch: arm64
|
||||||
nodejs_version: "^20.3.0"
|
nodejs_version: "^22"
|
||||||
nodejs_version_major: 20
|
nodejs_version_major: 22
|
||||||
platform: darwin-arm64
|
platform: darwin-arm64
|
||||||
- os: macos-15
|
- os: macos-15
|
||||||
nodejs_arch: arm64
|
nodejs_arch: arm64
|
||||||
nodejs_version: "^22.9.0"
|
nodejs_version: "^24"
|
||||||
nodejs_version_major: 22
|
nodejs_version_major: 24
|
||||||
platform: darwin-arm64
|
platform: darwin-arm64
|
||||||
- os: windows-2022
|
- os: windows-2022
|
||||||
nodejs_arch: x86
|
nodejs_arch: x86
|
||||||
nodejs_version: "18.18.2" # pinned to avoid 18.19.0 and npm 10
|
nodejs_version: "^20.9.0"
|
||||||
nodejs_version_major: 18
|
nodejs_version_major: 20
|
||||||
platform: win32-ia32
|
platform: win32-ia32
|
||||||
package: true
|
package: true
|
||||||
- os: windows-2022
|
|
||||||
nodejs_arch: x86
|
|
||||||
nodejs_version: "^20.3.0"
|
|
||||||
nodejs_version_major: 20
|
|
||||||
platform: win32-ia32
|
|
||||||
- os: windows-2022
|
|
||||||
nodejs_arch: x86
|
|
||||||
nodejs_version: "^22.9.0"
|
|
||||||
nodejs_version_major: 22
|
|
||||||
platform: win32-ia32
|
|
||||||
- os: windows-2022
|
- os: windows-2022
|
||||||
nodejs_arch: x64
|
nodejs_arch: x64
|
||||||
nodejs_version: "^18.17.0"
|
nodejs_version: "^20.9.0"
|
||||||
nodejs_version_major: 18
|
nodejs_version_major: 20
|
||||||
platform: win32-x64
|
platform: win32-x64
|
||||||
package: true
|
package: true
|
||||||
- os: windows-2022
|
- os: windows-2022
|
||||||
nodejs_arch: x64
|
nodejs_arch: x64
|
||||||
nodejs_version: "^20.3.0"
|
nodejs_version: "^22"
|
||||||
nodejs_version_major: 20
|
nodejs_version_major: 22
|
||||||
platform: win32-x64
|
platform: win32-x64
|
||||||
- os: windows-2022
|
- os: windows-2022
|
||||||
nodejs_arch: x64
|
nodejs_arch: x64
|
||||||
nodejs_version: "^22.9.0"
|
nodejs_version: "^24"
|
||||||
nodejs_version_major: 22
|
nodejs_version_major: 24
|
||||||
platform: win32-x64
|
platform: win32-x64
|
||||||
- os: windows-11-arm
|
- os: windows-11-arm
|
||||||
nodejs_arch: arm64
|
nodejs_arch: arm64
|
||||||
nodejs_version: "^20.3.0"
|
nodejs_version: "^20.9.0"
|
||||||
nodejs_version_major: 20
|
nodejs_version_major: 20
|
||||||
platform: win32-arm64
|
platform: win32-arm64
|
||||||
package: true
|
package: true
|
||||||
- os: windows-11-arm
|
- os: windows-11-arm
|
||||||
nodejs_arch: arm64
|
nodejs_arch: arm64
|
||||||
nodejs_version: "^22.9.0"
|
nodejs_version: "^22"
|
||||||
nodejs_version_major: 22
|
nodejs_version_major: 22
|
||||||
platform: win32-arm64
|
platform: win32-arm64
|
||||||
|
- os: windows-11-arm
|
||||||
|
nodejs_arch: arm64
|
||||||
|
nodejs_version: "^24"
|
||||||
|
nodejs_version_major: 24
|
||||||
|
platform: win32-arm64
|
||||||
steps:
|
steps:
|
||||||
- name: Dependencies (Rocky Linux glibc)
|
- name: Dependencies (Rocky Linux glibc)
|
||||||
if: contains(matrix.container, 'rockylinux')
|
if: contains(matrix.container, 'rockylinux')
|
||||||
@@ -159,22 +160,22 @@ jobs:
|
|||||||
run: apk add build-base git python3 font-noto --update-cache
|
run: apk add build-base git python3 font-noto --update-cache
|
||||||
- name: Dependencies (Python 3.11 - macOS, Windows)
|
- name: Dependencies (Python 3.11 - macOS, Windows)
|
||||||
if: contains(matrix.os, 'macos') || contains(matrix.os, 'windows')
|
if: contains(matrix.os, 'macos') || contains(matrix.os, 'windows')
|
||||||
uses: actions/setup-python@v5
|
uses: actions/setup-python@v6
|
||||||
with:
|
with:
|
||||||
python-version: "3.12"
|
python-version: "3.12"
|
||||||
- name: Dependencies (Node.js)
|
- name: Dependencies (Node.js)
|
||||||
if: "!contains(matrix.platform, 'linuxmusl')"
|
if: "!contains(matrix.platform, 'linuxmusl')"
|
||||||
uses: actions/setup-node@v5
|
uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
node-version: ${{ matrix.nodejs_version }}
|
node-version: ${{ matrix.nodejs_version }}
|
||||||
architecture: ${{ matrix.nodejs_arch }}
|
architecture: ${{ matrix.nodejs_arch }}
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v6
|
||||||
- run: npm install
|
- run: npm install
|
||||||
- run: npm run build
|
- run: npm run build
|
||||||
- run: npm run test-unit
|
- run: npm run test-unit
|
||||||
- if: matrix.package
|
- if: matrix.package
|
||||||
run: npm run package-from-local-build
|
run: npm run package-from-local-build
|
||||||
- uses: actions/upload-artifact@v4
|
- uses: actions/upload-artifact@v6
|
||||||
if: matrix.package
|
if: matrix.package
|
||||||
with:
|
with:
|
||||||
name: ${{ matrix.platform }}
|
name: ${{ matrix.platform }}
|
||||||
@@ -191,16 +192,18 @@ jobs:
|
|||||||
image: ${{ matrix.container }}
|
image: ${{ matrix.container }}
|
||||||
volumes:
|
volumes:
|
||||||
- /opt:/opt:rw,rshared
|
- /opt:/opt:rw,rshared
|
||||||
- /opt:/__e/node20:ro,rshared
|
- /opt:/__e/node24:ro,rshared
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- container: node:18-alpine3.17
|
- container: node:20-alpine3.20
|
||||||
nodejs_version_major: 18
|
|
||||||
package: true
|
|
||||||
- container: node:20-alpine3.18
|
|
||||||
nodejs_version_major: 20
|
nodejs_version_major: 20
|
||||||
|
package: true
|
||||||
|
- container: node:22-alpine3.20
|
||||||
|
nodejs_version_major: 22
|
||||||
|
- container: node:24-alpine3.22
|
||||||
|
nodejs_version_major: 24
|
||||||
steps:
|
steps:
|
||||||
- name: Allow Linux musl containers on ARM64 runners # https://github.com/actions/runner/issues/801#issuecomment-2394425757
|
- name: Allow Linux musl containers on ARM64 runners # https://github.com/actions/runner/issues/801#issuecomment-2394425757
|
||||||
shell: sh
|
shell: sh
|
||||||
@@ -211,13 +214,13 @@ jobs:
|
|||||||
ln -s /usr/bin/node /opt/bin/node
|
ln -s /usr/bin/node /opt/bin/node
|
||||||
- name: Dependencies
|
- name: Dependencies
|
||||||
run: apk add build-base git python3 font-noto --update-cache
|
run: apk add build-base git python3 font-noto --update-cache
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v6
|
||||||
- run: npm install
|
- run: npm install
|
||||||
- run: npm run build
|
- run: npm run build
|
||||||
- run: npm run test-unit
|
- run: npm run test-unit
|
||||||
- if: matrix.package
|
- if: matrix.package
|
||||||
run: npm run package-from-local-build
|
run: npm run package-from-local-build
|
||||||
- uses: actions/upload-artifact@v4
|
- uses: actions/upload-artifact@v6
|
||||||
if: matrix.package
|
if: matrix.package
|
||||||
with:
|
with:
|
||||||
name: linuxmusl-arm64
|
name: linuxmusl-arm64
|
||||||
@@ -238,20 +241,20 @@ jobs:
|
|||||||
base_image: "balenalib/rpi-raspbian:bullseye"
|
base_image: "balenalib/rpi-raspbian:bullseye"
|
||||||
nodejs_arch: armv6l
|
nodejs_arch: armv6l
|
||||||
nodejs_hostname: unofficial-builds.nodejs.org
|
nodejs_hostname: unofficial-builds.nodejs.org
|
||||||
nodejs_version: "18.17.0"
|
nodejs_version: "20.9.0"
|
||||||
nodejs_version_major: 18
|
nodejs_version_major: 20
|
||||||
- platform: linux-s390x
|
- platform: linux-s390x
|
||||||
base_image: "--platform=linux/s390x s390x/debian:bookworm"
|
base_image: "--platform=linux/s390x s390x/debian:bookworm"
|
||||||
nodejs_arch: s390x
|
nodejs_arch: s390x
|
||||||
nodejs_hostname: nodejs.org
|
nodejs_hostname: nodejs.org
|
||||||
nodejs_version: "18.17.0"
|
nodejs_version: "20.9.0"
|
||||||
nodejs_version_major: 18
|
nodejs_version_major: 20
|
||||||
- platform: linux-ppc64
|
- platform: linux-ppc64
|
||||||
base_image: "--platform=linux/ppc64le ppc64le/debian:bookworm"
|
base_image: "--platform=linux/ppc64le ppc64le/debian:bookworm"
|
||||||
nodejs_arch: ppc64le
|
nodejs_arch: ppc64le
|
||||||
nodejs_hostname: nodejs.org
|
nodejs_hostname: nodejs.org
|
||||||
nodejs_version: "18.17.0"
|
nodejs_version: "20.9.0"
|
||||||
nodejs_version_major: 18
|
nodejs_version_major: 20
|
||||||
- platform: linux-riscv64
|
- platform: linux-riscv64
|
||||||
base_image: "--platform=linux/riscv64 riscv64/debian:trixie"
|
base_image: "--platform=linux/riscv64 riscv64/debian:trixie"
|
||||||
compiler_flags: "-march=rv64gc"
|
compiler_flags: "-march=rv64gc"
|
||||||
@@ -260,7 +263,7 @@ jobs:
|
|||||||
nodejs_version: "20.19.5"
|
nodejs_version: "20.19.5"
|
||||||
nodejs_version_major: 20
|
nodejs_version_major: 20
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v6
|
||||||
- uses: uraimo/run-on-arch-action@v3
|
- uses: uraimo/run-on-arch-action@v3
|
||||||
with:
|
with:
|
||||||
arch: none
|
arch: none
|
||||||
@@ -279,19 +282,39 @@ jobs:
|
|||||||
npm run build
|
npm run build
|
||||||
node --test test/unit/io.js
|
node --test test/unit/io.js
|
||||||
npm run package-from-local-build
|
npm run package-from-local-build
|
||||||
- uses: actions/upload-artifact@v4
|
- uses: actions/upload-artifact@v6
|
||||||
with:
|
with:
|
||||||
name: ${{ matrix.platform }}
|
name: ${{ matrix.platform }}
|
||||||
path: npm/${{ matrix.platform }}
|
path: npm/${{ matrix.platform }}
|
||||||
retention-days: 1
|
retention-days: 1
|
||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
|
build-freebsd:
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
needs: lint
|
||||||
|
name: "build-freebsd"
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
- uses: vmactions/freebsd-vm@v1
|
||||||
|
continue-on-error: true
|
||||||
|
with:
|
||||||
|
prepare: |
|
||||||
|
pkg update -f
|
||||||
|
pkg upgrade -y
|
||||||
|
pkg install -y devel/git devel/pkgconf graphics/vips www/node22 www/npm
|
||||||
|
pkg-config --modversion vips-cpp
|
||||||
|
run: |
|
||||||
|
npm install
|
||||||
|
npm run build
|
||||||
|
node --test test/unit/io.js
|
||||||
build-emscripten:
|
build-emscripten:
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
needs: lint
|
needs: lint
|
||||||
name: "build-wasm32 [package]"
|
name: "build-wasm32 [package]"
|
||||||
runs-on: ubuntu-24.04
|
runs-on: ubuntu-24.04
|
||||||
container: "emscripten/emsdk:4.0.18"
|
container: "emscripten/emsdk:4.0.21"
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: Dependencies
|
- name: Dependencies
|
||||||
@@ -311,7 +334,7 @@ jobs:
|
|||||||
test "$EMSCRIPTEN_VERSION_LIBVIPS" = "$EMSCRIPTEN_VERSION_SHARP"
|
test "$EMSCRIPTEN_VERSION_LIBVIPS" = "$EMSCRIPTEN_VERSION_SHARP"
|
||||||
- run: emmake npm run test-unit
|
- run: emmake npm run test-unit
|
||||||
- run: emmake npm run package-from-local-build
|
- run: emmake npm run package-from-local-build
|
||||||
- uses: actions/upload-artifact@v4
|
- uses: actions/upload-artifact@v6
|
||||||
with:
|
with:
|
||||||
name: wasm32
|
name: wasm32
|
||||||
path: npm/wasm32
|
path: npm/wasm32
|
||||||
@@ -329,12 +352,12 @@ jobs:
|
|||||||
- build-emscripten
|
- build-emscripten
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/download-artifact@v4
|
- uses: actions/download-artifact@v7
|
||||||
with:
|
with:
|
||||||
path: npm
|
path: npm
|
||||||
- name: Create npm workspace tarball
|
- name: Create npm workspace tarball
|
||||||
run: tar -vcaf npm-workspace.tar.xz --directory npm --exclude=from-local-build.js .
|
run: tar -vcaf npm-workspace.tar.xz --directory npm --exclude=from-local-build.js .
|
||||||
- uses: actions/setup-node@v5
|
- uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
node-version: '24'
|
node-version: '24'
|
||||||
- name: Create release notes
|
- name: Create release notes
|
||||||
|
|||||||
2
.github/workflows/npm.yml
vendored
2
.github/workflows/npm.yml
vendored
@@ -96,7 +96,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Install Node.js
|
- name: Install Node.js
|
||||||
if: ${{ matrix.runtime == 'node' }}
|
if: ${{ matrix.runtime == 'node' }}
|
||||||
uses: actions/setup-node@v5
|
uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
node-version: 20
|
node-version: 20
|
||||||
- name: Install pnpm
|
- name: Install pnpm
|
||||||
|
|||||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,7 +1,6 @@
|
|||||||
src/build
|
src/build
|
||||||
src/node_modules
|
src/node_modules
|
||||||
node_modules
|
node_modules
|
||||||
/coverage
|
|
||||||
npm/*/*
|
npm/*/*
|
||||||
!npm/*/package.json
|
!npm/*/package.json
|
||||||
test/bench/node_modules
|
test/bench/node_modules
|
||||||
@@ -9,7 +8,6 @@ test/fixtures/output*
|
|||||||
test/fixtures/vips-properties.xml
|
test/fixtures/vips-properties.xml
|
||||||
test/leak/libvips.supp
|
test/leak/libvips.supp
|
||||||
.DS_Store
|
.DS_Store
|
||||||
.nyc_output
|
|
||||||
.vscode/
|
.vscode/
|
||||||
package-lock.json
|
package-lock.json
|
||||||
.idea
|
.idea
|
||||||
|
|||||||
@@ -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
|
It can be used with all JavaScript runtimes
|
||||||
that provide support for Node-API v9, including
|
that provide support for Node-API v9, including
|
||||||
Node.js (^18.17.0 or >= 20.3.0), Deno and Bun.
|
Node.js (>= 20.9.0), Deno and Bun.
|
||||||
|
|
||||||
Resizing an image is typically 4x-5x faster than using the
|
Resizing an image is typically 4x-5x faster than using the
|
||||||
quickest ImageMagick and GraphicsMagick settings
|
quickest ImageMagick and GraphicsMagick settings
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://biomejs.dev/schemas/2.3.4/schema.json",
|
"$schema": "https://biomejs.dev/schemas/2.3.10/schema.json",
|
||||||
"vcs": {
|
"vcs": {
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"clientKind": "git",
|
"clientKind": "git",
|
||||||
|
|||||||
@@ -11,8 +11,9 @@
|
|||||||
"astro": "astro"
|
"astro": "astro"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@astrojs/starlight": "^0.36.2",
|
"@astrojs/starlight": "^0.37.1",
|
||||||
"astro": "^5.15.3",
|
"astro": "^5.16.6",
|
||||||
"starlight-auto-sidebar": "^0.1.3"
|
"jsdoc-to-markdown": "^9.1.3",
|
||||||
|
"starlight-auto-sidebar": "^0.1.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -326,3 +326,6 @@ GitHub: https://github.com/tpatel
|
|||||||
|
|
||||||
Name: Maël Nison
|
Name: Maël Nison
|
||||||
GitHub: https://github.com/arcanis
|
GitHub: https://github.com/arcanis
|
||||||
|
|
||||||
|
Name: Dmytro Tiapukhin
|
||||||
|
GitHub: https://github.com/eddienubes
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ A `Promise` is returned when `callback` is not provided.
|
|||||||
- `tifftagPhotoshop`: Buffer containing raw TIFFTAG_PHOTOSHOP data, if present
|
- `tifftagPhotoshop`: Buffer containing raw TIFFTAG_PHOTOSHOP data, if present
|
||||||
- `formatMagick`: String containing format for images loaded via *magick
|
- `formatMagick`: String containing format for images loaded via *magick
|
||||||
- `comments`: Array of keyword/text pairs representing PNG text blocks, if present.
|
- `comments`: Array of keyword/text pairs representing PNG text blocks, if present.
|
||||||
|
- `gainMap.image`: HDR gain map, if present, as compressed JPEG image.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -170,7 +170,7 @@ inputStream
|
|||||||
|
|
||||||
|
|
||||||
## sharpen
|
## sharpen
|
||||||
> sharpen([options], [flat], [jagged]) ⇒ <code>Sharp</code>
|
> sharpen([options]) ⇒ <code>Sharp</code>
|
||||||
|
|
||||||
Sharpen the image.
|
Sharpen the image.
|
||||||
|
|
||||||
@@ -189,15 +189,13 @@ See [libvips sharpen](https://www.libvips.org/API/current/method.Image.sharpen.h
|
|||||||
|
|
||||||
| Param | Type | Default | Description |
|
| Param | Type | Default | Description |
|
||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
| [options] | <code>Object</code> \| <code>number</code> | | if present, is an Object with attributes |
|
| [options] | <code>Object</code> | | if present, is an Object with attributes |
|
||||||
| [options.sigma] | <code>number</code> | | the sigma of the Gaussian mask, where `sigma = 1 + radius / 2`, between 0.000001 and 10 |
|
| [options.sigma] | <code>number</code> | | the sigma of the Gaussian mask, where `sigma = 1 + radius / 2`, between 0.000001 and 10 |
|
||||||
| [options.m1] | <code>number</code> | <code>1.0</code> | the level of sharpening to apply to "flat" areas, between 0 and 1000000 |
|
| [options.m1] | <code>number</code> | <code>1.0</code> | the level of sharpening to apply to "flat" areas, between 0 and 1000000 |
|
||||||
| [options.m2] | <code>number</code> | <code>2.0</code> | the level of sharpening to apply to "jagged" areas, between 0 and 1000000 |
|
| [options.m2] | <code>number</code> | <code>2.0</code> | the level of sharpening to apply to "jagged" areas, between 0 and 1000000 |
|
||||||
| [options.x1] | <code>number</code> | <code>2.0</code> | threshold between "flat" and "jagged", between 0 and 1000000 |
|
| [options.x1] | <code>number</code> | <code>2.0</code> | threshold between "flat" and "jagged", between 0 and 1000000 |
|
||||||
| [options.y2] | <code>number</code> | <code>10.0</code> | maximum amount of brightening, between 0 and 1000000 |
|
| [options.y2] | <code>number</code> | <code>10.0</code> | maximum amount of brightening, between 0 and 1000000 |
|
||||||
| [options.y3] | <code>number</code> | <code>20.0</code> | maximum amount of darkening, between 0 and 1000000 |
|
| [options.y3] | <code>number</code> | <code>20.0</code> | maximum amount of darkening, between 0 and 1000000 |
|
||||||
| [flat] | <code>number</code> | | (deprecated) see `options.m1`. |
|
|
||||||
| [jagged] | <code>number</code> | | (deprecated) see `options.m2`. |
|
|
||||||
|
|
||||||
**Example**
|
**Example**
|
||||||
```js
|
```js
|
||||||
@@ -360,8 +358,6 @@ with all white pixel values made fully transparent.
|
|||||||
|
|
||||||
Existing alpha channel values for non-white pixels remain unchanged.
|
Existing alpha channel values for non-white pixels remain unchanged.
|
||||||
|
|
||||||
This feature is experimental and the API may change.
|
|
||||||
|
|
||||||
|
|
||||||
**Since**: 0.32.1
|
**Since**: 0.32.1
|
||||||
**Example**
|
**Example**
|
||||||
|
|||||||
@@ -117,6 +117,38 @@ await sharp(pixelArray, { raw: { width, height, channels } })
|
|||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## toUint8Array
|
||||||
|
> toUint8Array() ⇒ <code>Promise.<{data: Uint8Array, info: Object}></code>
|
||||||
|
|
||||||
|
Write output to a `Uint8Array` backed by a transferable `ArrayBuffer`.
|
||||||
|
JPEG, PNG, WebP, AVIF, TIFF, GIF and raw pixel data output are supported.
|
||||||
|
|
||||||
|
Use [toFormat](#toformat) or one of the format-specific functions such as [jpeg](#jpeg), [png](#png) etc. to set the output format.
|
||||||
|
|
||||||
|
If no explicit format is set, the output format will match the input image, except SVG input which becomes PNG output.
|
||||||
|
|
||||||
|
By default all metadata will be removed, which includes EXIF-based orientation.
|
||||||
|
See [keepExif](#keepexif) and similar methods for control over this.
|
||||||
|
|
||||||
|
Resolves with an `Object` containing:
|
||||||
|
- `data` is the output image as a `Uint8Array` backed by a transferable `ArrayBuffer`.
|
||||||
|
- `info` contains properties relating to the output image such as `width` and `height`.
|
||||||
|
|
||||||
|
|
||||||
|
**Since**: v0.35.0
|
||||||
|
**Example**
|
||||||
|
```js
|
||||||
|
const { data, info } = await sharp(input).toUint8Array();
|
||||||
|
```
|
||||||
|
**Example**
|
||||||
|
```js
|
||||||
|
const { data } = await sharp(input)
|
||||||
|
.avif()
|
||||||
|
.toUint8Array();
|
||||||
|
const base64String = data.toBase64();
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
## keepExif
|
## keepExif
|
||||||
> keepExif() ⇒ <code>Sharp</code>
|
> keepExif() ⇒ <code>Sharp</code>
|
||||||
|
|
||||||
@@ -250,6 +282,27 @@ const outputWithP3 = await sharp(input)
|
|||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## withGainMap
|
||||||
|
> withGainMap() ⇒ <code>Sharp</code>
|
||||||
|
|
||||||
|
If the input contains gain map metadata, use it to convert the main image to HDR (High Dynamic Range) before further processing.
|
||||||
|
The input gain map is discarded.
|
||||||
|
|
||||||
|
If the output is JPEG, generate and attach a new ISO 21496-1 gain map.
|
||||||
|
JPEG output options other than `quality` are ignored.
|
||||||
|
|
||||||
|
This feature is experimental and the API may change.
|
||||||
|
|
||||||
|
|
||||||
|
**Since**: 0.35.0
|
||||||
|
**Example**
|
||||||
|
```js
|
||||||
|
const outputWithGainMap = await sharp(inputWithGainMap)
|
||||||
|
.withGainMap()
|
||||||
|
.toBuffer();
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
## keepXmp
|
## keepXmp
|
||||||
> keepXmp() ⇒ <code>Sharp</code>
|
> keepXmp() ⇒ <code>Sharp</code>
|
||||||
|
|
||||||
@@ -510,6 +563,7 @@ Use these WebP options for output image.
|
|||||||
| [options.delay] | <code>number</code> \| <code>Array.<number></code> | | delay(s) between animation frames (in milliseconds) |
|
| [options.delay] | <code>number</code> \| <code>Array.<number></code> | | delay(s) between animation frames (in milliseconds) |
|
||||||
| [options.minSize] | <code>boolean</code> | <code>false</code> | prevent use of animation key frames to minimise file size (slow) |
|
| [options.minSize] | <code>boolean</code> | <code>false</code> | prevent use of animation key frames to minimise file size (slow) |
|
||||||
| [options.mixed] | <code>boolean</code> | <code>false</code> | allow mixture of lossy and lossless animation frames (slow) |
|
| [options.mixed] | <code>boolean</code> | <code>false</code> | allow mixture of lossy and lossless animation frames (slow) |
|
||||||
|
| [options.exact] | <code>boolean</code> | <code>false</code> | preserve the colour data in transparent pixels |
|
||||||
| [options.force] | <code>boolean</code> | <code>true</code> | force WebP output, otherwise attempt to use input format |
|
| [options.force] | <code>boolean</code> | <code>true</code> | force WebP output, otherwise attempt to use input format |
|
||||||
|
|
||||||
**Example**
|
**Example**
|
||||||
@@ -663,7 +717,7 @@ instead of providing `xres` and `yres` in pixels/mm.
|
|||||||
| [options.xres] | <code>number</code> | <code>1.0</code> | horizontal resolution in pixels/mm |
|
| [options.xres] | <code>number</code> | <code>1.0</code> | horizontal resolution in pixels/mm |
|
||||||
| [options.yres] | <code>number</code> | <code>1.0</code> | vertical resolution in pixels/mm |
|
| [options.yres] | <code>number</code> | <code>1.0</code> | vertical resolution in pixels/mm |
|
||||||
| [options.resolutionUnit] | <code>string</code> | <code>"'inch'"</code> | resolution unit options: inch, cm |
|
| [options.resolutionUnit] | <code>string</code> | <code>"'inch'"</code> | resolution unit options: inch, cm |
|
||||||
| [options.bitdepth] | <code>number</code> | <code>8</code> | reduce bitdepth to 1, 2 or 4 bit |
|
| [options.bitdepth] | <code>number</code> | <code>0</code> | reduce bitdepth to 1, 2 or 4 bit |
|
||||||
| [options.miniswhite] | <code>boolean</code> | <code>false</code> | write 1-bit images as miniswhite |
|
| [options.miniswhite] | <code>boolean</code> | <code>false</code> | write 1-bit images as miniswhite |
|
||||||
|
|
||||||
**Example**
|
**Example**
|
||||||
@@ -687,8 +741,7 @@ Use these AVIF options for output image.
|
|||||||
AVIF image sequences are not supported.
|
AVIF image sequences are not supported.
|
||||||
Prebuilt binaries support a bitdepth of 8 only.
|
Prebuilt binaries support a bitdepth of 8 only.
|
||||||
|
|
||||||
This feature is experimental on the Windows ARM64 platform
|
When using Windows ARM64, this feature requires a CPU with ARM64v8.4 or later.
|
||||||
and requires a CPU with ARM64v8.4 or later.
|
|
||||||
|
|
||||||
|
|
||||||
**Throws**:
|
**Throws**:
|
||||||
@@ -705,6 +758,7 @@ and requires a CPU with ARM64v8.4 or later.
|
|||||||
| [options.effort] | <code>number</code> | <code>4</code> | CPU effort, between 0 (fastest) and 9 (slowest) |
|
| [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.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 |
|
| [options.bitdepth] | <code>number</code> | <code>8</code> | set bitdepth to 8, 10 or 12 bit |
|
||||||
|
| [options.tune] | <code>string</code> | <code>"'iq'"</code> | tune output for a quality metric, one of 'iq' (default), 'ssim' (default when lossless) or 'psnr' |
|
||||||
|
|
||||||
**Example**
|
**Example**
|
||||||
```js
|
```js
|
||||||
@@ -744,6 +798,7 @@ globally-installed libvips compiled with support for libheif, libde265 and x265.
|
|||||||
| [options.effort] | <code>number</code> | <code>4</code> | CPU effort, between 0 (fastest) and 9 (slowest) |
|
| [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.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 |
|
| [options.bitdepth] | <code>number</code> | <code>8</code> | set bitdepth to 8, 10 or 12 bit |
|
||||||
|
| [options.tune] | <code>string</code> | <code>"'ssim'"</code> | tune output for a quality metric, one of 'ssim' (default), 'psnr' or 'iq' |
|
||||||
|
|
||||||
**Example**
|
**Example**
|
||||||
```js
|
```js
|
||||||
|
|||||||
@@ -284,6 +284,7 @@ The `info` response Object will contain `trimOffsetLeft` and `trimOffsetTop` pro
|
|||||||
| [options.background] | <code>string</code> \| <code>Object</code> | <code>"'top-left pixel'"</code> | Background colour, parsed by the [color](https://www.npmjs.org/package/color) module, defaults to that of the top-left pixel. |
|
| [options.background] | <code>string</code> \| <code>Object</code> | <code>"'top-left pixel'"</code> | Background colour, parsed by the [color](https://www.npmjs.org/package/color) module, defaults to that of the top-left pixel. |
|
||||||
| [options.threshold] | <code>number</code> | <code>10</code> | Allowed difference from the above colour, a positive number. |
|
| [options.threshold] | <code>number</code> | <code>10</code> | Allowed difference from the above colour, a positive number. |
|
||||||
| [options.lineArt] | <code>boolean</code> | <code>false</code> | Does the input more closely resemble line art (e.g. vector) rather than being photographic? |
|
| [options.lineArt] | <code>boolean</code> | <code>false</code> | Does the input more closely resemble line art (e.g. vector) rather than being photographic? |
|
||||||
|
| [options.margin] | <code>number</code> | <code>0</code> | Leave a margin around trimmed content, value is in pixels. |
|
||||||
|
|
||||||
**Example**
|
**Example**
|
||||||
```js
|
```js
|
||||||
@@ -320,4 +321,13 @@ const output = await sharp(input)
|
|||||||
threshold: 42,
|
threshold: 42,
|
||||||
})
|
})
|
||||||
.toBuffer();
|
.toBuffer();
|
||||||
|
```
|
||||||
|
**Example**
|
||||||
|
```js
|
||||||
|
// Trim image leaving (up to) a 10 pixel margin around the trimmed content.
|
||||||
|
const output = await sharp(input)
|
||||||
|
.trim({
|
||||||
|
margin: 10
|
||||||
|
})
|
||||||
|
.toBuffer();
|
||||||
```
|
```
|
||||||
46
docs/src/content/docs/changelog/v0.35.0.md
Normal file
46
docs/src/content/docs/changelog/v0.35.0.md
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
---
|
||||||
|
title: v0.35.0 - TBC
|
||||||
|
slug: changelog/v0.35.0
|
||||||
|
---
|
||||||
|
|
||||||
|
* Breaking: Drop support for Node.js 18, now requires Node.js >= 20.9.0.
|
||||||
|
|
||||||
|
* Breaking: Remove `install` script from `package.json` file.
|
||||||
|
Compiling from source is now opt-in via the `build` script.
|
||||||
|
|
||||||
|
* Breaking: AVIF output is now tuned using SSIMULACRA2-based `iq` quality metrics rather than `ssim`.
|
||||||
|
|
||||||
|
* Breaking: Remove deprecated `failOnError` constructor property.
|
||||||
|
|
||||||
|
* Breaking: Remove deprecated `paletteBitDepth` from `metadata` response.
|
||||||
|
|
||||||
|
* Breaking: Remove deprecated properties from `sharpen` operation.
|
||||||
|
|
||||||
|
* Breaking: Rename `format.jp2k` as `format.jp2` for API consistency.
|
||||||
|
|
||||||
|
* Upgrade to libvips v8.18.0 for upstream bug fixes.
|
||||||
|
|
||||||
|
* Ensure TIFF output `bitdepth` option is limited to 1, 2 or 4.
|
||||||
|
|
||||||
|
* Deprecate Windows 32-bit (win32-ia32) prebuilt binaries.
|
||||||
|
|
||||||
|
* Add AVIF/HEIF `tune` option for control over quality metrics.
|
||||||
|
[#4227](https://github.com/lovell/sharp/issues/4227)
|
||||||
|
|
||||||
|
* Add `withGainMap` to process HDR JPEG images with embedded gain maps.
|
||||||
|
[#4314](https://github.com/lovell/sharp/issues/4314)
|
||||||
|
|
||||||
|
* Add `toUint8Array` for output image as a `TypedArray` backed by a transferable `ArrayBuffer`.
|
||||||
|
[#4355](https://github.com/lovell/sharp/issues/4355)
|
||||||
|
|
||||||
|
* TypeScript: Ensure `FormatEnum` keys match reality.
|
||||||
|
[#4475](https://github.com/lovell/sharp/issues/4475)
|
||||||
|
|
||||||
|
* Add `margin` option to `trim` operation.
|
||||||
|
[#4480](https://github.com/lovell/sharp/issues/4480)
|
||||||
|
[@eddienubes](https://github.com/eddienubes)
|
||||||
|
|
||||||
|
* Ensure HEIF primary item is used as default page/frame.
|
||||||
|
[#4487](https://github.com/lovell/sharp/issues/4487)
|
||||||
|
|
||||||
|
* Add WebP `exact` option for control over transparent pixel colour values.
|
||||||
@@ -10,7 +10,7 @@ smaller, web-friendly JPEG, PNG, WebP, GIF and AVIF images of varying dimensions
|
|||||||
|
|
||||||
It can be used with all JavaScript runtimes
|
It can be used with all JavaScript runtimes
|
||||||
that provide support for Node-API v9, including
|
that provide support for Node-API v9, including
|
||||||
Node.js >= 18.17.0, Deno and Bun.
|
Node.js >= 20.9.0, Deno and Bun.
|
||||||
|
|
||||||
Resizing an image is typically 4x-5x faster than using the
|
Resizing an image is typically 4x-5x faster than using the
|
||||||
quickest ImageMagick and GraphicsMagick settings
|
quickest ImageMagick and GraphicsMagick settings
|
||||||
|
|||||||
@@ -20,10 +20,6 @@ npm install sharp
|
|||||||
pnpm add sharp
|
pnpm add sharp
|
||||||
```
|
```
|
||||||
|
|
||||||
When using `pnpm`, add `sharp` to
|
|
||||||
[ignoredBuiltDependencies](https://pnpm.io/settings#ignoredbuiltdependencies)
|
|
||||||
to silence warnings.
|
|
||||||
|
|
||||||
```sh frame="none"
|
```sh frame="none"
|
||||||
yarn add sharp
|
yarn add sharp
|
||||||
```
|
```
|
||||||
@@ -39,7 +35,7 @@ deno run --allow-env --allow-ffi --allow-read --allow-sys ...
|
|||||||
|
|
||||||
## Prerequisites
|
## Prerequisites
|
||||||
|
|
||||||
* Node-API v9 compatible runtime e.g. Node.js ^18.17.0 or >=20.3.0.
|
* Node-API v9 compatible runtime e.g. Node.js >= 20.9.0.
|
||||||
|
|
||||||
## Prebuilt binaries
|
## Prebuilt binaries
|
||||||
|
|
||||||
@@ -54,8 +50,8 @@ Ready-compiled sharp and libvips binaries are provided for use on the most commo
|
|||||||
* Linux s390x (glibc >= 2.36)
|
* Linux s390x (glibc >= 2.36)
|
||||||
* Linux x64 (glibc >= 2.26, musl >= 1.2.2, CPU with SSE4.2)
|
* Linux x64 (glibc >= 2.26, musl >= 1.2.2, CPU with SSE4.2)
|
||||||
* Windows x64
|
* Windows x64
|
||||||
* Windows x86
|
* Windows x86 (deprecated, Node.js 20 only)
|
||||||
* Windows ARM64 (experimental, CPU with ARMv8.4 required for all features)
|
* Windows ARM64 (CPU with ARMv8.4 required for all features)
|
||||||
|
|
||||||
This provides support for the
|
This provides support for the
|
||||||
JPEG, PNG, WebP, AVIF (limited to 8-bit depth), TIFF, GIF and SVG (input) image formats.
|
JPEG, PNG, WebP, AVIF (limited to 8-bit depth), TIFF, GIF and SVG (input) image formats.
|
||||||
@@ -112,13 +108,13 @@ and on macOS when running Node.js under Rosetta.
|
|||||||
|
|
||||||
## Building from source
|
## Building from source
|
||||||
|
|
||||||
This module will be compiled from source when:
|
```sh frame="none"
|
||||||
|
npm install sharp
|
||||||
|
npm explore sharp -- npm run build
|
||||||
|
```
|
||||||
|
|
||||||
* a globally-installed libvips is detected, or
|
The build process will search for a globally-installed libvips.
|
||||||
* using `npm explore sharp -- npm run build`, or
|
This detection logic can be skipped by setting the
|
||||||
* using the deprecated `npm run --build-from-source` at `npm install` time.
|
|
||||||
|
|
||||||
The logic to detect a globally-installed libvips can be skipped by setting the
|
|
||||||
`SHARP_IGNORE_GLOBAL_LIBVIPS` (never try to use it) or
|
`SHARP_IGNORE_GLOBAL_LIBVIPS` (never try to use it) or
|
||||||
`SHARP_FORCE_GLOBAL_LIBVIPS` (always try to use it, even when missing or outdated)
|
`SHARP_FORCE_GLOBAL_LIBVIPS` (always try to use it, even when missing or outdated)
|
||||||
environment variables.
|
environment variables.
|
||||||
@@ -129,21 +125,12 @@ Building from source requires:
|
|||||||
* [node-addon-api](https://www.npmjs.com/package/node-addon-api) version 7+
|
* [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
|
* [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:
|
If `node-addon-api` or `node-gyp` cannot be found, try adding them via:
|
||||||
|
|
||||||
```sh frame="none"
|
```sh frame="none"
|
||||||
npm install --save node-addon-api node-gyp
|
npm install --save node-addon-api node-gyp
|
||||||
```
|
```
|
||||||
|
|
||||||
When using `pnpm`, you may need to add `sharp` to
|
|
||||||
[onlyBuiltDependencies](https://pnpm.io/settings#onlybuiltdependencies)
|
|
||||||
to ensure the installation script can be run.
|
|
||||||
|
|
||||||
For cross-compiling, the `--platform`, `--arch` and `--libc` npm flags
|
|
||||||
(or the `npm_config_platform`, `npm_config_arch` and `npm_config_libc` environment variables)
|
|
||||||
can be used to configure the target environment.
|
|
||||||
|
|
||||||
## WebAssembly
|
## WebAssembly
|
||||||
|
|
||||||
Experimental support is provided for runtime environments that provide
|
Experimental support is provided for runtime environments that provide
|
||||||
@@ -166,10 +153,8 @@ as well as the additional [building from source](#building-from-source) dependen
|
|||||||
|
|
||||||
```sh frame="none"
|
```sh frame="none"
|
||||||
pkg install -y pkgconf vips
|
pkg install -y pkgconf vips
|
||||||
```
|
npm install sharp
|
||||||
|
npm explore sharp -- npm run build
|
||||||
```sh frame="none"
|
|
||||||
cd /usr/ports/graphics/vips/ && make install clean
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Linux memory allocator
|
## Linux memory allocator
|
||||||
@@ -203,6 +188,12 @@ and how to configure it.
|
|||||||
Some package managers use symbolic links
|
Some package managers use symbolic links
|
||||||
but AWS Lambda does not support these within deployment packages.
|
but AWS Lambda does not support these within deployment packages.
|
||||||
|
|
||||||
|
An alternative approach is to use a well-maintained, third-party Lambda Layer:
|
||||||
|
|
||||||
|
- [cbschuld/sharp-aws-lambda-layer](https://github.com/cbschuld/sharp-aws-lambda-layer)
|
||||||
|
- [pH200/sharp-layer](https://github.com/pH200/sharp-layer)
|
||||||
|
- [zoellner/sharp-heic-lambda-layer](https://github.com/zoellner/sharp-heic-lambda-layer)
|
||||||
|
|
||||||
To get the best performance select the largest memory available.
|
To get the best performance select the largest memory available.
|
||||||
A 1536 MB function provides ~12x more CPU time than a 128 MB function.
|
A 1536 MB function provides ~12x more CPU time than a 128 MB function.
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ const {
|
|||||||
spawnRebuild,
|
spawnRebuild,
|
||||||
} = require('../lib/libvips');
|
} = require('../lib/libvips');
|
||||||
|
|
||||||
log('Attempting to build from source via node-gyp');
|
log('Building from source');
|
||||||
log('See https://sharp.pixelplumbing.com/install#building-from-source');
|
log('See https://sharp.pixelplumbing.com/install#building-from-source');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -29,7 +29,7 @@ try {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (useGlobalLibvips(log)) {
|
if (useGlobalLibvips(log)) {
|
||||||
log(`Detected globally-installed libvips v${globalLibvipsVersion()}`);
|
log(`Found globally-installed libvips v${globalLibvipsVersion()}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const status = spawnRebuild();
|
const status = spawnRebuild();
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
/*!
|
|
||||||
Copyright 2013 Lovell Fuller and others.
|
|
||||||
SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
try {
|
|
||||||
const { useGlobalLibvips } = require('../lib/libvips');
|
|
||||||
if (useGlobalLibvips() || process.env.npm_config_build_from_source) {
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
const summary = err.message.split(/\n/).slice(0, 1);
|
|
||||||
console.log(`sharp: skipping install check: ${summary}`);
|
|
||||||
}
|
|
||||||
@@ -278,6 +278,7 @@ const Sharp = function (input, options) {
|
|||||||
trimBackground: [],
|
trimBackground: [],
|
||||||
trimThreshold: -1,
|
trimThreshold: -1,
|
||||||
trimLineArt: false,
|
trimLineArt: false,
|
||||||
|
trimMargin: 0,
|
||||||
dilateWidth: 0,
|
dilateWidth: 0,
|
||||||
erodeWidth: 0,
|
erodeWidth: 0,
|
||||||
gamma: 0,
|
gamma: 0,
|
||||||
@@ -306,6 +307,7 @@ const Sharp = function (input, options) {
|
|||||||
fileOut: '',
|
fileOut: '',
|
||||||
formatOut: 'input',
|
formatOut: 'input',
|
||||||
streamOut: false,
|
streamOut: false,
|
||||||
|
typedArrayOut: false,
|
||||||
keepMetadata: 0,
|
keepMetadata: 0,
|
||||||
withMetadataOrientation: -1,
|
withMetadataOrientation: -1,
|
||||||
withMetadataDensity: 0,
|
withMetadataDensity: 0,
|
||||||
@@ -313,6 +315,7 @@ const Sharp = function (input, options) {
|
|||||||
withExif: {},
|
withExif: {},
|
||||||
withExifMerge: true,
|
withExifMerge: true,
|
||||||
withXmp: '',
|
withXmp: '',
|
||||||
|
withGainMap: false,
|
||||||
resolveWithObject: false,
|
resolveWithObject: false,
|
||||||
loop: -1,
|
loop: -1,
|
||||||
delay: [],
|
delay: [],
|
||||||
@@ -348,6 +351,7 @@ const Sharp = function (input, options) {
|
|||||||
webpEffort: 4,
|
webpEffort: 4,
|
||||||
webpMinSize: false,
|
webpMinSize: false,
|
||||||
webpMixed: false,
|
webpMixed: false,
|
||||||
|
webpExact: false,
|
||||||
gifBitdepth: 8,
|
gifBitdepth: 8,
|
||||||
gifEffort: 7,
|
gifEffort: 7,
|
||||||
gifDither: 1,
|
gifDither: 1,
|
||||||
@@ -362,7 +366,7 @@ const Sharp = function (input, options) {
|
|||||||
tiffPredictor: 'horizontal',
|
tiffPredictor: 'horizontal',
|
||||||
tiffPyramid: false,
|
tiffPyramid: false,
|
||||||
tiffMiniswhite: false,
|
tiffMiniswhite: false,
|
||||||
tiffBitdepth: 8,
|
tiffBitdepth: 0,
|
||||||
tiffTile: false,
|
tiffTile: false,
|
||||||
tiffTileHeight: 256,
|
tiffTileHeight: 256,
|
||||||
tiffTileWidth: 256,
|
tiffTileWidth: 256,
|
||||||
@@ -375,6 +379,7 @@ const Sharp = function (input, options) {
|
|||||||
heifEffort: 4,
|
heifEffort: 4,
|
||||||
heifChromaSubsampling: '4:4:4',
|
heifChromaSubsampling: '4:4:4',
|
||||||
heifBitdepth: 8,
|
heifBitdepth: 8,
|
||||||
|
heifTune: 'ssim',
|
||||||
jxlDistance: 1,
|
jxlDistance: 1,
|
||||||
jxlDecodingTier: 0,
|
jxlDecodingTier: 0,
|
||||||
jxlEffort: 7,
|
jxlEffort: 7,
|
||||||
|
|||||||
72
lib/index.d.ts
vendored
72
lib/index.d.ts
vendored
@@ -259,7 +259,6 @@ declare namespace sharp {
|
|||||||
* Set the pipeline colourspace.
|
* Set the pipeline colourspace.
|
||||||
* The input image will be converted to the provided colourspace at the start of the pipeline.
|
* The input image will be converted to the provided colourspace at the start of the pipeline.
|
||||||
* All operations will use this colourspace before converting to the output colourspace, as defined by toColourspace.
|
* All operations will use this colourspace before converting to the output colourspace, as defined by toColourspace.
|
||||||
* This feature is experimental and has not yet been fully-tested with all operations.
|
|
||||||
*
|
*
|
||||||
* @param colourspace pipeline colourspace e.g. rgb16, scrgb, lab, grey16 ...
|
* @param colourspace pipeline colourspace e.g. rgb16, scrgb, lab, grey16 ...
|
||||||
* @throws {Error} Invalid parameters
|
* @throws {Error} Invalid parameters
|
||||||
@@ -470,21 +469,6 @@ declare namespace sharp {
|
|||||||
*/
|
*/
|
||||||
sharpen(options?: SharpenOptions): Sharp;
|
sharpen(options?: SharpenOptions): Sharp;
|
||||||
|
|
||||||
/**
|
|
||||||
* Sharpen the image.
|
|
||||||
* When used without parameters, performs a fast, mild sharpen of the output image.
|
|
||||||
* When a sigma is provided, performs a slower, more accurate sharpen of the L channel in the LAB colour space.
|
|
||||||
* Fine-grained control over the level of sharpening in "flat" (m1) and "jagged" (m2) areas is available.
|
|
||||||
* @param sigma the sigma of the Gaussian mask, where sigma = 1 + radius / 2.
|
|
||||||
* @param flat the level of sharpening to apply to "flat" areas. (optional, default 1.0)
|
|
||||||
* @param jagged the level of sharpening to apply to "jagged" areas. (optional, default 2.0)
|
|
||||||
* @throws {Error} Invalid parameters
|
|
||||||
* @returns A sharp instance that can be used to chain operations
|
|
||||||
*
|
|
||||||
* @deprecated Use the object parameter `sharpen({sigma, m1, m2, x1, y2, y3})` instead
|
|
||||||
*/
|
|
||||||
sharpen(sigma?: number, flat?: number, jagged?: number): Sharp;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Apply median filter. When used without parameters the default window is 3x3.
|
* Apply median filter. When used without parameters the default window is 3x3.
|
||||||
* @param size square mask size: size x size (optional, default 3)
|
* @param size square mask size: size x size (optional, default 3)
|
||||||
@@ -693,6 +677,13 @@ declare namespace sharp {
|
|||||||
*/
|
*/
|
||||||
toBuffer(options: { resolveWithObject: true }): Promise<{ data: Buffer; info: OutputInfo }>;
|
toBuffer(options: { resolveWithObject: true }): Promise<{ data: Buffer; info: OutputInfo }>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write output to a Uint8Array backed by a transferable ArrayBuffer. JPEG, PNG, WebP, AVIF, TIFF, GIF and RAW output are supported.
|
||||||
|
* By default, the format will match the input image, except SVG input which becomes PNG output.
|
||||||
|
* @returns A promise that resolves with an object containing the Uint8Array data and an info object containing the output image format, size (bytes), width, height and channels
|
||||||
|
*/
|
||||||
|
toUint8Array(): Promise<{ data: Uint8Array; info: OutputInfo }>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Keep all EXIF metadata from the input image in the output image.
|
* Keep all EXIF metadata from the input image in the output image.
|
||||||
* EXIF metadata is unsupported for TIFF output.
|
* EXIF metadata is unsupported for TIFF output.
|
||||||
@@ -849,7 +840,7 @@ declare namespace sharp {
|
|||||||
* @returns A sharp instance that can be used to chain operations
|
* @returns A sharp instance that can be used to chain operations
|
||||||
*/
|
*/
|
||||||
toFormat(
|
toFormat(
|
||||||
format: keyof FormatEnum | AvailableFormatInfo,
|
format: keyof FormatEnum | AvailableFormatInfo | "avif",
|
||||||
options?:
|
options?:
|
||||||
| OutputOptions
|
| OutputOptions
|
||||||
| JpegOptions
|
| JpegOptions
|
||||||
@@ -903,7 +894,7 @@ declare namespace sharp {
|
|||||||
* - sharp.gravity: north, northeast, east, southeast, south, southwest, west, northwest, center or centre.
|
* - sharp.gravity: north, northeast, east, southeast, south, southwest, west, northwest, center or centre.
|
||||||
* - sharp.strategy: cover only, dynamically crop using either the entropy or attention strategy. Some of these values are based on the object-position CSS property.
|
* - sharp.strategy: cover only, dynamically crop using either the entropy or attention strategy. Some of these values are based on the object-position CSS property.
|
||||||
*
|
*
|
||||||
* The experimental strategy-based approach resizes so one dimension is at its target length then repeatedly ranks edge regions,
|
* The strategy-based approach resizes so one dimension is at its target length then repeatedly ranks edge regions,
|
||||||
* discarding the edge with the lowest score based on the selected strategy.
|
* discarding the edge with the lowest score based on the selected strategy.
|
||||||
* - entropy: focus on the region with the highest Shannon entropy.
|
* - entropy: focus on the region with the highest Shannon entropy.
|
||||||
* - attention: focus on the region with the highest luminance frequency, colour saturation and presence of skin tones.
|
* - attention: focus on the region with the highest luminance frequency, colour saturation and presence of skin tones.
|
||||||
@@ -992,14 +983,6 @@ declare namespace sharp {
|
|||||||
* 'none' (least), 'truncated', 'error' or 'warning' (most), highers level imply lower levels, invalid metadata will always abort. (optional, default 'warning')
|
* 'none' (least), 'truncated', 'error' or 'warning' (most), highers level imply lower levels, invalid metadata will always abort. (optional, default 'warning')
|
||||||
*/
|
*/
|
||||||
failOn?: FailOnOptions | undefined;
|
failOn?: FailOnOptions | undefined;
|
||||||
/**
|
|
||||||
* By default halt processing and raise an error when loading invalid images.
|
|
||||||
* Set this flag to false if you'd rather apply a "best effort" to decode images,
|
|
||||||
* even if the data is corrupt or invalid. (optional, default true)
|
|
||||||
*
|
|
||||||
* @deprecated Use `failOn` instead
|
|
||||||
*/
|
|
||||||
failOnError?: boolean | undefined;
|
|
||||||
/**
|
/**
|
||||||
* Do not process input images where the number of pixels (width x height) exceeds this limit.
|
* Do not process input images where the number of pixels (width x height) exceeds this limit.
|
||||||
* Assumes image dimensions contained in the input metadata can be trusted.
|
* Assumes image dimensions contained in the input metadata can be trusted.
|
||||||
@@ -1184,6 +1167,8 @@ declare namespace sharp {
|
|||||||
|
|
||||||
type HeifCompression = 'av1' | 'hevc';
|
type HeifCompression = 'av1' | 'hevc';
|
||||||
|
|
||||||
|
type HeifTune = 'iq' | 'ssim' | 'psnr';
|
||||||
|
|
||||||
type Unit = 'inch' | 'cm';
|
type Unit = 'inch' | 'cm';
|
||||||
|
|
||||||
interface WriteableMetadata {
|
interface WriteableMetadata {
|
||||||
@@ -1277,6 +1262,8 @@ declare namespace sharp {
|
|||||||
formatMagick?: string | undefined;
|
formatMagick?: string | undefined;
|
||||||
/** Array of keyword/text pairs representing PNG text blocks, if present. */
|
/** Array of keyword/text pairs representing PNG text blocks, if present. */
|
||||||
comments?: CommentsMetadata[] | undefined;
|
comments?: CommentsMetadata[] | undefined;
|
||||||
|
/** HDR gain map, if present */
|
||||||
|
gainMap?: GainMapMetadata | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface LevelMetadata {
|
interface LevelMetadata {
|
||||||
@@ -1289,16 +1276,21 @@ declare namespace sharp {
|
|||||||
text: string;
|
text: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface GainMapMetadata {
|
||||||
|
/** JPEG image */
|
||||||
|
image: Buffer;
|
||||||
|
}
|
||||||
|
|
||||||
interface Stats {
|
interface Stats {
|
||||||
/** Array of channel statistics for each channel in the image. */
|
/** Array of channel statistics for each channel in the image. */
|
||||||
channels: ChannelStats[];
|
channels: ChannelStats[];
|
||||||
/** Value to identify if the image is opaque or transparent, based on the presence and use of alpha channel */
|
/** Value to identify if the image is opaque or transparent, based on the presence and use of alpha channel */
|
||||||
isOpaque: boolean;
|
isOpaque: boolean;
|
||||||
/** Histogram-based estimation of greyscale entropy, discarding alpha channel if any (experimental) */
|
/** Histogram-based estimation of greyscale entropy, discarding alpha channel if any */
|
||||||
entropy: number;
|
entropy: number;
|
||||||
/** Estimation of greyscale sharpness based on the standard deviation of a Laplacian convolution, discarding alpha channel if any (experimental) */
|
/** Estimation of greyscale sharpness based on the standard deviation of a Laplacian convolution, discarding alpha channel if any */
|
||||||
sharpness: number;
|
sharpness: number;
|
||||||
/** Object containing most dominant sRGB colour based on a 4096-bin 3D histogram (experimental) */
|
/** Object containing most dominant sRGB colour based on a 4096-bin 3D histogram */
|
||||||
dominant: { r: number; g: number; b: number };
|
dominant: { r: number; g: number; b: number };
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1404,11 +1396,13 @@ declare namespace sharp {
|
|||||||
/** Level of CPU effort to reduce file size, integer 0-6 (optional, default 4) */
|
/** Level of CPU effort to reduce file size, integer 0-6 (optional, default 4) */
|
||||||
effort?: number | undefined;
|
effort?: number | undefined;
|
||||||
/** Prevent use of animation key frames to minimise file size (slow) (optional, default false) */
|
/** Prevent use of animation key frames to minimise file size (slow) (optional, default false) */
|
||||||
minSize?: boolean;
|
minSize?: boolean | undefined;
|
||||||
/** Allow mixture of lossy and lossless animation frames (slow) (optional, default false) */
|
/** Allow mixture of lossy and lossless animation frames (slow) (optional, default false) */
|
||||||
mixed?: boolean;
|
mixed?: boolean | undefined;
|
||||||
/** Preset options: one of default, photo, picture, drawing, icon, text (optional, default 'default') */
|
/** Preset options: one of default, photo, picture, drawing, icon, text (optional, default 'default') */
|
||||||
preset?: keyof PresetEnum | undefined;
|
preset?: keyof PresetEnum | undefined;
|
||||||
|
/** Preserve the colour data in transparent pixels (optional, default false) */
|
||||||
|
exact?: boolean | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface AvifOptions extends OutputOptions {
|
interface AvifOptions extends OutputOptions {
|
||||||
@@ -1422,6 +1416,8 @@ declare namespace sharp {
|
|||||||
chromaSubsampling?: string | undefined;
|
chromaSubsampling?: string | undefined;
|
||||||
/** Set bitdepth to 8, 10 or 12 bit (optional, default 8) */
|
/** Set bitdepth to 8, 10 or 12 bit (optional, default 8) */
|
||||||
bitdepth?: 8 | 10 | 12 | undefined;
|
bitdepth?: 8 | 10 | 12 | undefined;
|
||||||
|
/** Tune output for a quality metric, one of 'iq', 'ssim' or 'psnr' (optional, default 'iq') */
|
||||||
|
tune?: HeifTune | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface HeifOptions extends OutputOptions {
|
interface HeifOptions extends OutputOptions {
|
||||||
@@ -1437,6 +1433,8 @@ declare namespace sharp {
|
|||||||
chromaSubsampling?: string | undefined;
|
chromaSubsampling?: string | undefined;
|
||||||
/** Set bitdepth to 8, 10 or 12 bit (optional, default 8) */
|
/** Set bitdepth to 8, 10 or 12 bit (optional, default 8) */
|
||||||
bitdepth?: 8 | 10 | 12 | undefined;
|
bitdepth?: 8 | 10 | 12 | undefined;
|
||||||
|
/** Tune output for a quality metric, one of 'ssim', 'psnr' or 'iq' (optional, default 'ssim') */
|
||||||
|
tune?: HeifTune | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface GifOptions extends OutputOptions, AnimationOptions {
|
interface GifOptions extends OutputOptions, AnimationOptions {
|
||||||
@@ -1481,8 +1479,8 @@ declare namespace sharp {
|
|||||||
xres?: number | undefined;
|
xres?: number | undefined;
|
||||||
/** Vertical resolution in pixels/mm (optional, default 1.0) */
|
/** Vertical resolution in pixels/mm (optional, default 1.0) */
|
||||||
yres?: number | undefined;
|
yres?: number | undefined;
|
||||||
/** Reduce bitdepth to 1, 2 or 4 bit (optional, default 8) */
|
/** Reduce bitdepth to 1, 2 or 4 bit (optional) */
|
||||||
bitdepth?: 1 | 2 | 4 | 8 | undefined;
|
bitdepth?: 1 | 2 | 4 | undefined;
|
||||||
/** Write 1-bit images as miniswhite (optional, default false) */
|
/** Write 1-bit images as miniswhite (optional, default false) */
|
||||||
miniswhite?: boolean | undefined;
|
miniswhite?: boolean | undefined;
|
||||||
/** Resolution unit options: inch, cm (optional, default 'inch') */
|
/** Resolution unit options: inch, cm (optional, default 'inch') */
|
||||||
@@ -1608,6 +1606,8 @@ declare namespace sharp {
|
|||||||
threshold?: number | undefined;
|
threshold?: number | undefined;
|
||||||
/** Does the input more closely resemble line art (e.g. vector) rather than being photographic? (optional, default false) */
|
/** Does the input more closely resemble line art (e.g. vector) rather than being photographic? (optional, default false) */
|
||||||
lineArt?: boolean | undefined;
|
lineArt?: boolean | undefined;
|
||||||
|
/** Leave a margin around trimmed content, value is in pixels. (optional, default 0) */
|
||||||
|
margin?: number | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface RawOptions {
|
interface RawOptions {
|
||||||
@@ -1913,16 +1913,13 @@ declare namespace sharp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface FormatEnum {
|
interface FormatEnum {
|
||||||
avif: AvailableFormatInfo;
|
|
||||||
dcraw: AvailableFormatInfo;
|
dcraw: AvailableFormatInfo;
|
||||||
dz: AvailableFormatInfo;
|
dz: AvailableFormatInfo;
|
||||||
exr: AvailableFormatInfo;
|
exr: AvailableFormatInfo;
|
||||||
fits: AvailableFormatInfo;
|
fits: AvailableFormatInfo;
|
||||||
gif: AvailableFormatInfo;
|
gif: AvailableFormatInfo;
|
||||||
heif: AvailableFormatInfo;
|
heif: AvailableFormatInfo;
|
||||||
input: AvailableFormatInfo;
|
|
||||||
jpeg: AvailableFormatInfo;
|
jpeg: AvailableFormatInfo;
|
||||||
jpg: AvailableFormatInfo;
|
|
||||||
jp2: AvailableFormatInfo;
|
jp2: AvailableFormatInfo;
|
||||||
jxl: AvailableFormatInfo;
|
jxl: AvailableFormatInfo;
|
||||||
magick: AvailableFormatInfo;
|
magick: AvailableFormatInfo;
|
||||||
@@ -1934,8 +1931,7 @@ declare namespace sharp {
|
|||||||
raw: AvailableFormatInfo;
|
raw: AvailableFormatInfo;
|
||||||
svg: AvailableFormatInfo;
|
svg: AvailableFormatInfo;
|
||||||
tiff: AvailableFormatInfo;
|
tiff: AvailableFormatInfo;
|
||||||
tif: AvailableFormatInfo;
|
vips: AvailableFormatInfo;
|
||||||
v: AvailableFormatInfo;
|
|
||||||
webp: AvailableFormatInfo;
|
webp: AvailableFormatInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
11
lib/input.js
11
lib/input.js
@@ -30,7 +30,7 @@ const inputStreamParameters = [
|
|||||||
// Format-specific
|
// Format-specific
|
||||||
'jp2', 'openSlide', 'pdf', 'raw', 'svg', 'tiff',
|
'jp2', 'openSlide', 'pdf', 'raw', 'svg', 'tiff',
|
||||||
// Deprecated
|
// Deprecated
|
||||||
'failOnError', 'openSlideLevel', 'pdfBackground', 'tiffSubifd'
|
'openSlideLevel', 'pdfBackground', 'tiffSubifd'
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -106,14 +106,6 @@ function _createInputDescriptor (input, inputOptions, containerOptions) {
|
|||||||
}`);
|
}`);
|
||||||
}
|
}
|
||||||
if (is.object(inputOptions)) {
|
if (is.object(inputOptions)) {
|
||||||
// Deprecated: failOnError
|
|
||||||
if (is.defined(inputOptions.failOnError)) {
|
|
||||||
if (is.bool(inputOptions.failOnError)) {
|
|
||||||
inputDescriptor.failOn = inputOptions.failOnError ? 'warning' : 'none';
|
|
||||||
} else {
|
|
||||||
throw is.invalidParameterError('failOnError', 'boolean', inputOptions.failOnError);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// failOn
|
// failOn
|
||||||
if (is.defined(inputOptions.failOn)) {
|
if (is.defined(inputOptions.failOn)) {
|
||||||
if (is.string(inputOptions.failOn) && is.inArray(inputOptions.failOn, ['none', 'truncated', 'error', 'warning'])) {
|
if (is.string(inputOptions.failOn) && is.inArray(inputOptions.failOn, ['none', 'truncated', 'error', 'warning'])) {
|
||||||
@@ -607,6 +599,7 @@ function _isStreamInput () {
|
|||||||
* - `tifftagPhotoshop`: Buffer containing raw TIFFTAG_PHOTOSHOP data, if present
|
* - `tifftagPhotoshop`: Buffer containing raw TIFFTAG_PHOTOSHOP data, if present
|
||||||
* - `formatMagick`: String containing format for images loaded via *magick
|
* - `formatMagick`: String containing format for images loaded via *magick
|
||||||
* - `comments`: Array of keyword/text pairs representing PNG text blocks, if present.
|
* - `comments`: Array of keyword/text pairs representing PNG text blocks, if present.
|
||||||
|
* - `gainMap.image`: HDR gain map, if present, as compressed JPEG image.
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* const metadata = await sharp(input).metadata();
|
* const metadata = await sharp(input).metadata();
|
||||||
|
|||||||
@@ -259,45 +259,18 @@ function affine (matrix, options) {
|
|||||||
* })
|
* })
|
||||||
* .toBuffer();
|
* .toBuffer();
|
||||||
*
|
*
|
||||||
* @param {Object|number} [options] - if present, is an Object with attributes
|
* @param {Object} [options] - if present, is an Object with attributes
|
||||||
* @param {number} [options.sigma] - the sigma of the Gaussian mask, where `sigma = 1 + radius / 2`, between 0.000001 and 10
|
* @param {number} [options.sigma] - the sigma of the Gaussian mask, where `sigma = 1 + radius / 2`, between 0.000001 and 10
|
||||||
* @param {number} [options.m1=1.0] - the level of sharpening to apply to "flat" areas, between 0 and 1000000
|
* @param {number} [options.m1=1.0] - the level of sharpening to apply to "flat" areas, between 0 and 1000000
|
||||||
* @param {number} [options.m2=2.0] - the level of sharpening to apply to "jagged" areas, between 0 and 1000000
|
* @param {number} [options.m2=2.0] - the level of sharpening to apply to "jagged" areas, between 0 and 1000000
|
||||||
* @param {number} [options.x1=2.0] - threshold between "flat" and "jagged", between 0 and 1000000
|
* @param {number} [options.x1=2.0] - threshold between "flat" and "jagged", between 0 and 1000000
|
||||||
* @param {number} [options.y2=10.0] - maximum amount of brightening, between 0 and 1000000
|
* @param {number} [options.y2=10.0] - maximum amount of brightening, between 0 and 1000000
|
||||||
* @param {number} [options.y3=20.0] - maximum amount of darkening, between 0 and 1000000
|
* @param {number} [options.y3=20.0] - maximum amount of darkening, between 0 and 1000000
|
||||||
* @param {number} [flat] - (deprecated) see `options.m1`.
|
|
||||||
* @param {number} [jagged] - (deprecated) see `options.m2`.
|
|
||||||
* @returns {Sharp}
|
* @returns {Sharp}
|
||||||
* @throws {Error} Invalid parameters
|
* @throws {Error} Invalid parameters
|
||||||
*/
|
*/
|
||||||
function sharpen (options, flat, jagged) {
|
function sharpen (options) {
|
||||||
if (!is.defined(options)) {
|
if (is.plainObject(options)) {
|
||||||
// No arguments: default to mild sharpen
|
|
||||||
this.options.sharpenSigma = -1;
|
|
||||||
} else if (is.bool(options)) {
|
|
||||||
// Deprecated boolean argument: apply mild sharpen?
|
|
||||||
this.options.sharpenSigma = options ? -1 : 0;
|
|
||||||
} else if (is.number(options) && is.inRange(options, 0.01, 10000)) {
|
|
||||||
// Deprecated numeric argument: specific sigma
|
|
||||||
this.options.sharpenSigma = options;
|
|
||||||
// Deprecated control over flat areas
|
|
||||||
if (is.defined(flat)) {
|
|
||||||
if (is.number(flat) && is.inRange(flat, 0, 10000)) {
|
|
||||||
this.options.sharpenM1 = flat;
|
|
||||||
} else {
|
|
||||||
throw is.invalidParameterError('flat', 'number between 0 and 10000', flat);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Deprecated control over jagged areas
|
|
||||||
if (is.defined(jagged)) {
|
|
||||||
if (is.number(jagged) && is.inRange(jagged, 0, 10000)) {
|
|
||||||
this.options.sharpenM2 = jagged;
|
|
||||||
} else {
|
|
||||||
throw is.invalidParameterError('jagged', 'number between 0 and 10000', jagged);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (is.plainObject(options)) {
|
|
||||||
if (is.number(options.sigma) && is.inRange(options.sigma, 0.000001, 10)) {
|
if (is.number(options.sigma) && is.inRange(options.sigma, 0.000001, 10)) {
|
||||||
this.options.sharpenSigma = options.sigma;
|
this.options.sharpenSigma = options.sigma;
|
||||||
} else {
|
} else {
|
||||||
@@ -339,7 +312,7 @@ function sharpen (options, flat, jagged) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw is.invalidParameterError('sigma', 'number between 0.01 and 10000', options);
|
this.options.sharpenSigma = -1;
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@@ -510,8 +483,6 @@ function flatten (options) {
|
|||||||
*
|
*
|
||||||
* Existing alpha channel values for non-white pixels remain unchanged.
|
* Existing alpha channel values for non-white pixels remain unchanged.
|
||||||
*
|
*
|
||||||
* This feature is experimental and the API may change.
|
|
||||||
*
|
|
||||||
* @since 0.32.1
|
* @since 0.32.1
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ function toFile (fileOut, callback) {
|
|||||||
err = new Error('Missing output file path');
|
err = new Error('Missing output file path');
|
||||||
} else if (is.string(this.options.input.file) && path.resolve(this.options.input.file) === path.resolve(fileOut)) {
|
} else if (is.string(this.options.input.file) && path.resolve(this.options.input.file) === path.resolve(fileOut)) {
|
||||||
err = new Error('Cannot use same file for input and output');
|
err = new Error('Cannot use same file for input and output');
|
||||||
} else if (jp2Regex.test(path.extname(fileOut)) && !this.constructor.format.jp2k.output.file) {
|
} else if (jp2Regex.test(path.extname(fileOut)) && !this.constructor.format.jp2.output.file) {
|
||||||
err = errJp2Save();
|
err = errJp2Save();
|
||||||
}
|
}
|
||||||
if (err) {
|
if (err) {
|
||||||
@@ -164,6 +164,41 @@ function toBuffer (options, callback) {
|
|||||||
return this._pipeline(is.fn(options) ? options : callback, stack);
|
return this._pipeline(is.fn(options) ? options : callback, stack);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write output to a `Uint8Array` backed by a transferable `ArrayBuffer`.
|
||||||
|
* JPEG, PNG, WebP, AVIF, TIFF, GIF and raw pixel data output are supported.
|
||||||
|
*
|
||||||
|
* Use {@link #toformat toFormat} or one of the format-specific functions such as {@link #jpeg jpeg}, {@link #png png} etc. to set the output format.
|
||||||
|
*
|
||||||
|
* If no explicit format is set, the output format will match the input image, except SVG input which becomes PNG output.
|
||||||
|
*
|
||||||
|
* By default all metadata will be removed, which includes EXIF-based orientation.
|
||||||
|
* See {@link #keepexif keepExif} and similar methods for control over this.
|
||||||
|
*
|
||||||
|
* Resolves with an `Object` containing:
|
||||||
|
* - `data` is the output image as a `Uint8Array` backed by a transferable `ArrayBuffer`.
|
||||||
|
* - `info` contains properties relating to the output image such as `width` and `height`.
|
||||||
|
*
|
||||||
|
* @since v0.35.0
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* const { data, info } = await sharp(input).toUint8Array();
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* const { data } = await sharp(input)
|
||||||
|
* .avif()
|
||||||
|
* .toUint8Array();
|
||||||
|
* const base64String = data.toBase64();
|
||||||
|
*
|
||||||
|
* @returns {Promise<{ data: Uint8Array, info: Object }>}
|
||||||
|
*/
|
||||||
|
function toUint8Array () {
|
||||||
|
this.options.resolveWithObject = true;
|
||||||
|
this.options.typedArrayOut = true;
|
||||||
|
const stack = Error();
|
||||||
|
return this._pipeline(null, stack);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Keep all EXIF metadata from the input image in the output image.
|
* Keep all EXIF metadata from the input image in the output image.
|
||||||
*
|
*
|
||||||
@@ -319,6 +354,30 @@ function withIccProfile (icc, options) {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the input contains gain map metadata, use it to convert the main image to HDR (High Dynamic Range) before further processing.
|
||||||
|
* The input gain map is discarded.
|
||||||
|
*
|
||||||
|
* If the output is JPEG, generate and attach a new ISO 21496-1 gain map.
|
||||||
|
* JPEG output options other than `quality` are ignored.
|
||||||
|
*
|
||||||
|
* This feature is experimental and the API may change.
|
||||||
|
*
|
||||||
|
* @since 0.35.0
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* const outputWithGainMap = await sharp(inputWithGainMap)
|
||||||
|
* .withGainMap()
|
||||||
|
* .toBuffer();
|
||||||
|
*
|
||||||
|
* @returns {Sharp}
|
||||||
|
*/
|
||||||
|
function withGainMap() {
|
||||||
|
this.options.withGainMap = true;
|
||||||
|
this.options.colourspace = 'scrgb';
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Keep XMP metadata from the input image in the output image.
|
* Keep XMP metadata from the input image in the output image.
|
||||||
*
|
*
|
||||||
@@ -690,6 +749,7 @@ function png (options) {
|
|||||||
* @param {number|number[]} [options.delay] - delay(s) between animation frames (in milliseconds)
|
* @param {number|number[]} [options.delay] - delay(s) between animation frames (in milliseconds)
|
||||||
* @param {boolean} [options.minSize=false] - prevent use of animation key frames to minimise file size (slow)
|
* @param {boolean} [options.minSize=false] - prevent use of animation key frames to minimise file size (slow)
|
||||||
* @param {boolean} [options.mixed=false] - allow mixture of lossy and lossless animation frames (slow)
|
* @param {boolean} [options.mixed=false] - allow mixture of lossy and lossless animation frames (slow)
|
||||||
|
* @param {boolean} [options.exact=false] - preserve the colour data in transparent pixels
|
||||||
* @param {boolean} [options.force=true] - force WebP output, otherwise attempt to use input format
|
* @param {boolean} [options.force=true] - force WebP output, otherwise attempt to use input format
|
||||||
* @returns {Sharp}
|
* @returns {Sharp}
|
||||||
* @throws {Error} Invalid options
|
* @throws {Error} Invalid options
|
||||||
@@ -742,6 +802,9 @@ function webp (options) {
|
|||||||
if (is.defined(options.mixed)) {
|
if (is.defined(options.mixed)) {
|
||||||
this._setBooleanOption('webpMixed', options.mixed);
|
this._setBooleanOption('webpMixed', options.mixed);
|
||||||
}
|
}
|
||||||
|
if (is.defined(options.exact)) {
|
||||||
|
this._setBooleanOption('webpExact', options.exact);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
trySetAnimationOptions(options, this.options);
|
trySetAnimationOptions(options, this.options);
|
||||||
return this._updateFormatOut('webp', options);
|
return this._updateFormatOut('webp', options);
|
||||||
@@ -887,7 +950,7 @@ function gif (options) {
|
|||||||
*/
|
*/
|
||||||
function jp2 (options) {
|
function jp2 (options) {
|
||||||
/* node:coverage ignore next 41 */
|
/* node:coverage ignore next 41 */
|
||||||
if (!this.constructor.format.jp2k.output.buffer) {
|
if (!this.constructor.format.jp2.output.buffer) {
|
||||||
throw errJp2Save();
|
throw errJp2Save();
|
||||||
}
|
}
|
||||||
if (is.object(options)) {
|
if (is.object(options)) {
|
||||||
@@ -992,7 +1055,7 @@ function trySetAnimationOptions (source, target) {
|
|||||||
* @param {number} [options.xres=1.0] - horizontal resolution in pixels/mm
|
* @param {number} [options.xres=1.0] - horizontal resolution in pixels/mm
|
||||||
* @param {number} [options.yres=1.0] - vertical resolution in pixels/mm
|
* @param {number} [options.yres=1.0] - vertical resolution in pixels/mm
|
||||||
* @param {string} [options.resolutionUnit='inch'] - resolution unit options: inch, cm
|
* @param {string} [options.resolutionUnit='inch'] - resolution unit options: inch, cm
|
||||||
* @param {number} [options.bitdepth=8] - reduce bitdepth to 1, 2 or 4 bit
|
* @param {number} [options.bitdepth=0] - reduce bitdepth to 1, 2 or 4 bit
|
||||||
* @param {boolean} [options.miniswhite=false] - write 1-bit images as miniswhite
|
* @param {boolean} [options.miniswhite=false] - write 1-bit images as miniswhite
|
||||||
* @returns {Sharp}
|
* @returns {Sharp}
|
||||||
* @throws {Error} Invalid options
|
* @throws {Error} Invalid options
|
||||||
@@ -1007,10 +1070,10 @@ function tiff (options) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (is.defined(options.bitdepth)) {
|
if (is.defined(options.bitdepth)) {
|
||||||
if (is.integer(options.bitdepth) && is.inArray(options.bitdepth, [1, 2, 4, 8])) {
|
if (is.integer(options.bitdepth) && is.inArray(options.bitdepth, [1, 2, 4])) {
|
||||||
this.options.tiffBitdepth = options.bitdepth;
|
this.options.tiffBitdepth = options.bitdepth;
|
||||||
} else {
|
} else {
|
||||||
throw is.invalidParameterError('bitdepth', '1, 2, 4 or 8', options.bitdepth);
|
throw is.invalidParameterError('bitdepth', '1, 2 or 4', options.bitdepth);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// tiling
|
// tiling
|
||||||
@@ -1092,8 +1155,7 @@ function tiff (options) {
|
|||||||
* AVIF image sequences are not supported.
|
* AVIF image sequences are not supported.
|
||||||
* Prebuilt binaries support a bitdepth of 8 only.
|
* Prebuilt binaries support a bitdepth of 8 only.
|
||||||
*
|
*
|
||||||
* This feature is experimental on the Windows ARM64 platform
|
* When using Windows ARM64, this feature requires a CPU with ARM64v8.4 or later.
|
||||||
* and requires a CPU with ARM64v8.4 or later.
|
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* const data = await sharp(input)
|
* const data = await sharp(input)
|
||||||
@@ -1113,11 +1175,13 @@ function tiff (options) {
|
|||||||
* @param {number} [options.effort=4] - CPU effort, between 0 (fastest) and 9 (slowest)
|
* @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 {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
|
* @param {number} [options.bitdepth=8] - set bitdepth to 8, 10 or 12 bit
|
||||||
|
* @param {string} [options.tune='iq'] - tune output for a quality metric, one of 'iq' (default), 'ssim' (default when lossless) or 'psnr'
|
||||||
* @returns {Sharp}
|
* @returns {Sharp}
|
||||||
* @throws {Error} Invalid options
|
* @throws {Error} Invalid options
|
||||||
*/
|
*/
|
||||||
function avif (options) {
|
function avif (options) {
|
||||||
return this.heif({ ...options, compression: 'av1' });
|
const tune = is.object(options) && is.defined(options.tune) ? options.tune : 'iq';
|
||||||
|
return this.heif({ ...options, compression: 'av1', tune });
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1140,6 +1204,7 @@ function avif (options) {
|
|||||||
* @param {number} [options.effort=4] - CPU effort, between 0 (fastest) and 9 (slowest)
|
* @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 {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
|
* @param {number} [options.bitdepth=8] - set bitdepth to 8, 10 or 12 bit
|
||||||
|
* @param {string} [options.tune='ssim'] - tune output for a quality metric, one of 'ssim' (default), 'psnr' or 'iq'
|
||||||
* @returns {Sharp}
|
* @returns {Sharp}
|
||||||
* @throws {Error} Invalid options
|
* @throws {Error} Invalid options
|
||||||
*/
|
*/
|
||||||
@@ -1188,6 +1253,17 @@ function heif (options) {
|
|||||||
throw is.invalidParameterError('bitdepth', '8, 10 or 12', options.bitdepth);
|
throw is.invalidParameterError('bitdepth', '8, 10 or 12', options.bitdepth);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (is.defined(options.tune)) {
|
||||||
|
if (is.string(options.tune) && is.inArray(options.tune, ['iq', 'ssim', 'psnr'])) {
|
||||||
|
if (this.options.heifLossless && options.tune === 'iq') {
|
||||||
|
this.options.heifTune = 'ssim';
|
||||||
|
} else {
|
||||||
|
this.options.heifTune = options.tune;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw is.invalidParameterError('tune', 'one of: psnr, ssim, iq', options.tune);
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
throw is.invalidParameterError('options', 'Object', options);
|
throw is.invalidParameterError('options', 'Object', options);
|
||||||
}
|
}
|
||||||
@@ -1635,11 +1711,13 @@ module.exports = (Sharp) => {
|
|||||||
// Public
|
// Public
|
||||||
toFile,
|
toFile,
|
||||||
toBuffer,
|
toBuffer,
|
||||||
|
toUint8Array,
|
||||||
keepExif,
|
keepExif,
|
||||||
withExif,
|
withExif,
|
||||||
withExifMerge,
|
withExifMerge,
|
||||||
keepIccProfile,
|
keepIccProfile,
|
||||||
withIccProfile,
|
withIccProfile,
|
||||||
|
withGainMap,
|
||||||
keepXmp,
|
keepXmp,
|
||||||
withXmp,
|
withXmp,
|
||||||
keepMetadata,
|
keepMetadata,
|
||||||
|
|||||||
@@ -540,10 +540,19 @@ function extract (options) {
|
|||||||
* })
|
* })
|
||||||
* .toBuffer();
|
* .toBuffer();
|
||||||
*
|
*
|
||||||
|
* @example
|
||||||
|
* // Trim image leaving (up to) a 10 pixel margin around the trimmed content.
|
||||||
|
* const output = await sharp(input)
|
||||||
|
* .trim({
|
||||||
|
* margin: 10
|
||||||
|
* })
|
||||||
|
* .toBuffer();
|
||||||
|
*
|
||||||
* @param {Object} [options]
|
* @param {Object} [options]
|
||||||
* @param {string|Object} [options.background='top-left pixel'] - Background colour, parsed by the [color](https://www.npmjs.org/package/color) module, defaults to that of the top-left pixel.
|
* @param {string|Object} [options.background='top-left pixel'] - Background colour, parsed by the [color](https://www.npmjs.org/package/color) module, defaults to that of the top-left pixel.
|
||||||
* @param {number} [options.threshold=10] - Allowed difference from the above colour, a positive number.
|
* @param {number} [options.threshold=10] - Allowed difference from the above colour, a positive number.
|
||||||
* @param {boolean} [options.lineArt=false] - Does the input more closely resemble line art (e.g. vector) rather than being photographic?
|
* @param {boolean} [options.lineArt=false] - Does the input more closely resemble line art (e.g. vector) rather than being photographic?
|
||||||
|
* @param {number} [options.margin=0] - Leave a margin around trimmed content, value is in pixels.
|
||||||
* @returns {Sharp}
|
* @returns {Sharp}
|
||||||
* @throws {Error} Invalid parameters
|
* @throws {Error} Invalid parameters
|
||||||
*/
|
*/
|
||||||
@@ -564,6 +573,13 @@ function trim (options) {
|
|||||||
if (is.defined(options.lineArt)) {
|
if (is.defined(options.lineArt)) {
|
||||||
this._setBooleanOption('trimLineArt', options.lineArt);
|
this._setBooleanOption('trimLineArt', options.lineArt);
|
||||||
}
|
}
|
||||||
|
if (is.defined(options.margin)) {
|
||||||
|
if (is.integer(options.margin) && options.margin >= 0) {
|
||||||
|
this.options.trimMargin = options.margin;
|
||||||
|
} else {
|
||||||
|
throw is.invalidParameterError('margin', 'positive integer', options.margin);
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
throw is.invalidParameterError('trim', 'object', options);
|
throw is.invalidParameterError('trim', 'object', options);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,12 +7,13 @@
|
|||||||
|
|
||||||
const { familySync, versionSync } = require('detect-libc');
|
const { familySync, versionSync } = require('detect-libc');
|
||||||
|
|
||||||
|
const { version } = require('../package.json');
|
||||||
const { runtimePlatformArch, isUnsupportedNodeRuntime, prebuiltPlatforms, minimumLibvipsVersion } = require('./libvips');
|
const { runtimePlatformArch, isUnsupportedNodeRuntime, prebuiltPlatforms, minimumLibvipsVersion } = require('./libvips');
|
||||||
const runtimePlatform = runtimePlatformArch();
|
const runtimePlatform = runtimePlatformArch();
|
||||||
|
|
||||||
const paths = [
|
const paths = [
|
||||||
`../src/build/Release/sharp-${runtimePlatform}.node`,
|
`../src/build/Release/sharp-${runtimePlatform}-${version}.node`,
|
||||||
'../src/build/Release/sharp-wasm32.node',
|
`../src/build/Release/sharp-wasm32-${version}.node`,
|
||||||
`@img/sharp-${runtimePlatform}/sharp.node`,
|
`@img/sharp-${runtimePlatform}/sharp.node`,
|
||||||
'@img/sharp-wasm32/sharp.node'
|
'@img/sharp-wasm32/sharp.node'
|
||||||
];
|
];
|
||||||
@@ -72,6 +73,7 @@ if (sharp) {
|
|||||||
} else {
|
} else {
|
||||||
help.push(
|
help.push(
|
||||||
`- Manually install libvips >= ${minimumLibvipsVersion}`,
|
`- Manually install libvips >= ${minimumLibvipsVersion}`,
|
||||||
|
' See https://sharp.pixelplumbing.com/install#building-from-source',
|
||||||
'- Add experimental WebAssembly-based dependencies:',
|
'- Add experimental WebAssembly-based dependencies:',
|
||||||
' npm install --cpu=wasm32 sharp',
|
' npm install --cpu=wasm32 sharp',
|
||||||
' npm install @img/sharp-wasm32'
|
' npm install @img/sharp-wasm32'
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ const format = sharp.format();
|
|||||||
format.heif.output.alias = ['avif', 'heic'];
|
format.heif.output.alias = ['avif', 'heic'];
|
||||||
format.jpeg.output.alias = ['jpe', 'jpg'];
|
format.jpeg.output.alias = ['jpe', 'jpg'];
|
||||||
format.tiff.output.alias = ['tif'];
|
format.tiff.output.alias = ['tif'];
|
||||||
format.jp2k.output.alias = ['j2c', 'j2k', 'jp2', 'jpx'];
|
format.jp2.output.alias = ['j2c', 'j2k', 'jp2', 'jpx'];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An Object containing the available interpolators and their proper values
|
* An Object containing the available interpolators and their proper values
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@img/sharp-darwin-arm64",
|
"name": "@img/sharp-darwin-arm64",
|
||||||
"version": "0.34.5",
|
"version": "0.35.0-rc.0",
|
||||||
"description": "Prebuilt sharp for use with macOS 64-bit ARM",
|
"description": "Prebuilt sharp for use with macOS 64-bit ARM",
|
||||||
"author": "Lovell Fuller <npm@lovell.info>",
|
"author": "Lovell Fuller <npm@lovell.info>",
|
||||||
"homepage": "https://sharp.pixelplumbing.com",
|
"homepage": "https://sharp.pixelplumbing.com",
|
||||||
@@ -15,9 +15,10 @@
|
|||||||
},
|
},
|
||||||
"preferUnplugged": true,
|
"preferUnplugged": true,
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@img/sharp-libvips-darwin-arm64": "1.2.4"
|
"@img/sharp-libvips-darwin-arm64": "1.3.0-rc.2"
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
|
"index.cjs",
|
||||||
"lib"
|
"lib"
|
||||||
],
|
],
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
@@ -25,11 +26,11 @@
|
|||||||
},
|
},
|
||||||
"type": "commonjs",
|
"type": "commonjs",
|
||||||
"exports": {
|
"exports": {
|
||||||
"./sharp.node": "./lib/sharp-darwin-arm64.node",
|
"./sharp.node": "./index.cjs",
|
||||||
"./package": "./package.json"
|
"./package": "./package.json"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
"node": ">=20.9.0"
|
||||||
},
|
},
|
||||||
"os": [
|
"os": [
|
||||||
"darwin"
|
"darwin"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@img/sharp-darwin-x64",
|
"name": "@img/sharp-darwin-x64",
|
||||||
"version": "0.34.5",
|
"version": "0.35.0-rc.0",
|
||||||
"description": "Prebuilt sharp for use with macOS x64",
|
"description": "Prebuilt sharp for use with macOS x64",
|
||||||
"author": "Lovell Fuller <npm@lovell.info>",
|
"author": "Lovell Fuller <npm@lovell.info>",
|
||||||
"homepage": "https://sharp.pixelplumbing.com",
|
"homepage": "https://sharp.pixelplumbing.com",
|
||||||
@@ -15,9 +15,10 @@
|
|||||||
},
|
},
|
||||||
"preferUnplugged": true,
|
"preferUnplugged": true,
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@img/sharp-libvips-darwin-x64": "1.2.4"
|
"@img/sharp-libvips-darwin-x64": "1.3.0-rc.2"
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
|
"index.cjs",
|
||||||
"lib"
|
"lib"
|
||||||
],
|
],
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
@@ -25,11 +26,11 @@
|
|||||||
},
|
},
|
||||||
"type": "commonjs",
|
"type": "commonjs",
|
||||||
"exports": {
|
"exports": {
|
||||||
"./sharp.node": "./lib/sharp-darwin-x64.node",
|
"./sharp.node": "./index.cjs",
|
||||||
"./package": "./package.json"
|
"./package": "./package.json"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
"node": ">=20.9.0"
|
||||||
},
|
},
|
||||||
"os": [
|
"os": [
|
||||||
"darwin"
|
"darwin"
|
||||||
|
|||||||
@@ -44,9 +44,10 @@ cpSync(releaseDir, libDir, {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Generate README
|
// Generate README and index.cjs
|
||||||
const { name, description } = require(`./${platform}/package.json`);
|
const { version, name, description } = require(`./${platform}/package.json`);
|
||||||
writeFileSync(join(destDir, 'README.md'), `# \`${name}\`\n\n${description}.\n${licensing}`);
|
writeFileSync(join(destDir, 'README.md'), `# \`${name}\`\n\n${description}.\n${licensing}`);
|
||||||
|
writeFileSync(join(destDir, 'index.cjs'), `module.exports = require('./lib/sharp-${platform}-${version}.node');`);
|
||||||
|
|
||||||
// Copy Apache-2.0 LICENSE
|
// Copy Apache-2.0 LICENSE
|
||||||
copyFileSync(join(__dirname, '..', 'LICENSE'), join(destDir, 'LICENSE'));
|
copyFileSync(join(__dirname, '..', 'LICENSE'), join(destDir, 'LICENSE'));
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@img/sharp-linux-arm",
|
"name": "@img/sharp-linux-arm",
|
||||||
"version": "0.34.5",
|
"version": "0.35.0-rc.0",
|
||||||
"description": "Prebuilt sharp for use with Linux (glibc) ARM (32-bit)",
|
"description": "Prebuilt sharp for use with Linux (glibc) ARM (32-bit)",
|
||||||
"author": "Lovell Fuller <npm@lovell.info>",
|
"author": "Lovell Fuller <npm@lovell.info>",
|
||||||
"homepage": "https://sharp.pixelplumbing.com",
|
"homepage": "https://sharp.pixelplumbing.com",
|
||||||
@@ -15,9 +15,10 @@
|
|||||||
},
|
},
|
||||||
"preferUnplugged": true,
|
"preferUnplugged": true,
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@img/sharp-libvips-linux-arm": "1.2.4"
|
"@img/sharp-libvips-linux-arm": "1.3.0-rc.2"
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
|
"index.cjs",
|
||||||
"lib"
|
"lib"
|
||||||
],
|
],
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
@@ -25,11 +26,11 @@
|
|||||||
},
|
},
|
||||||
"type": "commonjs",
|
"type": "commonjs",
|
||||||
"exports": {
|
"exports": {
|
||||||
"./sharp.node": "./lib/sharp-linux-arm.node",
|
"./sharp.node": "./index.cjs",
|
||||||
"./package": "./package.json"
|
"./package": "./package.json"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
"node": ">=20.9.0"
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"glibc": ">=2.31"
|
"glibc": ">=2.31"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@img/sharp-linux-arm64",
|
"name": "@img/sharp-linux-arm64",
|
||||||
"version": "0.34.5",
|
"version": "0.35.0-rc.0",
|
||||||
"description": "Prebuilt sharp for use with Linux (glibc) 64-bit ARM",
|
"description": "Prebuilt sharp for use with Linux (glibc) 64-bit ARM",
|
||||||
"author": "Lovell Fuller <npm@lovell.info>",
|
"author": "Lovell Fuller <npm@lovell.info>",
|
||||||
"homepage": "https://sharp.pixelplumbing.com",
|
"homepage": "https://sharp.pixelplumbing.com",
|
||||||
@@ -15,9 +15,10 @@
|
|||||||
},
|
},
|
||||||
"preferUnplugged": true,
|
"preferUnplugged": true,
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@img/sharp-libvips-linux-arm64": "1.2.4"
|
"@img/sharp-libvips-linux-arm64": "1.3.0-rc.2"
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
|
"index.cjs",
|
||||||
"lib"
|
"lib"
|
||||||
],
|
],
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
@@ -25,11 +26,11 @@
|
|||||||
},
|
},
|
||||||
"type": "commonjs",
|
"type": "commonjs",
|
||||||
"exports": {
|
"exports": {
|
||||||
"./sharp.node": "./lib/sharp-linux-arm64.node",
|
"./sharp.node": "./index.cjs",
|
||||||
"./package": "./package.json"
|
"./package": "./package.json"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
"node": ">=20.9.0"
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"glibc": ">=2.26"
|
"glibc": ">=2.26"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@img/sharp-linux-ppc64",
|
"name": "@img/sharp-linux-ppc64",
|
||||||
"version": "0.34.5",
|
"version": "0.35.0-rc.0",
|
||||||
"description": "Prebuilt sharp for use with Linux (glibc) ppc64",
|
"description": "Prebuilt sharp for use with Linux (glibc) ppc64",
|
||||||
"author": "Lovell Fuller <npm@lovell.info>",
|
"author": "Lovell Fuller <npm@lovell.info>",
|
||||||
"homepage": "https://sharp.pixelplumbing.com",
|
"homepage": "https://sharp.pixelplumbing.com",
|
||||||
@@ -15,9 +15,10 @@
|
|||||||
},
|
},
|
||||||
"preferUnplugged": true,
|
"preferUnplugged": true,
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@img/sharp-libvips-linux-ppc64": "1.2.4"
|
"@img/sharp-libvips-linux-ppc64": "1.3.0-rc.2"
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
|
"index.cjs",
|
||||||
"lib"
|
"lib"
|
||||||
],
|
],
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
@@ -25,11 +26,11 @@
|
|||||||
},
|
},
|
||||||
"type": "commonjs",
|
"type": "commonjs",
|
||||||
"exports": {
|
"exports": {
|
||||||
"./sharp.node": "./lib/sharp-linux-ppc64.node",
|
"./sharp.node": "./index.cjs",
|
||||||
"./package": "./package.json"
|
"./package": "./package.json"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
"node": ">=20.9.0"
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"glibc": ">=2.36"
|
"glibc": ">=2.36"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@img/sharp-linux-riscv64",
|
"name": "@img/sharp-linux-riscv64",
|
||||||
"version": "0.34.5",
|
"version": "0.35.0-rc.0",
|
||||||
"description": "Prebuilt sharp for use with Linux (glibc) RISC-V 64-bit",
|
"description": "Prebuilt sharp for use with Linux (glibc) RISC-V 64-bit",
|
||||||
"author": "Lovell Fuller <npm@lovell.info>",
|
"author": "Lovell Fuller <npm@lovell.info>",
|
||||||
"homepage": "https://sharp.pixelplumbing.com",
|
"homepage": "https://sharp.pixelplumbing.com",
|
||||||
@@ -15,9 +15,10 @@
|
|||||||
},
|
},
|
||||||
"preferUnplugged": true,
|
"preferUnplugged": true,
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@img/sharp-libvips-linux-riscv64": "1.2.4"
|
"@img/sharp-libvips-linux-riscv64": "1.3.0-rc.2"
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
|
"index.cjs",
|
||||||
"lib"
|
"lib"
|
||||||
],
|
],
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
@@ -25,11 +26,11 @@
|
|||||||
},
|
},
|
||||||
"type": "commonjs",
|
"type": "commonjs",
|
||||||
"exports": {
|
"exports": {
|
||||||
"./sharp.node": "./lib/sharp-linux-riscv64.node",
|
"./sharp.node": "./index.cjs",
|
||||||
"./package": "./package.json"
|
"./package": "./package.json"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
"node": ">=20.9.0"
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"glibc": ">=2.41"
|
"glibc": ">=2.41"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@img/sharp-linux-s390x",
|
"name": "@img/sharp-linux-s390x",
|
||||||
"version": "0.34.5",
|
"version": "0.35.0-rc.0",
|
||||||
"description": "Prebuilt sharp for use with Linux (glibc) s390x",
|
"description": "Prebuilt sharp for use with Linux (glibc) s390x",
|
||||||
"author": "Lovell Fuller <npm@lovell.info>",
|
"author": "Lovell Fuller <npm@lovell.info>",
|
||||||
"homepage": "https://sharp.pixelplumbing.com",
|
"homepage": "https://sharp.pixelplumbing.com",
|
||||||
@@ -15,9 +15,10 @@
|
|||||||
},
|
},
|
||||||
"preferUnplugged": true,
|
"preferUnplugged": true,
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@img/sharp-libvips-linux-s390x": "1.2.4"
|
"@img/sharp-libvips-linux-s390x": "1.3.0-rc.2"
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
|
"index.cjs",
|
||||||
"lib"
|
"lib"
|
||||||
],
|
],
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
@@ -25,11 +26,11 @@
|
|||||||
},
|
},
|
||||||
"type": "commonjs",
|
"type": "commonjs",
|
||||||
"exports": {
|
"exports": {
|
||||||
"./sharp.node": "./lib/sharp-linux-s390x.node",
|
"./sharp.node": "./index.cjs",
|
||||||
"./package": "./package.json"
|
"./package": "./package.json"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
"node": ">=20.9.0"
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"glibc": ">=2.36"
|
"glibc": ">=2.36"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@img/sharp-linux-x64",
|
"name": "@img/sharp-linux-x64",
|
||||||
"version": "0.34.5",
|
"version": "0.35.0-rc.0",
|
||||||
"description": "Prebuilt sharp for use with Linux (glibc) x64",
|
"description": "Prebuilt sharp for use with Linux (glibc) x64",
|
||||||
"author": "Lovell Fuller <npm@lovell.info>",
|
"author": "Lovell Fuller <npm@lovell.info>",
|
||||||
"homepage": "https://sharp.pixelplumbing.com",
|
"homepage": "https://sharp.pixelplumbing.com",
|
||||||
@@ -15,9 +15,10 @@
|
|||||||
},
|
},
|
||||||
"preferUnplugged": true,
|
"preferUnplugged": true,
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@img/sharp-libvips-linux-x64": "1.2.4"
|
"@img/sharp-libvips-linux-x64": "1.3.0-rc.2"
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
|
"index.cjs",
|
||||||
"lib"
|
"lib"
|
||||||
],
|
],
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
@@ -25,11 +26,11 @@
|
|||||||
},
|
},
|
||||||
"type": "commonjs",
|
"type": "commonjs",
|
||||||
"exports": {
|
"exports": {
|
||||||
"./sharp.node": "./lib/sharp-linux-x64.node",
|
"./sharp.node": "./index.cjs",
|
||||||
"./package": "./package.json"
|
"./package": "./package.json"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
"node": ">=20.9.0"
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"glibc": ">=2.26"
|
"glibc": ">=2.26"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@img/sharp-linuxmusl-arm64",
|
"name": "@img/sharp-linuxmusl-arm64",
|
||||||
"version": "0.34.5",
|
"version": "0.35.0-rc.0",
|
||||||
"description": "Prebuilt sharp for use with Linux (musl) 64-bit ARM",
|
"description": "Prebuilt sharp for use with Linux (musl) 64-bit ARM",
|
||||||
"author": "Lovell Fuller <npm@lovell.info>",
|
"author": "Lovell Fuller <npm@lovell.info>",
|
||||||
"homepage": "https://sharp.pixelplumbing.com",
|
"homepage": "https://sharp.pixelplumbing.com",
|
||||||
@@ -15,9 +15,10 @@
|
|||||||
},
|
},
|
||||||
"preferUnplugged": true,
|
"preferUnplugged": true,
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@img/sharp-libvips-linuxmusl-arm64": "1.2.4"
|
"@img/sharp-libvips-linuxmusl-arm64": "1.3.0-rc.2"
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
|
"index.cjs",
|
||||||
"lib"
|
"lib"
|
||||||
],
|
],
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
@@ -25,11 +26,11 @@
|
|||||||
},
|
},
|
||||||
"type": "commonjs",
|
"type": "commonjs",
|
||||||
"exports": {
|
"exports": {
|
||||||
"./sharp.node": "./lib/sharp-linuxmusl-arm64.node",
|
"./sharp.node": "./index.cjs",
|
||||||
"./package": "./package.json"
|
"./package": "./package.json"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
"node": ">=20.9.0"
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"musl": ">=1.2.2"
|
"musl": ">=1.2.2"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@img/sharp-linuxmusl-x64",
|
"name": "@img/sharp-linuxmusl-x64",
|
||||||
"version": "0.34.5",
|
"version": "0.35.0-rc.0",
|
||||||
"description": "Prebuilt sharp for use with Linux (musl) x64",
|
"description": "Prebuilt sharp for use with Linux (musl) x64",
|
||||||
"author": "Lovell Fuller <npm@lovell.info>",
|
"author": "Lovell Fuller <npm@lovell.info>",
|
||||||
"homepage": "https://sharp.pixelplumbing.com",
|
"homepage": "https://sharp.pixelplumbing.com",
|
||||||
@@ -15,9 +15,10 @@
|
|||||||
},
|
},
|
||||||
"preferUnplugged": true,
|
"preferUnplugged": true,
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@img/sharp-libvips-linuxmusl-x64": "1.2.4"
|
"@img/sharp-libvips-linuxmusl-x64": "1.3.0-rc.2"
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
|
"index.cjs",
|
||||||
"lib"
|
"lib"
|
||||||
],
|
],
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
@@ -25,11 +26,11 @@
|
|||||||
},
|
},
|
||||||
"type": "commonjs",
|
"type": "commonjs",
|
||||||
"exports": {
|
"exports": {
|
||||||
"./sharp.node": "./lib/sharp-linuxmusl-x64.node",
|
"./sharp.node": "./index.cjs",
|
||||||
"./package": "./package.json"
|
"./package": "./package.json"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
"node": ">=20.9.0"
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"musl": ">=1.2.2"
|
"musl": ">=1.2.2"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@img/sharp",
|
"name": "@img/sharp",
|
||||||
"version": "0.34.5",
|
"version": "0.35.0-rc.0",
|
||||||
"private": "true",
|
"private": "true",
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
"darwin-arm64",
|
"darwin-arm64",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@img/sharp-wasm32",
|
"name": "@img/sharp-wasm32",
|
||||||
"version": "0.34.5",
|
"version": "0.35.0-rc.0",
|
||||||
"description": "Prebuilt sharp for use with wasm32",
|
"description": "Prebuilt sharp for use with wasm32",
|
||||||
"author": "Lovell Fuller <npm@lovell.info>",
|
"author": "Lovell Fuller <npm@lovell.info>",
|
||||||
"homepage": "https://sharp.pixelplumbing.com",
|
"homepage": "https://sharp.pixelplumbing.com",
|
||||||
@@ -23,15 +23,15 @@
|
|||||||
},
|
},
|
||||||
"type": "commonjs",
|
"type": "commonjs",
|
||||||
"exports": {
|
"exports": {
|
||||||
"./sharp.node": "./lib/sharp-wasm32.node.js",
|
"./sharp.node": "./index.cjs",
|
||||||
"./package": "./package.json",
|
"./package": "./package.json",
|
||||||
"./versions": "./versions.json"
|
"./versions": "./versions.json"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
"node": ">=20.9.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@emnapi/runtime": "^1.7.0"
|
"@emnapi/runtime": "^1.7.1"
|
||||||
},
|
},
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"wasm32"
|
"wasm32"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@img/sharp-win32-arm64",
|
"name": "@img/sharp-win32-arm64",
|
||||||
"version": "0.34.5",
|
"version": "0.35.0-rc.0",
|
||||||
"description": "Prebuilt sharp for use with Windows 64-bit ARM",
|
"description": "Prebuilt sharp for use with Windows 64-bit ARM",
|
||||||
"author": "Lovell Fuller <npm@lovell.info>",
|
"author": "Lovell Fuller <npm@lovell.info>",
|
||||||
"homepage": "https://sharp.pixelplumbing.com",
|
"homepage": "https://sharp.pixelplumbing.com",
|
||||||
@@ -15,6 +15,7 @@
|
|||||||
},
|
},
|
||||||
"preferUnplugged": true,
|
"preferUnplugged": true,
|
||||||
"files": [
|
"files": [
|
||||||
|
"index.cjs",
|
||||||
"lib",
|
"lib",
|
||||||
"versions.json"
|
"versions.json"
|
||||||
],
|
],
|
||||||
@@ -23,12 +24,12 @@
|
|||||||
},
|
},
|
||||||
"type": "commonjs",
|
"type": "commonjs",
|
||||||
"exports": {
|
"exports": {
|
||||||
"./sharp.node": "./lib/sharp-win32-arm64.node",
|
"./sharp.node": "./index.cjs",
|
||||||
"./package": "./package.json",
|
"./package": "./package.json",
|
||||||
"./versions": "./versions.json"
|
"./versions": "./versions.json"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
"node": ">=20.9.0"
|
||||||
},
|
},
|
||||||
"os": [
|
"os": [
|
||||||
"win32"
|
"win32"
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@img/sharp-win32-ia32",
|
"name": "@img/sharp-win32-ia32",
|
||||||
"version": "0.34.5",
|
"version": "0.35.0-rc.0",
|
||||||
"description": "Prebuilt sharp for use with Windows x86 (32-bit)",
|
"description": "Prebuilt sharp for use with Windows x86 (deprecated)",
|
||||||
"author": "Lovell Fuller <npm@lovell.info>",
|
"author": "Lovell Fuller <npm@lovell.info>",
|
||||||
"homepage": "https://sharp.pixelplumbing.com",
|
"homepage": "https://sharp.pixelplumbing.com",
|
||||||
"repository": {
|
"repository": {
|
||||||
@@ -15,6 +15,7 @@
|
|||||||
},
|
},
|
||||||
"preferUnplugged": true,
|
"preferUnplugged": true,
|
||||||
"files": [
|
"files": [
|
||||||
|
"index.cjs",
|
||||||
"lib",
|
"lib",
|
||||||
"versions.json"
|
"versions.json"
|
||||||
],
|
],
|
||||||
@@ -23,12 +24,12 @@
|
|||||||
},
|
},
|
||||||
"type": "commonjs",
|
"type": "commonjs",
|
||||||
"exports": {
|
"exports": {
|
||||||
"./sharp.node": "./lib/sharp-win32-ia32.node",
|
"./sharp.node": "./index.cjs",
|
||||||
"./package": "./package.json",
|
"./package": "./package.json",
|
||||||
"./versions": "./versions.json"
|
"./versions": "./versions.json"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
"node": "^20.9.0"
|
||||||
},
|
},
|
||||||
"os": [
|
"os": [
|
||||||
"win32"
|
"win32"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@img/sharp-win32-x64",
|
"name": "@img/sharp-win32-x64",
|
||||||
"version": "0.34.5",
|
"version": "0.35.0-rc.0",
|
||||||
"description": "Prebuilt sharp for use with Windows x64",
|
"description": "Prebuilt sharp for use with Windows x64",
|
||||||
"author": "Lovell Fuller <npm@lovell.info>",
|
"author": "Lovell Fuller <npm@lovell.info>",
|
||||||
"homepage": "https://sharp.pixelplumbing.com",
|
"homepage": "https://sharp.pixelplumbing.com",
|
||||||
@@ -15,6 +15,7 @@
|
|||||||
},
|
},
|
||||||
"preferUnplugged": true,
|
"preferUnplugged": true,
|
||||||
"files": [
|
"files": [
|
||||||
|
"index.cjs",
|
||||||
"lib",
|
"lib",
|
||||||
"versions.json"
|
"versions.json"
|
||||||
],
|
],
|
||||||
@@ -23,12 +24,12 @@
|
|||||||
},
|
},
|
||||||
"type": "commonjs",
|
"type": "commonjs",
|
||||||
"exports": {
|
"exports": {
|
||||||
"./sharp.node": "./lib/sharp-win32-x64.node",
|
"./sharp.node": "./index.cjs",
|
||||||
"./package": "./package.json",
|
"./package": "./package.json",
|
||||||
"./versions": "./versions.json"
|
"./versions": "./versions.json"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
"node": ">=20.9.0"
|
||||||
},
|
},
|
||||||
"os": [
|
"os": [
|
||||||
"win32"
|
"win32"
|
||||||
|
|||||||
81
package.json
81
package.json
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "sharp",
|
"name": "sharp",
|
||||||
"description": "High performance Node.js image processing, the fastest module to resize JPEG, PNG, WebP, GIF, AVIF and TIFF images",
|
"description": "High performance Node.js image processing, the fastest module to resize JPEG, PNG, WebP, GIF, AVIF and TIFF images",
|
||||||
"version": "0.34.5",
|
"version": "0.35.0-rc.0",
|
||||||
"author": "Lovell Fuller <npm@lovell.info>",
|
"author": "Lovell Fuller <npm@lovell.info>",
|
||||||
"homepage": "https://sharp.pixelplumbing.com",
|
"homepage": "https://sharp.pixelplumbing.com",
|
||||||
"contributors": [
|
"contributors": [
|
||||||
@@ -89,12 +89,12 @@
|
|||||||
"Lachlan Newman <lachnewman007@gmail.com>",
|
"Lachlan Newman <lachnewman007@gmail.com>",
|
||||||
"Dennis Beatty <dennis@dcbeatty.com>",
|
"Dennis Beatty <dennis@dcbeatty.com>",
|
||||||
"Ingvar Stepanyan <me@rreverser.com>",
|
"Ingvar Stepanyan <me@rreverser.com>",
|
||||||
"Don Denton <don@happycollision.com>"
|
"Don Denton <don@happycollision.com>",
|
||||||
|
"Dmytro Tiapukhin <cool.gegeg@gmail.com>"
|
||||||
],
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "node install/build.js",
|
"build": "node install/build.js",
|
||||||
"install": "node install/check.js || npm run build",
|
"clean": "rm -rf src/build/ test/fixtures/output.*",
|
||||||
"clean": "rm -rf src/build/ .nyc_output/ coverage/ test/fixtures/output.*",
|
|
||||||
"test": "npm run lint && npm run test-unit",
|
"test": "npm run lint && npm run test-unit",
|
||||||
"lint": "npm run lint-cpp && npm run lint-js && npm run lint-types",
|
"lint": "npm run lint-cpp && npm run lint-js && npm run lint-types",
|
||||||
"lint-cpp": "cpplint --quiet src/*.h src/*.cc",
|
"lint-cpp": "cpplint --quiet src/*.h src/*.cc",
|
||||||
@@ -144,57 +144,56 @@
|
|||||||
"semver": "^7.7.3"
|
"semver": "^7.7.3"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@img/sharp-darwin-arm64": "0.34.5",
|
"@img/sharp-darwin-arm64": "0.35.0-rc.0",
|
||||||
"@img/sharp-darwin-x64": "0.34.5",
|
"@img/sharp-darwin-x64": "0.35.0-rc.0",
|
||||||
"@img/sharp-libvips-darwin-arm64": "1.2.4",
|
"@img/sharp-libvips-darwin-arm64": "1.3.0-rc.2",
|
||||||
"@img/sharp-libvips-darwin-x64": "1.2.4",
|
"@img/sharp-libvips-darwin-x64": "1.3.0-rc.2",
|
||||||
"@img/sharp-libvips-linux-arm": "1.2.4",
|
"@img/sharp-libvips-linux-arm": "1.3.0-rc.2",
|
||||||
"@img/sharp-libvips-linux-arm64": "1.2.4",
|
"@img/sharp-libvips-linux-arm64": "1.3.0-rc.2",
|
||||||
"@img/sharp-libvips-linux-ppc64": "1.2.4",
|
"@img/sharp-libvips-linux-ppc64": "1.3.0-rc.2",
|
||||||
"@img/sharp-libvips-linux-riscv64": "1.2.4",
|
"@img/sharp-libvips-linux-riscv64": "1.3.0-rc.2",
|
||||||
"@img/sharp-libvips-linux-s390x": "1.2.4",
|
"@img/sharp-libvips-linux-s390x": "1.3.0-rc.2",
|
||||||
"@img/sharp-libvips-linux-x64": "1.2.4",
|
"@img/sharp-libvips-linux-x64": "1.3.0-rc.2",
|
||||||
"@img/sharp-libvips-linuxmusl-arm64": "1.2.4",
|
"@img/sharp-libvips-linuxmusl-arm64": "1.3.0-rc.2",
|
||||||
"@img/sharp-libvips-linuxmusl-x64": "1.2.4",
|
"@img/sharp-libvips-linuxmusl-x64": "1.3.0-rc.2",
|
||||||
"@img/sharp-linux-arm": "0.34.5",
|
"@img/sharp-linux-arm": "0.35.0-rc.0",
|
||||||
"@img/sharp-linux-arm64": "0.34.5",
|
"@img/sharp-linux-arm64": "0.35.0-rc.0",
|
||||||
"@img/sharp-linux-ppc64": "0.34.5",
|
"@img/sharp-linux-ppc64": "0.35.0-rc.0",
|
||||||
"@img/sharp-linux-riscv64": "0.34.5",
|
"@img/sharp-linux-riscv64": "0.35.0-rc.0",
|
||||||
"@img/sharp-linux-s390x": "0.34.5",
|
"@img/sharp-linux-s390x": "0.35.0-rc.0",
|
||||||
"@img/sharp-linux-x64": "0.34.5",
|
"@img/sharp-linux-x64": "0.35.0-rc.0",
|
||||||
"@img/sharp-linuxmusl-arm64": "0.34.5",
|
"@img/sharp-linuxmusl-arm64": "0.35.0-rc.0",
|
||||||
"@img/sharp-linuxmusl-x64": "0.34.5",
|
"@img/sharp-linuxmusl-x64": "0.35.0-rc.0",
|
||||||
"@img/sharp-wasm32": "0.34.5",
|
"@img/sharp-wasm32": "0.35.0-rc.0",
|
||||||
"@img/sharp-win32-arm64": "0.34.5",
|
"@img/sharp-win32-arm64": "0.35.0-rc.0",
|
||||||
"@img/sharp-win32-ia32": "0.34.5",
|
"@img/sharp-win32-ia32": "0.35.0-rc.0",
|
||||||
"@img/sharp-win32-x64": "0.34.5"
|
"@img/sharp-win32-x64": "0.35.0-rc.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@biomejs/biome": "^2.3.4",
|
"@biomejs/biome": "^2.3.10",
|
||||||
"@cpplint/cli": "^0.1.0",
|
"@cpplint/cli": "^0.1.0",
|
||||||
"@emnapi/runtime": "^1.7.0",
|
"@emnapi/runtime": "^1.7.1",
|
||||||
"@img/sharp-libvips-dev": "1.2.4",
|
"@img/sharp-libvips-dev": "1.3.0-rc.2",
|
||||||
"@img/sharp-libvips-dev-wasm32": "1.2.4",
|
"@img/sharp-libvips-dev-wasm32": "1.3.0-rc.2",
|
||||||
"@img/sharp-libvips-win32-arm64": "1.2.4",
|
"@img/sharp-libvips-win32-arm64": "1.3.0-rc.2",
|
||||||
"@img/sharp-libvips-win32-ia32": "1.2.4",
|
"@img/sharp-libvips-win32-ia32": "1.3.0-rc.2",
|
||||||
"@img/sharp-libvips-win32-x64": "1.2.4",
|
"@img/sharp-libvips-win32-x64": "1.3.0-rc.2",
|
||||||
"@types/node": "*",
|
"@types/node": "*",
|
||||||
"emnapi": "^1.7.0",
|
"emnapi": "^1.7.1",
|
||||||
"exif-reader": "^2.0.2",
|
"exif-reader": "^2.0.3",
|
||||||
"extract-zip": "^2.0.1",
|
"extract-zip": "^2.0.1",
|
||||||
"icc": "^3.0.0",
|
"icc": "^3.0.0",
|
||||||
"jsdoc-to-markdown": "^9.1.3",
|
|
||||||
"node-addon-api": "^8.5.0",
|
"node-addon-api": "^8.5.0",
|
||||||
"node-gyp": "^11.5.0",
|
"node-gyp": "^12.1.0",
|
||||||
"tar-fs": "^3.1.1",
|
"tar-fs": "^3.1.1",
|
||||||
"tsd": "^0.33.0"
|
"tsd": "^0.33.0"
|
||||||
},
|
},
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
"node": ">=20.9.0"
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"libvips": ">=8.17.3"
|
"libvips": ">=8.18.0"
|
||||||
},
|
},
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://opencollective.com/libvips"
|
"url": "https://opencollective.com/libvips"
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
'variables': {
|
'variables': {
|
||||||
'vips_version': '<!(node -p "require(\'../lib/libvips\').minimumLibvipsVersion")',
|
'vips_version': '<!(node -p "require(\'../lib/libvips\').minimumLibvipsVersion")',
|
||||||
'platform_and_arch': '<!(node -p "require(\'../lib/libvips\').buildPlatformArch()")',
|
'platform_and_arch': '<!(node -p "require(\'../lib/libvips\').buildPlatformArch()")',
|
||||||
|
'sharp_version': '<!(node -p "require(\'../package.json\').version")',
|
||||||
'sharp_libvips_version': '<!(node -p "require(\'../package.json\').optionalDependencies[\'@img/sharp-libvips-<(platform_and_arch)\']")',
|
'sharp_libvips_version': '<!(node -p "require(\'../package.json\').optionalDependencies[\'@img/sharp-libvips-<(platform_and_arch)\']")',
|
||||||
'sharp_libvips_yarn_locator': '<!(node -p "require(\'../lib/libvips\').yarnLocator()")',
|
'sharp_libvips_yarn_locator': '<!(node -p "require(\'../lib/libvips\').yarnLocator()")',
|
||||||
'sharp_libvips_include_dir': '<!(node -p "require(\'../lib/libvips\').buildSharpLibvipsIncludeDir()")',
|
'sharp_libvips_include_dir': '<!(node -p "require(\'../lib/libvips\').buildSharpLibvipsIncludeDir()")',
|
||||||
@@ -20,6 +21,7 @@
|
|||||||
'defines': [
|
'defines': [
|
||||||
'_VIPS_PUBLIC=__declspec(dllexport)',
|
'_VIPS_PUBLIC=__declspec(dllexport)',
|
||||||
'_ALLOW_KEYWORD_MACROS',
|
'_ALLOW_KEYWORD_MACROS',
|
||||||
|
'_HAS_EXCEPTIONS=1',
|
||||||
'G_DISABLE_ASSERT',
|
'G_DISABLE_ASSERT',
|
||||||
'G_DISABLE_CAST_CHECKS',
|
'G_DISABLE_CAST_CHECKS',
|
||||||
'G_DISABLE_CHECKS'
|
'G_DISABLE_CHECKS'
|
||||||
@@ -81,7 +83,7 @@
|
|||||||
}]
|
}]
|
||||||
]
|
]
|
||||||
}, {
|
}, {
|
||||||
'target_name': 'sharp-<(platform_and_arch)',
|
'target_name': 'sharp-<(platform_and_arch)-<(sharp_version)',
|
||||||
'defines': [
|
'defines': [
|
||||||
'G_DISABLE_ASSERT',
|
'G_DISABLE_ASSERT',
|
||||||
'G_DISABLE_CAST_CHECKS',
|
'G_DISABLE_CAST_CHECKS',
|
||||||
@@ -147,7 +149,8 @@
|
|||||||
['OS == "win"', {
|
['OS == "win"', {
|
||||||
'defines': [
|
'defines': [
|
||||||
'_ALLOW_KEYWORD_MACROS',
|
'_ALLOW_KEYWORD_MACROS',
|
||||||
'_FILE_OFFSET_BITS=64'
|
'_FILE_OFFSET_BITS=64',
|
||||||
|
'_HAS_EXCEPTIONS=1'
|
||||||
],
|
],
|
||||||
'link_settings': {
|
'link_settings': {
|
||||||
'libraries': [
|
'libraries': [
|
||||||
@@ -282,7 +285,7 @@
|
|||||||
'target_name': 'copy-dll',
|
'target_name': 'copy-dll',
|
||||||
'type': 'none',
|
'type': 'none',
|
||||||
'dependencies': [
|
'dependencies': [
|
||||||
'sharp-<(platform_and_arch)'
|
'sharp-<(platform_and_arch)-<(sharp_version)'
|
||||||
],
|
],
|
||||||
'conditions': [
|
'conditions': [
|
||||||
['OS == "win"', {
|
['OS == "win"', {
|
||||||
|
|||||||
@@ -289,6 +289,7 @@ namespace sharp {
|
|||||||
case ImageType::JXL: id = "jxl"; break;
|
case ImageType::JXL: id = "jxl"; break;
|
||||||
case ImageType::RAD: id = "rad"; break;
|
case ImageType::RAD: id = "rad"; break;
|
||||||
case ImageType::DCRAW: id = "dcraw"; break;
|
case ImageType::DCRAW: id = "dcraw"; break;
|
||||||
|
case ImageType::UHDR: id = "uhdr"; 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;
|
||||||
@@ -339,6 +340,9 @@ namespace sharp {
|
|||||||
{ "VipsForeignLoadRadBuffer", ImageType::RAD },
|
{ "VipsForeignLoadRadBuffer", ImageType::RAD },
|
||||||
{ "VipsForeignLoadDcRawFile", ImageType::DCRAW },
|
{ "VipsForeignLoadDcRawFile", ImageType::DCRAW },
|
||||||
{ "VipsForeignLoadDcRawBuffer", ImageType::DCRAW },
|
{ "VipsForeignLoadDcRawBuffer", ImageType::DCRAW },
|
||||||
|
{ "VipsForeignLoadUhdr", ImageType::UHDR },
|
||||||
|
{ "VipsForeignLoadUhdrFile", ImageType::UHDR },
|
||||||
|
{ "VipsForeignLoadUhdrBuffer", ImageType::UHDR },
|
||||||
{ "VipsForeignLoadVips", ImageType::VIPS },
|
{ "VipsForeignLoadVips", ImageType::VIPS },
|
||||||
{ "VipsForeignLoadVipsFile", ImageType::VIPS },
|
{ "VipsForeignLoadVipsFile", ImageType::VIPS },
|
||||||
{ "VipsForeignLoadRaw", ImageType::RAW }
|
{ "VipsForeignLoadRaw", ImageType::RAW }
|
||||||
@@ -356,6 +360,9 @@ namespace sharp {
|
|||||||
imageType = it->second;
|
imageType = it->second;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (imageType == ImageType::UHDR) {
|
||||||
|
imageType = ImageType::JPEG;
|
||||||
|
}
|
||||||
return imageType;
|
return imageType;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -375,6 +382,9 @@ namespace sharp {
|
|||||||
imageType = ImageType::MISSING;
|
imageType = ImageType::MISSING;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (imageType == ImageType::UHDR) {
|
||||||
|
imageType = ImageType::JPEG;
|
||||||
|
}
|
||||||
return imageType;
|
return imageType;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -416,7 +426,7 @@ namespace sharp {
|
|||||||
}
|
}
|
||||||
if (ImageTypeSupportsPage(imageType)) {
|
if (ImageTypeSupportsPage(imageType)) {
|
||||||
option->set("n", descriptor->pages);
|
option->set("n", descriptor->pages);
|
||||||
option->set("page", descriptor->page);
|
option->set("page", std::max(0, descriptor->page));
|
||||||
}
|
}
|
||||||
switch (imageType) {
|
switch (imageType) {
|
||||||
case ImageType::SVG:
|
case ImageType::SVG:
|
||||||
@@ -446,6 +456,22 @@ namespace sharp {
|
|||||||
return option;
|
return option;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Should HEIF image be re-opened using the primary item?
|
||||||
|
*/
|
||||||
|
static bool HeifPrimaryPageReopen(VImage image, InputDescriptor *descriptor) {
|
||||||
|
if (image.get_typeof(VIPS_META_N_PAGES) == G_TYPE_INT && image.get_typeof("heif-primary") == G_TYPE_INT) {
|
||||||
|
if (image.get_int(VIPS_META_N_PAGES) > 1 && descriptor->pages == 1 && descriptor->page == -1) {
|
||||||
|
int const pagePrimary = image.get_int("heif-primary");
|
||||||
|
if (pagePrimary != 0) {
|
||||||
|
descriptor->page = pagePrimary;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Open an image from the given InputDescriptor (filesystem, compressed buffer, raw pixel data)
|
Open an image from the given InputDescriptor (filesystem, compressed buffer, raw pixel data)
|
||||||
*/
|
*/
|
||||||
@@ -480,12 +506,15 @@ namespace sharp {
|
|||||||
image = VImage::new_from_buffer(descriptor->buffer, descriptor->bufferLength, nullptr, option);
|
image = VImage::new_from_buffer(descriptor->buffer, descriptor->bufferLength, nullptr, option);
|
||||||
if (imageType == ImageType::SVG || imageType == ImageType::PDF || imageType == ImageType::MAGICK) {
|
if (imageType == ImageType::SVG || imageType == ImageType::PDF || imageType == ImageType::MAGICK) {
|
||||||
image = SetDensity(image, descriptor->density);
|
image = SetDensity(image, descriptor->density);
|
||||||
|
} else if (imageType == ImageType::HEIF && HeifPrimaryPageReopen(image, descriptor)) {
|
||||||
|
option = GetOptionsForImageType(imageType, descriptor);
|
||||||
|
image = VImage::new_from_buffer(descriptor->buffer, descriptor->bufferLength, nullptr, option);
|
||||||
}
|
}
|
||||||
} catch (vips::VError const &err) {
|
} catch (std::runtime_error const &err) {
|
||||||
throw vips::VError(std::string("Input buffer has corrupt header: ") + err.what());
|
throw std::runtime_error(std::string("Input buffer has corrupt header: ") + err.what());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw vips::VError("Input buffer contains unsupported image format");
|
throw std::runtime_error("Input buffer contains unsupported image format");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -556,10 +585,10 @@ namespace sharp {
|
|||||||
imageType = DetermineImageType(descriptor->file.data());
|
imageType = DetermineImageType(descriptor->file.data());
|
||||||
if (imageType == ImageType::MISSING) {
|
if (imageType == ImageType::MISSING) {
|
||||||
if (descriptor->file.find("<svg") != std::string::npos) {
|
if (descriptor->file.find("<svg") != std::string::npos) {
|
||||||
throw vips::VError("Input file is missing, did you mean "
|
throw std::runtime_error("Input file is missing, did you mean "
|
||||||
"sharp(Buffer.from('" + descriptor->file.substr(0, 8) + "...')?");
|
"sharp(Buffer.from('" + descriptor->file.substr(0, 8) + "...')?");
|
||||||
}
|
}
|
||||||
throw vips::VError("Input file is missing: " + descriptor->file);
|
throw std::runtime_error("Input file is missing: " + descriptor->file);
|
||||||
}
|
}
|
||||||
if (imageType != ImageType::UNKNOWN) {
|
if (imageType != ImageType::UNKNOWN) {
|
||||||
try {
|
try {
|
||||||
@@ -567,12 +596,15 @@ namespace sharp {
|
|||||||
image = VImage::new_from_file(descriptor->file.data(), option);
|
image = VImage::new_from_file(descriptor->file.data(), option);
|
||||||
if (imageType == ImageType::SVG || imageType == ImageType::PDF || imageType == ImageType::MAGICK) {
|
if (imageType == ImageType::SVG || imageType == ImageType::PDF || imageType == ImageType::MAGICK) {
|
||||||
image = SetDensity(image, descriptor->density);
|
image = SetDensity(image, descriptor->density);
|
||||||
|
} else if (imageType == ImageType::HEIF && HeifPrimaryPageReopen(image, descriptor)) {
|
||||||
|
option = GetOptionsForImageType(imageType, descriptor);
|
||||||
|
image = VImage::new_from_file(descriptor->file.data(), option);
|
||||||
}
|
}
|
||||||
} catch (vips::VError const &err) {
|
} catch (std::runtime_error const &err) {
|
||||||
throw vips::VError(std::string("Input file has corrupt header: ") + err.what());
|
throw std::runtime_error(std::string("Input file has corrupt header: ") + err.what());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw vips::VError("Input file contains unsupported image format");
|
throw std::runtime_error("Input file contains unsupported image format");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -580,7 +612,7 @@ namespace sharp {
|
|||||||
// Limit input images to a given number of pixels, where pixels = width * height
|
// Limit input images to a given number of pixels, where pixels = width * height
|
||||||
if (descriptor->limitInputPixels > 0 &&
|
if (descriptor->limitInputPixels > 0 &&
|
||||||
static_cast<uint64_t>(image.width()) * image.height() > descriptor->limitInputPixels) {
|
static_cast<uint64_t>(image.width()) * image.height() > descriptor->limitInputPixels) {
|
||||||
throw vips::VError("Input image exceeds pixel limit");
|
throw std::runtime_error("Input image exceeds pixel limit");
|
||||||
}
|
}
|
||||||
return std::make_tuple(image, imageType);
|
return std::make_tuple(image, imageType);
|
||||||
}
|
}
|
||||||
@@ -756,19 +788,19 @@ namespace sharp {
|
|||||||
: image.height();
|
: image.height();
|
||||||
if (imageType == ImageType::JPEG) {
|
if (imageType == ImageType::JPEG) {
|
||||||
if (image.width() > 65535 || height > 65535) {
|
if (image.width() > 65535 || height > 65535) {
|
||||||
throw vips::VError("Processed image is too large for the JPEG format");
|
throw std::runtime_error("Processed image is too large for the JPEG format");
|
||||||
}
|
}
|
||||||
} else if (imageType == ImageType::WEBP) {
|
} else if (imageType == ImageType::WEBP) {
|
||||||
if (image.width() > 16383 || height > 16383) {
|
if (image.width() > 16383 || height > 16383) {
|
||||||
throw vips::VError("Processed image is too large for the WebP format");
|
throw std::runtime_error("Processed image is too large for the WebP format");
|
||||||
}
|
}
|
||||||
} else if (imageType == ImageType::GIF) {
|
} else if (imageType == ImageType::GIF) {
|
||||||
if (image.width() > 65535 || height > 65535) {
|
if (image.width() > 65535 || height > 65535) {
|
||||||
throw vips::VError("Processed image is too large for the GIF format");
|
throw std::runtime_error("Processed image is too large for the GIF format");
|
||||||
}
|
}
|
||||||
} else if (imageType == ImageType::HEIF) {
|
} else if (imageType == ImageType::HEIF) {
|
||||||
if (image.width() > 16384 || height > 16384) {
|
if (image.width() > 16384 || height > 16384) {
|
||||||
throw vips::VError("Processed image is too large for the HEIF format");
|
throw std::runtime_error("Processed image is too large for the HEIF format");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1127,4 +1159,20 @@ namespace sharp {
|
|||||||
}
|
}
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Does this image have a gain map?
|
||||||
|
*/
|
||||||
|
bool HasGainMap(VImage image) {
|
||||||
|
return image.get_typeof("gainmap-data") == VIPS_TYPE_BLOB;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Removes gain map, if any.
|
||||||
|
*/
|
||||||
|
VImage RemoveGainMap(VImage image) {
|
||||||
|
VImage copy = image.copy();
|
||||||
|
copy.remove("gainmap-data");
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
} // namespace sharp
|
} // namespace sharp
|
||||||
|
|||||||
19
src/common.h
19
src/common.h
@@ -18,9 +18,9 @@
|
|||||||
// Verify platform and compiler compatibility
|
// Verify platform and compiler compatibility
|
||||||
|
|
||||||
#if (VIPS_MAJOR_VERSION < 8) || \
|
#if (VIPS_MAJOR_VERSION < 8) || \
|
||||||
(VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION < 17) || \
|
(VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION < 18) || \
|
||||||
(VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION == 17 && VIPS_MICRO_VERSION < 3)
|
(VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION == 18 && VIPS_MICRO_VERSION < 0)
|
||||||
#error "libvips version 8.17.3+ is required - please see https://sharp.pixelplumbing.com/install"
|
#error "libvips version 8.18.0+ is required - please see https://sharp.pixelplumbing.com/install"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(__has_include)
|
#if defined(__has_include)
|
||||||
@@ -105,7 +105,7 @@ namespace sharp {
|
|||||||
rawPremultiplied(false),
|
rawPremultiplied(false),
|
||||||
rawPageHeight(0),
|
rawPageHeight(0),
|
||||||
pages(1),
|
pages(1),
|
||||||
page(0),
|
page(-1),
|
||||||
createChannels(0),
|
createChannels(0),
|
||||||
createWidth(0),
|
createWidth(0),
|
||||||
createHeight(0),
|
createHeight(0),
|
||||||
@@ -173,6 +173,7 @@ namespace sharp {
|
|||||||
JXL,
|
JXL,
|
||||||
RAD,
|
RAD,
|
||||||
DCRAW,
|
DCRAW,
|
||||||
|
UHDR,
|
||||||
VIPS,
|
VIPS,
|
||||||
RAW,
|
RAW,
|
||||||
UNKNOWN,
|
UNKNOWN,
|
||||||
@@ -397,6 +398,16 @@ namespace sharp {
|
|||||||
*/
|
*/
|
||||||
VImage StaySequential(VImage image, bool condition = true);
|
VImage StaySequential(VImage image, bool condition = true);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Does this image have a gain map?
|
||||||
|
*/
|
||||||
|
bool HasGainMap(VImage image);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Removes gain map, if any.
|
||||||
|
*/
|
||||||
|
VImage RemoveGainMap(VImage image);
|
||||||
|
|
||||||
} // namespace sharp
|
} // namespace sharp
|
||||||
|
|
||||||
#endif // SRC_COMMON_H_
|
#endif // SRC_COMMON_H_
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ class MetadataWorker : public Napi::AsyncWorker {
|
|||||||
sharp::ImageType imageType = sharp::ImageType::UNKNOWN;
|
sharp::ImageType imageType = sharp::ImageType::UNKNOWN;
|
||||||
try {
|
try {
|
||||||
std::tie(image, imageType) = OpenInput(baton->input);
|
std::tie(image, imageType) = OpenInput(baton->input);
|
||||||
} catch (vips::VError const &err) {
|
} catch (std::runtime_error const &err) {
|
||||||
(baton->err).append(err.what());
|
(baton->err).append(err.what());
|
||||||
}
|
}
|
||||||
if (imageType != sharp::ImageType::UNKNOWN) {
|
if (imageType != sharp::ImageType::UNKNOWN) {
|
||||||
@@ -141,6 +141,14 @@ class MetadataWorker : public Napi::AsyncWorker {
|
|||||||
memcpy(baton->tifftagPhotoshop, tifftagPhotoshop, tifftagPhotoshopLength);
|
memcpy(baton->tifftagPhotoshop, tifftagPhotoshop, tifftagPhotoshopLength);
|
||||||
baton->tifftagPhotoshopLength = tifftagPhotoshopLength;
|
baton->tifftagPhotoshopLength = tifftagPhotoshopLength;
|
||||||
}
|
}
|
||||||
|
// Gain Map
|
||||||
|
if (image.get_typeof("gainmap-data") == VIPS_TYPE_BLOB) {
|
||||||
|
size_t gainMapLength;
|
||||||
|
void const *gainMap = image.get_blob("gainmap-data", &gainMapLength);
|
||||||
|
baton->gainMap = static_cast<char *>(g_malloc(gainMapLength));
|
||||||
|
memcpy(baton->gainMap, gainMap, gainMapLength);
|
||||||
|
baton->gainMapLength = gainMapLength;
|
||||||
|
}
|
||||||
// PNG comments
|
// PNG comments
|
||||||
vips_image_map(image.get_image(), readPNGComment, &baton->comments);
|
vips_image_map(image.get_image(), readPNGComment, &baton->comments);
|
||||||
}
|
}
|
||||||
@@ -182,10 +190,6 @@ class MetadataWorker : public Napi::AsyncWorker {
|
|||||||
info.Set("isPalette", baton->isPalette);
|
info.Set("isPalette", baton->isPalette);
|
||||||
if (baton->bitsPerSample > 0) {
|
if (baton->bitsPerSample > 0) {
|
||||||
info.Set("bitsPerSample", baton->bitsPerSample);
|
info.Set("bitsPerSample", baton->bitsPerSample);
|
||||||
if (baton->isPalette) {
|
|
||||||
// Deprecated, remove with libvips 8.17.0
|
|
||||||
info.Set("paletteBitDepth", baton->bitsPerSample);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (baton->pages > 0) {
|
if (baton->pages > 0) {
|
||||||
info.Set("pages", baton->pages);
|
info.Set("pages", baton->pages);
|
||||||
@@ -276,6 +280,12 @@ class MetadataWorker : public Napi::AsyncWorker {
|
|||||||
Napi::Buffer<char>::NewOrCopy(env, baton->tifftagPhotoshop,
|
Napi::Buffer<char>::NewOrCopy(env, baton->tifftagPhotoshop,
|
||||||
baton->tifftagPhotoshopLength, sharp::FreeCallback));
|
baton->tifftagPhotoshopLength, sharp::FreeCallback));
|
||||||
}
|
}
|
||||||
|
if (baton->gainMapLength > 0) {
|
||||||
|
Napi::Object gainMap = Napi::Object::New(env);
|
||||||
|
info.Set("gainMap", gainMap);
|
||||||
|
gainMap.Set("image",
|
||||||
|
Napi::Buffer<char>::NewOrCopy(env, baton->gainMap, baton->gainMapLength, sharp::FreeCallback));
|
||||||
|
}
|
||||||
if (baton->comments.size() > 0) {
|
if (baton->comments.size() > 0) {
|
||||||
int i = 0;
|
int i = 0;
|
||||||
Napi::Array comments = Napi::Array::New(env, baton->comments.size());
|
Napi::Array comments = Napi::Array::New(env, baton->comments.size());
|
||||||
|
|||||||
@@ -53,6 +53,8 @@ struct MetadataBaton {
|
|||||||
size_t xmpLength;
|
size_t xmpLength;
|
||||||
char *tifftagPhotoshop;
|
char *tifftagPhotoshop;
|
||||||
size_t tifftagPhotoshopLength;
|
size_t tifftagPhotoshopLength;
|
||||||
|
char *gainMap;
|
||||||
|
size_t gainMapLength;
|
||||||
MetadataComments comments;
|
MetadataComments comments;
|
||||||
std::string err;
|
std::string err;
|
||||||
|
|
||||||
@@ -82,7 +84,9 @@ struct MetadataBaton {
|
|||||||
xmp(nullptr),
|
xmp(nullptr),
|
||||||
xmpLength(0),
|
xmpLength(0),
|
||||||
tifftagPhotoshop(nullptr),
|
tifftagPhotoshop(nullptr),
|
||||||
tifftagPhotoshopLength(0) {}
|
tifftagPhotoshopLength(0),
|
||||||
|
gainMap(nullptr),
|
||||||
|
gainMapLength(0) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
Napi::Value metadata(const Napi::CallbackInfo& info);
|
Napi::Value metadata(const Napi::CallbackInfo& info);
|
||||||
|
|||||||
@@ -14,7 +14,6 @@
|
|||||||
#include "./operations.h"
|
#include "./operations.h"
|
||||||
|
|
||||||
using vips::VImage;
|
using vips::VImage;
|
||||||
using vips::VError;
|
|
||||||
|
|
||||||
namespace sharp {
|
namespace sharp {
|
||||||
/*
|
/*
|
||||||
@@ -285,9 +284,9 @@ namespace sharp {
|
|||||||
/*
|
/*
|
||||||
Trim an image
|
Trim an image
|
||||||
*/
|
*/
|
||||||
VImage Trim(VImage image, std::vector<double> background, double threshold, bool const lineArt) {
|
VImage Trim(VImage image, std::vector<double> background, double threshold, bool const lineArt, int const margin) {
|
||||||
if (image.width() < 3 && image.height() < 3) {
|
if (image.width() < 3 && image.height() < 3) {
|
||||||
throw VError("Image to trim must be at least 3x3 pixels");
|
throw std::runtime_error("Image to trim must be at least 3x3 pixels");
|
||||||
}
|
}
|
||||||
if (background.size() == 0) {
|
if (background.size() == 0) {
|
||||||
// Top-left pixel provides the default background colour if none is given
|
// Top-left pixel provides the default background colour if none is given
|
||||||
@@ -320,18 +319,36 @@ namespace sharp {
|
|||||||
if (widthA > 0 && heightA > 0) {
|
if (widthA > 0 && heightA > 0) {
|
||||||
if (width > 0 && height > 0) {
|
if (width > 0 && height > 0) {
|
||||||
// Combined bounding box (B)
|
// Combined bounding box (B)
|
||||||
int const leftB = std::min(left, leftA);
|
int leftB = std::min(left, leftA);
|
||||||
int const topB = std::min(top, topA);
|
int topB = std::min(top, topA);
|
||||||
int const widthB = std::max(left + width, leftA + widthA) - leftB;
|
int widthB = std::max(left + width, leftA + widthA) - leftB;
|
||||||
int const heightB = std::max(top + height, topA + heightA) - topB;
|
int heightB = std::max(top + height, topA + heightA) - topB;
|
||||||
|
if (margin > 0) {
|
||||||
|
leftB = std::max(0, leftB - margin);
|
||||||
|
topB = std::max(0, topB - margin);
|
||||||
|
widthB = std::min(image.width() - leftB, widthB + 2 * margin);
|
||||||
|
heightB = std::min(image.height() - topB, heightB + 2 * margin);
|
||||||
|
}
|
||||||
return image.extract_area(leftB, topB, widthB, heightB);
|
return image.extract_area(leftB, topB, widthB, heightB);
|
||||||
} else {
|
} else {
|
||||||
// Use alpha only
|
// Use alpha only
|
||||||
|
if (margin > 0) {
|
||||||
|
leftA = std::max(0, leftA - margin);
|
||||||
|
topA = std::max(0, topA - margin);
|
||||||
|
widthA = std::min(image.width() - leftA, widthA + 2 * margin);
|
||||||
|
heightA = std::min(image.height() - topA, heightA + 2 * margin);
|
||||||
|
}
|
||||||
return image.extract_area(leftA, topA, widthA, heightA);
|
return image.extract_area(leftA, topA, widthA, heightA);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (width > 0 && height > 0) {
|
if (width > 0 && height > 0) {
|
||||||
|
if (margin > 0) {
|
||||||
|
left = std::max(0, left - margin);
|
||||||
|
top = std::max(0, top - margin);
|
||||||
|
width = std::min(image.width() - left, width + 2 * margin);
|
||||||
|
height = std::min(image.height() - top, height + 2 * margin);
|
||||||
|
}
|
||||||
return image.extract_area(left, top, width, height);
|
return image.extract_area(left, top, width, height);
|
||||||
}
|
}
|
||||||
return image;
|
return image;
|
||||||
@@ -343,7 +360,7 @@ namespace sharp {
|
|||||||
VImage Linear(VImage image, std::vector<double> const a, std::vector<double> const b) {
|
VImage Linear(VImage image, std::vector<double> const a, std::vector<double> const b) {
|
||||||
size_t const bands = static_cast<size_t>(image.bands());
|
size_t const bands = static_cast<size_t>(image.bands());
|
||||||
if (a.size() > bands) {
|
if (a.size() > bands) {
|
||||||
throw VError("Band expansion using linear is unsupported");
|
throw std::runtime_error("Band expansion using linear is unsupported");
|
||||||
}
|
}
|
||||||
bool const uchar = !Is16Bit(image.interpretation());
|
bool const uchar = !Is16Bit(image.interpretation());
|
||||||
if (image.has_alpha() && a.size() != bands && (a.size() == 1 || a.size() == bands - 1 || bands - 1 == 1)) {
|
if (image.has_alpha() && a.size() != bands && (a.size() == 1 || a.size() == bands - 1 || bands - 1 == 1)) {
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ namespace sharp {
|
|||||||
/*
|
/*
|
||||||
Trim an image
|
Trim an image
|
||||||
*/
|
*/
|
||||||
VImage Trim(VImage image, std::vector<double> background, double threshold, bool const lineArt);
|
VImage Trim(VImage image, std::vector<double> background, double threshold, bool const lineArt, int const margin);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Linear adjustment (a * in + b)
|
* Linear adjustment (a * in + b)
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|||||||
if (nPages == -1) {
|
if (nPages == -1) {
|
||||||
// Resolve the number of pages if we need to render until the end of the document
|
// Resolve the number of pages if we need to render until the end of the document
|
||||||
nPages = image.get_typeof(VIPS_META_N_PAGES) != 0
|
nPages = image.get_typeof(VIPS_META_N_PAGES) != 0
|
||||||
? image.get_int(VIPS_META_N_PAGES) - baton->input->page
|
? image.get_int(VIPS_META_N_PAGES) - std::max(0, baton->input->page)
|
||||||
: 1;
|
: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,7 +153,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|||||||
if (baton->trimThreshold >= 0.0) {
|
if (baton->trimThreshold >= 0.0) {
|
||||||
MultiPageUnsupported(nPages, "Trim");
|
MultiPageUnsupported(nPages, "Trim");
|
||||||
image = sharp::StaySequential(image);
|
image = sharp::StaySequential(image);
|
||||||
image = sharp::Trim(image, baton->trimBackground, baton->trimThreshold, baton->trimLineArt);
|
image = sharp::Trim(image, baton->trimBackground, baton->trimThreshold, baton->trimLineArt, baton->trimMargin);
|
||||||
baton->trimOffsetLeft = image.xoffset();
|
baton->trimOffsetLeft = image.xoffset();
|
||||||
baton->trimOffsetTop = image.yoffset();
|
baton->trimOffsetTop = image.yoffset();
|
||||||
}
|
}
|
||||||
@@ -274,7 +274,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|||||||
}
|
}
|
||||||
sharp::SetDensity(image, baton->input->density);
|
sharp::SetDensity(image, baton->input->density);
|
||||||
if (image.width() > 32767 || image.height() > 32767) {
|
if (image.width() > 32767 || image.height() > 32767) {
|
||||||
throw vips::VError("Input SVG image will exceed 32767x32767 pixel limit when scaled");
|
throw std::runtime_error("Input SVG image will exceed 32767x32767 pixel limit when scaled");
|
||||||
}
|
}
|
||||||
} else if (inputImageType == sharp::ImageType::PDF) {
|
} else if (inputImageType == sharp::ImageType::PDF) {
|
||||||
if (baton->input->buffer != nullptr) {
|
if (baton->input->buffer != nullptr) {
|
||||||
@@ -290,12 +290,20 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (inputImageType == sharp::ImageType::SVG && (image.width() > 32767 || image.height() > 32767)) {
|
if (inputImageType == sharp::ImageType::SVG && (image.width() > 32767 || image.height() > 32767)) {
|
||||||
throw vips::VError("Input SVG image exceeds 32767x32767 pixel limit");
|
throw std::runtime_error("Input SVG image exceeds 32767x32767 pixel limit");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (baton->input->autoOrient) {
|
if (baton->input->autoOrient) {
|
||||||
image = sharp::RemoveExifOrientation(image);
|
image = sharp::RemoveExifOrientation(image);
|
||||||
}
|
}
|
||||||
|
if (sharp::HasGainMap(image)) {
|
||||||
|
if (baton->withGainMap) {
|
||||||
|
image = image.uhdr2scRGB();
|
||||||
|
}
|
||||||
|
image = sharp::RemoveGainMap(image);
|
||||||
|
} else {
|
||||||
|
baton->withGainMap = false;
|
||||||
|
}
|
||||||
|
|
||||||
// Any pre-shrinking may already have been done
|
// Any pre-shrinking may already have been done
|
||||||
inputWidth = image.width();
|
inputWidth = image.width();
|
||||||
@@ -335,7 +343,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|||||||
image.interpretation() != VIPS_INTERPRETATION_LABS &&
|
image.interpretation() != VIPS_INTERPRETATION_LABS &&
|
||||||
image.interpretation() != VIPS_INTERPRETATION_GREY16 &&
|
image.interpretation() != VIPS_INTERPRETATION_GREY16 &&
|
||||||
baton->colourspacePipeline != VIPS_INTERPRETATION_CMYK &&
|
baton->colourspacePipeline != VIPS_INTERPRETATION_CMYK &&
|
||||||
!baton->input->ignoreIcc
|
!baton->input->ignoreIcc && !baton->withGainMap
|
||||||
) {
|
) {
|
||||||
// Convert to sRGB/P3 using embedded profile
|
// Convert to sRGB/P3 using embedded profile
|
||||||
try {
|
try {
|
||||||
@@ -667,7 +675,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|||||||
|
|
||||||
// Verify within current dimensions
|
// Verify within current dimensions
|
||||||
if (compositeImage.width() > image.width() || compositeImage.height() > image.height()) {
|
if (compositeImage.width() > image.width() || compositeImage.height() > image.height()) {
|
||||||
throw vips::VError("Image to composite must have same dimensions or smaller");
|
throw std::runtime_error("Image to composite must have same dimensions or smaller");
|
||||||
}
|
}
|
||||||
// Check if overlay is tiled
|
// Check if overlay is tiled
|
||||||
if (composite->tile) {
|
if (composite->tile) {
|
||||||
@@ -957,6 +965,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|||||||
->set("effort", baton->webpEffort)
|
->set("effort", baton->webpEffort)
|
||||||
->set("min_size", baton->webpMinSize)
|
->set("min_size", baton->webpMinSize)
|
||||||
->set("mixed", baton->webpMixed)
|
->set("mixed", baton->webpMixed)
|
||||||
|
->set("exact", baton->webpExact)
|
||||||
->set("alpha_q", baton->webpAlphaQuality)));
|
->set("alpha_q", baton->webpAlphaQuality)));
|
||||||
baton->bufferOut = static_cast<char*>(area->data);
|
baton->bufferOut = static_cast<char*>(area->data);
|
||||||
baton->bufferOutLength = area->length;
|
baton->bufferOutLength = area->length;
|
||||||
@@ -1024,6 +1033,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|||||||
->set("compression", baton->heifCompression)
|
->set("compression", baton->heifCompression)
|
||||||
->set("effort", baton->heifEffort)
|
->set("effort", baton->heifEffort)
|
||||||
->set("bitdepth", baton->heifBitdepth)
|
->set("bitdepth", baton->heifBitdepth)
|
||||||
|
->set("tune", baton->heifTune.c_str())
|
||||||
->set("subsample_mode", baton->heifChromaSubsampling == "4:4:4"
|
->set("subsample_mode", baton->heifChromaSubsampling == "4:4:4"
|
||||||
? VIPS_FOREIGN_SUBSAMPLE_OFF : VIPS_FOREIGN_SUBSAMPLE_ON)
|
? VIPS_FOREIGN_SUBSAMPLE_OFF : VIPS_FOREIGN_SUBSAMPLE_ON)
|
||||||
->set("lossless", baton->heifLossless)));
|
->set("lossless", baton->heifLossless)));
|
||||||
@@ -1076,20 +1086,19 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|||||||
// Get raw image data
|
// Get raw image data
|
||||||
baton->bufferOut = static_cast<char*>(image.write_to_memory(&baton->bufferOutLength));
|
baton->bufferOut = static_cast<char*>(image.write_to_memory(&baton->bufferOutLength));
|
||||||
if (baton->bufferOut == nullptr) {
|
if (baton->bufferOut == nullptr) {
|
||||||
(baton->err).append("Could not allocate enough memory for raw output");
|
throw std::runtime_error("Could not allocate enough memory for raw output");
|
||||||
return Error();
|
|
||||||
}
|
}
|
||||||
baton->formatOut = "raw";
|
baton->formatOut = "raw";
|
||||||
} else {
|
} else {
|
||||||
// Unsupported output format
|
// Unsupported output format
|
||||||
(baton->err).append("Unsupported output format ");
|
auto unsupported = std::string("Unsupported output format ");
|
||||||
if (baton->formatOut == "input") {
|
if (baton->formatOut == "input") {
|
||||||
(baton->err).append("when trying to match input format of ");
|
unsupported.append("when trying to match input format of ");
|
||||||
(baton->err).append(ImageTypeId(inputImageType));
|
unsupported.append(ImageTypeId(inputImageType));
|
||||||
} else {
|
} else {
|
||||||
(baton->err).append(baton->formatOut);
|
unsupported.append(baton->formatOut);
|
||||||
}
|
}
|
||||||
return Error();
|
throw std::runtime_error(unsupported);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// File output
|
// File output
|
||||||
@@ -1168,6 +1177,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|||||||
->set("effort", baton->webpEffort)
|
->set("effort", baton->webpEffort)
|
||||||
->set("min_size", baton->webpMinSize)
|
->set("min_size", baton->webpMinSize)
|
||||||
->set("mixed", baton->webpMixed)
|
->set("mixed", baton->webpMixed)
|
||||||
|
->set("exact", baton->webpExact)
|
||||||
->set("alpha_q", baton->webpAlphaQuality));
|
->set("alpha_q", baton->webpAlphaQuality));
|
||||||
baton->formatOut = "webp";
|
baton->formatOut = "webp";
|
||||||
} else if (baton->formatOut == "gif" || (mightMatchInput && isGif) ||
|
} else if (baton->formatOut == "gif" || (mightMatchInput && isGif) ||
|
||||||
@@ -1223,6 +1233,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|||||||
->set("compression", baton->heifCompression)
|
->set("compression", baton->heifCompression)
|
||||||
->set("effort", baton->heifEffort)
|
->set("effort", baton->heifEffort)
|
||||||
->set("bitdepth", baton->heifBitdepth)
|
->set("bitdepth", baton->heifBitdepth)
|
||||||
|
->set("tune", baton->heifTune.c_str())
|
||||||
->set("subsample_mode", baton->heifChromaSubsampling == "4:4:4"
|
->set("subsample_mode", baton->heifChromaSubsampling == "4:4:4"
|
||||||
? VIPS_FOREIGN_SUBSAMPLE_OFF : VIPS_FOREIGN_SUBSAMPLE_ON)
|
? VIPS_FOREIGN_SUBSAMPLE_OFF : VIPS_FOREIGN_SUBSAMPLE_ON)
|
||||||
->set("lossless", baton->heifLossless));
|
->set("lossless", baton->heifLossless));
|
||||||
@@ -1262,7 +1273,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|||||||
return Error();
|
return Error();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (vips::VError const &err) {
|
} catch (std::runtime_error const &err) {
|
||||||
char const *what = err.what();
|
char const *what = err.what();
|
||||||
if (what && what[0]) {
|
if (what && what[0]) {
|
||||||
(baton->err).append(what);
|
(baton->err).append(what);
|
||||||
@@ -1294,7 +1305,6 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|||||||
}
|
}
|
||||||
warning = sharp::VipsWarningPop();
|
warning = sharp::VipsWarningPop();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (baton->err.empty()) {
|
if (baton->err.empty()) {
|
||||||
int width = baton->width;
|
int width = baton->width;
|
||||||
int height = baton->height;
|
int height = baton->height;
|
||||||
@@ -1337,12 +1347,21 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (baton->bufferOutLength > 0) {
|
if (baton->bufferOutLength > 0) {
|
||||||
// Add buffer size to info
|
|
||||||
info.Set("size", static_cast<uint32_t>(baton->bufferOutLength));
|
info.Set("size", static_cast<uint32_t>(baton->bufferOutLength));
|
||||||
// Pass ownership of output data to Buffer instance
|
if (baton->typedArrayOut) {
|
||||||
Napi::Buffer<char> data = Napi::Buffer<char>::NewOrCopy(env, static_cast<char*>(baton->bufferOut),
|
// ECMAScript ArrayBuffer with Uint8Array view
|
||||||
baton->bufferOutLength, sharp::FreeCallback);
|
Napi::ArrayBuffer ab = Napi::ArrayBuffer::New(env, baton->bufferOutLength);
|
||||||
Callback().Call(Receiver().Value(), { env.Null(), data, info });
|
memcpy(ab.Data(), baton->bufferOut, baton->bufferOutLength);
|
||||||
|
sharp::FreeCallback(static_cast<char*>(baton->bufferOut), nullptr);
|
||||||
|
Napi::TypedArrayOf<uint8_t> data = Napi::TypedArrayOf<uint8_t>::New(env,
|
||||||
|
baton->bufferOutLength, ab, 0, napi_uint8_array);
|
||||||
|
Callback().Call(Receiver().Value(), { env.Null(), data, info });
|
||||||
|
} else {
|
||||||
|
// Node.js Buffer
|
||||||
|
Napi::Buffer<char> data = Napi::Buffer<char>::NewOrCopy(env, static_cast<char*>(baton->bufferOut),
|
||||||
|
baton->bufferOutLength, sharp::FreeCallback);
|
||||||
|
Callback().Call(Receiver().Value(), { env.Null(), data, info });
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// Add file size to info
|
// Add file size to info
|
||||||
if (baton->formatOut != "dz" || sharp::IsDzZip(baton->fileOut)) {
|
if (baton->formatOut != "dz" || sharp::IsDzZip(baton->fileOut)) {
|
||||||
@@ -1386,7 +1405,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|||||||
|
|
||||||
void MultiPageUnsupported(int const pages, std::string op) {
|
void MultiPageUnsupported(int const pages, std::string op) {
|
||||||
if (pages > 1) {
|
if (pages > 1) {
|
||||||
throw vips::VError(op + " is not supported for multi-page images");
|
throw std::runtime_error(op + " is not supported for multi-page images");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1469,6 +1488,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|||||||
{"preset", vips_enum_nick(VIPS_TYPE_FOREIGN_WEBP_PRESET, baton->webpPreset)},
|
{"preset", vips_enum_nick(VIPS_TYPE_FOREIGN_WEBP_PRESET, baton->webpPreset)},
|
||||||
{"min_size", baton->webpMinSize ? "true" : "false"},
|
{"min_size", baton->webpMinSize ? "true" : "false"},
|
||||||
{"mixed", baton->webpMixed ? "true" : "false"},
|
{"mixed", baton->webpMixed ? "true" : "false"},
|
||||||
|
{"exact", baton->webpExact ? "true" : "false"},
|
||||||
{"effort", std::to_string(baton->webpEffort)}
|
{"effort", std::to_string(baton->webpEffort)}
|
||||||
};
|
};
|
||||||
suffix = AssembleSuffixString(".webp", options);
|
suffix = AssembleSuffixString(".webp", options);
|
||||||
@@ -1615,6 +1635,7 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
|||||||
baton->trimBackground = sharp::AttrAsVectorOfDouble(options, "trimBackground");
|
baton->trimBackground = sharp::AttrAsVectorOfDouble(options, "trimBackground");
|
||||||
baton->trimThreshold = sharp::AttrAsDouble(options, "trimThreshold");
|
baton->trimThreshold = sharp::AttrAsDouble(options, "trimThreshold");
|
||||||
baton->trimLineArt = sharp::AttrAsBool(options, "trimLineArt");
|
baton->trimLineArt = sharp::AttrAsBool(options, "trimLineArt");
|
||||||
|
baton->trimMargin = sharp::AttrAsUint32(options, "trimMargin");
|
||||||
baton->gamma = sharp::AttrAsDouble(options, "gamma");
|
baton->gamma = sharp::AttrAsDouble(options, "gamma");
|
||||||
baton->gammaOut = sharp::AttrAsDouble(options, "gammaOut");
|
baton->gammaOut = sharp::AttrAsDouble(options, "gammaOut");
|
||||||
baton->linearA = sharp::AttrAsVectorOfDouble(options, "linearA");
|
baton->linearA = sharp::AttrAsVectorOfDouble(options, "linearA");
|
||||||
@@ -1692,6 +1713,7 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
|||||||
// Output
|
// Output
|
||||||
baton->formatOut = sharp::AttrAsStr(options, "formatOut");
|
baton->formatOut = sharp::AttrAsStr(options, "formatOut");
|
||||||
baton->fileOut = sharp::AttrAsStr(options, "fileOut");
|
baton->fileOut = sharp::AttrAsStr(options, "fileOut");
|
||||||
|
baton->typedArrayOut = sharp::AttrAsBool(options, "typedArrayOut");
|
||||||
baton->keepMetadata = sharp::AttrAsUint32(options, "keepMetadata");
|
baton->keepMetadata = sharp::AttrAsUint32(options, "keepMetadata");
|
||||||
baton->withMetadataOrientation = sharp::AttrAsUint32(options, "withMetadataOrientation");
|
baton->withMetadataOrientation = sharp::AttrAsUint32(options, "withMetadataOrientation");
|
||||||
baton->withMetadataDensity = sharp::AttrAsDouble(options, "withMetadataDensity");
|
baton->withMetadataDensity = sharp::AttrAsDouble(options, "withMetadataDensity");
|
||||||
@@ -1706,6 +1728,7 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
|||||||
}
|
}
|
||||||
baton->withExifMerge = sharp::AttrAsBool(options, "withExifMerge");
|
baton->withExifMerge = sharp::AttrAsBool(options, "withExifMerge");
|
||||||
baton->withXmp = sharp::AttrAsStr(options, "withXmp");
|
baton->withXmp = sharp::AttrAsStr(options, "withXmp");
|
||||||
|
baton->withGainMap = sharp::AttrAsBool(options, "withGainMap");
|
||||||
baton->timeoutSeconds = sharp::AttrAsUint32(options, "timeoutSeconds");
|
baton->timeoutSeconds = sharp::AttrAsUint32(options, "timeoutSeconds");
|
||||||
baton->loop = sharp::AttrAsUint32(options, "loop");
|
baton->loop = sharp::AttrAsUint32(options, "loop");
|
||||||
baton->delay = sharp::AttrAsInt32Vector(options, "delay");
|
baton->delay = sharp::AttrAsInt32Vector(options, "delay");
|
||||||
@@ -1741,6 +1764,7 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
|||||||
baton->webpEffort = sharp::AttrAsUint32(options, "webpEffort");
|
baton->webpEffort = sharp::AttrAsUint32(options, "webpEffort");
|
||||||
baton->webpMinSize = sharp::AttrAsBool(options, "webpMinSize");
|
baton->webpMinSize = sharp::AttrAsBool(options, "webpMinSize");
|
||||||
baton->webpMixed = sharp::AttrAsBool(options, "webpMixed");
|
baton->webpMixed = sharp::AttrAsBool(options, "webpMixed");
|
||||||
|
baton->webpExact = sharp::AttrAsBool(options, "webpExact");
|
||||||
baton->gifBitdepth = sharp::AttrAsUint32(options, "gifBitdepth");
|
baton->gifBitdepth = sharp::AttrAsUint32(options, "gifBitdepth");
|
||||||
baton->gifEffort = sharp::AttrAsUint32(options, "gifEffort");
|
baton->gifEffort = sharp::AttrAsUint32(options, "gifEffort");
|
||||||
baton->gifDither = sharp::AttrAsDouble(options, "gifDither");
|
baton->gifDither = sharp::AttrAsDouble(options, "gifDither");
|
||||||
@@ -1775,6 +1799,7 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
|||||||
baton->heifEffort = sharp::AttrAsUint32(options, "heifEffort");
|
baton->heifEffort = sharp::AttrAsUint32(options, "heifEffort");
|
||||||
baton->heifChromaSubsampling = sharp::AttrAsStr(options, "heifChromaSubsampling");
|
baton->heifChromaSubsampling = sharp::AttrAsStr(options, "heifChromaSubsampling");
|
||||||
baton->heifBitdepth = sharp::AttrAsUint32(options, "heifBitdepth");
|
baton->heifBitdepth = sharp::AttrAsUint32(options, "heifBitdepth");
|
||||||
|
baton->heifTune = sharp::AttrAsStr(options, "heifTune");
|
||||||
baton->jxlDistance = sharp::AttrAsDouble(options, "jxlDistance");
|
baton->jxlDistance = sharp::AttrAsDouble(options, "jxlDistance");
|
||||||
baton->jxlDecodingTier = sharp::AttrAsUint32(options, "jxlDecodingTier");
|
baton->jxlDecodingTier = sharp::AttrAsUint32(options, "jxlDecodingTier");
|
||||||
baton->jxlEffort = sharp::AttrAsUint32(options, "jxlEffort");
|
baton->jxlEffort = sharp::AttrAsUint32(options, "jxlEffort");
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ struct PipelineBaton {
|
|||||||
size_t bufferOutLength;
|
size_t bufferOutLength;
|
||||||
int pageHeightOut;
|
int pageHeightOut;
|
||||||
int pagesOut;
|
int pagesOut;
|
||||||
|
bool typedArrayOut;
|
||||||
std::vector<Composite *> composite;
|
std::vector<Composite *> composite;
|
||||||
std::vector<sharp::InputDescriptor *> joinChannelIn;
|
std::vector<sharp::InputDescriptor *> joinChannelIn;
|
||||||
int topOffsetPre;
|
int topOffsetPre;
|
||||||
@@ -101,6 +102,7 @@ struct PipelineBaton {
|
|||||||
bool trimLineArt;
|
bool trimLineArt;
|
||||||
int trimOffsetLeft;
|
int trimOffsetLeft;
|
||||||
int trimOffsetTop;
|
int trimOffsetTop;
|
||||||
|
int trimMargin;
|
||||||
std::vector<double> linearA;
|
std::vector<double> linearA;
|
||||||
std::vector<double> linearB;
|
std::vector<double> linearB;
|
||||||
int dilateWidth;
|
int dilateWidth;
|
||||||
@@ -167,6 +169,7 @@ struct PipelineBaton {
|
|||||||
int webpEffort;
|
int webpEffort;
|
||||||
bool webpMinSize;
|
bool webpMinSize;
|
||||||
bool webpMixed;
|
bool webpMixed;
|
||||||
|
bool webpExact;
|
||||||
int gifBitdepth;
|
int gifBitdepth;
|
||||||
int gifEffort;
|
int gifEffort;
|
||||||
double gifDither;
|
double gifDither;
|
||||||
@@ -194,6 +197,7 @@ struct PipelineBaton {
|
|||||||
std::string heifChromaSubsampling;
|
std::string heifChromaSubsampling;
|
||||||
bool heifLossless;
|
bool heifLossless;
|
||||||
int heifBitdepth;
|
int heifBitdepth;
|
||||||
|
std::string heifTune;
|
||||||
double jxlDistance;
|
double jxlDistance;
|
||||||
int jxlDecodingTier;
|
int jxlDecodingTier;
|
||||||
int jxlEffort;
|
int jxlEffort;
|
||||||
@@ -208,6 +212,7 @@ struct PipelineBaton {
|
|||||||
std::unordered_map<std::string, std::string> withExif;
|
std::unordered_map<std::string, std::string> withExif;
|
||||||
bool withExifMerge;
|
bool withExifMerge;
|
||||||
std::string withXmp;
|
std::string withXmp;
|
||||||
|
bool withGainMap;
|
||||||
int timeoutSeconds;
|
int timeoutSeconds;
|
||||||
std::vector<double> convKernel;
|
std::vector<double> convKernel;
|
||||||
int convKernelWidth;
|
int convKernelWidth;
|
||||||
@@ -242,6 +247,7 @@ struct PipelineBaton {
|
|||||||
bufferOutLength(0),
|
bufferOutLength(0),
|
||||||
pageHeightOut(0),
|
pageHeightOut(0),
|
||||||
pagesOut(0),
|
pagesOut(0),
|
||||||
|
typedArrayOut(false),
|
||||||
topOffsetPre(-1),
|
topOffsetPre(-1),
|
||||||
topOffsetPost(-1),
|
topOffsetPost(-1),
|
||||||
channels(0),
|
channels(0),
|
||||||
@@ -281,6 +287,7 @@ struct PipelineBaton {
|
|||||||
trimLineArt(false),
|
trimLineArt(false),
|
||||||
trimOffsetLeft(0),
|
trimOffsetLeft(0),
|
||||||
trimOffsetTop(0),
|
trimOffsetTop(0),
|
||||||
|
trimMargin(0),
|
||||||
linearA{},
|
linearA{},
|
||||||
linearB{},
|
linearB{},
|
||||||
dilateWidth(0),
|
dilateWidth(0),
|
||||||
@@ -344,6 +351,7 @@ struct PipelineBaton {
|
|||||||
webpEffort(4),
|
webpEffort(4),
|
||||||
webpMinSize(false),
|
webpMinSize(false),
|
||||||
webpMixed(false),
|
webpMixed(false),
|
||||||
|
webpExact(false),
|
||||||
gifBitdepth(8),
|
gifBitdepth(8),
|
||||||
gifEffort(7),
|
gifEffort(7),
|
||||||
gifDither(1.0),
|
gifDither(1.0),
|
||||||
@@ -357,7 +365,7 @@ struct PipelineBaton {
|
|||||||
tiffBigtiff(false),
|
tiffBigtiff(false),
|
||||||
tiffPredictor(VIPS_FOREIGN_TIFF_PREDICTOR_HORIZONTAL),
|
tiffPredictor(VIPS_FOREIGN_TIFF_PREDICTOR_HORIZONTAL),
|
||||||
tiffPyramid(false),
|
tiffPyramid(false),
|
||||||
tiffBitdepth(8),
|
tiffBitdepth(0),
|
||||||
tiffMiniswhite(false),
|
tiffMiniswhite(false),
|
||||||
tiffTile(false),
|
tiffTile(false),
|
||||||
tiffTileHeight(256),
|
tiffTileHeight(256),
|
||||||
@@ -371,6 +379,7 @@ struct PipelineBaton {
|
|||||||
heifChromaSubsampling("4:4:4"),
|
heifChromaSubsampling("4:4:4"),
|
||||||
heifLossless(false),
|
heifLossless(false),
|
||||||
heifBitdepth(8),
|
heifBitdepth(8),
|
||||||
|
heifTune("ssim"),
|
||||||
jxlDistance(1.0),
|
jxlDistance(1.0),
|
||||||
jxlDecodingTier(0),
|
jxlDecodingTier(0),
|
||||||
jxlEffort(7),
|
jxlEffort(7),
|
||||||
@@ -381,6 +390,7 @@ struct PipelineBaton {
|
|||||||
withMetadataOrientation(-1),
|
withMetadataOrientation(-1),
|
||||||
withMetadataDensity(0.0),
|
withMetadataDensity(0.0),
|
||||||
withExifMerge(true),
|
withExifMerge(true),
|
||||||
|
withGainMap(false),
|
||||||
timeoutSeconds(0),
|
timeoutSeconds(0),
|
||||||
convKernelWidth(0),
|
convKernelWidth(0),
|
||||||
convKernelHeight(0),
|
convKernelHeight(0),
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ class StatsWorker : public Napi::AsyncWorker {
|
|||||||
sharp::ImageType imageType = sharp::ImageType::UNKNOWN;
|
sharp::ImageType imageType = sharp::ImageType::UNKNOWN;
|
||||||
try {
|
try {
|
||||||
std::tie(image, imageType) = OpenInput(baton->input);
|
std::tie(image, imageType) = OpenInput(baton->input);
|
||||||
} catch (vips::VError const &err) {
|
} catch (std::runtime_error const &err) {
|
||||||
(baton->err).append(err.what());
|
(baton->err).append(err.what());
|
||||||
}
|
}
|
||||||
if (imageType != sharp::ImageType::UNKNOWN) {
|
if (imageType != sharp::ImageType::UNKNOWN) {
|
||||||
@@ -92,7 +92,7 @@ class StatsWorker : public Napi::AsyncWorker {
|
|||||||
baton->dominantRed = dx * 16 + 8;
|
baton->dominantRed = dx * 16 + 8;
|
||||||
baton->dominantGreen = dy * 16 + 8;
|
baton->dominantGreen = dy * 16 + 8;
|
||||||
baton->dominantBlue = dz * 16 + 8;
|
baton->dominantBlue = dz * 16 + 8;
|
||||||
} catch (vips::VError const &err) {
|
} catch (std::runtime_error const &err) {
|
||||||
(baton->err).append(err.what());
|
(baton->err).append(err.what());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -112,7 +112,6 @@ class StatsWorker : public Napi::AsyncWorker {
|
|||||||
debuglog.Call(Receiver().Value(), { Napi::String::New(env, warning) });
|
debuglog.Call(Receiver().Value(), { Napi::String::New(env, warning) });
|
||||||
warning = sharp::VipsWarningPop();
|
warning = sharp::VipsWarningPop();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (baton->err.empty()) {
|
if (baton->err.empty()) {
|
||||||
// Stats Object
|
// Stats Object
|
||||||
Napi::Object info = Napi::Object::New(env);
|
Napi::Object info = Napi::Object::New(env);
|
||||||
|
|||||||
@@ -123,6 +123,7 @@ Napi::Value format(const Napi::CallbackInfo& info) {
|
|||||||
"jpeg", "png", "webp", "tiff", "magick", "openslide", "dz",
|
"jpeg", "png", "webp", "tiff", "magick", "openslide", "dz",
|
||||||
"ppm", "fits", "gif", "svg", "heif", "pdf", "vips", "jp2k", "jxl", "rad", "dcraw"
|
"ppm", "fits", "gif", "svg", "heif", "pdf", "vips", "jp2k", "jxl", "rad", "dcraw"
|
||||||
}) {
|
}) {
|
||||||
|
std::string id = f == "jp2k" ? "jp2" : f;
|
||||||
// Input
|
// Input
|
||||||
const VipsObjectClass *oc = vips_class_find("VipsOperation", (f + "load").c_str());
|
const VipsObjectClass *oc = vips_class_find("VipsOperation", (f + "load").c_str());
|
||||||
Napi::Boolean hasInputFile = Napi::Boolean::New(env, oc);
|
Napi::Boolean hasInputFile = Napi::Boolean::New(env, oc);
|
||||||
@@ -154,11 +155,11 @@ Napi::Value format(const Napi::CallbackInfo& info) {
|
|||||||
output.Set("stream", hasOutputBuffer);
|
output.Set("stream", hasOutputBuffer);
|
||||||
// Other attributes
|
// Other attributes
|
||||||
Napi::Object container = Napi::Object::New(env);
|
Napi::Object container = Napi::Object::New(env);
|
||||||
container.Set("id", f);
|
container.Set("id", id);
|
||||||
container.Set("input", input);
|
container.Set("input", input);
|
||||||
container.Set("output", output);
|
container.Set("output", output);
|
||||||
// Add to set of formats
|
// Add to set of formats
|
||||||
format.Set(f, container);
|
format.Set(id, container);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Raw, uncompressed data
|
// Raw, uncompressed data
|
||||||
@@ -243,7 +244,7 @@ Napi::Value _maxColourDistance(const Napi::CallbackInfo& info) {
|
|||||||
}
|
}
|
||||||
// Calculate colour distance
|
// Calculate colour distance
|
||||||
maxColourDistance = image1.dE00(image2).max();
|
maxColourDistance = image1.dE00(image2).max();
|
||||||
} catch (vips::VError const &err) {
|
} catch (std::runtime_error const &err) {
|
||||||
throw Napi::Error::New(env, err.what());
|
throw Napi::Error::New(env, err.what());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -228,6 +228,19 @@ async.series({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}).add('sharp-buffer-uint8array', {
|
||||||
|
defer: true,
|
||||||
|
fn: (deferred) => {
|
||||||
|
sharp(inputJpgBuffer)
|
||||||
|
.resize(width, height)
|
||||||
|
.toUint8Array()
|
||||||
|
.then(() => {
|
||||||
|
deferred.resolve();
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
throw err;
|
||||||
|
});
|
||||||
|
}
|
||||||
}).add('sharp-file-file', {
|
}).add('sharp-file-file', {
|
||||||
defer: true,
|
defer: true,
|
||||||
fn: (deferred) => {
|
fn: (deferred) => {
|
||||||
@@ -266,6 +279,19 @@ async.series({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}).add('sharp-file-uint8array', {
|
||||||
|
defer: true,
|
||||||
|
fn: (deferred) => {
|
||||||
|
sharp(fixtures.inputJpg)
|
||||||
|
.resize(width, height)
|
||||||
|
.toUint8Array()
|
||||||
|
.then(() => {
|
||||||
|
deferred.resolve();
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
throw err;
|
||||||
|
});
|
||||||
|
}
|
||||||
}).add('sharp-promise', {
|
}).add('sharp-promise', {
|
||||||
defer: true,
|
defer: true,
|
||||||
fn: (deferred) => {
|
fn: (deferred) => {
|
||||||
|
|||||||
BIN
test/fixtures/gain-map.jpg
vendored
Normal file
BIN
test/fixtures/gain-map.jpg
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.1 MiB |
4
test/fixtures/index.js
vendored
4
test/fixtures/index.js
vendored
@@ -70,9 +70,11 @@ module.exports = {
|
|||||||
inputJpgRandom: getPath('random.jpg'), // convert -size 200x200 xc: +noise Random random.jpg
|
inputJpgRandom: getPath('random.jpg'), // convert -size 200x200 xc: +noise Random random.jpg
|
||||||
inputJpgThRandom: getPath('thRandom.jpg'), // convert random.jpg -channel G -threshold 5% -separate +channel -negate thRandom.jpg
|
inputJpgThRandom: getPath('thRandom.jpg'), // convert random.jpg -channel G -threshold 5% -separate +channel -negate thRandom.jpg
|
||||||
inputJpgLossless: getPath('testimgl.jpg'), // Lossless JPEG from ftp://ftp.fu-berlin.de/unix/X11/graphics/ImageMagick/delegates/ljpeg-6b.tar.gz
|
inputJpgLossless: getPath('testimgl.jpg'), // Lossless JPEG from ftp://ftp.fu-berlin.de/unix/X11/graphics/ImageMagick/delegates/ljpeg-6b.tar.gz
|
||||||
|
inputJpgWithGainMap: getPath('gain-map.jpg'), // https://github.com/libvips/libvips/issues/3799
|
||||||
|
|
||||||
inputPng: getPath('50020484-00001.png'), // http://c.searspartsdirect.com/lis_png/PLDM/50020484-00001.png
|
inputPng: getPath('50020484-00001.png'), // http://c.searspartsdirect.com/lis_png/PLDM/50020484-00001.png
|
||||||
inputPngGradients: getPath('gradients-rgb8.png'),
|
inputPngGradients: getPath('gradients-rgb8.png'),
|
||||||
|
inputPngWithSlightGradientBorder: getPath('slight-gradient-border.png'),
|
||||||
inputPngWithTransparency: getPath('blackbug.png'), // public domain
|
inputPngWithTransparency: getPath('blackbug.png'), // public domain
|
||||||
inputPngCompleteTransparency: getPath('full-transparent.png'),
|
inputPngCompleteTransparency: getPath('full-transparent.png'),
|
||||||
inputPngWithGreyAlpha: getPath('grey-8bit-alpha.png'),
|
inputPngWithGreyAlpha: getPath('grey-8bit-alpha.png'),
|
||||||
@@ -125,7 +127,7 @@ module.exports = {
|
|||||||
inputSvgSmallViewBox: getPath('circle.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
|
||||||
inputAvif: getPath('sdr_cosmos12920_cicp1-13-6_yuv444_full_qp10.avif'), // CC by-nc-nd https://github.com/AOMediaCodec/av1-avif/tree/master/testFiles/Netflix
|
inputAvif: getPath('sdr_cosmos12920_cicp1-13-6_yuv444_full_qp10.avif'), // CC by-nc-nd https://github.com/AOMediaCodec/av1-avif/tree/master/testFiles/Netflix
|
||||||
|
inputAvifWithPitmBox: getPath('pitm.avif'), // https://github.com/lovell/sharp/issues/4487
|
||||||
inputJPGBig: getPath('flowers.jpeg'),
|
inputJPGBig: getPath('flowers.jpeg'),
|
||||||
|
|
||||||
inputPngDotAndLines: getPath('dot-and-lines.png'),
|
inputPngDotAndLines: getPath('dot-and-lines.png'),
|
||||||
|
|||||||
BIN
test/fixtures/pitm.avif
vendored
Normal file
BIN
test/fixtures/pitm.avif
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 65 KiB |
BIN
test/fixtures/slight-gradient-border.png
vendored
Normal file
BIN
test/fixtures/slight-gradient-border.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 34 KiB |
@@ -86,6 +86,9 @@ let transformer = sharp()
|
|||||||
});
|
});
|
||||||
readableStream.pipe(transformer).pipe(writableStream);
|
readableStream.pipe(transformer).pipe(writableStream);
|
||||||
|
|
||||||
|
sharp().toUint8Array();
|
||||||
|
sharp().toUint8Array().then(({ data }) => data.byteLength);
|
||||||
|
|
||||||
console.log(sharp.format);
|
console.log(sharp.format);
|
||||||
console.log(sharp.versions);
|
console.log(sharp.versions);
|
||||||
|
|
||||||
@@ -231,7 +234,7 @@ sharp(input)
|
|||||||
|
|
||||||
sharp(input)
|
sharp(input)
|
||||||
.resize(100, 100)
|
.resize(100, 100)
|
||||||
.toFormat('jpg')
|
.toFormat('avif')
|
||||||
.toBuffer({ resolveWithObject: false })
|
.toBuffer({ resolveWithObject: false })
|
||||||
.then((outputBuffer: Buffer) => {
|
.then((outputBuffer: Buffer) => {
|
||||||
// Resolves with a Buffer object when resolveWithObject is false
|
// Resolves with a Buffer object when resolveWithObject is false
|
||||||
@@ -264,9 +267,7 @@ sharp(input)
|
|||||||
// Output to tif
|
// Output to tif
|
||||||
sharp(input)
|
sharp(input)
|
||||||
.resize(100, 100)
|
.resize(100, 100)
|
||||||
.toFormat('tif')
|
|
||||||
.toFormat('tiff')
|
.toFormat('tiff')
|
||||||
.toFormat(sharp.format.tif)
|
|
||||||
.toFormat(sharp.format.tiff)
|
.toFormat(sharp.format.tiff)
|
||||||
.toBuffer();
|
.toBuffer();
|
||||||
|
|
||||||
@@ -362,7 +363,7 @@ sharp(input)
|
|||||||
.avif({ quality: 50, lossless: false, effort: 5, chromaSubsampling: '4:2:0' })
|
.avif({ quality: 50, lossless: false, effort: 5, chromaSubsampling: '4:2:0' })
|
||||||
.heif()
|
.heif()
|
||||||
.heif({})
|
.heif({})
|
||||||
.heif({ quality: 50, compression: 'hevc', lossless: false, effort: 5, chromaSubsampling: '4:2:0' })
|
.heif({ quality: 50, compression: 'hevc', lossless: false, effort: 5, chromaSubsampling: '4:2:0', tune: 'psnr' })
|
||||||
.toBuffer({ resolveWithObject: true })
|
.toBuffer({ resolveWithObject: true })
|
||||||
.then(({ data, info }) => {
|
.then(({ data, info }) => {
|
||||||
console.log(data);
|
console.log(data);
|
||||||
@@ -545,8 +546,8 @@ sharp('input.tiff').jxl({ decodingTier: 4 }).toFile('out.jxl');
|
|||||||
sharp('input.tiff').jxl({ lossless: true }).toFile('out.jxl');
|
sharp('input.tiff').jxl({ lossless: true }).toFile('out.jxl');
|
||||||
sharp('input.tiff').jxl({ effort: 7 }).toFile('out.jxl');
|
sharp('input.tiff').jxl({ effort: 7 }).toFile('out.jxl');
|
||||||
|
|
||||||
// Support `minSize` and `mixed` webp options
|
// Support webp options
|
||||||
sharp('input.tiff').webp({ minSize: true, mixed: true }).toFile('out.gif');
|
sharp('input.tiff').webp({ minSize: true, mixed: true, exact: true }).toFile('out.webp');
|
||||||
|
|
||||||
// 'failOn' input param
|
// 'failOn' input param
|
||||||
sharp('input.tiff', { failOn: 'none' });
|
sharp('input.tiff', { failOn: 'none' });
|
||||||
@@ -598,7 +599,7 @@ const vertexSplitQuadraticBasisSpline: string = sharp.interpolators.vertexSplitQ
|
|||||||
// Triming
|
// Triming
|
||||||
sharp(input).trim({ background: '#000' }).toBuffer();
|
sharp(input).trim({ background: '#000' }).toBuffer();
|
||||||
sharp(input).trim({ threshold: 10, lineArt: true }).toBuffer();
|
sharp(input).trim({ threshold: 10, lineArt: true }).toBuffer();
|
||||||
sharp(input).trim({ background: '#bf1942', threshold: 30 }).toBuffer();
|
sharp(input).trim({ background: '#bf1942', threshold: 30, margin: 20 }).toBuffer();
|
||||||
|
|
||||||
// Text input
|
// Text input
|
||||||
sharp({
|
sharp({
|
||||||
@@ -771,3 +772,35 @@ sharp().erode();
|
|||||||
sharp().erode(1);
|
sharp().erode(1);
|
||||||
sharp().dilate();
|
sharp().dilate();
|
||||||
sharp().dilate(1);
|
sharp().dilate(1);
|
||||||
|
|
||||||
|
sharp.format.dcraw;
|
||||||
|
sharp.format.dz;
|
||||||
|
sharp.format.fits;
|
||||||
|
sharp.format.gif;
|
||||||
|
sharp.format.heif;
|
||||||
|
sharp.format.jp2;
|
||||||
|
sharp.format.jpeg;
|
||||||
|
sharp.format.jxl;
|
||||||
|
sharp.format.magick;
|
||||||
|
sharp.format.openslide;
|
||||||
|
sharp.format.pdf;
|
||||||
|
sharp.format.png;
|
||||||
|
sharp.format.ppm;
|
||||||
|
sharp.format.rad;
|
||||||
|
sharp.format.raw;
|
||||||
|
sharp.format.svg;
|
||||||
|
sharp.format.tiff;
|
||||||
|
sharp.format.vips;
|
||||||
|
sharp.format.webp;
|
||||||
|
// @ts-expect-error
|
||||||
|
sharp.format.avif;
|
||||||
|
// @ts-expect-error
|
||||||
|
sharp.format.input;
|
||||||
|
// @ts-expect-error
|
||||||
|
sharp.format.jp2k;
|
||||||
|
// @ts-expect-error
|
||||||
|
sharp.format.jpg;
|
||||||
|
// @ts-expect-error
|
||||||
|
sharp.format.tif;
|
||||||
|
// @ts-expect-error
|
||||||
|
sharp.format.v;
|
||||||
|
|||||||
@@ -7,7 +7,13 @@ const { describe, it } = require('node:test');
|
|||||||
const assert = require('node:assert');
|
const assert = require('node:assert');
|
||||||
|
|
||||||
const sharp = require('../../');
|
const sharp = require('../../');
|
||||||
const { inputAvif, inputJpg, inputGifAnimated } = require('../fixtures');
|
const {
|
||||||
|
inputAvif,
|
||||||
|
inputAvifWithPitmBox,
|
||||||
|
inputJpg,
|
||||||
|
inputGifAnimated,
|
||||||
|
inputPng,
|
||||||
|
} = require('../fixtures');
|
||||||
|
|
||||||
describe('AVIF', () => {
|
describe('AVIF', () => {
|
||||||
it('called without options does not throw an error', () => {
|
it('called without options does not throw an error', () => {
|
||||||
@@ -17,16 +23,13 @@ describe('AVIF', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('can convert AVIF to JPEG', async () => {
|
it('can convert AVIF to JPEG', async () => {
|
||||||
const data = await sharp(inputAvif)
|
const data = await sharp(inputAvif).resize(32).jpeg().toBuffer();
|
||||||
.resize(32)
|
|
||||||
.jpeg()
|
|
||||||
.toBuffer();
|
|
||||||
const { size, ...metadata } = await sharp(data).metadata();
|
const { size, ...metadata } = await sharp(data).metadata();
|
||||||
void size;
|
void size;
|
||||||
assert.deepStrictEqual(metadata, {
|
assert.deepStrictEqual(metadata, {
|
||||||
autoOrient: {
|
autoOrient: {
|
||||||
height: 13,
|
height: 13,
|
||||||
width: 32
|
width: 32,
|
||||||
},
|
},
|
||||||
channels: 3,
|
channels: 3,
|
||||||
chromaSubsampling: '4:2:0',
|
chromaSubsampling: '4:2:0',
|
||||||
@@ -41,7 +44,7 @@ describe('AVIF', () => {
|
|||||||
isProgressive: false,
|
isProgressive: false,
|
||||||
isPalette: false,
|
isPalette: false,
|
||||||
space: 'srgb',
|
space: 'srgb',
|
||||||
width: 32
|
width: 32,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -55,7 +58,7 @@ describe('AVIF', () => {
|
|||||||
assert.deepStrictEqual(metadata, {
|
assert.deepStrictEqual(metadata, {
|
||||||
autoOrient: {
|
autoOrient: {
|
||||||
height: 26,
|
height: 26,
|
||||||
width: 32
|
width: 32,
|
||||||
},
|
},
|
||||||
channels: 3,
|
channels: 3,
|
||||||
compression: 'av1',
|
compression: 'av1',
|
||||||
@@ -70,20 +73,47 @@ describe('AVIF', () => {
|
|||||||
pagePrimary: 0,
|
pagePrimary: 0,
|
||||||
pages: 1,
|
pages: 1,
|
||||||
space: 'srgb',
|
space: 'srgb',
|
||||||
width: 32
|
width: 32,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can passthrough AVIF', async () => {
|
it('can convert PNG to lossless AVIF', async () => {
|
||||||
const data = await sharp(inputAvif)
|
const data = await sharp(inputPng)
|
||||||
.resize(32)
|
.resize(32)
|
||||||
|
.avif({ lossless: true, effort: 0 })
|
||||||
.toBuffer();
|
.toBuffer();
|
||||||
const { size, ...metadata } = await sharp(data).metadata();
|
const { size, ...metadata } = await sharp(data).metadata();
|
||||||
void size;
|
void size;
|
||||||
|
assert.deepStrictEqual(metadata, {
|
||||||
|
autoOrient: {
|
||||||
|
height: 24,
|
||||||
|
width: 32,
|
||||||
|
},
|
||||||
|
channels: 3,
|
||||||
|
compression: 'av1',
|
||||||
|
depth: 'uchar',
|
||||||
|
format: 'heif',
|
||||||
|
hasAlpha: false,
|
||||||
|
hasProfile: false,
|
||||||
|
height: 24,
|
||||||
|
isProgressive: false,
|
||||||
|
isPalette: false,
|
||||||
|
bitsPerSample: 8,
|
||||||
|
pagePrimary: 0,
|
||||||
|
pages: 1,
|
||||||
|
space: 'srgb',
|
||||||
|
width: 32,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can passthrough AVIF', async () => {
|
||||||
|
const data = await sharp(inputAvif).resize(32).toBuffer();
|
||||||
|
const { size, ...metadata } = await sharp(data).metadata();
|
||||||
|
void size;
|
||||||
assert.deepStrictEqual(metadata, {
|
assert.deepStrictEqual(metadata, {
|
||||||
autoOrient: {
|
autoOrient: {
|
||||||
height: 13,
|
height: 13,
|
||||||
width: 32
|
width: 32,
|
||||||
},
|
},
|
||||||
channels: 3,
|
channels: 3,
|
||||||
compression: 'av1',
|
compression: 'av1',
|
||||||
@@ -98,7 +128,7 @@ describe('AVIF', () => {
|
|||||||
pagePrimary: 0,
|
pagePrimary: 0,
|
||||||
pages: 1,
|
pages: 1,
|
||||||
space: 'srgb',
|
space: 'srgb',
|
||||||
width: 32
|
width: 32,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -112,7 +142,7 @@ describe('AVIF', () => {
|
|||||||
assert.deepStrictEqual(metadata, {
|
assert.deepStrictEqual(metadata, {
|
||||||
autoOrient: {
|
autoOrient: {
|
||||||
height: 300,
|
height: 300,
|
||||||
width: 10
|
width: 10,
|
||||||
},
|
},
|
||||||
channels: 4,
|
channels: 4,
|
||||||
compression: 'av1',
|
compression: 'av1',
|
||||||
@@ -127,7 +157,7 @@ describe('AVIF', () => {
|
|||||||
pagePrimary: 0,
|
pagePrimary: 0,
|
||||||
pages: 1,
|
pages: 1,
|
||||||
space: 'srgb',
|
space: 'srgb',
|
||||||
width: 10
|
width: 10,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -142,7 +172,7 @@ describe('AVIF', () => {
|
|||||||
assert.deepStrictEqual(metadata, {
|
assert.deepStrictEqual(metadata, {
|
||||||
autoOrient: {
|
autoOrient: {
|
||||||
height: 26,
|
height: 26,
|
||||||
width: 32
|
width: 32,
|
||||||
},
|
},
|
||||||
channels: 3,
|
channels: 3,
|
||||||
compression: 'av1',
|
compression: 'av1',
|
||||||
@@ -157,28 +187,89 @@ describe('AVIF', () => {
|
|||||||
pagePrimary: 0,
|
pagePrimary: 0,
|
||||||
pages: 1,
|
pages: 1,
|
||||||
space: 'srgb',
|
space: 'srgb',
|
||||||
width: 32
|
width: 32,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Invalid width - too large', async () =>
|
it('Invalid width - too large', async () =>
|
||||||
assert.rejects(
|
assert.rejects(
|
||||||
() => sharp({ create: { width: 16385, height: 16, channels: 3, background: 'red' } }).avif().toBuffer(),
|
() =>
|
||||||
/Processed image is too large for the HEIF format/
|
sharp({
|
||||||
)
|
create: { width: 16385, height: 16, channels: 3, background: 'red' },
|
||||||
);
|
})
|
||||||
|
.avif()
|
||||||
|
.toBuffer(),
|
||||||
|
/Processed image is too large for the HEIF format/,
|
||||||
|
));
|
||||||
|
|
||||||
it('Invalid height - too large', async () =>
|
it('Invalid height - too large', async () =>
|
||||||
assert.rejects(
|
assert.rejects(
|
||||||
() => sharp({ create: { width: 16, height: 16385, channels: 3, background: 'red' } }).avif().toBuffer(),
|
() =>
|
||||||
/Processed image is too large for the HEIF format/
|
sharp({
|
||||||
)
|
create: { width: 16, height: 16385, channels: 3, background: 'red' },
|
||||||
);
|
})
|
||||||
|
.avif()
|
||||||
|
.toBuffer(),
|
||||||
|
/Processed image is too large for the HEIF format/,
|
||||||
|
));
|
||||||
|
|
||||||
it('Invalid bitdepth value throws error', () =>
|
it('Invalid bitdepth value throws error', () =>
|
||||||
assert.throws(
|
assert.throws(
|
||||||
() => sharp().avif({ bitdepth: 11 }),
|
() => sharp().avif({ bitdepth: 11 }),
|
||||||
/Expected 8, 10 or 12 for bitdepth but received 11 of type number/
|
/Expected 8, 10 or 12 for bitdepth but received 11 of type number/,
|
||||||
)
|
));
|
||||||
);
|
|
||||||
|
it('Different tune options result in different file sizes', async () => {
|
||||||
|
const ssim = await sharp(inputJpg)
|
||||||
|
.resize(32)
|
||||||
|
.avif({ tune: 'ssim', effort: 0 })
|
||||||
|
.toBuffer();
|
||||||
|
const iq = await sharp(inputJpg)
|
||||||
|
.resize(32)
|
||||||
|
.avif({ tune: 'iq', effort: 0 })
|
||||||
|
.toBuffer();
|
||||||
|
assert(ssim.length < iq.length);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('AVIF with non-zero primary item uses it as default page', async () => {
|
||||||
|
const { exif, ...metadata } = await sharp(inputAvifWithPitmBox).metadata();
|
||||||
|
void exif;
|
||||||
|
assert.deepStrictEqual(metadata, {
|
||||||
|
format: 'heif',
|
||||||
|
width: 4096,
|
||||||
|
height: 800,
|
||||||
|
space: 'srgb',
|
||||||
|
channels: 3,
|
||||||
|
depth: 'uchar',
|
||||||
|
isProgressive: false,
|
||||||
|
isPalette: false,
|
||||||
|
bitsPerSample: 8,
|
||||||
|
pages: 5,
|
||||||
|
pagePrimary: 4,
|
||||||
|
compression: 'av1',
|
||||||
|
resolutionUnit: 'cm',
|
||||||
|
hasProfile: false,
|
||||||
|
hasAlpha: false,
|
||||||
|
autoOrient: { width: 4096, height: 800 },
|
||||||
|
});
|
||||||
|
|
||||||
|
const data = await sharp(inputAvifWithPitmBox)
|
||||||
|
.png({ compressionLevel: 0 })
|
||||||
|
.toBuffer();
|
||||||
|
const { size, ...pngMetadata } = await sharp(data).metadata();
|
||||||
|
assert.deepStrictEqual(pngMetadata, {
|
||||||
|
format: 'png',
|
||||||
|
width: 4096,
|
||||||
|
height: 800,
|
||||||
|
space: 'srgb',
|
||||||
|
channels: 3,
|
||||||
|
depth: 'uchar',
|
||||||
|
isProgressive: false,
|
||||||
|
isPalette: false,
|
||||||
|
bitsPerSample: 8,
|
||||||
|
hasProfile: false,
|
||||||
|
hasAlpha: false,
|
||||||
|
autoOrient: { width: 4096, height: 800 },
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -54,23 +54,6 @@ describe('failOn', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('deprecated failOnError', () => {
|
|
||||||
assert.doesNotThrow(
|
|
||||||
() => sharp({ failOnError: true })
|
|
||||||
);
|
|
||||||
assert.doesNotThrow(
|
|
||||||
() => sharp({ failOnError: false })
|
|
||||||
);
|
|
||||||
assert.throws(
|
|
||||||
() => sharp({ failOnError: 'zoinks' }),
|
|
||||||
/Expected boolean for failOnError but received zoinks of type string/
|
|
||||||
);
|
|
||||||
assert.throws(
|
|
||||||
() => sharp({ failOnError: 1 }),
|
|
||||||
/Expected boolean for failOnError but received 1 of type number/
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns errors to callback for truncated JPEG', (_t, done) => {
|
it('returns errors to callback for truncated JPEG', (_t, done) => {
|
||||||
sharp(fixtures.inputJpgTruncated, { failOn: 'truncated' }).toBuffer((err, data, info) => {
|
sharp(fixtures.inputJpgTruncated, { failOn: 'truncated' }).toBuffer((err, data, info) => {
|
||||||
assert.ok(err.message.includes('VipsJpeg: premature end of'), err);
|
assert.ok(err.message.includes('VipsJpeg: premature end of'), err);
|
||||||
|
|||||||
69
test/unit/gain-map.js
Normal file
69
test/unit/gain-map.js
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
/*!
|
||||||
|
Copyright 2013 Lovell Fuller and others.
|
||||||
|
SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
const { describe, it } = require('node:test');
|
||||||
|
|
||||||
|
const sharp = require('../../');
|
||||||
|
const fixtures = require('../fixtures');
|
||||||
|
|
||||||
|
describe('Gain maps', () => {
|
||||||
|
it('Metadata contains gainMap', async (t) => {
|
||||||
|
t.plan(4);
|
||||||
|
|
||||||
|
const { format, gainMap } = await sharp(
|
||||||
|
fixtures.inputJpgWithGainMap,
|
||||||
|
).metadata();
|
||||||
|
t.assert.strictEqual(format, 'jpeg');
|
||||||
|
t.assert.strictEqual(typeof gainMap, 'object');
|
||||||
|
t.assert.ok(Buffer.isBuffer(gainMap.image));
|
||||||
|
t.assert.strictEqual(gainMap.image.length, 31738);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Can be regenerated', async (t) => {
|
||||||
|
t.plan(4);
|
||||||
|
|
||||||
|
const data = await sharp(fixtures.inputJpgWithGainMap)
|
||||||
|
.withGainMap()
|
||||||
|
.toBuffer();
|
||||||
|
const metadata = await sharp(data).metadata();
|
||||||
|
t.assert.strictEqual(metadata.format, 'jpeg');
|
||||||
|
t.assert.strictEqual(typeof metadata.gainMap, 'object');
|
||||||
|
t.assert.ok(Buffer.isBuffer(metadata.gainMap.image));
|
||||||
|
|
||||||
|
const {
|
||||||
|
format,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
channels,
|
||||||
|
depth,
|
||||||
|
space,
|
||||||
|
hasProfile,
|
||||||
|
chromaSubsampling,
|
||||||
|
} = await sharp(metadata.gainMap.image).metadata();
|
||||||
|
|
||||||
|
t.assert.deepEqual(
|
||||||
|
{
|
||||||
|
format,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
channels,
|
||||||
|
depth,
|
||||||
|
space,
|
||||||
|
hasProfile,
|
||||||
|
chromaSubsampling,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
format: 'jpeg',
|
||||||
|
width: 1920,
|
||||||
|
height: 1080,
|
||||||
|
channels: 1,
|
||||||
|
depth: 'uchar',
|
||||||
|
space: 'b-w',
|
||||||
|
hasProfile: true,
|
||||||
|
chromaSubsampling: '4:4:4',
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -96,4 +96,14 @@ describe('HEIF', () => {
|
|||||||
sharp().heif({ compression: 'av1', bitdepth: 11 });
|
sharp().heif({ compression: 'av1', bitdepth: 11 });
|
||||||
}, /Error: Expected 8, 10 or 12 for bitdepth but received 11 of type number/);
|
}, /Error: Expected 8, 10 or 12 for bitdepth but received 11 of type number/);
|
||||||
});
|
});
|
||||||
|
it('valid tune does not throw an error', () => {
|
||||||
|
assert.doesNotThrow(() => {
|
||||||
|
sharp().heif({ compression: 'hevc', tune: 'psnr' });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('invalid tune should throw an error', () => {
|
||||||
|
assert.throws(() => {
|
||||||
|
sharp().heif({ compression: 'hevc', tune: 'fail' });
|
||||||
|
}, /Error: Expected one of: psnr, ssim, iq for tune but received fail of type string/);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ const fs = require('node:fs');
|
|||||||
const path = require('node:path');
|
const path = require('node:path');
|
||||||
const { afterEach, beforeEach, describe, it } = require('node:test');
|
const { afterEach, beforeEach, describe, it } = require('node:test');
|
||||||
const assert = require('node:assert');
|
const assert = require('node:assert');
|
||||||
|
const { isMarkedAsUntransferable } = require('node:worker_threads');
|
||||||
|
|
||||||
const sharp = require('../../');
|
const sharp = require('../../');
|
||||||
const fixtures = require('../fixtures');
|
const fixtures = require('../fixtures');
|
||||||
@@ -1092,4 +1093,39 @@ describe('Input/output', () => {
|
|||||||
assert.strictEqual(channels, 3);
|
assert.strictEqual(channels, 3);
|
||||||
assert.strictEqual(format, 'jpeg');
|
assert.strictEqual(format, 'jpeg');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('toBuffer resolves with an untransferable Buffer', async () => {
|
||||||
|
const data = await sharp(fixtures.inputJpg)
|
||||||
|
.resize({ width: 8, height: 8 })
|
||||||
|
.toBuffer();
|
||||||
|
|
||||||
|
if (isMarkedAsUntransferable) {
|
||||||
|
assert.strictEqual(isMarkedAsUntransferable(data.buffer), true);
|
||||||
|
}
|
||||||
|
assert.strictEqual(ArrayBuffer.isView(data), true);
|
||||||
|
assert.strictEqual(ArrayBuffer.isView(data.buffer), false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('toUint8Array resolves with a transferable Uint8Array', async () => {
|
||||||
|
const { data, info } = await sharp(fixtures.inputJpg)
|
||||||
|
.resize({ width: 8, height: 8 })
|
||||||
|
.toUint8Array();
|
||||||
|
|
||||||
|
assert.strictEqual(data instanceof Uint8Array, true);
|
||||||
|
if (isMarkedAsUntransferable) {
|
||||||
|
assert.strictEqual(isMarkedAsUntransferable(data.buffer), false);
|
||||||
|
}
|
||||||
|
assert.strictEqual(ArrayBuffer.isView(data), true);
|
||||||
|
assert.strictEqual(info.format, 'jpeg');
|
||||||
|
assert.strictEqual(info.width, 8);
|
||||||
|
assert.strictEqual(info.height, 8);
|
||||||
|
assert.strictEqual(data.byteLength, info.size);
|
||||||
|
assert.strictEqual(data[0], 0xFF);
|
||||||
|
assert.strictEqual(data[1], 0xD8);
|
||||||
|
|
||||||
|
const metadata = await sharp(data).metadata();
|
||||||
|
assert.strictEqual(metadata.format, 'jpeg');
|
||||||
|
assert.strictEqual(metadata.width, 8);
|
||||||
|
assert.strictEqual(metadata.height, 8);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ const sharp = require('../../');
|
|||||||
const fixtures = require('../fixtures');
|
const fixtures = require('../fixtures');
|
||||||
|
|
||||||
describe('JP2 output', () => {
|
describe('JP2 output', () => {
|
||||||
if (!sharp.format.jp2k.input.buffer) {
|
if (!sharp.format.jp2.input.buffer) {
|
||||||
it('JP2 output should fail due to missing OpenJPEG', () =>
|
it('JP2 output should fail due to missing OpenJPEG', () =>
|
||||||
assert.rejects(async () =>
|
assert.rejects(async () =>
|
||||||
sharp(fixtures.inputJpg)
|
sharp(fixtures.inputJpg)
|
||||||
|
|||||||
@@ -180,7 +180,7 @@ describe('libvips binaries', () => {
|
|||||||
process.env.npm_config_arch = 's390x';
|
process.env.npm_config_arch = 's390x';
|
||||||
process.env.npm_config_libc = '';
|
process.env.npm_config_libc = '';
|
||||||
const locatorHash = libvips.yarnLocator();
|
const locatorHash = libvips.yarnLocator();
|
||||||
assert.strictEqual(locatorHash, '4ab19140fd');
|
assert.strictEqual(locatorHash, 'f7e557e9d6');
|
||||||
delete process.env.npm_config_platform;
|
delete process.env.npm_config_platform;
|
||||||
delete process.env.npm_config_arch;
|
delete process.env.npm_config_arch;
|
||||||
delete process.env.npm_config_libc;
|
delete process.env.npm_config_libc;
|
||||||
|
|||||||
@@ -154,7 +154,6 @@ describe('PNG', () => {
|
|||||||
isProgressive: false,
|
isProgressive: false,
|
||||||
isPalette: true,
|
isPalette: true,
|
||||||
bitsPerSample: 8,
|
bitsPerSample: 8,
|
||||||
paletteBitDepth: 8,
|
|
||||||
hasProfile: false,
|
hasProfile: false,
|
||||||
hasAlpha: false
|
hasAlpha: false
|
||||||
});
|
});
|
||||||
@@ -226,12 +225,10 @@ describe('PNG', () => {
|
|||||||
.png({ colours: 2, palette: false })
|
.png({ colours: 2, palette: false })
|
||||||
.toBuffer();
|
.toBuffer();
|
||||||
|
|
||||||
const { channels, isPalette, bitsPerSample, paletteBitDepth, size, space } = await sharp(data).metadata();
|
const { channels, isPalette, bitsPerSample, space } = await sharp(data).metadata();
|
||||||
assert.strictEqual(channels, 1);
|
assert.strictEqual(channels, 1);
|
||||||
assert.strictEqual(isPalette, false);
|
assert.strictEqual(isPalette, false);
|
||||||
assert.strictEqual(bitsPerSample, 1);
|
assert.strictEqual(bitsPerSample, 1);
|
||||||
assert.strictEqual(paletteBitDepth, undefined);
|
|
||||||
assert.strictEqual(size, 89);
|
|
||||||
assert.strictEqual(space, 'b-w');
|
assert.strictEqual(space, 'b-w');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -94,24 +94,6 @@ describe('Sharpen', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('invalid sigma', () => {
|
|
||||||
assert.throws(() => {
|
|
||||||
sharp(fixtures.inputJpg).sharpen(-1.5);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('invalid flat', () => {
|
|
||||||
assert.throws(() => {
|
|
||||||
sharp(fixtures.inputJpg).sharpen(1, -1);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('invalid jagged', () => {
|
|
||||||
assert.throws(() => {
|
|
||||||
sharp(fixtures.inputJpg).sharpen(1, 1, -1);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('invalid options.sigma', () => assert.throws(
|
it('invalid options.sigma', () => assert.throws(
|
||||||
() => sharp().sharpen({ sigma: -1 }),
|
() => sharp().sharpen({ sigma: -1 }),
|
||||||
/Expected number between 0\.000001 and 10 for options\.sigma but received -1 of type number/
|
/Expected number between 0\.000001 and 10 for options\.sigma but received -1 of type number/
|
||||||
@@ -144,24 +126,23 @@ describe('Sharpen', () => {
|
|||||||
|
|
||||||
it('sharpened image is larger than non-sharpened', (_t, done) => {
|
it('sharpened image is larger than non-sharpened', (_t, done) => {
|
||||||
sharp(fixtures.inputJpg)
|
sharp(fixtures.inputJpg)
|
||||||
.resize(320, 240)
|
.resize(32, 24)
|
||||||
.sharpen(false)
|
|
||||||
.toBuffer((err, notSharpened, info) => {
|
.toBuffer((err, notSharpened, info) => {
|
||||||
if (err) throw err;
|
if (err) throw err;
|
||||||
assert.strictEqual(true, notSharpened.length > 0);
|
assert.strictEqual(true, notSharpened.length > 0);
|
||||||
assert.strictEqual('jpeg', info.format);
|
assert.strictEqual('jpeg', info.format);
|
||||||
assert.strictEqual(320, info.width);
|
assert.strictEqual(32, info.width);
|
||||||
assert.strictEqual(240, info.height);
|
assert.strictEqual(24, info.height);
|
||||||
sharp(fixtures.inputJpg)
|
sharp(fixtures.inputJpg)
|
||||||
.resize(320, 240)
|
.resize(32, 24)
|
||||||
.sharpen(true)
|
.sharpen()
|
||||||
.toBuffer((err, sharpened, info) => {
|
.toBuffer((err, sharpened, info) => {
|
||||||
if (err) throw err;
|
if (err) throw err;
|
||||||
assert.strictEqual(true, sharpened.length > 0);
|
assert.strictEqual(true, sharpened.length > 0);
|
||||||
assert.strictEqual(true, sharpened.length > notSharpened.length);
|
assert.strictEqual(true, sharpened.length > notSharpened.length);
|
||||||
assert.strictEqual('jpeg', info.format);
|
assert.strictEqual('jpeg', info.format);
|
||||||
assert.strictEqual(320, info.width);
|
assert.strictEqual(32, info.width);
|
||||||
assert.strictEqual(240, info.height);
|
assert.strictEqual(24, info.height);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -122,7 +122,6 @@ describe('TIFF', () => {
|
|||||||
sharp(fixtures.inputTiff8BitDepth)
|
sharp(fixtures.inputTiff8BitDepth)
|
||||||
.toColourspace('b-w') // can only squash 1 band uchar images
|
.toColourspace('b-w') // can only squash 1 band uchar images
|
||||||
.tiff({
|
.tiff({
|
||||||
bitdepth: 8,
|
|
||||||
compression: 'none',
|
compression: 'none',
|
||||||
predictor: 'none'
|
predictor: 'none'
|
||||||
})
|
})
|
||||||
@@ -154,7 +153,7 @@ describe('TIFF', () => {
|
|||||||
it('Invalid TIFF bitdepth value throws error', () => {
|
it('Invalid TIFF bitdepth value throws error', () => {
|
||||||
assert.throws(() => {
|
assert.throws(() => {
|
||||||
sharp().tiff({ bitdepth: 3 });
|
sharp().tiff({ bitdepth: 3 });
|
||||||
}, /Error: Expected 1, 2, 4 or 8 for bitdepth but received 3 of type number/);
|
}, /Error: Expected 1, 2 or 4 for bitdepth but received 3 of type number/);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('TIFF setting xres and yres on file', () =>
|
it('TIFF setting xres and yres on file', () =>
|
||||||
|
|||||||
@@ -222,6 +222,9 @@ describe('Trim borders', () => {
|
|||||||
},
|
},
|
||||||
'Invalid lineArt': {
|
'Invalid lineArt': {
|
||||||
lineArt: 'fail'
|
lineArt: 'fail'
|
||||||
|
},
|
||||||
|
'Invalid margin': {
|
||||||
|
margin: -1
|
||||||
}
|
}
|
||||||
}).forEach(([description, parameter]) => {
|
}).forEach(([description, parameter]) => {
|
||||||
it(description, () => {
|
it(description, () => {
|
||||||
@@ -289,4 +292,42 @@ describe('Trim borders', () => {
|
|||||||
assert.strictEqual(trimOffsetLeft, 0);
|
assert.strictEqual(trimOffsetLeft, 0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('Adds margin around content', () => {
|
||||||
|
it('Should trim complex gradients', async () => {
|
||||||
|
const { info } = await sharp(fixtures.inputPngGradients)
|
||||||
|
.trim({ threshold: 50, margin: 100 })
|
||||||
|
.toBuffer({ resolveWithObject: true });
|
||||||
|
|
||||||
|
const { width, height, trimOffsetTop, trimOffsetLeft } = info;
|
||||||
|
assert.strictEqual(width, 1000);
|
||||||
|
assert.strictEqual(height, 443);
|
||||||
|
assert.strictEqual(trimOffsetTop, -557);
|
||||||
|
assert.strictEqual(trimOffsetLeft, 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should trim simple gradients', async () => {
|
||||||
|
const { info } = await sharp(fixtures.inputPngWithSlightGradientBorder)
|
||||||
|
.trim({ threshold: 70, margin: 50 })
|
||||||
|
.toBuffer({ resolveWithObject: true });
|
||||||
|
|
||||||
|
const { width, height, trimOffsetTop, trimOffsetLeft } = info;
|
||||||
|
assert.strictEqual(width, 900);
|
||||||
|
assert.strictEqual(height, 900);
|
||||||
|
assert.strictEqual(trimOffsetTop, -50);
|
||||||
|
assert.strictEqual(trimOffsetLeft, -50);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should not overflow image bounding box', async () => {
|
||||||
|
const { info } = await sharp(fixtures.inputPngWithSlightGradientBorder)
|
||||||
|
.trim({ threshold: 70, margin: 9999999 })
|
||||||
|
.toBuffer({ resolveWithObject: true });
|
||||||
|
|
||||||
|
const { width, height, trimOffsetTop, trimOffsetLeft } = info;
|
||||||
|
assert.strictEqual(width, 1000);
|
||||||
|
assert.strictEqual(height, 1000);
|
||||||
|
assert.strictEqual(trimOffsetTop, 0);
|
||||||
|
assert.strictEqual(trimOffsetLeft, 0);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -213,6 +213,33 @@ describe('WebP', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('valid exact', () => {
|
||||||
|
assert.doesNotThrow(() => sharp().webp({ exact: true }));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('invalid exact throws', () => {
|
||||||
|
assert.throws(
|
||||||
|
() => sharp().webp({ exact: 'fail' }),
|
||||||
|
/Expected boolean for webpExact but received fail of type string/
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('saving exact pixel colour values produces larger file size', async () => {
|
||||||
|
const withExact = await
|
||||||
|
sharp(fixtures.inputPngAlphaPremultiplicationSmall)
|
||||||
|
.resize(8, 8)
|
||||||
|
.webp({ exact: true, effort: 0 })
|
||||||
|
.toBuffer();
|
||||||
|
|
||||||
|
const withoutExact = await
|
||||||
|
sharp(fixtures.inputPngAlphaPremultiplicationSmall)
|
||||||
|
.resize(8, 8)
|
||||||
|
.webp({ exact: false, effort: 0 })
|
||||||
|
.toBuffer()
|
||||||
|
|
||||||
|
assert.strictEqual(true, withExact.length > withoutExact.length);
|
||||||
|
});
|
||||||
|
|
||||||
it('invalid loop throws', () => {
|
it('invalid loop throws', () => {
|
||||||
assert.throws(() => {
|
assert.throws(() => {
|
||||||
sharp().webp({ loop: -1 });
|
sharp().webp({ loop: -1 });
|
||||||
|
|||||||
Reference in New Issue
Block a user