Compare commits
42 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
978a788f40 | ||
|
|
6e91d55971 | ||
|
|
d4ce0a1e36 | ||
|
|
148608b377 | ||
|
|
f725f4acb7 | ||
|
|
d07a549438 | ||
|
|
551441cedd | ||
|
|
46c14e939b | ||
|
|
6084647795 | ||
|
|
e0a598ae62 | ||
|
|
28833eb04a | ||
|
|
b24c9c86d1 | ||
|
|
b7add480c7 | ||
|
|
eabb671b10 | ||
|
|
513ed02b76 | ||
|
|
b7ddbe71f7 | ||
|
|
21d1a7ca62 | ||
|
|
4c2d28a7ad | ||
|
|
2afec9e3ed | ||
|
|
69790421b7 | ||
|
|
3f08f6a359 | ||
|
|
719c2db8da | ||
|
|
a9aa55c32d | ||
|
|
3f6d9d6ee9 | ||
|
|
b32568159f | ||
|
|
bb48d0d857 | ||
|
|
536412515f | ||
|
|
fcc6eaadd3 | ||
|
|
7dc78e8796 | ||
|
|
c65de3fe6d | ||
|
|
d000f57773 | ||
|
|
75cddbdb6d | ||
|
|
e418d91511 | ||
|
|
6c2e6c5432 | ||
|
|
8c6d9fdc62 | ||
|
|
468e95427e | ||
|
|
6d7a5ace6b | ||
|
|
cbaec198a5 | ||
|
|
7467fa8b50 | ||
|
|
61640fb5c7 | ||
|
|
19cb4b62b0 | ||
|
|
81ee8bc30f |
77
.circleci/config.yml
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
version: 2.1
|
||||||
|
|
||||||
|
workflows:
|
||||||
|
build:
|
||||||
|
jobs:
|
||||||
|
- linux-arm64-glibc-node-12:
|
||||||
|
filters:
|
||||||
|
tags:
|
||||||
|
only: /^v.*/
|
||||||
|
- linux-arm64-musl-node-12:
|
||||||
|
filters:
|
||||||
|
tags:
|
||||||
|
only: /^v.*/
|
||||||
|
- linux-arm64-glibc-node-16:
|
||||||
|
filters:
|
||||||
|
tags:
|
||||||
|
only: /^v.*/
|
||||||
|
- linux-arm64-musl-node-16:
|
||||||
|
filters:
|
||||||
|
tags:
|
||||||
|
only: /^v.*/
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
linux-arm64-glibc-node-12:
|
||||||
|
resource_class: arm.medium
|
||||||
|
machine:
|
||||||
|
image: ubuntu-2004:202101-01
|
||||||
|
steps:
|
||||||
|
- checkout
|
||||||
|
- run: |
|
||||||
|
sudo docker run -dit --name sharp --volume "${PWD}:/mnt/sharp" --workdir /mnt/sharp arm64v8/debian:bullseye
|
||||||
|
sudo docker exec sharp sh -c "apt-get update && apt-get install -y build-essential git python3 curl"
|
||||||
|
sudo docker exec sharp sh -c "curl -s https://deb.nodesource.com/gpgkey/nodesource.gpg.key | apt-key add -"
|
||||||
|
sudo docker exec sharp sh -c "echo 'deb https://deb.nodesource.com/node_12.x sid main' >/etc/apt/sources.list.d/nodesource.list"
|
||||||
|
sudo docker exec sharp sh -c "apt-get update && apt-get install -y nodejs"
|
||||||
|
- run: sudo docker exec sharp sh -c "npm install --build-from-source --unsafe-perm"
|
||||||
|
- run: sudo docker exec sharp sh -c "npm test"
|
||||||
|
- run: "[[ -n $CIRCLE_TAG ]] && sudo docker exec --env prebuild_upload sharp sh -c \"npx prebuild --runtime napi --target 5 --upload=$prebuild_upload\" || true"
|
||||||
|
linux-arm64-glibc-node-16:
|
||||||
|
resource_class: arm.medium
|
||||||
|
machine:
|
||||||
|
image: ubuntu-2004:202101-01
|
||||||
|
steps:
|
||||||
|
- checkout
|
||||||
|
- run: |
|
||||||
|
sudo chown 0.0 ${PWD}
|
||||||
|
sudo docker run -dit --name sharp --volume "${PWD}:/mnt/sharp" --workdir /mnt/sharp arm64v8/debian:bullseye
|
||||||
|
sudo docker exec sharp sh -c "apt-get update && apt-get install -y build-essential git python3 curl"
|
||||||
|
sudo docker exec sharp sh -c "curl -s https://deb.nodesource.com/gpgkey/nodesource.gpg.key | apt-key add -"
|
||||||
|
sudo docker exec sharp sh -c "echo 'deb https://deb.nodesource.com/node_16.x sid main' >/etc/apt/sources.list.d/nodesource.list"
|
||||||
|
sudo docker exec sharp sh -c "apt-get update && apt-get install -y nodejs"
|
||||||
|
- run: sudo docker exec sharp sh -c "npm install --build-from-source --unsafe-perm"
|
||||||
|
- run: sudo docker exec sharp sh -c "npm test"
|
||||||
|
linux-arm64-musl-node-12:
|
||||||
|
resource_class: arm.medium
|
||||||
|
machine:
|
||||||
|
image: ubuntu-2004:202101-01
|
||||||
|
steps:
|
||||||
|
- checkout
|
||||||
|
- run: |
|
||||||
|
sudo docker run -dit --name sharp --volume "${PWD}:/mnt/sharp" --workdir /mnt/sharp node:12-alpine3.11
|
||||||
|
sudo docker exec sharp sh -c "apk add build-base git python3 --update-cache"
|
||||||
|
- run: sudo docker exec sharp sh -c "npm install --build-from-source --unsafe-perm"
|
||||||
|
- run: sudo docker exec sharp sh -c "npm test"
|
||||||
|
- run: "[[ -n $CIRCLE_TAG ]] && sudo docker exec --env prebuild_upload sharp sh -c \"npx prebuild --runtime napi --target 5 --upload=$prebuild_upload\" || true"
|
||||||
|
linux-arm64-musl-node-16:
|
||||||
|
resource_class: arm.medium
|
||||||
|
machine:
|
||||||
|
image: ubuntu-2004:202101-01
|
||||||
|
steps:
|
||||||
|
- checkout
|
||||||
|
- run: |
|
||||||
|
sudo chown 0.0 ${PWD}
|
||||||
|
sudo docker run -dit --name sharp --volume "${PWD}:/mnt/sharp" --workdir /mnt/sharp node:16-alpine3.11
|
||||||
|
sudo docker exec sharp sh -c "apk add build-base git python3 --update-cache"
|
||||||
|
- run: sudo docker exec sharp sh -c "npm install --build-from-source --unsafe-perm"
|
||||||
|
- run: sudo docker exec sharp sh -c "npm test"
|
||||||
27
.github/workflows/ci-darwin-arm64v8.yml
vendored
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
name: CI (MacStadium)
|
||||||
|
on:
|
||||||
|
- push
|
||||||
|
- pull_request
|
||||||
|
jobs:
|
||||||
|
CI:
|
||||||
|
runs-on: macos-m1
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
shell: /usr/bin/arch -arch arm64e /bin/bash -l {0}
|
||||||
|
steps:
|
||||||
|
- name: Dependencies
|
||||||
|
uses: actions/setup-node@v2
|
||||||
|
with:
|
||||||
|
node-version: 16
|
||||||
|
architecture: arm64
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
- name: Install
|
||||||
|
run: npm install --build-from-source --unsafe-perm
|
||||||
|
- name: Test
|
||||||
|
run: npm test
|
||||||
|
- name: Prebuild
|
||||||
|
if: startsWith(github.ref, 'refs/tags/')
|
||||||
|
env:
|
||||||
|
prebuild_upload: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
run: npx prebuild --runtime napi --target 5
|
||||||
24
.github/workflows/ci.yml
vendored
@@ -1,3 +1,4 @@
|
|||||||
|
name: CI (GitHub)
|
||||||
on:
|
on:
|
||||||
- push
|
- push
|
||||||
- pull_request
|
- pull_request
|
||||||
@@ -11,43 +12,34 @@ jobs:
|
|||||||
include:
|
include:
|
||||||
- os: ubuntu-20.04
|
- os: ubuntu-20.04
|
||||||
container: centos:7
|
container: centos:7
|
||||||
nodejs_version: 10
|
nodejs_version: 12
|
||||||
coverage: true
|
coverage: true
|
||||||
prebuild: true
|
prebuild: true
|
||||||
- os: ubuntu-20.04
|
|
||||||
container: centos:7
|
|
||||||
nodejs_version: 12
|
|
||||||
- os: ubuntu-20.04
|
- os: ubuntu-20.04
|
||||||
container: centos:7
|
container: centos:7
|
||||||
nodejs_version: 14
|
nodejs_version: 14
|
||||||
- os: ubuntu-20.04
|
- os: ubuntu-20.04
|
||||||
container: centos:7
|
container: centos:7
|
||||||
nodejs_version: 16
|
nodejs_version: 16
|
||||||
- os: ubuntu-20.04
|
|
||||||
container: node:10-alpine3.11
|
|
||||||
prebuild: true
|
|
||||||
- os: ubuntu-20.04
|
- os: ubuntu-20.04
|
||||||
container: node:12-alpine3.11
|
container: node:12-alpine3.11
|
||||||
|
prebuild: true
|
||||||
- os: ubuntu-20.04
|
- os: ubuntu-20.04
|
||||||
container: node:14-alpine3.11
|
container: node:14-alpine3.11
|
||||||
- os: ubuntu-20.04
|
- os: ubuntu-20.04
|
||||||
container: node:14-alpine3.13
|
container: node:14-alpine3.13
|
||||||
- os: ubuntu-20.04
|
- os: ubuntu-20.04
|
||||||
container: node:16-alpine3.11
|
container: node:16-alpine3.11
|
||||||
- os: macos-10.15
|
|
||||||
nodejs_version: 10
|
|
||||||
prebuild: true
|
|
||||||
- os: macos-10.15
|
- os: macos-10.15
|
||||||
nodejs_version: 12
|
nodejs_version: 12
|
||||||
|
prebuild: true
|
||||||
- os: macos-10.15
|
- os: macos-10.15
|
||||||
nodejs_version: 14
|
nodejs_version: 14
|
||||||
- os: macos-10.15
|
- os: macos-10.15
|
||||||
nodejs_version: 16
|
nodejs_version: 16
|
||||||
- os: windows-2019
|
|
||||||
nodejs_version: 10
|
|
||||||
prebuild: true
|
|
||||||
- os: windows-2019
|
- os: windows-2019
|
||||||
nodejs_version: 12
|
nodejs_version: 12
|
||||||
|
prebuild: true
|
||||||
- os: windows-2019
|
- os: windows-2019
|
||||||
nodejs_version: 14
|
nodejs_version: 14
|
||||||
- os: windows-2019
|
- os: windows-2019
|
||||||
@@ -57,7 +49,9 @@ jobs:
|
|||||||
if: contains(matrix.container, 'centos')
|
if: contains(matrix.container, 'centos')
|
||||||
run: |
|
run: |
|
||||||
curl -sL https://rpm.nodesource.com/setup_${{ matrix.nodejs_version }}.x | bash -
|
curl -sL https://rpm.nodesource.com/setup_${{ matrix.nodejs_version }}.x | bash -
|
||||||
yum install -y gcc-c++ make git python3 nodejs
|
yum install -y centos-release-scl
|
||||||
|
yum install -y devtoolset-10-gcc-c++ make git python3 nodejs
|
||||||
|
echo "/opt/rh/devtoolset-10/root/usr/bin" >> $GITHUB_PATH
|
||||||
- name: Dependencies (Linux musl)
|
- name: Dependencies (Linux musl)
|
||||||
if: contains(matrix.container, 'alpine')
|
if: contains(matrix.container, 'alpine')
|
||||||
run: apk add build-base git python3 --update-cache
|
run: apk add build-base git python3 --update-cache
|
||||||
@@ -84,4 +78,4 @@ jobs:
|
|||||||
if: matrix.prebuild && startsWith(github.ref, 'refs/tags/')
|
if: matrix.prebuild && startsWith(github.ref, 'refs/tags/')
|
||||||
env:
|
env:
|
||||||
prebuild_upload: ${{ secrets.GITHUB_TOKEN }}
|
prebuild_upload: ${{ secrets.GITHUB_TOKEN }}
|
||||||
run: npx prebuild --runtime napi --target 3
|
run: npx prebuild --runtime napi --target 5
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
{
|
{
|
||||||
"include-regex": "(sharp\\.node|libvips-cpp\\.dll)",
|
"include-regex": "(sharp-.+\\.node|libvips-cpp\\.dll)",
|
||||||
"strip": true
|
"strip": true
|
||||||
}
|
}
|
||||||
|
|||||||
108
.travis.yml
@@ -1,108 +0,0 @@
|
|||||||
jobs:
|
|
||||||
include:
|
|
||||||
- name: "Linux ARM64v8 (Debian 11, glibc 2.29) - Node.js 10"
|
|
||||||
arch: arm64
|
|
||||||
os: linux
|
|
||||||
dist: bionic
|
|
||||||
language: shell
|
|
||||||
before_install:
|
|
||||||
- sudo docker run -dit --name sharp --volume "${PWD}:/mnt/sharp" --workdir /mnt/sharp arm64v8/debian:bullseye
|
|
||||||
- sudo docker exec sharp sh -c "apt-get update && apt-get install -y build-essential git python3 curl"
|
|
||||||
- sudo docker exec sharp sh -c "curl -s https://deb.nodesource.com/gpgkey/nodesource.gpg.key | apt-key add -"
|
|
||||||
- sudo docker exec sharp sh -c "echo 'deb https://deb.nodesource.com/node_10.x sid main' >/etc/apt/sources.list.d/nodesource.list"
|
|
||||||
- sudo docker exec sharp sh -c "apt-get update && apt-get install -y nodejs=10.*"
|
|
||||||
install: sudo docker exec sharp sh -c "npm install --build-from-source --unsafe-perm"
|
|
||||||
script: sudo docker exec sharp sh -c "npm test"
|
|
||||||
after_success: "[[ -n $TRAVIS_TAG ]] && sudo docker exec --env prebuild_upload sharp sh -c \"npx prebuild --runtime napi --target 3\""
|
|
||||||
|
|
||||||
- name: "Linux ARM64v8 (Debian 11, glibc 2.29) - Node.js 12"
|
|
||||||
arch: arm64
|
|
||||||
os: linux
|
|
||||||
dist: bionic
|
|
||||||
language: shell
|
|
||||||
before_install:
|
|
||||||
- sudo docker run -dit --name sharp --volume "${PWD}:/mnt/sharp" --workdir /mnt/sharp arm64v8/debian:bullseye
|
|
||||||
- sudo docker exec sharp sh -c "apt-get update && apt-get install -y build-essential git python3 curl"
|
|
||||||
- sudo docker exec sharp sh -c "curl -s https://deb.nodesource.com/gpgkey/nodesource.gpg.key | apt-key add -"
|
|
||||||
- sudo docker exec sharp sh -c "echo 'deb https://deb.nodesource.com/node_12.x sid main' >/etc/apt/sources.list.d/nodesource.list"
|
|
||||||
- sudo docker exec sharp sh -c "apt-get update && apt-get install -y nodejs"
|
|
||||||
install: sudo docker exec sharp sh -c "npm install --build-from-source --unsafe-perm"
|
|
||||||
script: sudo docker exec sharp sh -c "npm test"
|
|
||||||
|
|
||||||
- name: "Linux ARM64v8 (Debian 11, glibc 2.29) - Node.js 14"
|
|
||||||
arch: arm64
|
|
||||||
os: linux
|
|
||||||
dist: bionic
|
|
||||||
language: shell
|
|
||||||
before_install:
|
|
||||||
- sudo docker run -dit --name sharp --volume "${PWD}:/mnt/sharp" --workdir /mnt/sharp arm64v8/debian:bullseye
|
|
||||||
- sudo docker exec sharp sh -c "apt-get update && apt-get install -y build-essential git python3 curl"
|
|
||||||
- sudo docker exec sharp sh -c "curl -s https://deb.nodesource.com/gpgkey/nodesource.gpg.key | apt-key add -"
|
|
||||||
- sudo docker exec sharp sh -c "echo 'deb https://deb.nodesource.com/node_14.x sid main' >/etc/apt/sources.list.d/nodesource.list"
|
|
||||||
- sudo docker exec sharp sh -c "apt-get update && apt-get install -y nodejs"
|
|
||||||
install: sudo docker exec sharp sh -c "npm install --build-from-source --unsafe-perm"
|
|
||||||
script: sudo docker exec sharp sh -c "npm test"
|
|
||||||
|
|
||||||
- name: "Linux ARM64v8 (Debian 11, glibc 2.29) - Node.js 16"
|
|
||||||
arch: arm64
|
|
||||||
os: linux
|
|
||||||
dist: bionic
|
|
||||||
language: shell
|
|
||||||
before_install:
|
|
||||||
- sudo chown 0.0 ${PWD}
|
|
||||||
- sudo docker run -dit --name sharp --volume "${PWD}:/mnt/sharp" --workdir /mnt/sharp arm64v8/debian:bullseye
|
|
||||||
- sudo docker exec sharp sh -c "apt-get update && apt-get install -y build-essential git python3 curl"
|
|
||||||
- sudo docker exec sharp sh -c "curl -s https://deb.nodesource.com/gpgkey/nodesource.gpg.key | apt-key add -"
|
|
||||||
- sudo docker exec sharp sh -c "echo 'deb https://deb.nodesource.com/node_16.x sid main' >/etc/apt/sources.list.d/nodesource.list"
|
|
||||||
- sudo docker exec sharp sh -c "apt-get update && apt-get install -y nodejs"
|
|
||||||
install: sudo docker exec sharp sh -c "npm install --build-from-source --unsafe-perm"
|
|
||||||
script: sudo docker exec sharp sh -c "npm test"
|
|
||||||
|
|
||||||
- name: "Linux ARM64v8 (Alpine 3.11, musl 1.1.24) - Node.js 10"
|
|
||||||
arch: arm64
|
|
||||||
os: linux
|
|
||||||
dist: focal
|
|
||||||
language: shell
|
|
||||||
before_install:
|
|
||||||
- sudo docker run -dit --name sharp --volume "${PWD}:/mnt/sharp" --workdir /mnt/sharp node:10-alpine3.11
|
|
||||||
- sudo docker exec sharp sh -c "apk add build-base git python3 --update-cache"
|
|
||||||
install: sudo docker exec sharp sh -c "npm install --build-from-source --unsafe-perm"
|
|
||||||
script: sudo docker exec sharp sh -c "npm test"
|
|
||||||
after_success: "[[ -n $TRAVIS_TAG ]] && sudo docker exec --env prebuild_upload sharp sh -c \"npx prebuild --runtime napi --target 3\""
|
|
||||||
|
|
||||||
- name: "Linux ARM64v8 (Alpine 3.11, musl 1.1.24) - Node.js 12"
|
|
||||||
arch: arm64
|
|
||||||
os: linux
|
|
||||||
dist: focal
|
|
||||||
language: shell
|
|
||||||
before_install:
|
|
||||||
- sudo docker run -dit --name sharp --volume "${PWD}:/mnt/sharp" --workdir /mnt/sharp node:12-alpine3.11
|
|
||||||
- sudo docker exec sharp sh -c "apk add build-base git python3 --update-cache"
|
|
||||||
install: sudo docker exec sharp sh -c "npm install --build-from-source --unsafe-perm"
|
|
||||||
script: sudo docker exec sharp sh -c "npm test"
|
|
||||||
|
|
||||||
- name: "Linux ARM64v8 (Alpine 3.11, musl 1.1.24) - Node.js 14"
|
|
||||||
arch: arm64
|
|
||||||
os: linux
|
|
||||||
dist: focal
|
|
||||||
language: shell
|
|
||||||
before_install:
|
|
||||||
- sudo docker run -dit --name sharp --volume "${PWD}:/mnt/sharp" --workdir /mnt/sharp node:14-alpine3.11
|
|
||||||
- sudo docker exec sharp sh -c "apk add build-base git python3 --update-cache"
|
|
||||||
install: sudo docker exec sharp sh -c "npm install --build-from-source --unsafe-perm"
|
|
||||||
script: sudo docker exec sharp sh -c "npm test"
|
|
||||||
|
|
||||||
- name: "Linux ARM64v8 (Alpine 3.11, musl 1.1.24) - Node.js 16"
|
|
||||||
arch: arm64
|
|
||||||
os: linux
|
|
||||||
dist: focal
|
|
||||||
language: shell
|
|
||||||
before_install:
|
|
||||||
- sudo chown 0.0 ${PWD}
|
|
||||||
- sudo docker run -dit --name sharp --volume "${PWD}:/mnt/sharp" --workdir /mnt/sharp node:16-alpine3.11
|
|
||||||
- sudo docker exec sharp sh -c "apk add build-base git python3 --update-cache"
|
|
||||||
install: sudo docker exec sharp sh -c "npm install --build-from-source --unsafe-perm"
|
|
||||||
script: sudo docker exec sharp sh -c "npm test"
|
|
||||||
|
|
||||||
cache:
|
|
||||||
npm: false
|
|
||||||
@@ -16,7 +16,7 @@ Lanczos resampling ensures quality is not sacrificed for speed.
|
|||||||
As well as image resizing, operations such as
|
As well as image resizing, operations such as
|
||||||
rotation, extraction, compositing and gamma correction are available.
|
rotation, extraction, compositing and gamma correction are available.
|
||||||
|
|
||||||
Most modern macOS, Windows and Linux systems running Node.js v10+
|
Most modern macOS, Windows and Linux systems running Node.js >= 12.13.0
|
||||||
do not require any additional install or runtime dependencies.
|
do not require any additional install or runtime dependencies.
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
@@ -99,7 +99,7 @@ A [guide for contributors](https://github.com/lovell/sharp/blob/master/.github/C
|
|||||||
covers reporting bugs, requesting features and submitting code changes.
|
covers reporting bugs, requesting features and submitting code changes.
|
||||||
|
|
||||||
[](https://coveralls.io/r/lovell/sharp?branch=master)
|
[](https://coveralls.io/r/lovell/sharp?branch=master)
|
||||||
[](https://nodejs.org/dist/latest/docs/api/n-api.html#n_api_n_api_version_matrix)
|
[](https://nodejs.org/dist/latest/docs/api/n-api.html#n_api_n_api_version_matrix)
|
||||||
|
|
||||||
## Licensing
|
## Licensing
|
||||||
|
|
||||||
|
|||||||
@@ -4,9 +4,8 @@ build: off
|
|||||||
platform: x86
|
platform: x86
|
||||||
environment:
|
environment:
|
||||||
matrix:
|
matrix:
|
||||||
- nodejs_version: "10"
|
|
||||||
prebuild: true
|
|
||||||
- nodejs_version: "12"
|
- nodejs_version: "12"
|
||||||
|
prebuild: true
|
||||||
- nodejs_version: "14"
|
- nodejs_version: "14"
|
||||||
- nodejs_version: "16"
|
- nodejs_version: "16"
|
||||||
install:
|
install:
|
||||||
@@ -15,4 +14,4 @@ install:
|
|||||||
test_script:
|
test_script:
|
||||||
- npm test
|
- npm test
|
||||||
on_success:
|
on_success:
|
||||||
- if [%prebuild%] == [true] if [%APPVEYOR_REPO_TAG%] == [true] npx prebuild --runtime napi --target 3
|
- if [%prebuild%] == [true] if [%APPVEYOR_REPO_TAG%] == [true] npx prebuild --runtime napi --target 5
|
||||||
|
|||||||
21
binding.gyp
@@ -1,7 +1,8 @@
|
|||||||
{
|
{
|
||||||
'variables': {
|
'variables': {
|
||||||
'vips_version': '<!(node -p "require(\'./lib/libvips\').minimumLibvipsVersion")',
|
'vips_version': '<!(node -p "require(\'./lib/libvips\').minimumLibvipsVersion")',
|
||||||
'sharp_vendor_dir': '<(module_root_dir)/vendor/<(vips_version)'
|
'platform_and_arch': '<!(node -p "require(\'./lib/platform\')()")',
|
||||||
|
'sharp_vendor_dir': './vendor/<(vips_version)/<(platform_and_arch)'
|
||||||
},
|
},
|
||||||
'targets': [{
|
'targets': [{
|
||||||
'target_name': 'libvips-cpp',
|
'target_name': 'libvips-cpp',
|
||||||
@@ -37,6 +38,7 @@
|
|||||||
'msvs_settings': {
|
'msvs_settings': {
|
||||||
'VCCLCompilerTool': {
|
'VCCLCompilerTool': {
|
||||||
'ExceptionHandling': 1,
|
'ExceptionHandling': 1,
|
||||||
|
'Optimization': 1,
|
||||||
'WholeProgramOptimization': 'true'
|
'WholeProgramOptimization': 'true'
|
||||||
},
|
},
|
||||||
'VCLibrarianTool': {
|
'VCLibrarianTool': {
|
||||||
@@ -65,9 +67,9 @@
|
|||||||
}]
|
}]
|
||||||
]
|
]
|
||||||
}, {
|
}, {
|
||||||
'target_name': 'sharp',
|
'target_name': 'sharp-<(platform_and_arch)',
|
||||||
'defines': [
|
'defines': [
|
||||||
'NAPI_VERSION=3'
|
'NAPI_VERSION=5'
|
||||||
],
|
],
|
||||||
'dependencies': [
|
'dependencies': [
|
||||||
'<!(node -p "require(\'node-addon-api\').gyp")',
|
'<!(node -p "require(\'node-addon-api\').gyp")',
|
||||||
@@ -138,7 +140,7 @@
|
|||||||
}],
|
}],
|
||||||
['OS == "mac"', {
|
['OS == "mac"', {
|
||||||
'link_settings': {
|
'link_settings': {
|
||||||
'library_dirs': ['<(sharp_vendor_dir)/lib'],
|
'library_dirs': ['../<(sharp_vendor_dir)/lib'],
|
||||||
'libraries': [
|
'libraries': [
|
||||||
'libvips-cpp.42.dylib'
|
'libvips-cpp.42.dylib'
|
||||||
]
|
]
|
||||||
@@ -146,7 +148,7 @@
|
|||||||
'xcode_settings': {
|
'xcode_settings': {
|
||||||
'OTHER_LDFLAGS': [
|
'OTHER_LDFLAGS': [
|
||||||
# Ensure runtime linking is relative to sharp.node
|
# Ensure runtime linking is relative to sharp.node
|
||||||
'-Wl,-rpath,\'@loader_path/../../vendor/<(vips_version)/lib\''
|
'-Wl,-rpath,\'@loader_path/../../<(sharp_vendor_dir)/lib\''
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}],
|
}],
|
||||||
@@ -155,13 +157,13 @@
|
|||||||
'_GLIBCXX_USE_CXX11_ABI=1'
|
'_GLIBCXX_USE_CXX11_ABI=1'
|
||||||
],
|
],
|
||||||
'link_settings': {
|
'link_settings': {
|
||||||
'library_dirs': ['<(sharp_vendor_dir)/lib'],
|
'library_dirs': ['../<(sharp_vendor_dir)/lib'],
|
||||||
'libraries': [
|
'libraries': [
|
||||||
'-l:libvips-cpp.so.42'
|
'-l:libvips-cpp.so.42'
|
||||||
],
|
],
|
||||||
'ldflags': [
|
'ldflags': [
|
||||||
# Ensure runtime linking is relative to sharp.node
|
# Ensure runtime linking is relative to sharp.node
|
||||||
'-Wl,-s -Wl,--disable-new-dtags -Wl,-rpath=\'$$ORIGIN/../../vendor/<(vips_version)/lib\''
|
'-Wl,-s -Wl,--disable-new-dtags -Wl,-rpath=\'$$ORIGIN/../../<(sharp_vendor_dir)/lib\''
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}]
|
}]
|
||||||
@@ -172,7 +174,7 @@
|
|||||||
'-std=c++0x',
|
'-std=c++0x',
|
||||||
'-fexceptions',
|
'-fexceptions',
|
||||||
'-Wall',
|
'-Wall',
|
||||||
'-O3'
|
'-Os'
|
||||||
],
|
],
|
||||||
'xcode_settings': {
|
'xcode_settings': {
|
||||||
'CLANG_CXX_LANGUAGE_STANDARD': 'c++11',
|
'CLANG_CXX_LANGUAGE_STANDARD': 'c++11',
|
||||||
@@ -182,7 +184,7 @@
|
|||||||
'OTHER_CPLUSPLUSFLAGS': [
|
'OTHER_CPLUSPLUSFLAGS': [
|
||||||
'-fexceptions',
|
'-fexceptions',
|
||||||
'-Wall',
|
'-Wall',
|
||||||
'-O3'
|
'-Oz'
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
'configurations': {
|
'configurations': {
|
||||||
@@ -202,6 +204,7 @@
|
|||||||
'msvs_settings': {
|
'msvs_settings': {
|
||||||
'VCCLCompilerTool': {
|
'VCCLCompilerTool': {
|
||||||
'ExceptionHandling': 1,
|
'ExceptionHandling': 1,
|
||||||
|
'Optimization': 1,
|
||||||
'WholeProgramOptimization': 'true'
|
'WholeProgramOptimization': 'true'
|
||||||
},
|
},
|
||||||
'VCLibrarianTool': {
|
'VCLibrarianTool': {
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ Lanczos resampling ensures quality is not sacrificed for speed.
|
|||||||
As well as image resizing, operations such as
|
As well as image resizing, operations such as
|
||||||
rotation, extraction, compositing and gamma correction are available.
|
rotation, extraction, compositing and gamma correction are available.
|
||||||
|
|
||||||
Most modern macOS, Windows and Linux systems running Node.js v10+
|
Most modern macOS, Windows and Linux systems running Node.js >= 12.13.0
|
||||||
do not require any additional install or runtime dependencies.
|
do not require any additional install or runtime dependencies.
|
||||||
|
|
||||||
### Formats
|
### Formats
|
||||||
|
|||||||
@@ -64,13 +64,18 @@ Extract a single channel from a multi-channel image.
|
|||||||
### Examples
|
### Examples
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
sharp(input)
|
// green.jpg is a greyscale image containing the green channel of the input
|
||||||
|
await sharp(input)
|
||||||
.extractChannel('green')
|
.extractChannel('green')
|
||||||
.toColourspace('b-w')
|
.toFile('green.jpg');
|
||||||
.toFile('green.jpg', function(err, info) {
|
```
|
||||||
// info.channels === 1
|
|
||||||
// green.jpg is a greyscale image containing the green channel of the input
|
```javascript
|
||||||
});
|
// red1 is the red value of the first pixel, red2 the second pixel etc.
|
||||||
|
const [red1, red2, ...] = await sharp(input)
|
||||||
|
.extractChannel(0)
|
||||||
|
.raw()
|
||||||
|
.toBuffer();
|
||||||
```
|
```
|
||||||
|
|
||||||
* Throws **[Error][3]** Invalid channel
|
* Throws **[Error][3]** Invalid channel
|
||||||
|
|||||||
@@ -40,6 +40,51 @@ Alternative spelling of `greyscale`.
|
|||||||
|
|
||||||
Returns **Sharp**
|
Returns **Sharp**
|
||||||
|
|
||||||
|
## pipelineColourspace
|
||||||
|
|
||||||
|
Set the pipeline colourspace.
|
||||||
|
|
||||||
|
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][6].
|
||||||
|
|
||||||
|
This feature is experimental and has not yet been fully-tested with all operations.
|
||||||
|
|
||||||
|
### Parameters
|
||||||
|
|
||||||
|
* `colourspace` **[string][1]?** pipeline colourspace e.g. `rgb16`, `scrgb`, `lab`, `grey16` [...][7]
|
||||||
|
|
||||||
|
### Examples
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Run pipeline in 16 bits per channel RGB while converting final result to 8 bits per channel sRGB.
|
||||||
|
await sharp(input)
|
||||||
|
.pipelineColourspace('rgb16')
|
||||||
|
.toColourspace('srgb')
|
||||||
|
.toFile('16bpc-pipeline-to-8bpc-output.png')
|
||||||
|
```
|
||||||
|
|
||||||
|
* Throws **[Error][4]** Invalid parameters
|
||||||
|
|
||||||
|
Returns **Sharp**
|
||||||
|
|
||||||
|
**Meta**
|
||||||
|
|
||||||
|
* **since**: 0.29.0
|
||||||
|
|
||||||
|
## pipelineColorspace
|
||||||
|
|
||||||
|
Alternative spelling of `pipelineColourspace`.
|
||||||
|
|
||||||
|
### Parameters
|
||||||
|
|
||||||
|
* `colorspace` **[string][1]?** pipeline colorspace.
|
||||||
|
|
||||||
|
<!---->
|
||||||
|
|
||||||
|
* Throws **[Error][4]** Invalid parameters
|
||||||
|
|
||||||
|
Returns **Sharp**
|
||||||
|
|
||||||
## toColourspace
|
## toColourspace
|
||||||
|
|
||||||
Set the output colourspace.
|
Set the output colourspace.
|
||||||
@@ -47,7 +92,7 @@ By default output image will be web-friendly sRGB, with additional channels inte
|
|||||||
|
|
||||||
### Parameters
|
### Parameters
|
||||||
|
|
||||||
* `colourspace` **[string][1]?** output colourspace e.g. `srgb`, `rgb`, `cmyk`, `lab`, `b-w` [...][6]
|
* `colourspace` **[string][1]?** output colourspace e.g. `srgb`, `rgb`, `cmyk`, `lab`, `b-w` [...][8]
|
||||||
|
|
||||||
### Examples
|
### Examples
|
||||||
|
|
||||||
@@ -86,4 +131,8 @@ Returns **Sharp**
|
|||||||
|
|
||||||
[5]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean
|
[5]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean
|
||||||
|
|
||||||
[6]: https://github.com/libvips/libvips/blob/master/libvips/iofuncs/enumtypes.c#L568
|
[6]: #tocolourspace
|
||||||
|
|
||||||
|
[7]: https://github.com/libvips/libvips/blob/41cff4e9d0838498487a00623462204eb10ee5b8/libvips/iofuncs/enumtypes.c#L774
|
||||||
|
|
||||||
|
[8]: https://github.com/libvips/libvips/blob/3c0bfdf74ce1dc37a6429bed47fa76f16e2cd70a/libvips/iofuncs/enumtypes.c#L777-L794
|
||||||
|
|||||||
@@ -13,43 +13,44 @@ Implements the [stream.Duplex][1] class.
|
|||||||
|
|
||||||
### Parameters
|
### Parameters
|
||||||
|
|
||||||
* `input` **([Buffer][2] | [Uint8Array][3] | [Uint8ClampedArray][4] | [string][5])?** if present, can be
|
* `input` **([Buffer][2] | [Uint8Array][3] | [Uint8ClampedArray][4] | [Int8Array][5] | [Uint16Array][6] | [Int16Array][7] | [Uint32Array][8] | [Int32Array][9] | [Float32Array][10] | [Float64Array][11] | [string][12])?** if present, can be
|
||||||
a Buffer / Uint8Array / Uint8ClampedArray containing JPEG, PNG, WebP, AVIF, GIF, SVG, TIFF or raw pixel image data, or
|
a Buffer / Uint8Array / Uint8ClampedArray containing JPEG, PNG, WebP, AVIF, GIF, SVG or TIFF image data, or
|
||||||
|
a TypedArray containing raw pixel image data, or
|
||||||
a String containing the filesystem path to an JPEG, PNG, WebP, AVIF, GIF, SVG or TIFF image file.
|
a String containing the filesystem path to an JPEG, PNG, WebP, AVIF, GIF, SVG or TIFF image file.
|
||||||
JPEG, PNG, WebP, AVIF, GIF, SVG, TIFF or raw pixel image data can be streamed into the object when not present.
|
JPEG, PNG, WebP, AVIF, GIF, SVG, TIFF or raw pixel image data can be streamed into the object when not present.
|
||||||
* `options` **[Object][6]?** if present, is an Object with optional attributes.
|
* `options` **[Object][13]?** if present, is an Object with optional attributes.
|
||||||
|
|
||||||
* `options.failOnError` **[boolean][7]** by default halt processing and raise an error when loading invalid images.
|
* `options.failOnError` **[boolean][14]** 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`)
|
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`)
|
||||||
* `options.limitInputPixels` **([number][8] | [boolean][7])** Do not process input images where the number of pixels
|
* `options.limitInputPixels` **([number][15] | [boolean][14])** 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.
|
(width x height) exceeds this limit. Assumes image dimensions contained in the input metadata can be trusted.
|
||||||
An integral Number of pixels, zero or false to remove limit, true to use default limit of 268402689 (0x3FFF x 0x3FFF). (optional, default `268402689`)
|
An integral Number of pixels, zero or false to remove limit, true to use default limit of 268402689 (0x3FFF x 0x3FFF). (optional, default `268402689`)
|
||||||
* `options.sequentialRead` **[boolean][7]** Set this to `true` to use sequential rather than random access where possible.
|
* `options.sequentialRead` **[boolean][14]** Set this to `true` to use sequential rather than random access where possible.
|
||||||
This can reduce memory usage and might improve performance on some systems. (optional, default `false`)
|
This can reduce memory usage and might improve performance on some systems. (optional, default `false`)
|
||||||
* `options.density` **[number][8]** number representing the DPI for vector images in the range 1 to 100000. (optional, default `72`)
|
* `options.density` **[number][15]** number representing the DPI for vector images in the range 1 to 100000. (optional, default `72`)
|
||||||
* `options.pages` **[number][8]** number of pages to extract for multi-page input (GIF, WebP, AVIF, TIFF, PDF), use -1 for all pages. (optional, default `1`)
|
* `options.pages` **[number][15]** number of pages to extract for multi-page input (GIF, WebP, AVIF, TIFF, PDF), use -1 for all pages. (optional, default `1`)
|
||||||
* `options.page` **[number][8]** page number to start extracting from for multi-page input (GIF, WebP, AVIF, TIFF, PDF), zero based. (optional, default `0`)
|
* `options.page` **[number][15]** page number to start extracting from for multi-page input (GIF, WebP, AVIF, TIFF, PDF), zero based. (optional, default `0`)
|
||||||
* `options.subifd` **[number][8]** subIFD (Sub Image File Directory) to extract for OME-TIFF, defaults to main image. (optional, default `-1`)
|
* `options.subifd` **[number][15]** subIFD (Sub Image File Directory) to extract for OME-TIFF, defaults to main image. (optional, default `-1`)
|
||||||
* `options.level` **[number][8]** level to extract from a multi-level input (OpenSlide), zero based. (optional, default `0`)
|
* `options.level` **[number][15]** level to extract from a multi-level input (OpenSlide), zero based. (optional, default `0`)
|
||||||
* `options.animated` **[boolean][7]** Set to `true` to read all frames/pages of an animated image (equivalent of setting `pages` to `-1`). (optional, default `false`)
|
* `options.animated` **[boolean][14]** Set to `true` to read all frames/pages of an animated image (equivalent of setting `pages` to `-1`). (optional, default `false`)
|
||||||
* `options.raw` **[Object][6]?** describes raw pixel input image data. See `raw()` for pixel ordering.
|
* `options.raw` **[Object][13]?** describes raw pixel input image data. See `raw()` for pixel ordering.
|
||||||
|
|
||||||
* `options.raw.width` **[number][8]?** integral number of pixels wide.
|
* `options.raw.width` **[number][15]?** integral number of pixels wide.
|
||||||
* `options.raw.height` **[number][8]?** integral number of pixels high.
|
* `options.raw.height` **[number][15]?** integral number of pixels high.
|
||||||
* `options.raw.channels` **[number][8]?** integral number of channels, between 1 and 4.
|
* `options.raw.channels` **[number][15]?** integral number of channels, between 1 and 4.
|
||||||
* `options.raw.premultiplied` **[boolean][7]?** specifies that the raw input has already been premultiplied, set to `true`
|
* `options.raw.premultiplied` **[boolean][14]?** specifies that the raw input has already been premultiplied, set to `true`
|
||||||
to avoid sharp premultiplying the image. (optional, default `false`)
|
to avoid sharp premultiplying the image. (optional, default `false`)
|
||||||
* `options.create` **[Object][6]?** describes a new image to be created.
|
* `options.create` **[Object][13]?** describes a new image to be created.
|
||||||
|
|
||||||
* `options.create.width` **[number][8]?** integral number of pixels wide.
|
* `options.create.width` **[number][15]?** integral number of pixels wide.
|
||||||
* `options.create.height` **[number][8]?** integral number of pixels high.
|
* `options.create.height` **[number][15]?** integral number of pixels high.
|
||||||
* `options.create.channels` **[number][8]?** integral number of channels, either 3 (RGB) or 4 (RGBA).
|
* `options.create.channels` **[number][15]?** integral number of channels, either 3 (RGB) or 4 (RGBA).
|
||||||
* `options.create.background` **([string][5] | [Object][6])?** parsed by the [color][9] module to extract values for red, green, blue and alpha.
|
* `options.create.background` **([string][12] | [Object][13])?** parsed by the [color][16] module to extract values for red, green, blue and alpha.
|
||||||
* `options.create.noise` **[Object][6]?** describes a noise to be created.
|
* `options.create.noise` **[Object][13]?** describes a noise to be created.
|
||||||
|
|
||||||
* `options.create.noise.type` **[string][5]?** type of generated noise, currently only `gaussian` is supported.
|
* `options.create.noise.type` **[string][12]?** type of generated noise, currently only `gaussian` is supported.
|
||||||
* `options.create.noise.mean` **[number][8]?** mean of pixels in generated noise.
|
* `options.create.noise.mean` **[number][15]?** mean of pixels in generated noise.
|
||||||
* `options.create.noise.sigma` **[number][8]?** standard deviation of pixels in generated noise.
|
* `options.create.noise.sigma` **[number][15]?** standard deviation of pixels in generated noise.
|
||||||
|
|
||||||
### Examples
|
### Examples
|
||||||
|
|
||||||
@@ -126,9 +127,9 @@ await sharp({
|
|||||||
}).toFile('noise.png');
|
}).toFile('noise.png');
|
||||||
```
|
```
|
||||||
|
|
||||||
* Throws **[Error][10]** Invalid parameters
|
* Throws **[Error][17]** Invalid parameters
|
||||||
|
|
||||||
Returns **[Sharp][11]**
|
Returns **[Sharp][18]**
|
||||||
|
|
||||||
## clone
|
## clone
|
||||||
|
|
||||||
@@ -196,7 +197,7 @@ Promise.all(promises)
|
|||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
Returns **[Sharp][11]**
|
Returns **[Sharp][18]**
|
||||||
|
|
||||||
[1]: http://nodejs.org/api/stream.html#stream_class_stream_duplex
|
[1]: http://nodejs.org/api/stream.html#stream_class_stream_duplex
|
||||||
|
|
||||||
@@ -206,16 +207,30 @@ Returns **[Sharp][11]**
|
|||||||
|
|
||||||
[4]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Uint8ClampedArray
|
[4]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Uint8ClampedArray
|
||||||
|
|
||||||
[5]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String
|
[5]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Int8Array
|
||||||
|
|
||||||
[6]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object
|
[6]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Uint16Array
|
||||||
|
|
||||||
[7]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean
|
[7]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Int16Array
|
||||||
|
|
||||||
[8]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number
|
[8]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Uint32Array
|
||||||
|
|
||||||
[9]: https://www.npmjs.org/package/color
|
[9]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Int32Array
|
||||||
|
|
||||||
[10]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Error
|
[10]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Float32Array
|
||||||
|
|
||||||
[11]: #sharp
|
[11]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Float64Array
|
||||||
|
|
||||||
|
[12]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String
|
||||||
|
|
||||||
|
[13]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object
|
||||||
|
|
||||||
|
[14]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean
|
||||||
|
|
||||||
|
[15]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number
|
||||||
|
|
||||||
|
[16]: https://www.npmjs.org/package/color
|
||||||
|
|
||||||
|
[17]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Error
|
||||||
|
|
||||||
|
[18]: #sharp
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ A `Promise` is returned when `callback` is not provided.
|
|||||||
* `pagePrimary`: Number of the primary page in a HEIF image
|
* `pagePrimary`: Number of the primary page in a HEIF image
|
||||||
* `levels`: Details of each level in a multi-level image provided as an array of objects, requires libvips compiled with support for OpenSlide
|
* `levels`: Details of each level in a multi-level image provided as an array of objects, requires libvips compiled with support for OpenSlide
|
||||||
* `subifds`: Number of Sub Image File Directories in an OME-TIFF image
|
* `subifds`: Number of Sub Image File Directories in an OME-TIFF image
|
||||||
|
* `background`: Default background colour, if present, for PNG (bKGD) and GIF images, either an RGB Object or a single greyscale value
|
||||||
|
* `compression`: The encoder used to compress an HEIF file, `av1` (AVIF) or `hevc` (HEIC)
|
||||||
* `hasProfile`: Boolean indicating the presence of an embedded ICC profile
|
* `hasProfile`: Boolean indicating the presence of an embedded ICC profile
|
||||||
* `hasAlpha`: Boolean indicating the presence of an alpha transparency channel
|
* `hasAlpha`: Boolean indicating the presence of an alpha transparency channel
|
||||||
* `orientation`: Number value of the EXIF Orientation header, if present
|
* `orientation`: Number value of the EXIF Orientation header, if present
|
||||||
@@ -75,6 +77,9 @@ A `Promise` is returned when `callback` is not provided.
|
|||||||
* `sharpness`: Estimation of greyscale sharpness based on the standard deviation of a Laplacian convolution, discarding alpha channel if any (experimental)
|
* `sharpness`: Estimation of greyscale sharpness based on the standard deviation of a Laplacian convolution, discarding alpha channel if any (experimental)
|
||||||
* `dominant`: Object containing most dominant sRGB colour based on a 4096-bin 3D histogram (experimental)
|
* `dominant`: Object containing most dominant sRGB colour based on a 4096-bin 3D histogram (experimental)
|
||||||
|
|
||||||
|
**Note**: Statistics are derived from the original input image. Any operations performed on the image must first be
|
||||||
|
written to a buffer in order to run `stats` on the result (see third example).
|
||||||
|
|
||||||
### Parameters
|
### Parameters
|
||||||
|
|
||||||
* `callback` **[Function][4]?** called with the arguments `(err, stats)`
|
* `callback` **[Function][4]?** called with the arguments `(err, stats)`
|
||||||
@@ -95,6 +100,14 @@ const { entropy, sharpness, dominant } = await sharp(input).stats();
|
|||||||
const { r, g, b } = dominant;
|
const { r, g, b } = dominant;
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const image = sharp(input);
|
||||||
|
// store intermediate result
|
||||||
|
const part = await image.extract(region).toBuffer();
|
||||||
|
// create new instance to obtain statistics of extracted region
|
||||||
|
const stats = await sharp(part).stats();
|
||||||
|
```
|
||||||
|
|
||||||
Returns **[Promise][5]<[Object][6]>**
|
Returns **[Promise][5]<[Object][6]>**
|
||||||
|
|
||||||
[1]: https://libvips.github.io/libvips/API/current/VipsImage.html#VipsInterpretation
|
[1]: https://libvips.github.io/libvips/API/current/VipsImage.html#VipsInterpretation
|
||||||
|
|||||||
@@ -221,7 +221,9 @@ Produce the "negative" of the image.
|
|||||||
|
|
||||||
### Parameters
|
### Parameters
|
||||||
|
|
||||||
* `negate` **[Boolean][6]** (optional, default `true`)
|
* `options` **[Object][2]?**
|
||||||
|
|
||||||
|
* `options.alpha` **[Boolean][6]** Whether or not to negate any alpha channel (optional, default `true`)
|
||||||
|
|
||||||
Returns **Sharp**
|
Returns **Sharp**
|
||||||
|
|
||||||
|
|||||||
@@ -379,7 +379,7 @@ most web browsers do not display these properly.
|
|||||||
* `options.quality` **[number][9]** quality, integer 1-100 (optional, default `50`)
|
* `options.quality` **[number][9]** quality, integer 1-100 (optional, default `50`)
|
||||||
* `options.lossless` **[boolean][7]** use lossless compression (optional, default `false`)
|
* `options.lossless` **[boolean][7]** use lossless compression (optional, default `false`)
|
||||||
* `options.speed` **[number][9]** CPU effort vs file size, 0 (slowest/smallest) to 8 (fastest/largest) (optional, default `5`)
|
* `options.speed` **[number][9]** CPU effort vs file size, 0 (slowest/smallest) to 8 (fastest/largest) (optional, default `5`)
|
||||||
* `options.chromaSubsampling` **[string][2]** set to '4:4:4' to prevent chroma subsampling otherwise defaults to '4:2:0' chroma subsampling, requires libvips v8.11.0 (optional, default `'4:2:0'`)
|
* `options.chromaSubsampling` **[string][2]** set to '4:2:0' to use chroma subsampling (optional, default `'4:4:4'`)
|
||||||
|
|
||||||
<!---->
|
<!---->
|
||||||
|
|
||||||
@@ -406,7 +406,7 @@ globally-installed libvips compiled with support for libheif, libde265 and x265.
|
|||||||
* `options.compression` **[string][2]** compression format: av1, hevc (optional, default `'av1'`)
|
* `options.compression` **[string][2]** compression format: av1, hevc (optional, default `'av1'`)
|
||||||
* `options.lossless` **[boolean][7]** use lossless compression (optional, default `false`)
|
* `options.lossless` **[boolean][7]** use lossless compression (optional, default `false`)
|
||||||
* `options.speed` **[number][9]** CPU effort vs file size, 0 (slowest/smallest) to 8 (fastest/largest) (optional, default `5`)
|
* `options.speed` **[number][9]** CPU effort vs file size, 0 (slowest/smallest) to 8 (fastest/largest) (optional, default `5`)
|
||||||
* `options.chromaSubsampling` **[string][2]** set to '4:4:4' to prevent chroma subsampling otherwise defaults to '4:2:0' chroma subsampling, requires libvips v8.11.0 (optional, default `'4:2:0'`)
|
* `options.chromaSubsampling` **[string][2]** set to '4:2:0' to use chroma subsampling (optional, default `'4:4:4'`)
|
||||||
|
|
||||||
<!---->
|
<!---->
|
||||||
|
|
||||||
@@ -420,30 +420,36 @@ Returns **Sharp**
|
|||||||
|
|
||||||
## raw
|
## raw
|
||||||
|
|
||||||
Force output to be raw, uncompressed, 8-bit unsigned integer (unit8) pixel data.
|
Force output to be raw, uncompressed pixel data.
|
||||||
Pixel ordering is left-to-right, top-to-bottom, without padding.
|
Pixel ordering is left-to-right, top-to-bottom, without padding.
|
||||||
Channel ordering will be RGB or RGBA for non-greyscale colourspaces.
|
Channel ordering will be RGB or RGBA for non-greyscale colourspaces.
|
||||||
|
|
||||||
|
### Parameters
|
||||||
|
|
||||||
|
* `options` **[Object][6]?** output options
|
||||||
|
|
||||||
|
* `options.depth` **[string][2]** bit depth, one of: char, uchar (default), short, ushort, int, uint, float, complex, double, dpcomplex (optional, default `'uchar'`)
|
||||||
|
|
||||||
### Examples
|
### Examples
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
// Extract raw RGB pixel data from JPEG input
|
// Extract raw, unsigned 8-bit RGB pixel data from JPEG input
|
||||||
const { data, info } = await sharp('input.jpg')
|
const { data, info } = await sharp('input.jpg')
|
||||||
.raw()
|
.raw()
|
||||||
.toBuffer({ resolveWithObject: true });
|
.toBuffer({ resolveWithObject: true });
|
||||||
```
|
```
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
// Extract alpha channel as raw pixel data from PNG input
|
// Extract alpha channel as raw, unsigned 16-bit pixel data from PNG input
|
||||||
const data = await sharp('input.png')
|
const data = await sharp('input.png')
|
||||||
.ensureAlpha()
|
.ensureAlpha()
|
||||||
.extractChannel(3)
|
.extractChannel(3)
|
||||||
.toColourspace('b-w')
|
.toColourspace('b-w')
|
||||||
.raw()
|
.raw({ depth: 'ushort' })
|
||||||
.toBuffer();
|
.toBuffer();
|
||||||
```
|
```
|
||||||
|
|
||||||
Returns **Sharp**
|
* Throws **[Error][4]** Invalid options
|
||||||
|
|
||||||
## tile
|
## tile
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,42 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## v0.29 - *circle*
|
||||||
|
|
||||||
|
Requires libvips v8.11.3
|
||||||
|
|
||||||
|
### v0.29.0 - 17th August 2021
|
||||||
|
|
||||||
|
* Drop support for Node.js 10, now requires Node.js >= 12.13.0.
|
||||||
|
|
||||||
|
* Add `background` property to PNG and GIF image metadata.
|
||||||
|
|
||||||
|
* Add `compression` property to HEIF image metadata.
|
||||||
|
[#2504](https://github.com/lovell/sharp/issues/2504)
|
||||||
|
|
||||||
|
* AVIF encoding now defaults to `4:4:4` chroma subsampling.
|
||||||
|
[#2562](https://github.com/lovell/sharp/issues/2562)
|
||||||
|
|
||||||
|
* Allow multiple platform-arch binaries in same `node_modules` installation tree.
|
||||||
|
[#2575](https://github.com/lovell/sharp/issues/2575)
|
||||||
|
|
||||||
|
* Default to single-channel `b-w` space when `extractChannel` is used.
|
||||||
|
[#2658](https://github.com/lovell/sharp/issues/2658)
|
||||||
|
|
||||||
|
* Allow installation directory to contain spaces (regression in v0.26.0).
|
||||||
|
[#2777](https://github.com/lovell/sharp/issues/2777)
|
||||||
|
|
||||||
|
* Add `pipelineColourspace` operator to set the processing space.
|
||||||
|
[#2704](https://github.com/lovell/sharp/pull/2704)
|
||||||
|
[@Daiz](https://github.com/Daiz)
|
||||||
|
|
||||||
|
* Allow bit depth to be set when using raw input and output.
|
||||||
|
[#2762](https://github.com/lovell/sharp/pull/2762)
|
||||||
|
[@mart-jansink](https://github.com/mart-jansink)
|
||||||
|
|
||||||
|
* Allow `negate` to act only on non-alpha channels.
|
||||||
|
[#2808](https://github.com/lovell/sharp/pull/2808)
|
||||||
|
[@rexxars](https://github.com/rexxars)
|
||||||
|
|
||||||
## v0.28 - *bijou*
|
## v0.28 - *bijou*
|
||||||
|
|
||||||
Requires libvips v8.10.6
|
Requires libvips v8.10.6
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
".*",
|
".*",
|
||||||
"build.js",
|
"build.js",
|
||||||
"firebase.json",
|
"firebase.json",
|
||||||
"*.md",
|
|
||||||
"image/**",
|
"image/**",
|
||||||
"search-index/**"
|
"search-index/**"
|
||||||
],
|
],
|
||||||
@@ -14,10 +13,9 @@
|
|||||||
{
|
{
|
||||||
"source": "**",
|
"source": "**",
|
||||||
"headers": [
|
"headers": [
|
||||||
{
|
{ "key": "Cache-Control", "value": "max-age=86400" },
|
||||||
"key": "Cache-Control",
|
{ "key": "X-Content-Type-Options", "value": "nosniff" },
|
||||||
"value": "max-age=86400"
|
{ "key": "X-Frame-Options", "value": "SAMEORIGIN" }
|
||||||
}
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -212,3 +212,9 @@ GitHub: https://github.com/florian-busch
|
|||||||
|
|
||||||
Name: Matthieu Salettes
|
Name: Matthieu Salettes
|
||||||
GitHub: https://github.com/msalettes
|
GitHub: https://github.com/msalettes
|
||||||
|
|
||||||
|
Name: Taneli Vatanen
|
||||||
|
GitHub: https://github.com/Daiz
|
||||||
|
|
||||||
|
Name: Mart Jansink
|
||||||
|
GitHub: https://github.com/mart-jansink
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
<meta name="description" content="Resize large images in common formats to smaller, web-friendly JPEG, PNG, WebP and AVIF images of varying dimensions">
|
<meta name="description" content="Resize large images in common formats to smaller, web-friendly JPEG, PNG, WebP and AVIF images of varying dimensions">
|
||||||
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; object-src 'none'; style-src 'unsafe-inline';
|
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; object-src 'none'; style-src 'unsafe-inline';
|
||||||
img-src 'unsafe-inline' data: https://pixel.plumbing/px/ https://cdn.jsdelivr.net/gh/lovell/ https://www.google-analytics.com;
|
img-src 'unsafe-inline' data: https://pixel.plumbing/px/ https://cdn.jsdelivr.net/gh/lovell/ https://www.google-analytics.com;
|
||||||
connect-src 'self' https://cdn.jsdelivr.net/gh/lovell/ https://www.google-analytics.com;
|
connect-src 'self' https://www.google-analytics.com;
|
||||||
script-src 'unsafe-inline' 'unsafe-eval'
|
script-src 'unsafe-inline' 'unsafe-eval'
|
||||||
https://cdn.jsdelivr.net/npm/docute@4/dist/docute.min.js
|
https://cdn.jsdelivr.net/npm/docute@4/dist/docute.min.js
|
||||||
https://www.google-analytics.com/analytics.js;">
|
https://www.google-analytics.com/analytics.js;">
|
||||||
@@ -19,8 +19,6 @@
|
|||||||
<link rel="apple-touch-icon-precomposed" sizes="72x72" href="https://pixel.plumbing/px/72x72/sharp-logo.svg">
|
<link rel="apple-touch-icon-precomposed" sizes="72x72" href="https://pixel.plumbing/px/72x72/sharp-logo.svg">
|
||||||
<link rel="apple-touch-icon-precomposed" href="https://pixel.plumbing/px/57x57/sharp-logo.svg">
|
<link rel="apple-touch-icon-precomposed" href="https://pixel.plumbing/px/57x57/sharp-logo.svg">
|
||||||
<link rel="author" href="/humans.txt" type="text/plain">
|
<link rel="author" href="/humans.txt" type="text/plain">
|
||||||
<link rel="preload" href="https://cdn.jsdelivr.net/gh/lovell/sharp@v0.28.3/docs/README.md" as="fetch" type="text/markdown" crossorigin>
|
|
||||||
<link rel="preload" href="https://cdn.jsdelivr.net/gh/lovell/sharp@master/docs/image/sharp-logo.svg" as="image" type="image/svg+xml" crossorigin>
|
|
||||||
<link rel="dns-prefetch" href="https://pixel.plumbing">
|
<link rel="dns-prefetch" href="https://pixel.plumbing">
|
||||||
<link rel="dns-prefetch" href="https://www.google-analytics.com">
|
<link rel="dns-prefetch" href="https://www.google-analytics.com">
|
||||||
<script type="application/ld+json">
|
<script type="application/ld+json">
|
||||||
@@ -105,7 +103,7 @@
|
|||||||
.then(function (entries) {
|
.then(function (entries) {
|
||||||
const results = [];
|
const results = [];
|
||||||
entries.forEach(function (entry) {
|
entries.forEach(function (entry) {
|
||||||
if (entry.k.includes(keyword)) {
|
if (entry.k.includes(keyword.trim().toLowerCase())) {
|
||||||
results.push({
|
results.push({
|
||||||
title: entry.t,
|
title: entry.t,
|
||||||
link: entry.l,
|
link: entry.l,
|
||||||
@@ -139,7 +137,6 @@
|
|||||||
docuteApiTitlePlugin,
|
docuteApiTitlePlugin,
|
||||||
docuteApiSearchPlugin
|
docuteApiSearchPlugin
|
||||||
],
|
],
|
||||||
sourcePath: 'https://cdn.jsdelivr.net/gh/lovell/sharp@v0.28.3/docs',
|
|
||||||
nav: [
|
nav: [
|
||||||
{
|
{
|
||||||
title: 'Funding',
|
title: 'Funding',
|
||||||
|
|||||||
@@ -10,20 +10,20 @@ yarn add sharp
|
|||||||
|
|
||||||
## Prerequisites
|
## Prerequisites
|
||||||
|
|
||||||
* Node.js v10+
|
* Node.js >= 12.13.0
|
||||||
|
|
||||||
## Prebuilt binaries
|
## Prebuilt binaries
|
||||||
|
|
||||||
Ready-compiled sharp and libvips binaries are provided for use with
|
Ready-compiled sharp and libvips binaries are provided for use on the most common platforms:
|
||||||
Node.js v10+ on the most common platforms:
|
|
||||||
|
|
||||||
* macOS x64 (>= 10.13)
|
* macOS x64 (>= 10.13)
|
||||||
|
* macOS ARM64
|
||||||
* Linux x64 (glibc >= 2.17, musl >= 1.1.24)
|
* Linux x64 (glibc >= 2.17, musl >= 1.1.24)
|
||||||
* Linux ARM64 (glibc >= 2.29, musl >= 1.1.24)
|
* Linux ARM64 (glibc >= 2.29, musl >= 1.1.24)
|
||||||
* Windows x64
|
* Windows x64
|
||||||
* Windows x86
|
* Windows x86
|
||||||
|
|
||||||
An ~7.5MB tarball containing libvips and its most commonly used dependencies
|
An ~7MB tarball containing libvips and its most commonly used dependencies
|
||||||
is downloaded via HTTPS and stored within `node_modules/sharp/vendor` during `npm install`.
|
is downloaded via HTTPS and stored within `node_modules/sharp/vendor` during `npm install`.
|
||||||
|
|
||||||
This provides support for the
|
This provides support for the
|
||||||
@@ -31,7 +31,6 @@ JPEG, PNG, WebP, AVIF, TIFF, GIF (input) and SVG (input) image formats.
|
|||||||
|
|
||||||
The following platforms have prebuilt libvips but not sharp:
|
The following platforms have prebuilt libvips but not sharp:
|
||||||
|
|
||||||
* macOS ARM64
|
|
||||||
* Linux ARMv6
|
* Linux ARMv6
|
||||||
* Linux ARMv7 (glibc >= 2.28)
|
* Linux ARMv7 (glibc >= 2.28)
|
||||||
* Windows ARM64
|
* Windows ARM64
|
||||||
@@ -61,15 +60,9 @@ Check the output of running `npm install --verbose sharp` for useful error messa
|
|||||||
|
|
||||||
## Apple M1
|
## Apple M1
|
||||||
|
|
||||||
Prebuilt libvips binaries are provided for macOS on ARM64 (since sharp v0.28.0).
|
Prebuilt sharp and libvips binaries are provided for macOS on ARM64 from sharp v0.29.0.
|
||||||
|
|
||||||
During `npm install` sharp will be built locally,
|
Prebuilt libvips binaries were provided for macOS on ARM64 from sharp v0.28.0.
|
||||||
which requires Xcode and Python - see
|
|
||||||
[building from source](#building-from-source).
|
|
||||||
|
|
||||||
When this new ARM64 CPU is made freely available
|
|
||||||
to open source projects via a CI service
|
|
||||||
then prebuilt sharp binaries can also be provided.
|
|
||||||
|
|
||||||
## Cross-platform
|
## Cross-platform
|
||||||
|
|
||||||
@@ -138,14 +131,10 @@ To install the prebuilt libvips binaries from a custom URL,
|
|||||||
set the `sharp_libvips_binary_host` npm config option
|
set the `sharp_libvips_binary_host` npm config option
|
||||||
or the `npm_config_sharp_libvips_binary_host` environment variable.
|
or the `npm_config_sharp_libvips_binary_host` environment variable.
|
||||||
|
|
||||||
The version subpath and file name are appended to these. There should be tarballs available
|
The version subpath and file name are appended to these.
|
||||||
that are compressed with both gzip and Brotli, as the format downloaded will vary depending
|
|
||||||
on whether the user's version of Node supports Brotli decompression (Node.js v10.16.0+)
|
|
||||||
|
|
||||||
For example, if `sharp_libvips_binary_host` is set to `https://hostname/path`
|
For example, if `sharp_libvips_binary_host` is set to `https://hostname/path`
|
||||||
and the libvips version is `1.2.3` then the resultant URL will be
|
and the libvips version is `1.2.3` then the resultant URL will be
|
||||||
`https://hostname/path/v1.2.3/libvips-1.2.3-platform-arch.tar.br` or
|
`https://hostname/path/v1.2.3/libvips-1.2.3-platform-arch.tar.br`.
|
||||||
`https://hostname/path/v1.2.3/libvips-1.2.3-platform-arch.tar.gz`.
|
|
||||||
|
|
||||||
See the Chinese mirror below for a further example.
|
See the Chinese mirror below for a further example.
|
||||||
|
|
||||||
@@ -210,32 +199,18 @@ to `false` when using the `yarn` package manager.
|
|||||||
|
|
||||||
## AWS Lambda
|
## AWS Lambda
|
||||||
|
|
||||||
The binaries in the `node_modules` directory of the
|
The `node_modules` directory of the
|
||||||
[deployment package](https://docs.aws.amazon.com/lambda/latest/dg/nodejs-package.html)
|
[deployment package](https://docs.aws.amazon.com/lambda/latest/dg/nodejs-package.html)
|
||||||
must be for the Linux x64 platform.
|
must include binaries for the Linux x64 platform.
|
||||||
|
|
||||||
When building your deployment package on machines other than Linux x64 (glibc),
|
When building your deployment package on machines other than Linux x64 (glibc),
|
||||||
run the following commands:
|
run the following additional command after `npm install`:
|
||||||
|
|
||||||
macOS:
|
|
||||||
```sh
|
```sh
|
||||||
rm -rf node_modules/sharp
|
npm install
|
||||||
SHARP_IGNORE_GLOBAL_LIBVIPS=1 npm install --arch=x64 --platform=linux sharp
|
SHARP_IGNORE_GLOBAL_LIBVIPS=1 npm install --arch=x64 --platform=linux sharp
|
||||||
```
|
```
|
||||||
|
|
||||||
Windows:
|
|
||||||
```sh
|
|
||||||
rmdir /s /q node_modules/sharp
|
|
||||||
npm install --arch=x64 --platform=linux sharp
|
|
||||||
```
|
|
||||||
|
|
||||||
Alternatively a Docker container closely matching the Lambda runtime can be used:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
rm -rf node_modules/sharp
|
|
||||||
docker run -v "$PWD":/var/task lambci/lambda:build-nodejs12.x npm install sharp
|
|
||||||
```
|
|
||||||
|
|
||||||
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.
|
||||||
|
|
||||||
|
|||||||
@@ -5,9 +5,11 @@ A test to benchmark the performance of this module relative to alternatives.
|
|||||||
## The contenders
|
## The contenders
|
||||||
|
|
||||||
* [jimp](https://www.npmjs.com/package/jimp) v0.16.1 - Image processing in pure JavaScript. Provides bicubic interpolation.
|
* [jimp](https://www.npmjs.com/package/jimp) v0.16.1 - Image processing in pure JavaScript. Provides bicubic interpolation.
|
||||||
* [mapnik](https://www.npmjs.org/package/mapnik) v4.5.6 - Whilst primarily a map renderer, Mapnik contains bitmap image utilities.
|
* [mapnik](https://www.npmjs.org/package/mapnik) v4.5.8 - Whilst primarily a map renderer, Mapnik contains bitmap image utilities.
|
||||||
* [imagemagick](https://www.npmjs.com/package/imagemagick) v0.1.3 - Supports filesystem only and "*has been unmaintained for a long time*".
|
* [imagemagick](https://www.npmjs.com/package/imagemagick) v0.1.3 - Supports filesystem only and "*has been unmaintained for a long time*".
|
||||||
* [gm](https://www.npmjs.com/package/gm) v1.23.1 - Fully featured wrapper around GraphicsMagick's `gm` command line utility.
|
* [gm](https://www.npmjs.com/package/gm) v1.23.1 - Fully featured wrapper around GraphicsMagick's `gm` command line utility.
|
||||||
|
* [@squoosh/lib](https://www.npmjs.com/package/@squoosh/lib) v0.4.0 - Image libraries transpiled to WebAssembly, includes GPLv3 code.
|
||||||
|
* [@squoosh/cli](https://www.npmjs.com/package/@squoosh/cli) v0.7.2 - Command line wrapper around `@squoosh/lib`, avoids GPLv3 by spawning process.
|
||||||
* sharp v0.28.0 / libvips v8.10.6 - Caching within libvips disabled to ensure a fair comparison.
|
* sharp v0.28.0 / libvips v8.10.6 - Caching within libvips disabled to ensure a fair comparison.
|
||||||
|
|
||||||
## The task
|
## The task
|
||||||
@@ -19,21 +21,23 @@ then compress to JPEG at a "quality" setting of 80.
|
|||||||
## Test environment
|
## Test environment
|
||||||
|
|
||||||
* AWS EC2 eu-west-1 [c5ad.xlarge](https://aws.amazon.com/ec2/instance-types/c5/) (4x AMD EPYC 7R32)
|
* AWS EC2 eu-west-1 [c5ad.xlarge](https://aws.amazon.com/ec2/instance-types/c5/) (4x AMD EPYC 7R32)
|
||||||
* Ubuntu 20.10 (ami-03f10415e8b0bfb86)
|
* Ubuntu 21.04 (ami-0d7626a9c2ceab1ac)
|
||||||
* Node.js v14.16.0
|
* Node.js 16.6.2
|
||||||
|
|
||||||
## Results
|
## Results
|
||||||
|
|
||||||
| Module | Input | Output | Ops/sec | Speed-up |
|
| Module | Input | Output | Ops/sec | Speed-up |
|
||||||
| :----------------- | :----- | :----- | ------: | -------: |
|
| :----------------- | :----- | :----- | ------: | -------: |
|
||||||
| jimp | buffer | buffer | 0.78 | 1.0 |
|
| jimp | buffer | buffer | 0.83 | 1.0 |
|
||||||
| mapnik | buffer | buffer | 3.39 | 4.3 |
|
| squoosh-cli | file | file | 1.09 | 1.3 |
|
||||||
| gm | buffer | buffer | 7.84 | 10.1 |
|
| squoosh-lib | buffer | buffer | 1.83 | 2.2 |
|
||||||
| gm | file | file | 9.24 | 11.8 |
|
| mapnik | buffer | buffer | 3.41 | 4.1 |
|
||||||
| imagemagick | file | file | 9.37 | 12.0 |
|
| gm | buffer | buffer | 8.34 | 10.0 |
|
||||||
| sharp | stream | stream | 26.84 | 34.4 |
|
| imagemagick | file | file | 8.67 | 10.4 |
|
||||||
| sharp | file | file | 29.76 | 38.2 |
|
| gm | file | file | 8.82 | 10.6 |
|
||||||
| sharp | buffer | buffer | 31.60 | 40.5 |
|
| sharp | stream | stream | 29.44 | 35.5 |
|
||||||
|
| sharp | file | file | 29.64 | 35.7 |
|
||||||
|
| sharp | buffer | buffer | 31.09 | 37.5 |
|
||||||
|
|
||||||
Greater libvips performance can be expected with caching enabled (default)
|
Greater libvips performance can be expected with caching enabled (default)
|
||||||
and using 8+ core machines, especially those with larger L1/L2 CPU caches.
|
and using 8+ core machines, especially those with larger L1/L2 CPU caches.
|
||||||
|
|||||||
@@ -4,19 +4,19 @@ const fs = require('fs');
|
|||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
|
||||||
const libvips = require('../lib/libvips');
|
const libvips = require('../lib/libvips');
|
||||||
|
const platform = require('../lib/platform');
|
||||||
|
|
||||||
const minimumLibvipsVersion = libvips.minimumLibvipsVersion;
|
const minimumLibvipsVersion = libvips.minimumLibvipsVersion;
|
||||||
|
|
||||||
const platform = process.env.npm_config_platform || process.platform;
|
const platformAndArch = platform();
|
||||||
if (platform === 'win32') {
|
|
||||||
const buildDir = path.join(__dirname, '..', 'build');
|
if (platformAndArch.startsWith('win32')) {
|
||||||
const buildReleaseDir = path.join(buildDir, 'Release');
|
const buildReleaseDir = path.join(__dirname, '..', 'build', 'Release');
|
||||||
libvips.log(`Creating ${buildReleaseDir}`);
|
libvips.log(`Creating ${buildReleaseDir}`);
|
||||||
try {
|
try {
|
||||||
libvips.mkdirSync(buildDir);
|
|
||||||
libvips.mkdirSync(buildReleaseDir);
|
libvips.mkdirSync(buildReleaseDir);
|
||||||
} catch (err) {}
|
} catch (err) {}
|
||||||
const vendorLibDir = path.join(__dirname, '..', 'vendor', minimumLibvipsVersion, 'lib');
|
const vendorLibDir = path.join(__dirname, '..', 'vendor', minimumLibvipsVersion, platformAndArch, 'lib');
|
||||||
libvips.log(`Copying DLLs from ${vendorLibDir} to ${buildReleaseDir}`);
|
libvips.log(`Copying DLLs from ${vendorLibDir} to ${buildReleaseDir}`);
|
||||||
try {
|
try {
|
||||||
fs
|
fs
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ const minimumGlibcVersionByArch = {
|
|||||||
|
|
||||||
const hasSharpPrebuild = [
|
const hasSharpPrebuild = [
|
||||||
'darwin-x64',
|
'darwin-x64',
|
||||||
|
'darwin-arm64',
|
||||||
'linux-arm64',
|
'linux-arm64',
|
||||||
'linux-x64',
|
'linux-x64',
|
||||||
'linuxmusl-x64',
|
'linuxmusl-x64',
|
||||||
@@ -35,7 +36,6 @@ const hasSharpPrebuild = [
|
|||||||
const { minimumLibvipsVersion, minimumLibvipsVersionLabelled } = libvips;
|
const { minimumLibvipsVersion, minimumLibvipsVersionLabelled } = libvips;
|
||||||
const distHost = process.env.npm_config_sharp_libvips_binary_host || 'https://github.com/lovell/sharp-libvips/releases/download';
|
const distHost = process.env.npm_config_sharp_libvips_binary_host || 'https://github.com/lovell/sharp-libvips/releases/download';
|
||||||
const distBaseUrl = process.env.npm_config_sharp_dist_base_url || process.env.SHARP_DIST_BASE_URL || `${distHost}/v${minimumLibvipsVersionLabelled}/`;
|
const distBaseUrl = process.env.npm_config_sharp_dist_base_url || process.env.SHARP_DIST_BASE_URL || `${distHost}/v${minimumLibvipsVersionLabelled}/`;
|
||||||
const supportsBrotli = ('BrotliDecompress' in zlib);
|
|
||||||
const installationForced = !!(process.env.npm_config_sharp_install_force || process.env.SHARP_INSTALL_FORCE);
|
const installationForced = !!(process.env.npm_config_sharp_install_force || process.env.SHARP_INSTALL_FORCE);
|
||||||
|
|
||||||
const fail = function (err) {
|
const fail = function (err) {
|
||||||
@@ -56,9 +56,7 @@ const handleError = function (err) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const extractTarball = function (tarPath, platformAndArch) {
|
const extractTarball = function (tarPath, platformAndArch) {
|
||||||
const vendorPath = path.join(__dirname, '..', 'vendor');
|
const versionedVendorPath = path.join(__dirname, '..', 'vendor', minimumLibvipsVersion, platformAndArch);
|
||||||
libvips.mkdirSync(vendorPath);
|
|
||||||
const versionedVendorPath = path.join(vendorPath, minimumLibvipsVersion);
|
|
||||||
libvips.mkdirSync(versionedVendorPath);
|
libvips.mkdirSync(versionedVendorPath);
|
||||||
|
|
||||||
const ignoreVendorInclude = hasSharpPrebuild.includes(platformAndArch) && !process.env.npm_config_build_from_source;
|
const ignoreVendorInclude = hasSharpPrebuild.includes(platformAndArch) && !process.env.npm_config_build_from_source;
|
||||||
@@ -68,7 +66,7 @@ const extractTarball = function (tarPath, platformAndArch) {
|
|||||||
|
|
||||||
stream.pipeline(
|
stream.pipeline(
|
||||||
fs.createReadStream(tarPath),
|
fs.createReadStream(tarPath),
|
||||||
supportsBrotli ? new zlib.BrotliDecompress() : new zlib.Gunzip(),
|
new zlib.BrotliDecompress(),
|
||||||
tarFs.extract(versionedVendorPath, { ignore }),
|
tarFs.extract(versionedVendorPath, { ignore }),
|
||||||
function (err) {
|
function (err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
@@ -121,10 +119,8 @@ try {
|
|||||||
handleError(new Error(`Expected Node.js version ${supportedNodeVersion} but found ${process.versions.node}`));
|
handleError(new Error(`Expected Node.js version ${supportedNodeVersion} but found ${process.versions.node}`));
|
||||||
}
|
}
|
||||||
|
|
||||||
const extension = supportsBrotli ? 'br' : 'gz';
|
|
||||||
|
|
||||||
// Download to per-process temporary file
|
// Download to per-process temporary file
|
||||||
const tarFilename = ['libvips', minimumLibvipsVersion, platformAndArch].join('-') + '.tar.' + extension;
|
const tarFilename = ['libvips', minimumLibvipsVersion, platformAndArch].join('-') + '.tar.br';
|
||||||
const tarPathCache = path.join(libvips.cachePath(), tarFilename);
|
const tarPathCache = path.join(libvips.cachePath(), tarFilename);
|
||||||
if (fs.existsSync(tarPathCache)) {
|
if (fs.existsSync(tarPathCache)) {
|
||||||
libvips.log(`Using cached ${tarPathCache}`);
|
libvips.log(`Using cached ${tarPathCache}`);
|
||||||
|
|||||||
@@ -72,13 +72,17 @@ function ensureAlpha (alpha) {
|
|||||||
* Extract a single channel from a multi-channel image.
|
* Extract a single channel from a multi-channel image.
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* sharp(input)
|
* // green.jpg is a greyscale image containing the green channel of the input
|
||||||
|
* await sharp(input)
|
||||||
* .extractChannel('green')
|
* .extractChannel('green')
|
||||||
* .toColourspace('b-w')
|
* .toFile('green.jpg');
|
||||||
* .toFile('green.jpg', function(err, info) {
|
*
|
||||||
* // info.channels === 1
|
* @example
|
||||||
* // green.jpg is a greyscale image containing the green channel of the input
|
* // red1 is the red value of the first pixel, red2 the second pixel etc.
|
||||||
* });
|
* const [red1, red2, ...] = await sharp(input)
|
||||||
|
* .extractChannel(0)
|
||||||
|
* .raw()
|
||||||
|
* .toBuffer();
|
||||||
*
|
*
|
||||||
* @param {number|string} channel - zero-indexed channel/band number to extract, or `red`, `green`, `blue` or `alpha`.
|
* @param {number|string} channel - zero-indexed channel/band number to extract, or `red`, `green`, `blue` or `alpha`.
|
||||||
* @returns {Sharp}
|
* @returns {Sharp}
|
||||||
@@ -94,7 +98,7 @@ function extractChannel (channel) {
|
|||||||
} else {
|
} else {
|
||||||
throw is.invalidParameterError('channel', 'integer or one of: red, green, blue, alpha', channel);
|
throw is.invalidParameterError('channel', 'integer or one of: red, green, blue, alpha', channel);
|
||||||
}
|
}
|
||||||
return this;
|
return this.toColourspace('b-w');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -54,6 +54,45 @@ function grayscale (grayscale) {
|
|||||||
return this.greyscale(grayscale);
|
return this.greyscale(grayscale);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the pipeline colourspace.
|
||||||
|
*
|
||||||
|
* 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 {@link toColourspace}.
|
||||||
|
*
|
||||||
|
* This feature is experimental and has not yet been fully-tested with all operations.
|
||||||
|
*
|
||||||
|
* @since 0.29.0
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* // Run pipeline in 16 bits per channel RGB while converting final result to 8 bits per channel sRGB.
|
||||||
|
* await sharp(input)
|
||||||
|
* .pipelineColourspace('rgb16')
|
||||||
|
* .toColourspace('srgb')
|
||||||
|
* .toFile('16bpc-pipeline-to-8bpc-output.png')
|
||||||
|
*
|
||||||
|
* @param {string} [colourspace] - pipeline colourspace e.g. `rgb16`, `scrgb`, `lab`, `grey16` [...](https://github.com/libvips/libvips/blob/41cff4e9d0838498487a00623462204eb10ee5b8/libvips/iofuncs/enumtypes.c#L774)
|
||||||
|
* @returns {Sharp}
|
||||||
|
* @throws {Error} Invalid parameters
|
||||||
|
*/
|
||||||
|
function pipelineColourspace (colourspace) {
|
||||||
|
if (!is.string(colourspace)) {
|
||||||
|
throw is.invalidParameterError('colourspace', 'string', colourspace);
|
||||||
|
}
|
||||||
|
this.options.colourspaceInput = colourspace;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Alternative spelling of `pipelineColourspace`.
|
||||||
|
* @param {string} [colorspace] - pipeline colorspace.
|
||||||
|
* @returns {Sharp}
|
||||||
|
* @throws {Error} Invalid parameters
|
||||||
|
*/
|
||||||
|
function pipelineColorspace (colorspace) {
|
||||||
|
return this.pipelineColourspace(colorspace);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the output colourspace.
|
* Set the output colourspace.
|
||||||
* By default output image will be web-friendly sRGB, with additional channels interpreted as alpha channels.
|
* By default output image will be web-friendly sRGB, with additional channels interpreted as alpha channels.
|
||||||
@@ -64,7 +103,7 @@ function grayscale (grayscale) {
|
|||||||
* .toColourspace('rgb16')
|
* .toColourspace('rgb16')
|
||||||
* .toFile('16-bpp.png')
|
* .toFile('16-bpp.png')
|
||||||
*
|
*
|
||||||
* @param {string} [colourspace] - output colourspace e.g. `srgb`, `rgb`, `cmyk`, `lab`, `b-w` [...](https://github.com/libvips/libvips/blob/master/libvips/iofuncs/enumtypes.c#L568)
|
* @param {string} [colourspace] - output colourspace e.g. `srgb`, `rgb`, `cmyk`, `lab`, `b-w` [...](https://github.com/libvips/libvips/blob/3c0bfdf74ce1dc37a6429bed47fa76f16e2cd70a/libvips/iofuncs/enumtypes.c#L777-L794)
|
||||||
* @returns {Sharp}
|
* @returns {Sharp}
|
||||||
* @throws {Error} Invalid parameters
|
* @throws {Error} Invalid parameters
|
||||||
*/
|
*/
|
||||||
@@ -119,6 +158,8 @@ module.exports = function (Sharp) {
|
|||||||
tint,
|
tint,
|
||||||
greyscale,
|
greyscale,
|
||||||
grayscale,
|
grayscale,
|
||||||
|
pipelineColourspace,
|
||||||
|
pipelineColorspace,
|
||||||
toColourspace,
|
toColourspace,
|
||||||
toColorspace,
|
toColorspace,
|
||||||
// Private
|
// Private
|
||||||
|
|||||||
@@ -5,32 +5,7 @@ const stream = require('stream');
|
|||||||
const is = require('./is');
|
const is = require('./is');
|
||||||
|
|
||||||
require('./libvips').hasVendoredLibvips();
|
require('./libvips').hasVendoredLibvips();
|
||||||
|
require('./sharp');
|
||||||
/* istanbul ignore next */
|
|
||||||
try {
|
|
||||||
require('../build/Release/sharp.node');
|
|
||||||
} catch (err) {
|
|
||||||
// Bail early if bindings aren't available
|
|
||||||
const help = ['', 'Something went wrong installing the "sharp" module', '', err.message, ''];
|
|
||||||
if (/NODE_MODULE_VERSION/.test(err.message)) {
|
|
||||||
help.push('- Ensure the version of Node.js used at install time matches that used at runtime');
|
|
||||||
} else if (/invalid ELF header/.test(err.message)) {
|
|
||||||
help.push(`- Ensure "${process.platform}" is used at install time as well as runtime`);
|
|
||||||
} else if (/dylib/.test(err.message) && /Incompatible library version/.test(err.message)) {
|
|
||||||
help.push('- Run "brew update && brew upgrade vips"');
|
|
||||||
} else {
|
|
||||||
help.push(
|
|
||||||
'- Remove the "node_modules/sharp" directory then run',
|
|
||||||
' "npm install --ignore-scripts=false --verbose sharp" and look for errors'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
help.push(
|
|
||||||
'- Consult the installation documentation at https://sharp.pixelplumbing.com/install',
|
|
||||||
'- Search for this error at https://github.com/lovell/sharp/issues', ''
|
|
||||||
);
|
|
||||||
const error = help.join('\n');
|
|
||||||
throw new Error(error);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use NODE_DEBUG=sharp to enable libvips warnings
|
// Use NODE_DEBUG=sharp to enable libvips warnings
|
||||||
const debuglog = util.debuglog('sharp');
|
const debuglog = util.debuglog('sharp');
|
||||||
@@ -117,8 +92,9 @@ const debuglog = util.debuglog('sharp');
|
|||||||
* }
|
* }
|
||||||
* }).toFile('noise.png');
|
* }).toFile('noise.png');
|
||||||
*
|
*
|
||||||
* @param {(Buffer|Uint8Array|Uint8ClampedArray|string)} [input] - if present, can be
|
* @param {(Buffer|Uint8Array|Uint8ClampedArray|Int8Array|Uint16Array|Int16Array|Uint32Array|Int32Array|Float32Array|Float64Array|string)} [input] - if present, can be
|
||||||
* a Buffer / Uint8Array / Uint8ClampedArray containing JPEG, PNG, WebP, AVIF, GIF, SVG, TIFF or raw pixel image data, or
|
* a Buffer / Uint8Array / Uint8ClampedArray containing JPEG, PNG, WebP, AVIF, GIF, SVG or TIFF image data, or
|
||||||
|
* a TypedArray containing raw pixel image data, or
|
||||||
* a String containing the filesystem path to an JPEG, PNG, WebP, AVIF, GIF, SVG or TIFF image file.
|
* a String containing the filesystem path to an JPEG, PNG, WebP, AVIF, GIF, SVG or TIFF image file.
|
||||||
* JPEG, PNG, WebP, AVIF, GIF, SVG, TIFF or raw pixel image data can be streamed into the object when not present.
|
* JPEG, PNG, WebP, AVIF, GIF, SVG, TIFF or raw pixel image data can be streamed into the object when not present.
|
||||||
* @param {Object} [options] - if present, is an Object with optional attributes.
|
* @param {Object} [options] - if present, is an Object with optional attributes.
|
||||||
@@ -204,6 +180,7 @@ const Sharp = function (input, options) {
|
|||||||
flatten: false,
|
flatten: false,
|
||||||
flattenBackground: [0, 0, 0],
|
flattenBackground: [0, 0, 0],
|
||||||
negate: false,
|
negate: false,
|
||||||
|
negateAlpha: true,
|
||||||
medianSize: 0,
|
medianSize: 0,
|
||||||
blurSigma: 0,
|
blurSigma: 0,
|
||||||
sharpenSigma: 0,
|
sharpenSigma: 0,
|
||||||
@@ -229,6 +206,7 @@ const Sharp = function (input, options) {
|
|||||||
removeAlpha: false,
|
removeAlpha: false,
|
||||||
ensureAlpha: -1,
|
ensureAlpha: -1,
|
||||||
colourspace: 'srgb',
|
colourspace: 'srgb',
|
||||||
|
colourspaceInput: 'last',
|
||||||
composite: [],
|
composite: [],
|
||||||
// output
|
// output
|
||||||
fileOut: '',
|
fileOut: '',
|
||||||
@@ -276,7 +254,8 @@ const Sharp = function (input, options) {
|
|||||||
heifLossless: false,
|
heifLossless: false,
|
||||||
heifCompression: 'av1',
|
heifCompression: 'av1',
|
||||||
heifSpeed: 5,
|
heifSpeed: 5,
|
||||||
heifChromaSubsampling: '4:2:0',
|
heifChromaSubsampling: '4:4:4',
|
||||||
|
rawDepth: 'uchar',
|
||||||
tileSize: 256,
|
tileSize: 256,
|
||||||
tileOverlap: 0,
|
tileOverlap: 0,
|
||||||
tileContainer: 'fs',
|
tileContainer: 'fs',
|
||||||
|
|||||||
48
lib/input.js
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
const color = require('color');
|
const color = require('color');
|
||||||
const is = require('./is');
|
const is = require('./is');
|
||||||
const sharp = require('../build/Release/sharp.node');
|
const sharp = require('./sharp');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extract input options, if any, from an object.
|
* Extract input options, if any, from an object.
|
||||||
@@ -34,8 +34,7 @@ function _createInputDescriptor (input, inputOptions, containerOptions) {
|
|||||||
throw Error('Input Buffer is empty');
|
throw Error('Input Buffer is empty');
|
||||||
}
|
}
|
||||||
inputDescriptor.buffer = input;
|
inputDescriptor.buffer = input;
|
||||||
} else if (is.uint8Array(input)) {
|
} else if (is.typedArray(input)) {
|
||||||
// Uint8Array or Uint8ClampedArray
|
|
||||||
if (input.length === 0) {
|
if (input.length === 0) {
|
||||||
throw Error('Input Bit Array is empty');
|
throw Error('Input Bit Array is empty');
|
||||||
}
|
}
|
||||||
@@ -104,6 +103,37 @@ function _createInputDescriptor (input, inputOptions, containerOptions) {
|
|||||||
inputDescriptor.rawHeight = inputOptions.raw.height;
|
inputDescriptor.rawHeight = inputOptions.raw.height;
|
||||||
inputDescriptor.rawChannels = inputOptions.raw.channels;
|
inputDescriptor.rawChannels = inputOptions.raw.channels;
|
||||||
inputDescriptor.rawPremultiplied = !!inputOptions.raw.premultiplied;
|
inputDescriptor.rawPremultiplied = !!inputOptions.raw.premultiplied;
|
||||||
|
|
||||||
|
switch (input.constructor) {
|
||||||
|
case Uint8Array:
|
||||||
|
case Uint8ClampedArray:
|
||||||
|
inputDescriptor.rawDepth = 'uchar';
|
||||||
|
break;
|
||||||
|
case Int8Array:
|
||||||
|
inputDescriptor.rawDepth = 'char';
|
||||||
|
break;
|
||||||
|
case Uint16Array:
|
||||||
|
inputDescriptor.rawDepth = 'ushort';
|
||||||
|
break;
|
||||||
|
case Int16Array:
|
||||||
|
inputDescriptor.rawDepth = 'short';
|
||||||
|
break;
|
||||||
|
case Uint32Array:
|
||||||
|
inputDescriptor.rawDepth = 'uint';
|
||||||
|
break;
|
||||||
|
case Int32Array:
|
||||||
|
inputDescriptor.rawDepth = 'int';
|
||||||
|
break;
|
||||||
|
case Float32Array:
|
||||||
|
inputDescriptor.rawDepth = 'float';
|
||||||
|
break;
|
||||||
|
case Float64Array:
|
||||||
|
inputDescriptor.rawDepth = 'double';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
inputDescriptor.rawDepth = 'uchar';
|
||||||
|
break;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new Error('Expected width, height and channels for raw pixel input');
|
throw new Error('Expected width, height and channels for raw pixel input');
|
||||||
}
|
}
|
||||||
@@ -271,6 +301,8 @@ function _isStreamInput () {
|
|||||||
* - `pagePrimary`: Number of the primary page in a HEIF image
|
* - `pagePrimary`: Number of the primary page in a HEIF image
|
||||||
* - `levels`: Details of each level in a multi-level image provided as an array of objects, requires libvips compiled with support for OpenSlide
|
* - `levels`: Details of each level in a multi-level image provided as an array of objects, requires libvips compiled with support for OpenSlide
|
||||||
* - `subifds`: Number of Sub Image File Directories in an OME-TIFF image
|
* - `subifds`: Number of Sub Image File Directories in an OME-TIFF image
|
||||||
|
* - `background`: Default background colour, if present, for PNG (bKGD) and GIF images, either an RGB Object or a single greyscale value
|
||||||
|
* - `compression`: The encoder used to compress an HEIF file, `av1` (AVIF) or `hevc` (HEIC)
|
||||||
* - `hasProfile`: Boolean indicating the presence of an embedded ICC profile
|
* - `hasProfile`: Boolean indicating the presence of an embedded ICC profile
|
||||||
* - `hasAlpha`: Boolean indicating the presence of an alpha transparency channel
|
* - `hasAlpha`: Boolean indicating the presence of an alpha transparency channel
|
||||||
* - `orientation`: Number value of the EXIF Orientation header, if present
|
* - `orientation`: Number value of the EXIF Orientation header, if present
|
||||||
@@ -356,6 +388,9 @@ function metadata (callback) {
|
|||||||
* - `sharpness`: Estimation of greyscale sharpness based on the standard deviation of a Laplacian convolution, discarding alpha channel if any (experimental)
|
* - `sharpness`: Estimation of greyscale sharpness based on the standard deviation of a Laplacian convolution, discarding alpha channel if any (experimental)
|
||||||
* - `dominant`: Object containing most dominant sRGB colour based on a 4096-bin 3D histogram (experimental)
|
* - `dominant`: Object containing most dominant sRGB colour based on a 4096-bin 3D histogram (experimental)
|
||||||
*
|
*
|
||||||
|
* **Note**: Statistics are derived from the original input image. Any operations performed on the image must first be
|
||||||
|
* written to a buffer in order to run `stats` on the result (see third example).
|
||||||
|
*
|
||||||
* @example
|
* @example
|
||||||
* const image = sharp(inputJpg);
|
* const image = sharp(inputJpg);
|
||||||
* image
|
* image
|
||||||
@@ -368,6 +403,13 @@ function metadata (callback) {
|
|||||||
* const { entropy, sharpness, dominant } = await sharp(input).stats();
|
* const { entropy, sharpness, dominant } = await sharp(input).stats();
|
||||||
* const { r, g, b } = dominant;
|
* const { r, g, b } = dominant;
|
||||||
*
|
*
|
||||||
|
* @example
|
||||||
|
* const image = sharp(input);
|
||||||
|
* // store intermediate result
|
||||||
|
* const part = await image.extract(region).toBuffer();
|
||||||
|
* // create new instance to obtain statistics of extracted region
|
||||||
|
* const stats = await sharp(part).stats();
|
||||||
|
*
|
||||||
* @param {Function} [callback] - called with the arguments `(err, stats)`
|
* @param {Function} [callback] - called with the arguments `(err, stats)`
|
||||||
* @returns {Promise<Object>}
|
* @returns {Promise<Object>}
|
||||||
*/
|
*/
|
||||||
|
|||||||
24
lib/is.js
@@ -49,12 +49,26 @@ const buffer = function (val) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Is this value a Uint8Array or Uint8ClampedArray object?
|
* Is this value a typed array object?. E.g. Uint8Array or Uint8ClampedArray?
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
const uint8Array = function (val) {
|
const typedArray = function (val) {
|
||||||
// allow both since Uint8ClampedArray simply clamps the values between 0-255
|
if (defined(val)) {
|
||||||
return val instanceof Uint8Array || val instanceof Uint8ClampedArray;
|
switch (val.constructor) {
|
||||||
|
case Uint8Array:
|
||||||
|
case Uint8ClampedArray:
|
||||||
|
case Int8Array:
|
||||||
|
case Uint16Array:
|
||||||
|
case Int16Array:
|
||||||
|
case Uint32Array:
|
||||||
|
case Int32Array:
|
||||||
|
case Float32Array:
|
||||||
|
case Float64Array:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -119,7 +133,7 @@ module.exports = {
|
|||||||
fn: fn,
|
fn: fn,
|
||||||
bool: bool,
|
bool: bool,
|
||||||
buffer: buffer,
|
buffer: buffer,
|
||||||
uint8Array: uint8Array,
|
typedArray: typedArray,
|
||||||
string: string,
|
string: string,
|
||||||
number: number,
|
number: number,
|
||||||
integer: integer,
|
integer: integer,
|
||||||
|
|||||||
@@ -21,9 +21,9 @@ const spawnSyncOptions = {
|
|||||||
|
|
||||||
const mkdirSync = function (dirPath) {
|
const mkdirSync = function (dirPath) {
|
||||||
try {
|
try {
|
||||||
fs.mkdirSync(dirPath);
|
fs.mkdirSync(dirPath, { recursive: true });
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
/* istanbul ignore if */
|
/* istanbul ignore next */
|
||||||
if (err.code !== 'EEXIST') {
|
if (err.code !== 'EEXIST') {
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
@@ -67,23 +67,8 @@ const globalLibvipsVersion = function () {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const hasVendoredLibvips = function () {
|
const hasVendoredLibvips = function () {
|
||||||
const currentPlatformId = platform();
|
const vendorPath = path.join(__dirname, '..', 'vendor', minimumLibvipsVersion, platform());
|
||||||
const vendorPath = path.join(__dirname, '..', 'vendor', minimumLibvipsVersion);
|
return fs.existsSync(vendorPath);
|
||||||
let vendorPlatformId;
|
|
||||||
try {
|
|
||||||
vendorPlatformId = require(path.join(vendorPath, 'platform.json'));
|
|
||||||
} catch (err) {}
|
|
||||||
/* istanbul ignore else */
|
|
||||||
if (vendorPlatformId) {
|
|
||||||
/* istanbul ignore else */
|
|
||||||
if (currentPlatformId === vendorPlatformId) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
throw new Error(`'${vendorPlatformId}' binaries cannot be used on the '${currentPlatformId}' platform. Please remove the 'node_modules/sharp' directory and run 'npm install' on the '${currentPlatformId}' platform.`);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const pkgConfigPath = function () {
|
const pkgConfigPath = function () {
|
||||||
|
|||||||
@@ -325,11 +325,19 @@ function gamma (gamma, gammaOut) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Produce the "negative" of the image.
|
* Produce the "negative" of the image.
|
||||||
* @param {Boolean} [negate=true]
|
* @param {Object} [options]
|
||||||
|
* @param {Boolean} [options.alpha=true] Whether or not to negate any alpha channel
|
||||||
* @returns {Sharp}
|
* @returns {Sharp}
|
||||||
*/
|
*/
|
||||||
function negate (negate) {
|
function negate (options) {
|
||||||
this.options.negate = is.bool(negate) ? negate : true;
|
this.options.negate = is.bool(options) ? options : true;
|
||||||
|
if (is.plainObject(options) && 'alpha' in options) {
|
||||||
|
if (!is.bool(options.alpha)) {
|
||||||
|
throw is.invalidParameterError('alpha', 'should be boolean value', options.alpha);
|
||||||
|
} else {
|
||||||
|
this.options.negateAlpha = options.alpha;
|
||||||
|
}
|
||||||
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const is = require('./is');
|
const is = require('./is');
|
||||||
const sharp = require('../build/Release/sharp.node');
|
const sharp = require('./sharp');
|
||||||
|
|
||||||
const formats = new Map([
|
const formats = new Map([
|
||||||
['heic', 'heif'],
|
['heic', 'heif'],
|
||||||
@@ -660,7 +660,7 @@ function tiff (options) {
|
|||||||
* @param {number} [options.quality=50] - quality, integer 1-100
|
* @param {number} [options.quality=50] - quality, integer 1-100
|
||||||
* @param {boolean} [options.lossless=false] - use lossless compression
|
* @param {boolean} [options.lossless=false] - use lossless compression
|
||||||
* @param {number} [options.speed=5] - CPU effort vs file size, 0 (slowest/smallest) to 8 (fastest/largest)
|
* @param {number} [options.speed=5] - CPU effort vs file size, 0 (slowest/smallest) to 8 (fastest/largest)
|
||||||
* @param {string} [options.chromaSubsampling='4:2:0'] - set to '4:4:4' to prevent chroma subsampling otherwise defaults to '4:2:0' chroma subsampling, requires libvips v8.11.0
|
* @param {string} [options.chromaSubsampling='4:4:4'] - set to '4:2:0' to use chroma subsampling
|
||||||
* @returns {Sharp}
|
* @returns {Sharp}
|
||||||
* @throws {Error} Invalid options
|
* @throws {Error} Invalid options
|
||||||
*/
|
*/
|
||||||
@@ -681,7 +681,7 @@ function avif (options) {
|
|||||||
* @param {string} [options.compression='av1'] - compression format: av1, hevc
|
* @param {string} [options.compression='av1'] - compression format: av1, hevc
|
||||||
* @param {boolean} [options.lossless=false] - use lossless compression
|
* @param {boolean} [options.lossless=false] - use lossless compression
|
||||||
* @param {number} [options.speed=5] - CPU effort vs file size, 0 (slowest/smallest) to 8 (fastest/largest)
|
* @param {number} [options.speed=5] - CPU effort vs file size, 0 (slowest/smallest) to 8 (fastest/largest)
|
||||||
* @param {string} [options.chromaSubsampling='4:2:0'] - set to '4:4:4' to prevent chroma subsampling otherwise defaults to '4:2:0' chroma subsampling, requires libvips v8.11.0
|
* @param {string} [options.chromaSubsampling='4:4:4'] - set to '4:2:0' to use chroma subsampling
|
||||||
* @returns {Sharp}
|
* @returns {Sharp}
|
||||||
* @throws {Error} Invalid options
|
* @throws {Error} Invalid options
|
||||||
*/
|
*/
|
||||||
@@ -727,28 +727,41 @@ function heif (options) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Force output to be raw, uncompressed, 8-bit unsigned integer (unit8) pixel data.
|
* Force output to be raw, uncompressed pixel data.
|
||||||
* Pixel ordering is left-to-right, top-to-bottom, without padding.
|
* Pixel ordering is left-to-right, top-to-bottom, without padding.
|
||||||
* Channel ordering will be RGB or RGBA for non-greyscale colourspaces.
|
* Channel ordering will be RGB or RGBA for non-greyscale colourspaces.
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* // Extract raw RGB pixel data from JPEG input
|
* // Extract raw, unsigned 8-bit RGB pixel data from JPEG input
|
||||||
* const { data, info } = await sharp('input.jpg')
|
* const { data, info } = await sharp('input.jpg')
|
||||||
* .raw()
|
* .raw()
|
||||||
* .toBuffer({ resolveWithObject: true });
|
* .toBuffer({ resolveWithObject: true });
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* // Extract alpha channel as raw pixel data from PNG input
|
* // Extract alpha channel as raw, unsigned 16-bit pixel data from PNG input
|
||||||
* const data = await sharp('input.png')
|
* const data = await sharp('input.png')
|
||||||
* .ensureAlpha()
|
* .ensureAlpha()
|
||||||
* .extractChannel(3)
|
* .extractChannel(3)
|
||||||
* .toColourspace('b-w')
|
* .toColourspace('b-w')
|
||||||
* .raw()
|
* .raw({ depth: 'ushort' })
|
||||||
* .toBuffer();
|
* .toBuffer();
|
||||||
*
|
*
|
||||||
* @returns {Sharp}
|
* @param {Object} [options] - output options
|
||||||
|
* @param {string} [options.depth='uchar'] - bit depth, one of: char, uchar (default), short, ushort, int, uint, float, complex, double, dpcomplex
|
||||||
|
* @throws {Error} Invalid options
|
||||||
*/
|
*/
|
||||||
function raw () {
|
function raw (options) {
|
||||||
|
if (is.object(options)) {
|
||||||
|
if (is.defined(options.depth)) {
|
||||||
|
if (is.string(options.depth) && is.inArray(options.depth,
|
||||||
|
['char', 'uchar', 'short', 'ushort', 'int', 'uint', 'float', 'complex', 'double', 'dpcomplex']
|
||||||
|
)) {
|
||||||
|
this.options.rawDepth = options.depth;
|
||||||
|
} else {
|
||||||
|
throw is.invalidParameterError('depth', 'one of: char, uchar, short, ushort, int, uint, float, complex, double, dpcomplex', options.depth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return this._updateFormatOut('raw');
|
return this._updateFormatOut('raw');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
24
lib/sharp.js
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const platformAndArch = require('./platform')();
|
||||||
|
|
||||||
|
/* istanbul ignore next */
|
||||||
|
try {
|
||||||
|
module.exports = require(`../build/Release/sharp-${platformAndArch}.node`);
|
||||||
|
} catch (err) {
|
||||||
|
// Bail early if bindings aren't available
|
||||||
|
const help = ['', 'Something went wrong installing the "sharp" module', '', err.message, '', 'Possible solutions:'];
|
||||||
|
if (/dylib/.test(err.message) && /Incompatible library version/.test(err.message)) {
|
||||||
|
help.push('- Update Homebrew: "brew update && brew upgrade vips"');
|
||||||
|
} else {
|
||||||
|
help.push(
|
||||||
|
'- Install with the --verbose flag and look for errors: "npm install --ignore-scripts=false --verbose sharp"',
|
||||||
|
`- Install for the current runtime: "npm install --platform=${process.platform} --arch=${process.arch} sharp"`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
help.push(
|
||||||
|
'- Consult the installation documentation: https://sharp.pixelplumbing.com/install'
|
||||||
|
);
|
||||||
|
console.error(help.join('\n'));
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
@@ -4,7 +4,7 @@ const events = require('events');
|
|||||||
const detectLibc = require('detect-libc');
|
const detectLibc = require('detect-libc');
|
||||||
|
|
||||||
const is = require('./is');
|
const is = require('./is');
|
||||||
const sharp = require('../build/Release/sharp.node');
|
const sharp = require('./sharp');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An Object containing nested boolean values representing the available input and output formats/methods.
|
* An Object containing nested boolean values representing the available input and output formats/methods.
|
||||||
|
|||||||
27
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, AVIF and TIFF images",
|
"description": "High performance Node.js image processing, the fastest module to resize JPEG, PNG, WebP, AVIF and TIFF images",
|
||||||
"version": "0.28.3",
|
"version": "0.29.0",
|
||||||
"author": "Lovell Fuller <npm@lovell.info>",
|
"author": "Lovell Fuller <npm@lovell.info>",
|
||||||
"homepage": "https://github.com/lovell/sharp",
|
"homepage": "https://github.com/lovell/sharp",
|
||||||
"contributors": [
|
"contributors": [
|
||||||
@@ -77,7 +77,8 @@
|
|||||||
"alza54 <alza54@thiocod.in>",
|
"alza54 <alza54@thiocod.in>",
|
||||||
"Jacob Smith <jacob@frende.me>",
|
"Jacob Smith <jacob@frende.me>",
|
||||||
"Michael Nutt <michael@nutt.im>",
|
"Michael Nutt <michael@nutt.im>",
|
||||||
"Brad Parham <baparham@gmail.com>"
|
"Brad Parham <baparham@gmail.com>",
|
||||||
|
"Taneli Vatanen <taneli.vatanen@gmail.com>"
|
||||||
],
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"install": "(node install/libvips && node install/dll-copy && prebuild-install) || (node install/can-compile && node-gyp rebuild && node install/dll-copy)",
|
"install": "(node install/libvips && node install/dll-copy && prebuild-install) || (node install/can-compile && node-gyp rebuild && node install/dll-copy)",
|
||||||
@@ -121,45 +122,45 @@
|
|||||||
"vips"
|
"vips"
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"color": "^3.1.3",
|
"color": "^4.0.1",
|
||||||
"detect-libc": "^1.0.3",
|
"detect-libc": "^1.0.3",
|
||||||
"node-addon-api": "^3.2.0",
|
"node-addon-api": "^4.0.0",
|
||||||
"prebuild-install": "^6.1.2",
|
"prebuild-install": "^6.1.4",
|
||||||
"semver": "^7.3.5",
|
"semver": "^7.3.5",
|
||||||
"simple-get": "^3.1.0",
|
"simple-get": "^3.1.0",
|
||||||
"tar-fs": "^2.1.1",
|
"tar-fs": "^2.1.1",
|
||||||
"tunnel-agent": "^0.6.0"
|
"tunnel-agent": "^0.6.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"async": "^3.2.0",
|
"async": "^3.2.1",
|
||||||
"cc": "^3.0.1",
|
"cc": "^3.0.1",
|
||||||
"decompress-zip": "^0.3.3",
|
"decompress-zip": "^0.3.3",
|
||||||
"documentation": "^13.2.5",
|
"documentation": "^13.2.5",
|
||||||
"exif-reader": "^1.0.3",
|
"exif-reader": "^1.0.3",
|
||||||
"icc": "^2.0.0",
|
"icc": "^2.0.0",
|
||||||
"license-checker": "^25.0.1",
|
"license-checker": "^25.0.1",
|
||||||
"mocha": "^8.4.0",
|
"mocha": "^9.0.3",
|
||||||
"mock-fs": "^4.14.0",
|
"mock-fs": "^5.0.0",
|
||||||
"nyc": "^15.1.0",
|
"nyc": "^15.1.0",
|
||||||
"prebuild": "^10.0.1",
|
"prebuild": "^10.0.1",
|
||||||
"rimraf": "^3.0.2",
|
"rimraf": "^3.0.2",
|
||||||
"semistandard": "^16.0.0"
|
"semistandard": "^16.0.1"
|
||||||
},
|
},
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"config": {
|
"config": {
|
||||||
"libvips": "8.10.6",
|
"libvips": "8.11.3",
|
||||||
"runtime": "napi",
|
"runtime": "napi",
|
||||||
"target": 3
|
"target": 5
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10"
|
"node": ">=12.13.0"
|
||||||
},
|
},
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://opencollective.com/libvips"
|
"url": "https://opencollective.com/libvips"
|
||||||
},
|
},
|
||||||
"binary": {
|
"binary": {
|
||||||
"napi_versions": [
|
"napi_versions": [
|
||||||
3
|
5
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"semistandard": {
|
"semistandard": {
|
||||||
|
|||||||
@@ -92,6 +92,9 @@ namespace sharp {
|
|||||||
}
|
}
|
||||||
// Raw pixel input
|
// Raw pixel input
|
||||||
if (HasAttr(input, "rawChannels")) {
|
if (HasAttr(input, "rawChannels")) {
|
||||||
|
descriptor->rawDepth = static_cast<VipsBandFormat>(
|
||||||
|
vips_enum_from_nick(nullptr, VIPS_TYPE_BAND_FORMAT,
|
||||||
|
AttrAsStr(input, "rawDepth").data()));
|
||||||
descriptor->rawChannels = AttrAsUint32(input, "rawChannels");
|
descriptor->rawChannels = AttrAsUint32(input, "rawChannels");
|
||||||
descriptor->rawWidth = AttrAsUint32(input, "rawWidth");
|
descriptor->rawWidth = AttrAsUint32(input, "rawWidth");
|
||||||
descriptor->rawHeight = AttrAsUint32(input, "rawHeight");
|
descriptor->rawHeight = AttrAsUint32(input, "rawHeight");
|
||||||
@@ -297,7 +300,7 @@ namespace sharp {
|
|||||||
if (descriptor->rawChannels > 0) {
|
if (descriptor->rawChannels > 0) {
|
||||||
// Raw, uncompressed pixel data
|
// Raw, uncompressed pixel data
|
||||||
image = VImage::new_from_memory(descriptor->buffer, descriptor->bufferLength,
|
image = VImage::new_from_memory(descriptor->buffer, descriptor->bufferLength,
|
||||||
descriptor->rawWidth, descriptor->rawHeight, descriptor->rawChannels, VIPS_FORMAT_UCHAR);
|
descriptor->rawWidth, descriptor->rawHeight, descriptor->rawChannels, descriptor->rawDepth);
|
||||||
if (descriptor->rawChannels < 3) {
|
if (descriptor->rawChannels < 3) {
|
||||||
image.get_image()->Type = VIPS_INTERPRETATION_B_W;
|
image.get_image()->Type = VIPS_INTERPRETATION_B_W;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -25,9 +25,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 < 10) || \
|
(VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION < 11) || \
|
||||||
(VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION == 10 && VIPS_MICRO_VERSION < 6)
|
(VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION == 11 && VIPS_MICRO_VERSION < 3)
|
||||||
#error "libvips version 8.10.6+ is required - please see https://sharp.pixelplumbing.com/install"
|
#error "libvips version 8.11.3+ is required - please see https://sharp.pixelplumbing.com/install"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if ((!defined(__clang__)) && defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 6)))
|
#if ((!defined(__clang__)) && defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 6)))
|
||||||
@@ -54,6 +54,7 @@ namespace sharp {
|
|||||||
size_t bufferLength;
|
size_t bufferLength;
|
||||||
bool isBuffer;
|
bool isBuffer;
|
||||||
double density;
|
double density;
|
||||||
|
VipsBandFormat rawDepth;
|
||||||
int rawChannels;
|
int rawChannels;
|
||||||
int rawWidth;
|
int rawWidth;
|
||||||
int rawHeight;
|
int rawHeight;
|
||||||
@@ -78,6 +79,7 @@ namespace sharp {
|
|||||||
bufferLength(0),
|
bufferLength(0),
|
||||||
isBuffer(FALSE),
|
isBuffer(FALSE),
|
||||||
density(72.0),
|
density(72.0),
|
||||||
|
rawDepth(VIPS_FORMAT_UCHAR),
|
||||||
rawChannels(0),
|
rawChannels(0),
|
||||||
rawWidth(0),
|
rawWidth(0),
|
||||||
rawHeight(0),
|
rawHeight(0),
|
||||||
|
|||||||
@@ -110,19 +110,6 @@ VSource::new_from_options( const char *options )
|
|||||||
return( out );
|
return( out );
|
||||||
}
|
}
|
||||||
|
|
||||||
VOption *
|
|
||||||
VOption::set( const char *name, const VSource value )
|
|
||||||
{
|
|
||||||
Pair *pair = new Pair( name );
|
|
||||||
|
|
||||||
pair->input = true;
|
|
||||||
g_value_init( &pair->value, VIPS_TYPE_SOURCE );
|
|
||||||
g_value_set_object( &pair->value, value.get_source() );
|
|
||||||
options.push_back( pair );
|
|
||||||
|
|
||||||
return( this );
|
|
||||||
}
|
|
||||||
|
|
||||||
VTarget
|
VTarget
|
||||||
VTarget::new_to_descriptor( int descriptor )
|
VTarget::new_to_descriptor( int descriptor )
|
||||||
{
|
{
|
||||||
@@ -162,17 +149,4 @@ VTarget::new_to_memory()
|
|||||||
return( out );
|
return( out );
|
||||||
}
|
}
|
||||||
|
|
||||||
VOption *
|
|
||||||
VOption::set( const char *name, const VTarget value )
|
|
||||||
{
|
|
||||||
Pair *pair = new Pair( name );
|
|
||||||
|
|
||||||
pair->input = true;
|
|
||||||
g_value_init( &pair->value, VIPS_TYPE_TARGET );
|
|
||||||
g_value_set_object( &pair->value, value.get_target() );
|
|
||||||
options.push_back( pair );
|
|
||||||
|
|
||||||
return( this );
|
|
||||||
}
|
|
||||||
|
|
||||||
VIPS_NAMESPACE_END
|
VIPS_NAMESPACE_END
|
||||||
|
|||||||
@@ -51,6 +51,12 @@
|
|||||||
|
|
||||||
VIPS_NAMESPACE_START
|
VIPS_NAMESPACE_START
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \namespace vips
|
||||||
|
*
|
||||||
|
* General docs for the vips namespace.
|
||||||
|
*/
|
||||||
|
|
||||||
std::vector<double>
|
std::vector<double>
|
||||||
to_vectorv( int n, ... )
|
to_vectorv( int n, ... )
|
||||||
{
|
{
|
||||||
@@ -140,6 +146,20 @@ VOption::set( const char *name, int value )
|
|||||||
return( this );
|
return( this );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// input guint64
|
||||||
|
VOption *
|
||||||
|
VOption::set( const char *name, guint64 value )
|
||||||
|
{
|
||||||
|
Pair *pair = new Pair( name );
|
||||||
|
|
||||||
|
pair->input = true;
|
||||||
|
g_value_init( &pair->value, G_TYPE_UINT64 );
|
||||||
|
g_value_set_uint64( &pair->value, value );
|
||||||
|
options.push_back( pair );
|
||||||
|
|
||||||
|
return( this );
|
||||||
|
}
|
||||||
|
|
||||||
// input double
|
// input double
|
||||||
VOption *
|
VOption *
|
||||||
VOption::set( const char *name, double value )
|
VOption::set( const char *name, double value )
|
||||||
@@ -167,39 +187,17 @@ VOption::set( const char *name, const char *value )
|
|||||||
return( this );
|
return( this );
|
||||||
}
|
}
|
||||||
|
|
||||||
// input image
|
// input vips object (image, source, target, etc. etc.)
|
||||||
VOption *
|
VOption *
|
||||||
VOption::set( const char *name, const VImage value )
|
VOption::set( const char *name, const VObject value )
|
||||||
{
|
{
|
||||||
Pair *pair = new Pair( name );
|
Pair *pair = new Pair( name );
|
||||||
|
VipsObject *object = value.get_object();
|
||||||
|
GType type = G_OBJECT_TYPE( object );
|
||||||
|
|
||||||
pair->input = true;
|
pair->input = true;
|
||||||
g_value_init( &pair->value, VIPS_TYPE_IMAGE );
|
g_value_init( &pair->value, type );
|
||||||
g_value_set_object( &pair->value, value.get_image() );
|
g_value_set_object( &pair->value, object );
|
||||||
options.push_back( pair );
|
|
||||||
|
|
||||||
return( this );
|
|
||||||
}
|
|
||||||
|
|
||||||
// input double array
|
|
||||||
VOption *
|
|
||||||
VOption::set( const char *name, std::vector<double> value )
|
|
||||||
{
|
|
||||||
Pair *pair = new Pair( name );
|
|
||||||
|
|
||||||
double *array;
|
|
||||||
unsigned int i;
|
|
||||||
|
|
||||||
pair->input = true;
|
|
||||||
|
|
||||||
g_value_init( &pair->value, VIPS_TYPE_ARRAY_DOUBLE );
|
|
||||||
vips_value_set_array_double( &pair->value, NULL,
|
|
||||||
static_cast< int >( value.size() ) );
|
|
||||||
array = vips_value_get_array_double( &pair->value, NULL );
|
|
||||||
|
|
||||||
for( i = 0; i < value.size(); i++ )
|
|
||||||
array[i] = value[i];
|
|
||||||
|
|
||||||
options.push_back( pair );
|
options.push_back( pair );
|
||||||
|
|
||||||
return( this );
|
return( this );
|
||||||
@@ -229,6 +227,30 @@ VOption::set( const char *name, std::vector<int> value )
|
|||||||
return( this );
|
return( this );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// input double array
|
||||||
|
VOption *
|
||||||
|
VOption::set( const char *name, std::vector<double> value )
|
||||||
|
{
|
||||||
|
Pair *pair = new Pair( name );
|
||||||
|
|
||||||
|
double *array;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
pair->input = true;
|
||||||
|
|
||||||
|
g_value_init( &pair->value, VIPS_TYPE_ARRAY_DOUBLE );
|
||||||
|
vips_value_set_array_double( &pair->value, NULL,
|
||||||
|
static_cast< int >( value.size() ) );
|
||||||
|
array = vips_value_get_array_double( &pair->value, NULL );
|
||||||
|
|
||||||
|
for( i = 0; i < value.size(); i++ )
|
||||||
|
array[i] = value[i];
|
||||||
|
|
||||||
|
options.push_back( pair );
|
||||||
|
|
||||||
|
return( this );
|
||||||
|
}
|
||||||
|
|
||||||
// input image array
|
// input image array
|
||||||
VOption *
|
VOption *
|
||||||
VOption::set( const char *name, std::vector<VImage> value )
|
VOption::set( const char *name, std::vector<VImage> value )
|
||||||
@@ -619,6 +641,22 @@ VImage::new_from_source( VSource source, const char *option_string,
|
|||||||
return( out );
|
return( out );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VImage
|
||||||
|
VImage::new_from_memory_steal( void *data, size_t size,
|
||||||
|
int width, int height, int bands, VipsBandFormat format )
|
||||||
|
{
|
||||||
|
VipsImage *image;
|
||||||
|
|
||||||
|
if( !(image = vips_image_new_from_memory( data, size,
|
||||||
|
width, height, bands, format )) )
|
||||||
|
throw( VError() );
|
||||||
|
|
||||||
|
g_signal_connect( image, "postclose",
|
||||||
|
G_CALLBACK( vips_image_free_buffer ), data);
|
||||||
|
|
||||||
|
return( VImage( image ) );
|
||||||
|
}
|
||||||
|
|
||||||
VImage
|
VImage
|
||||||
VImage::new_matrix( int width, int height )
|
VImage::new_matrix( int width, int height )
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -60,17 +60,4 @@ VInterpolate::new_from_name( const char *name, VOption *options )
|
|||||||
return( out );
|
return( out );
|
||||||
}
|
}
|
||||||
|
|
||||||
VOption *
|
|
||||||
VOption::set( const char *name, const VInterpolate value )
|
|
||||||
{
|
|
||||||
Pair *pair = new Pair( name );
|
|
||||||
|
|
||||||
pair->input = true;
|
|
||||||
g_value_init( &pair->value, VIPS_TYPE_INTERPOLATE );
|
|
||||||
g_value_set_object( &pair->value, value.get_interpolate() );
|
|
||||||
options.push_back( pair );
|
|
||||||
|
|
||||||
return( this );
|
|
||||||
}
|
|
||||||
|
|
||||||
VIPS_NAMESPACE_END
|
VIPS_NAMESPACE_END
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// bodies for vips operations
|
// bodies for vips operations
|
||||||
// Sun 5 Jul 22:36:37 BST 2020
|
// Wed May 12 11:30:00 AM CEST 2021
|
||||||
// this file is generated automatically, do not edit!
|
// this file is generated automatically, do not edit!
|
||||||
|
|
||||||
VImage VImage::CMC2LCh( VOption *options ) const
|
VImage VImage::CMC2LCh( VOption *options ) const
|
||||||
@@ -1065,6 +1065,18 @@ VImage VImage::fitsload( const char *filename, VOption *options )
|
|||||||
return( out );
|
return( out );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VImage VImage::fitsload_source( VSource source, VOption *options )
|
||||||
|
{
|
||||||
|
VImage out;
|
||||||
|
|
||||||
|
call( "fitsload_source",
|
||||||
|
(options ? options : VImage::option())->
|
||||||
|
set( "out", &out )->
|
||||||
|
set( "source", source ) );
|
||||||
|
|
||||||
|
return( out );
|
||||||
|
}
|
||||||
|
|
||||||
void VImage::fitssave( const char *filename, VOption *options ) const
|
void VImage::fitssave( const char *filename, VOption *options ) const
|
||||||
{
|
{
|
||||||
call( "fitssave",
|
call( "fitssave",
|
||||||
@@ -1656,6 +1668,70 @@ VImage VImage::join( VImage in2, VipsDirection direction, VOption *options ) con
|
|||||||
return( out );
|
return( out );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VImage VImage::jp2kload( const char *filename, VOption *options )
|
||||||
|
{
|
||||||
|
VImage out;
|
||||||
|
|
||||||
|
call( "jp2kload",
|
||||||
|
(options ? options : VImage::option())->
|
||||||
|
set( "out", &out )->
|
||||||
|
set( "filename", filename ) );
|
||||||
|
|
||||||
|
return( out );
|
||||||
|
}
|
||||||
|
|
||||||
|
VImage VImage::jp2kload_buffer( VipsBlob *buffer, VOption *options )
|
||||||
|
{
|
||||||
|
VImage out;
|
||||||
|
|
||||||
|
call( "jp2kload_buffer",
|
||||||
|
(options ? options : VImage::option())->
|
||||||
|
set( "out", &out )->
|
||||||
|
set( "buffer", buffer ) );
|
||||||
|
|
||||||
|
return( out );
|
||||||
|
}
|
||||||
|
|
||||||
|
VImage VImage::jp2kload_source( VSource source, VOption *options )
|
||||||
|
{
|
||||||
|
VImage out;
|
||||||
|
|
||||||
|
call( "jp2kload_source",
|
||||||
|
(options ? options : VImage::option())->
|
||||||
|
set( "out", &out )->
|
||||||
|
set( "source", source ) );
|
||||||
|
|
||||||
|
return( out );
|
||||||
|
}
|
||||||
|
|
||||||
|
void VImage::jp2ksave( const char *filename, VOption *options ) const
|
||||||
|
{
|
||||||
|
call( "jp2ksave",
|
||||||
|
(options ? options : VImage::option())->
|
||||||
|
set( "in", *this )->
|
||||||
|
set( "filename", filename ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
VipsBlob *VImage::jp2ksave_buffer( VOption *options ) const
|
||||||
|
{
|
||||||
|
VipsBlob *buffer;
|
||||||
|
|
||||||
|
call( "jp2ksave_buffer",
|
||||||
|
(options ? options : VImage::option())->
|
||||||
|
set( "in", *this )->
|
||||||
|
set( "buffer", &buffer ) );
|
||||||
|
|
||||||
|
return( buffer );
|
||||||
|
}
|
||||||
|
|
||||||
|
void VImage::jp2ksave_target( VTarget target, VOption *options ) const
|
||||||
|
{
|
||||||
|
call( "jp2ksave_target",
|
||||||
|
(options ? options : VImage::option())->
|
||||||
|
set( "in", *this )->
|
||||||
|
set( "target", target ) );
|
||||||
|
}
|
||||||
|
|
||||||
VImage VImage::jpegload( const char *filename, VOption *options )
|
VImage VImage::jpegload( const char *filename, VOption *options )
|
||||||
{
|
{
|
||||||
VImage out;
|
VImage out;
|
||||||
@@ -1727,6 +1803,70 @@ void VImage::jpegsave_target( VTarget target, VOption *options ) const
|
|||||||
set( "target", target ) );
|
set( "target", target ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VImage VImage::jxlload( const char *filename, VOption *options )
|
||||||
|
{
|
||||||
|
VImage out;
|
||||||
|
|
||||||
|
call( "jxlload",
|
||||||
|
(options ? options : VImage::option())->
|
||||||
|
set( "out", &out )->
|
||||||
|
set( "filename", filename ) );
|
||||||
|
|
||||||
|
return( out );
|
||||||
|
}
|
||||||
|
|
||||||
|
VImage VImage::jxlload_buffer( VipsBlob *buffer, VOption *options )
|
||||||
|
{
|
||||||
|
VImage out;
|
||||||
|
|
||||||
|
call( "jxlload_buffer",
|
||||||
|
(options ? options : VImage::option())->
|
||||||
|
set( "out", &out )->
|
||||||
|
set( "buffer", buffer ) );
|
||||||
|
|
||||||
|
return( out );
|
||||||
|
}
|
||||||
|
|
||||||
|
VImage VImage::jxlload_source( VSource source, VOption *options )
|
||||||
|
{
|
||||||
|
VImage out;
|
||||||
|
|
||||||
|
call( "jxlload_source",
|
||||||
|
(options ? options : VImage::option())->
|
||||||
|
set( "out", &out )->
|
||||||
|
set( "source", source ) );
|
||||||
|
|
||||||
|
return( out );
|
||||||
|
}
|
||||||
|
|
||||||
|
void VImage::jxlsave( const char *filename, VOption *options ) const
|
||||||
|
{
|
||||||
|
call( "jxlsave",
|
||||||
|
(options ? options : VImage::option())->
|
||||||
|
set( "in", *this )->
|
||||||
|
set( "filename", filename ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
VipsBlob *VImage::jxlsave_buffer( VOption *options ) const
|
||||||
|
{
|
||||||
|
VipsBlob *buffer;
|
||||||
|
|
||||||
|
call( "jxlsave_buffer",
|
||||||
|
(options ? options : VImage::option())->
|
||||||
|
set( "in", *this )->
|
||||||
|
set( "buffer", &buffer ) );
|
||||||
|
|
||||||
|
return( buffer );
|
||||||
|
}
|
||||||
|
|
||||||
|
void VImage::jxlsave_target( VTarget target, VOption *options ) const
|
||||||
|
{
|
||||||
|
call( "jxlsave_target",
|
||||||
|
(options ? options : VImage::option())->
|
||||||
|
set( "in", *this )->
|
||||||
|
set( "target", target ) );
|
||||||
|
}
|
||||||
|
|
||||||
VImage VImage::labelregions( VOption *options ) const
|
VImage VImage::labelregions( VOption *options ) const
|
||||||
{
|
{
|
||||||
VImage mask;
|
VImage mask;
|
||||||
@@ -2284,6 +2424,18 @@ VImage VImage::niftiload( const char *filename, VOption *options )
|
|||||||
return( out );
|
return( out );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VImage VImage::niftiload_source( VSource source, VOption *options )
|
||||||
|
{
|
||||||
|
VImage out;
|
||||||
|
|
||||||
|
call( "niftiload_source",
|
||||||
|
(options ? options : VImage::option())->
|
||||||
|
set( "out", &out )->
|
||||||
|
set( "source", source ) );
|
||||||
|
|
||||||
|
return( out );
|
||||||
|
}
|
||||||
|
|
||||||
void VImage::niftisave( const char *filename, VOption *options ) const
|
void VImage::niftisave( const char *filename, VOption *options ) const
|
||||||
{
|
{
|
||||||
call( "niftisave",
|
call( "niftisave",
|
||||||
@@ -2316,6 +2468,18 @@ VImage VImage::openslideload( const char *filename, VOption *options )
|
|||||||
return( out );
|
return( out );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VImage VImage::openslideload_source( VSource source, VOption *options )
|
||||||
|
{
|
||||||
|
VImage out;
|
||||||
|
|
||||||
|
call( "openslideload_source",
|
||||||
|
(options ? options : VImage::option())->
|
||||||
|
set( "out", &out )->
|
||||||
|
set( "source", source ) );
|
||||||
|
|
||||||
|
return( out );
|
||||||
|
}
|
||||||
|
|
||||||
VImage VImage::pdfload( const char *filename, VOption *options )
|
VImage VImage::pdfload( const char *filename, VOption *options )
|
||||||
{
|
{
|
||||||
VImage out;
|
VImage out;
|
||||||
@@ -3388,6 +3552,18 @@ VImage VImage::vipsload( const char *filename, VOption *options )
|
|||||||
return( out );
|
return( out );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VImage VImage::vipsload_source( VSource source, VOption *options )
|
||||||
|
{
|
||||||
|
VImage out;
|
||||||
|
|
||||||
|
call( "vipsload_source",
|
||||||
|
(options ? options : VImage::option())->
|
||||||
|
set( "out", &out )->
|
||||||
|
set( "source", source ) );
|
||||||
|
|
||||||
|
return( out );
|
||||||
|
}
|
||||||
|
|
||||||
void VImage::vipssave( const char *filename, VOption *options ) const
|
void VImage::vipssave( const char *filename, VOption *options ) const
|
||||||
{
|
{
|
||||||
call( "vipssave",
|
call( "vipssave",
|
||||||
@@ -3396,6 +3572,14 @@ void VImage::vipssave( const char *filename, VOption *options ) const
|
|||||||
set( "filename", filename ) );
|
set( "filename", filename ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VImage::vipssave_target( VTarget target, VOption *options ) const
|
||||||
|
{
|
||||||
|
call( "vipssave_target",
|
||||||
|
(options ? options : VImage::option())->
|
||||||
|
set( "in", *this )->
|
||||||
|
set( "target", target ) );
|
||||||
|
}
|
||||||
|
|
||||||
VImage VImage::webpload( const char *filename, VOption *options )
|
VImage VImage::webpload( const char *filename, VOption *options )
|
||||||
{
|
{
|
||||||
VImage out;
|
VImage out;
|
||||||
|
|||||||
@@ -90,6 +90,9 @@ class MetadataWorker : public Napi::AsyncWorker {
|
|||||||
baton->subifds = image.get_int(VIPS_META_N_SUBIFDS);
|
baton->subifds = image.get_int(VIPS_META_N_SUBIFDS);
|
||||||
}
|
}
|
||||||
baton->hasProfile = sharp::HasProfile(image);
|
baton->hasProfile = sharp::HasProfile(image);
|
||||||
|
if (image.get_typeof("background") == VIPS_TYPE_ARRAY_DOUBLE) {
|
||||||
|
baton->background = image.get_array_double("background");
|
||||||
|
}
|
||||||
// Derived attributes
|
// Derived attributes
|
||||||
baton->hasAlpha = sharp::HasAlpha(image);
|
baton->hasAlpha = sharp::HasAlpha(image);
|
||||||
baton->orientation = sharp::ExifOrientation(image);
|
baton->orientation = sharp::ExifOrientation(image);
|
||||||
@@ -209,6 +212,17 @@ class MetadataWorker : public Napi::AsyncWorker {
|
|||||||
if (baton->subifds > 0) {
|
if (baton->subifds > 0) {
|
||||||
info.Set("subifds", baton->subifds);
|
info.Set("subifds", baton->subifds);
|
||||||
}
|
}
|
||||||
|
if (!baton->background.empty()) {
|
||||||
|
if (baton->background.size() == 3) {
|
||||||
|
Napi::Object background = Napi::Object::New(env);
|
||||||
|
background.Set("r", baton->background[0]);
|
||||||
|
background.Set("g", baton->background[1]);
|
||||||
|
background.Set("b", baton->background[2]);
|
||||||
|
info.Set("background", background);
|
||||||
|
} else {
|
||||||
|
info.Set("background", baton->background[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
info.Set("hasProfile", baton->hasProfile);
|
info.Set("hasProfile", baton->hasProfile);
|
||||||
info.Set("hasAlpha", baton->hasAlpha);
|
info.Set("hasAlpha", baton->hasAlpha);
|
||||||
if (baton->orientation > 0) {
|
if (baton->orientation > 0) {
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ struct MetadataBaton {
|
|||||||
std::string compression;
|
std::string compression;
|
||||||
std::vector<std::pair<int, int>> levels;
|
std::vector<std::pair<int, int>> levels;
|
||||||
int subifds;
|
int subifds;
|
||||||
|
std::vector<double> background;
|
||||||
bool hasProfile;
|
bool hasProfile;
|
||||||
bool hasAlpha;
|
bool hasAlpha;
|
||||||
int orientation;
|
int orientation;
|
||||||
|
|||||||
@@ -112,6 +112,19 @@ namespace sharp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Produce the "negative" of the image.
|
||||||
|
*/
|
||||||
|
VImage Negate(VImage image, bool const negateAlpha) {
|
||||||
|
if (HasAlpha(image) && !negateAlpha) {
|
||||||
|
// Separate alpha channel
|
||||||
|
VImage alpha = image[image.bands() - 1];
|
||||||
|
return RemoveAlpha(image).invert().bandjoin(alpha);
|
||||||
|
} else {
|
||||||
|
return image.invert();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Gaussian blur. Use sigma of -1.0 for fast blur.
|
* Gaussian blur. Use sigma of -1.0 for fast blur.
|
||||||
*/
|
*/
|
||||||
@@ -282,4 +295,16 @@ namespace sharp {
|
|||||||
return image.linear(a, b);
|
return image.linear(a, b);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ensure the image is in a given colourspace
|
||||||
|
*/
|
||||||
|
VImage EnsureColourspace(VImage image, VipsInterpretation colourspace) {
|
||||||
|
if (colourspace != VIPS_INTERPRETATION_LAST && image.interpretation() != colourspace) {
|
||||||
|
image = image.colourspace(colourspace,
|
||||||
|
VImage::option()->set("source_space", image.interpretation()));
|
||||||
|
}
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace sharp
|
} // namespace sharp
|
||||||
|
|||||||
@@ -45,6 +45,11 @@ namespace sharp {
|
|||||||
*/
|
*/
|
||||||
VImage Gamma(VImage image, double const exponent);
|
VImage Gamma(VImage image, double const exponent);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Produce the "negative" of the image.
|
||||||
|
*/
|
||||||
|
VImage Negate(VImage image, bool const negateAlpha);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Gaussian blur. Use sigma of -1.0 for fast blur.
|
* Gaussian blur. Use sigma of -1.0 for fast blur.
|
||||||
*/
|
*/
|
||||||
@@ -97,6 +102,11 @@ namespace sharp {
|
|||||||
*/
|
*/
|
||||||
VImage Modulate(VImage image, double const brightness, double const saturation, int const hue);
|
VImage Modulate(VImage image, double const brightness, double const saturation, int const hue);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ensure the image is in a given colourspace
|
||||||
|
*/
|
||||||
|
VImage EnsureColourspace(VImage image, VipsInterpretation colourspace);
|
||||||
|
|
||||||
} // namespace sharp
|
} // namespace sharp
|
||||||
|
|
||||||
#endif // SRC_OPERATIONS_H_
|
#endif // SRC_OPERATIONS_H_
|
||||||
|
|||||||
@@ -67,6 +67,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|||||||
vips::VImage image;
|
vips::VImage image;
|
||||||
sharp::ImageType inputImageType;
|
sharp::ImageType inputImageType;
|
||||||
std::tie(image, inputImageType) = sharp::OpenInput(baton->input);
|
std::tie(image, inputImageType) = sharp::OpenInput(baton->input);
|
||||||
|
image = sharp::EnsureColourspace(image, baton->colourspaceInput);
|
||||||
|
|
||||||
// Calculate angle of rotation
|
// Calculate angle of rotation
|
||||||
VipsAngle rotation;
|
VipsAngle rotation;
|
||||||
@@ -214,7 +215,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|||||||
double yresidual = static_cast<double>(yshrink) / yfactor;
|
double yresidual = static_cast<double>(yshrink) / yfactor;
|
||||||
|
|
||||||
// If integral x and y shrink are equal, try to use shrink-on-load for JPEG and WebP,
|
// If integral x and y shrink are equal, try to use shrink-on-load for JPEG and WebP,
|
||||||
// but not when applying gamma correction, pre-resize extract or trim
|
// but not when applying gamma correction, pre-resize extract, trim or input colourspace
|
||||||
int shrink_on_load = 1;
|
int shrink_on_load = 1;
|
||||||
|
|
||||||
int shrink_on_load_factor = 1;
|
int shrink_on_load_factor = 1;
|
||||||
@@ -227,6 +228,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|||||||
xshrink == yshrink && xshrink >= 2 * shrink_on_load_factor &&
|
xshrink == yshrink && xshrink >= 2 * shrink_on_load_factor &&
|
||||||
(inputImageType == sharp::ImageType::JPEG || inputImageType == sharp::ImageType::WEBP) &&
|
(inputImageType == sharp::ImageType::JPEG || inputImageType == sharp::ImageType::WEBP) &&
|
||||||
baton->gamma == 0 && baton->topOffsetPre == -1 && baton->trimThreshold == 0.0 &&
|
baton->gamma == 0 && baton->topOffsetPre == -1 && baton->trimThreshold == 0.0 &&
|
||||||
|
baton->colourspaceInput == VIPS_INTERPRETATION_LAST &&
|
||||||
image.width() > 3 && image.height() > 3 && baton->input->pages == 1
|
image.width() > 3 && image.height() > 3 && baton->input->pages == 1
|
||||||
) {
|
) {
|
||||||
if (xshrink >= 8 * shrink_on_load_factor) {
|
if (xshrink >= 8 * shrink_on_load_factor) {
|
||||||
@@ -325,7 +327,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|||||||
|
|
||||||
// Negate the colours in the image
|
// Negate the colours in the image
|
||||||
if (baton->negate) {
|
if (baton->negate) {
|
||||||
image = image.invert();
|
image = sharp::Negate(image, baton->negateAlpha);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gamma encoding (darken)
|
// Gamma encoding (darken)
|
||||||
@@ -411,6 +413,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|||||||
|
|
||||||
for (unsigned int i = 0; i < baton->joinChannelIn.size(); i++) {
|
for (unsigned int i = 0; i < baton->joinChannelIn.size(); i++) {
|
||||||
std::tie(joinImage, joinImageType) = sharp::OpenInput(baton->joinChannelIn[i]);
|
std::tie(joinImage, joinImageType) = sharp::OpenInput(baton->joinChannelIn[i]);
|
||||||
|
joinImage = sharp::EnsureColourspace(joinImage, baton->colourspaceInput);
|
||||||
image = image.bandjoin(joinImage);
|
image = image.bandjoin(joinImage);
|
||||||
}
|
}
|
||||||
image = image.copy(VImage::option()->set("interpretation", baton->colourspace));
|
image = image.copy(VImage::option()->set("interpretation", baton->colourspace));
|
||||||
@@ -552,7 +555,8 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|||||||
for (Composite *composite : baton->composite) {
|
for (Composite *composite : baton->composite) {
|
||||||
VImage compositeImage;
|
VImage compositeImage;
|
||||||
sharp::ImageType compositeImageType = sharp::ImageType::UNKNOWN;
|
sharp::ImageType compositeImageType = sharp::ImageType::UNKNOWN;
|
||||||
std::tie(compositeImage, compositeImageType) = OpenInput(composite->input);
|
std::tie(compositeImage, compositeImageType) = sharp::OpenInput(composite->input);
|
||||||
|
compositeImage = sharp::EnsureColourspace(compositeImage, baton->colourspaceInput);
|
||||||
// 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 vips::VError("Image to composite must have same dimensions or smaller");
|
||||||
@@ -661,6 +665,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|||||||
VImage booleanImage;
|
VImage booleanImage;
|
||||||
sharp::ImageType booleanImageType = sharp::ImageType::UNKNOWN;
|
sharp::ImageType booleanImageType = sharp::ImageType::UNKNOWN;
|
||||||
std::tie(booleanImage, booleanImageType) = sharp::OpenInput(baton->boolean);
|
std::tie(booleanImage, booleanImageType) = sharp::OpenInput(baton->boolean);
|
||||||
|
booleanImage = sharp::EnsureColourspace(booleanImage, baton->colourspaceInput);
|
||||||
image = sharp::Boolean(image, booleanImage, baton->booleanOp);
|
image = sharp::Boolean(image, booleanImage, baton->booleanOp);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -765,8 +770,8 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|||||||
->set("Q", baton->jpegQuality)
|
->set("Q", baton->jpegQuality)
|
||||||
->set("interlace", baton->jpegProgressive)
|
->set("interlace", baton->jpegProgressive)
|
||||||
->set("subsample_mode", baton->jpegChromaSubsampling == "4:4:4"
|
->set("subsample_mode", baton->jpegChromaSubsampling == "4:4:4"
|
||||||
? VIPS_FOREIGN_JPEG_SUBSAMPLE_OFF
|
? VIPS_FOREIGN_SUBSAMPLE_OFF
|
||||||
: VIPS_FOREIGN_JPEG_SUBSAMPLE_ON)
|
: VIPS_FOREIGN_SUBSAMPLE_ON)
|
||||||
->set("trellis_quant", baton->jpegTrellisQuantisation)
|
->set("trellis_quant", baton->jpegTrellisQuantisation)
|
||||||
->set("quant_table", baton->jpegQuantisationTable)
|
->set("quant_table", baton->jpegQuantisationTable)
|
||||||
->set("overshoot_deringing", baton->jpegOvershootDeringing)
|
->set("overshoot_deringing", baton->jpegOvershootDeringing)
|
||||||
@@ -865,13 +870,11 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|||||||
// Write HEIF to buffer
|
// Write HEIF to buffer
|
||||||
VipsArea *area = reinterpret_cast<VipsArea*>(image.heifsave_buffer(VImage::option()
|
VipsArea *area = reinterpret_cast<VipsArea*>(image.heifsave_buffer(VImage::option()
|
||||||
->set("strip", !baton->withMetadata)
|
->set("strip", !baton->withMetadata)
|
||||||
->set("compression", baton->heifCompression)
|
|
||||||
->set("Q", baton->heifQuality)
|
->set("Q", baton->heifQuality)
|
||||||
|
->set("compression", baton->heifCompression)
|
||||||
->set("speed", baton->heifSpeed)
|
->set("speed", baton->heifSpeed)
|
||||||
#if defined(VIPS_TYPE_FOREIGN_SUBSAMPLE)
|
|
||||||
->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)
|
||||||
#endif
|
|
||||||
->set("lossless", baton->heifLossless)));
|
->set("lossless", baton->heifLossless)));
|
||||||
baton->bufferOut = static_cast<char*>(area->data);
|
baton->bufferOut = static_cast<char*>(area->data);
|
||||||
baton->bufferOutLength = area->length;
|
baton->bufferOutLength = area->length;
|
||||||
@@ -886,9 +889,9 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|||||||
image = image[0];
|
image = image[0];
|
||||||
baton->channels = 1;
|
baton->channels = 1;
|
||||||
}
|
}
|
||||||
if (image.format() != VIPS_FORMAT_UCHAR) {
|
if (image.format() != baton->rawDepth) {
|
||||||
// Cast pixels to uint8 (unsigned char)
|
// Cast pixels to requested format
|
||||||
image = image.cast(VIPS_FORMAT_UCHAR);
|
image = image.cast(baton->rawDepth);
|
||||||
}
|
}
|
||||||
// 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));
|
||||||
@@ -931,8 +934,8 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|||||||
->set("Q", baton->jpegQuality)
|
->set("Q", baton->jpegQuality)
|
||||||
->set("interlace", baton->jpegProgressive)
|
->set("interlace", baton->jpegProgressive)
|
||||||
->set("subsample_mode", baton->jpegChromaSubsampling == "4:4:4"
|
->set("subsample_mode", baton->jpegChromaSubsampling == "4:4:4"
|
||||||
? VIPS_FOREIGN_JPEG_SUBSAMPLE_OFF
|
? VIPS_FOREIGN_SUBSAMPLE_OFF
|
||||||
: VIPS_FOREIGN_JPEG_SUBSAMPLE_ON)
|
: VIPS_FOREIGN_SUBSAMPLE_ON)
|
||||||
->set("trellis_quant", baton->jpegTrellisQuantisation)
|
->set("trellis_quant", baton->jpegTrellisQuantisation)
|
||||||
->set("quant_table", baton->jpegQuantisationTable)
|
->set("quant_table", baton->jpegQuantisationTable)
|
||||||
->set("overshoot_deringing", baton->jpegOvershootDeringing)
|
->set("overshoot_deringing", baton->jpegOvershootDeringing)
|
||||||
@@ -1010,10 +1013,8 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|||||||
->set("Q", baton->heifQuality)
|
->set("Q", baton->heifQuality)
|
||||||
->set("compression", baton->heifCompression)
|
->set("compression", baton->heifCompression)
|
||||||
->set("speed", baton->heifSpeed)
|
->set("speed", baton->heifSpeed)
|
||||||
#if defined(VIPS_TYPE_FOREIGN_SUBSAMPLE)
|
|
||||||
->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)
|
||||||
#endif
|
|
||||||
->set("lossless", baton->heifLossless));
|
->set("lossless", baton->heifLossless));
|
||||||
baton->formatOut = "heif";
|
baton->formatOut = "heif";
|
||||||
} else if (baton->formatOut == "dz" || isDz || isDzZip) {
|
} else if (baton->formatOut == "dz" || isDz || isDzZip) {
|
||||||
@@ -1130,6 +1131,9 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|||||||
info.Set("width", static_cast<uint32_t>(width));
|
info.Set("width", static_cast<uint32_t>(width));
|
||||||
info.Set("height", static_cast<uint32_t>(height));
|
info.Set("height", static_cast<uint32_t>(height));
|
||||||
info.Set("channels", static_cast<uint32_t>(baton->channels));
|
info.Set("channels", static_cast<uint32_t>(baton->channels));
|
||||||
|
if (baton->formatOut == "raw") {
|
||||||
|
info.Set("depth", vips_enum_nick(VIPS_TYPE_BAND_FORMAT, baton->rawDepth));
|
||||||
|
}
|
||||||
info.Set("premultiplied", baton->premultiplied);
|
info.Set("premultiplied", baton->premultiplied);
|
||||||
if (baton->hasCropOffset) {
|
if (baton->hasCropOffset) {
|
||||||
info.Set("cropOffsetLeft", static_cast<int32_t>(baton->cropOffsetLeft));
|
info.Set("cropOffsetLeft", static_cast<int32_t>(baton->cropOffsetLeft));
|
||||||
@@ -1319,6 +1323,7 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
|||||||
baton->flatten = sharp::AttrAsBool(options, "flatten");
|
baton->flatten = sharp::AttrAsBool(options, "flatten");
|
||||||
baton->flattenBackground = sharp::AttrAsVectorOfDouble(options, "flattenBackground");
|
baton->flattenBackground = sharp::AttrAsVectorOfDouble(options, "flattenBackground");
|
||||||
baton->negate = sharp::AttrAsBool(options, "negate");
|
baton->negate = sharp::AttrAsBool(options, "negate");
|
||||||
|
baton->negateAlpha = sharp::AttrAsBool(options, "negateAlpha");
|
||||||
baton->blurSigma = sharp::AttrAsDouble(options, "blurSigma");
|
baton->blurSigma = sharp::AttrAsDouble(options, "blurSigma");
|
||||||
baton->brightness = sharp::AttrAsDouble(options, "brightness");
|
baton->brightness = sharp::AttrAsDouble(options, "brightness");
|
||||||
baton->saturation = sharp::AttrAsDouble(options, "saturation");
|
baton->saturation = sharp::AttrAsDouble(options, "saturation");
|
||||||
@@ -1389,6 +1394,10 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
|||||||
baton->recombMatrix[i] = sharp::AttrAsDouble(recombMatrix, i);
|
baton->recombMatrix[i] = sharp::AttrAsDouble(recombMatrix, i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
baton->colourspaceInput = sharp::GetInterpretation(sharp::AttrAsStr(options, "colourspaceInput"));
|
||||||
|
if (baton->colourspaceInput == VIPS_INTERPRETATION_ERROR) {
|
||||||
|
baton->colourspaceInput = VIPS_INTERPRETATION_LAST;
|
||||||
|
}
|
||||||
baton->colourspace = sharp::GetInterpretation(sharp::AttrAsStr(options, "colourspace"));
|
baton->colourspace = sharp::GetInterpretation(sharp::AttrAsStr(options, "colourspace"));
|
||||||
if (baton->colourspace == VIPS_INTERPRETATION_ERROR) {
|
if (baton->colourspace == VIPS_INTERPRETATION_ERROR) {
|
||||||
baton->colourspace = VIPS_INTERPRETATION_sRGB;
|
baton->colourspace = VIPS_INTERPRETATION_sRGB;
|
||||||
@@ -1451,6 +1460,11 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
|||||||
baton->heifSpeed = sharp::AttrAsUint32(options, "heifSpeed");
|
baton->heifSpeed = sharp::AttrAsUint32(options, "heifSpeed");
|
||||||
baton->heifChromaSubsampling = sharp::AttrAsStr(options, "heifChromaSubsampling");
|
baton->heifChromaSubsampling = sharp::AttrAsStr(options, "heifChromaSubsampling");
|
||||||
|
|
||||||
|
// Raw output
|
||||||
|
baton->rawDepth = static_cast<VipsBandFormat>(
|
||||||
|
vips_enum_from_nick(nullptr, VIPS_TYPE_BAND_FORMAT,
|
||||||
|
sharp::AttrAsStr(options, "rawDepth").data()));
|
||||||
|
|
||||||
// Animated output
|
// Animated output
|
||||||
if (sharp::HasAttr(options, "pageHeight")) {
|
if (sharp::HasAttr(options, "pageHeight")) {
|
||||||
baton->pageHeight = sharp::AttrAsUint32(options, "pageHeight");
|
baton->pageHeight = sharp::AttrAsUint32(options, "pageHeight");
|
||||||
|
|||||||
@@ -90,6 +90,7 @@ struct PipelineBaton {
|
|||||||
bool flatten;
|
bool flatten;
|
||||||
std::vector<double> flattenBackground;
|
std::vector<double> flattenBackground;
|
||||||
bool negate;
|
bool negate;
|
||||||
|
bool negateAlpha;
|
||||||
double blurSigma;
|
double blurSigma;
|
||||||
double brightness;
|
double brightness;
|
||||||
double saturation;
|
double saturation;
|
||||||
@@ -168,6 +169,7 @@ struct PipelineBaton {
|
|||||||
int heifSpeed;
|
int heifSpeed;
|
||||||
std::string heifChromaSubsampling;
|
std::string heifChromaSubsampling;
|
||||||
bool heifLossless;
|
bool heifLossless;
|
||||||
|
VipsBandFormat rawDepth;
|
||||||
std::string err;
|
std::string err;
|
||||||
bool withMetadata;
|
bool withMetadata;
|
||||||
int withMetadataOrientation;
|
int withMetadataOrientation;
|
||||||
@@ -185,6 +187,7 @@ struct PipelineBaton {
|
|||||||
int extractChannel;
|
int extractChannel;
|
||||||
bool removeAlpha;
|
bool removeAlpha;
|
||||||
double ensureAlpha;
|
double ensureAlpha;
|
||||||
|
VipsInterpretation colourspaceInput;
|
||||||
VipsInterpretation colourspace;
|
VipsInterpretation colourspace;
|
||||||
int pageHeight;
|
int pageHeight;
|
||||||
std::vector<int> delay;
|
std::vector<int> delay;
|
||||||
@@ -219,6 +222,7 @@ struct PipelineBaton {
|
|||||||
flatten(false),
|
flatten(false),
|
||||||
flattenBackground{ 0.0, 0.0, 0.0 },
|
flattenBackground{ 0.0, 0.0, 0.0 },
|
||||||
negate(false),
|
negate(false),
|
||||||
|
negateAlpha(true),
|
||||||
blurSigma(0.0),
|
blurSigma(0.0),
|
||||||
brightness(1.0),
|
brightness(1.0),
|
||||||
saturation(1.0),
|
saturation(1.0),
|
||||||
@@ -293,8 +297,9 @@ struct PipelineBaton {
|
|||||||
heifQuality(50),
|
heifQuality(50),
|
||||||
heifCompression(VIPS_FOREIGN_HEIF_COMPRESSION_AV1),
|
heifCompression(VIPS_FOREIGN_HEIF_COMPRESSION_AV1),
|
||||||
heifSpeed(5),
|
heifSpeed(5),
|
||||||
heifChromaSubsampling("4:2:0"),
|
heifChromaSubsampling("4:4:4"),
|
||||||
heifLossless(false),
|
heifLossless(false),
|
||||||
|
rawDepth(VIPS_FORMAT_UCHAR),
|
||||||
withMetadata(false),
|
withMetadata(false),
|
||||||
withMetadataOrientation(-1),
|
withMetadataOrientation(-1),
|
||||||
withMetadataDensity(0.0),
|
withMetadataDensity(0.0),
|
||||||
@@ -308,6 +313,7 @@ struct PipelineBaton {
|
|||||||
extractChannel(-1),
|
extractChannel(-1),
|
||||||
removeAlpha(false),
|
removeAlpha(false),
|
||||||
ensureAlpha(-1.0),
|
ensureAlpha(-1.0),
|
||||||
|
colourspaceInput(VIPS_INTERPRETATION_LAST),
|
||||||
colourspace(VIPS_INTERPRETATION_LAST),
|
colourspace(VIPS_INTERPRETATION_LAST),
|
||||||
pageHeight(0),
|
pageHeight(0),
|
||||||
delay{-1},
|
delay{-1},
|
||||||
|
|||||||
@@ -8,16 +8,18 @@
|
|||||||
"test": "node perf && node random && node parallel"
|
"test": "node perf && node random && node parallel"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"async": "3.2.0",
|
"@squoosh/cli": "0.7.2",
|
||||||
|
"@squoosh/lib": "0.4.0",
|
||||||
|
"async": "3.2.1",
|
||||||
"benchmark": "2.1.4",
|
"benchmark": "2.1.4",
|
||||||
"gm": "1.23.1",
|
"gm": "1.23.1",
|
||||||
"imagemagick": "0.1.3",
|
"imagemagick": "0.1.3",
|
||||||
"jimp": "0.16.1",
|
"jimp": "0.16.1",
|
||||||
"mapnik": "4.5.6",
|
"mapnik": "4.5.8",
|
||||||
"semver": "7.3.4"
|
"semver": "7.3.5"
|
||||||
},
|
},
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "14"
|
"node": "16"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
const os = require('os');
|
const os = require('os');
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
|
const { exec } = require('child_process');
|
||||||
|
|
||||||
const async = require('async');
|
const async = require('async');
|
||||||
const assert = require('assert');
|
const assert = require('assert');
|
||||||
@@ -13,6 +14,7 @@ const gm = require('gm');
|
|||||||
const imagemagick = require('imagemagick');
|
const imagemagick = require('imagemagick');
|
||||||
const mapnik = require('mapnik');
|
const mapnik = require('mapnik');
|
||||||
const jimp = require('jimp');
|
const jimp = require('jimp');
|
||||||
|
const squoosh = require('@squoosh/lib');
|
||||||
|
|
||||||
const fixtures = require('../fixtures');
|
const fixtures = require('../fixtures');
|
||||||
|
|
||||||
@@ -75,6 +77,65 @@ async.series({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
// squoosh-cli
|
||||||
|
jpegSuite.add('squoosh-cli-file-file', {
|
||||||
|
defer: true,
|
||||||
|
fn: function (deferred) {
|
||||||
|
exec(`./node_modules/.bin/squoosh-cli \
|
||||||
|
--output-dir ${os.tmpdir()} \
|
||||||
|
--resize '{"enabled":true,"width":${width},"height":${height},"method":"lanczos3","premultiply":false,"linearRGB":false}' \
|
||||||
|
--mozjpeg '{"quality":80,"progressive":false,"optimize_coding":true,"quant_table":0,"trellis_multipass":false,"chroma_subsample":2,"separate_chroma_quality":false}' \
|
||||||
|
"${fixtures.inputJpg}"`, function (err) {
|
||||||
|
if (err) {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
deferred.resolve();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// squoosh-lib (GPLv3)
|
||||||
|
jpegSuite.add('squoosh-lib-buffer-buffer', {
|
||||||
|
defer: true,
|
||||||
|
fn: function (deferred) {
|
||||||
|
const pool = new squoosh.ImagePool();
|
||||||
|
const image = pool.ingestImage(inputJpgBuffer);
|
||||||
|
image.decoded
|
||||||
|
.then(function () {
|
||||||
|
return image.preprocess({
|
||||||
|
resize: {
|
||||||
|
enabled: true,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
method: 'lanczos3',
|
||||||
|
premultiply: false,
|
||||||
|
linearRGB: false
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.then(function () {
|
||||||
|
return image.encode({
|
||||||
|
mozjpeg: {
|
||||||
|
quality: 80,
|
||||||
|
progressive: false,
|
||||||
|
optimize_coding: true,
|
||||||
|
quant_table: 0,
|
||||||
|
trellis_multipass: false,
|
||||||
|
chroma_subsample: 2,
|
||||||
|
separate_chroma_quality: false
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.then(function () {
|
||||||
|
return pool.close();
|
||||||
|
})
|
||||||
|
.then(function () {
|
||||||
|
return image.encodedWith.mozjpeg;
|
||||||
|
})
|
||||||
|
.then(function () {
|
||||||
|
deferred.resolve();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
// mapnik
|
// mapnik
|
||||||
jpegSuite.add('mapnik-file-file', {
|
jpegSuite.add('mapnik-file-file', {
|
||||||
defer: true,
|
defer: true,
|
||||||
|
|||||||
BIN
test/fixtures/expected/colourspace-gradients-gamma-resize.png
vendored
Normal file
|
After Width: | Height: | Size: 56 KiB |
BIN
test/fixtures/expected/extract-alpha-16bit.jpg
vendored
|
Before Width: | Height: | Size: 685 B |
BIN
test/fixtures/expected/extract-alpha-16bit.png
vendored
Normal file
|
After Width: | Height: | Size: 262 B |
BIN
test/fixtures/expected/negate-preserve-alpha-grey.png
vendored
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
test/fixtures/expected/negate-preserve-alpha-trans.png
vendored
Normal file
|
After Width: | Height: | Size: 5.4 KiB |
BIN
test/fixtures/expected/negate-preserve-alpha-trans.webp
vendored
Normal file
|
After Width: | Height: | Size: 46 KiB |
BIN
test/fixtures/expected/negate-preserve-alpha.png
vendored
Normal file
|
After Width: | Height: | Size: 40 KiB |
BIN
test/fixtures/expected/negate-preserve-alpha.webp
vendored
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
test/fixtures/gradients-rgb8.png
vendored
Normal file
|
After Width: | Height: | Size: 777 KiB |
3
test/fixtures/index.js
vendored
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const sharp = require('../../');
|
const sharp = require('../../');
|
||||||
const maxColourDistance = require('../../build/Release/sharp')._maxColourDistance;
|
const maxColourDistance = require('../../lib/sharp')._maxColourDistance;
|
||||||
|
|
||||||
// Helpers
|
// Helpers
|
||||||
const getPath = function (filename) {
|
const getPath = function (filename) {
|
||||||
@@ -74,6 +74,7 @@ module.exports = {
|
|||||||
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
|
||||||
|
|
||||||
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'),
|
||||||
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'),
|
||||||
|
|||||||
@@ -444,6 +444,22 @@
|
|||||||
...
|
...
|
||||||
fun:vips__init
|
fun:vips__init
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
leak_libvips_thread_pool_new
|
||||||
|
Memcheck:Leak
|
||||||
|
match-leak-kinds: possible
|
||||||
|
fun:calloc
|
||||||
|
...
|
||||||
|
fun:g_system_thread_new
|
||||||
|
}
|
||||||
|
{
|
||||||
|
leak_libvips_thread_pool_push
|
||||||
|
Memcheck:Leak
|
||||||
|
match-leak-kinds: possible
|
||||||
|
fun:calloc
|
||||||
|
...
|
||||||
|
fun:g_thread_pool_push
|
||||||
|
}
|
||||||
{
|
{
|
||||||
leak_rsvg_static_data
|
leak_rsvg_static_data
|
||||||
Memcheck:Leak
|
Memcheck:Leak
|
||||||
@@ -480,6 +496,14 @@
|
|||||||
...
|
...
|
||||||
fun:rsvg_handle_new_from_gfile_sync
|
fun:rsvg_handle_new_from_gfile_sync
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
leak_rsvg_rust_280_bytes_static_regex
|
||||||
|
Memcheck:Leak
|
||||||
|
match-leak-kinds: possible
|
||||||
|
fun:malloc
|
||||||
|
...
|
||||||
|
fun:rsvg_handle_get_dimensions_sub
|
||||||
|
}
|
||||||
|
|
||||||
# libuv warnings
|
# libuv warnings
|
||||||
{
|
{
|
||||||
@@ -871,3 +895,12 @@
|
|||||||
...
|
...
|
||||||
fun:_ZN2v88internal18ArrayBufferSweeper10ReleaseAllEv
|
fun:_ZN2v88internal18ArrayBufferSweeper10ReleaseAllEv
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
addr_v8_ZN2v88internal12_GLOBAL__N_119HandleApiCallHelperILb0EEENS0
|
||||||
|
Memcheck:Addr8
|
||||||
|
fun:strncmp
|
||||||
|
...
|
||||||
|
fun:_ZZN4node7binding6DLOpenERKN2v820FunctionCallbackInfoINS1_5ValueEEEENKUlPNS0_4DLibEE_clES8_
|
||||||
|
fun:_ZN4node7binding6DLOpenERKN2v820FunctionCallbackInfoINS1_5ValueEEE
|
||||||
|
fun:_ZN2v88internal12_GLOBAL__N_119HandleApiCallHelperILb0EEENS0_11MaybeHandleINS0_6ObjectEEEPNS0_7IsolateENS0_6HandleINS0_10HeapObjectEEESA_NS8_INS0_20FunctionTemplateInfoEEENS8_IS4_EENS0_16BuiltinArgumentsE
|
||||||
|
}
|
||||||
|
|||||||
@@ -90,7 +90,29 @@ describe('Colour space conversion', function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Invalid input', function () {
|
it('From sRGB with RGB16 pipeline, resize with gamma, to sRGB', function (done) {
|
||||||
|
sharp(fixtures.inputPngGradients)
|
||||||
|
.pipelineColourspace('rgb16')
|
||||||
|
.resize(320)
|
||||||
|
.gamma()
|
||||||
|
.toColourspace('srgb')
|
||||||
|
.toBuffer(function (err, data, info) {
|
||||||
|
if (err) throw err;
|
||||||
|
assert.strictEqual(320, info.width);
|
||||||
|
fixtures.assertSimilar(fixtures.expected('colourspace-gradients-gamma-resize.png'), data, {
|
||||||
|
threshold: 0
|
||||||
|
}, done);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Invalid pipelineColourspace input', function () {
|
||||||
|
assert.throws(function () {
|
||||||
|
sharp(fixtures.inputJpg)
|
||||||
|
.pipelineColorspace(null);
|
||||||
|
}, /Expected string for colourspace but received null of type object/);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Invalid toColourspace input', function () {
|
||||||
assert.throws(function () {
|
assert.throws(function () {
|
||||||
sharp(fixtures.inputJpg)
|
sharp(fixtures.inputJpg)
|
||||||
.toColourspace(null);
|
.toColourspace(null);
|
||||||
|
|||||||
@@ -57,8 +57,8 @@ describe('Image channel extraction', function () {
|
|||||||
it('With colorspace conversion', function (done) {
|
it('With colorspace conversion', function (done) {
|
||||||
const output = fixtures.path('output.extract-lch.jpg');
|
const output = fixtures.path('output.extract-lch.jpg');
|
||||||
sharp(fixtures.inputJpg)
|
sharp(fixtures.inputJpg)
|
||||||
.toColourspace('lch')
|
|
||||||
.extractChannel(1)
|
.extractChannel(1)
|
||||||
|
.toColourspace('lch')
|
||||||
.resize(320, 240, { fastShrinkOnLoad: false })
|
.resize(320, 240, { fastShrinkOnLoad: false })
|
||||||
.toFile(output, function (err, info) {
|
.toFile(output, function (err, info) {
|
||||||
if (err) throw err;
|
if (err) throw err;
|
||||||
@@ -70,12 +70,13 @@ describe('Image channel extraction', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('Alpha from 16-bit PNG', function (done) {
|
it('Alpha from 16-bit PNG', function (done) {
|
||||||
const output = fixtures.path('output.extract-alpha-16bit.jpg');
|
const output = fixtures.path('output.extract-alpha-16bit.png');
|
||||||
sharp(fixtures.inputPngWithTransparency16bit)
|
sharp(fixtures.inputPngWithTransparency16bit)
|
||||||
|
.resize(16)
|
||||||
.extractChannel(3)
|
.extractChannel(3)
|
||||||
.toFile(output, function (err, info) {
|
.toFile(output, function (err) {
|
||||||
if (err) throw err;
|
if (err) throw err;
|
||||||
fixtures.assertMaxColourDistance(output, fixtures.expected('extract-alpha-16bit.jpg'));
|
fixtures.assertMaxColourDistance(output, fixtures.expected('extract-alpha-16bit.png'));
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -247,7 +247,7 @@ describe('Image metadata', function () {
|
|||||||
assert.strictEqual('undefined', typeof metadata.size);
|
assert.strictEqual('undefined', typeof metadata.size);
|
||||||
assert.strictEqual(800, metadata.width);
|
assert.strictEqual(800, metadata.width);
|
||||||
assert.strictEqual(533, metadata.height);
|
assert.strictEqual(533, metadata.height);
|
||||||
assert.strictEqual(true, [3, 4].includes(metadata.channels)); // libvips 8.11.0 = 4
|
assert.strictEqual(3, metadata.channels);
|
||||||
assert.strictEqual('uchar', metadata.depth);
|
assert.strictEqual('uchar', metadata.depth);
|
||||||
assert.strictEqual('undefined', typeof metadata.density);
|
assert.strictEqual('undefined', typeof metadata.density);
|
||||||
assert.strictEqual('undefined', typeof metadata.chromaSubsampling);
|
assert.strictEqual('undefined', typeof metadata.chromaSubsampling);
|
||||||
@@ -256,6 +256,7 @@ describe('Image metadata', function () {
|
|||||||
assert.strictEqual('undefined', typeof metadata.orientation);
|
assert.strictEqual('undefined', typeof metadata.orientation);
|
||||||
assert.strictEqual('undefined', typeof metadata.exif);
|
assert.strictEqual('undefined', typeof metadata.exif);
|
||||||
assert.strictEqual('undefined', typeof metadata.icc);
|
assert.strictEqual('undefined', typeof metadata.icc);
|
||||||
|
assert.deepStrictEqual(metadata.background, { r: 138, g: 148, b: 102 });
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -266,7 +267,7 @@ describe('Image metadata', function () {
|
|||||||
assert.strictEqual('undefined', typeof metadata.size);
|
assert.strictEqual('undefined', typeof metadata.size);
|
||||||
assert.strictEqual(2, metadata.width);
|
assert.strictEqual(2, metadata.width);
|
||||||
assert.strictEqual(1, metadata.height);
|
assert.strictEqual(1, metadata.height);
|
||||||
assert.strictEqual(true, [2, 4].includes(metadata.channels)); // libvips 8.11.0 = 4
|
assert.strictEqual(4, metadata.channels);
|
||||||
assert.strictEqual('uchar', metadata.depth);
|
assert.strictEqual('uchar', metadata.depth);
|
||||||
assert.strictEqual('undefined', typeof metadata.density);
|
assert.strictEqual('undefined', typeof metadata.density);
|
||||||
assert.strictEqual('undefined', typeof metadata.chromaSubsampling);
|
assert.strictEqual('undefined', typeof metadata.chromaSubsampling);
|
||||||
@@ -285,7 +286,7 @@ describe('Image metadata', function () {
|
|||||||
.then(({
|
.then(({
|
||||||
format, width, height, space, channels, depth,
|
format, width, height, space, channels, depth,
|
||||||
isProgressive, pages, pageHeight, loop, delay,
|
isProgressive, pages, pageHeight, loop, delay,
|
||||||
hasProfile, hasAlpha
|
background, hasProfile, hasAlpha
|
||||||
}) => {
|
}) => {
|
||||||
assert.strictEqual(format, 'gif');
|
assert.strictEqual(format, 'gif');
|
||||||
assert.strictEqual(width, 80);
|
assert.strictEqual(width, 80);
|
||||||
@@ -298,6 +299,7 @@ describe('Image metadata', function () {
|
|||||||
assert.strictEqual(pageHeight, 80);
|
assert.strictEqual(pageHeight, 80);
|
||||||
assert.strictEqual(loop, 0);
|
assert.strictEqual(loop, 0);
|
||||||
assert.deepStrictEqual(delay, Array(30).fill(30));
|
assert.deepStrictEqual(delay, Array(30).fill(30));
|
||||||
|
assert.deepStrictEqual(background, { r: 0, g: 0, b: 0 });
|
||||||
assert.strictEqual(hasProfile, false);
|
assert.strictEqual(hasProfile, false);
|
||||||
assert.strictEqual(hasAlpha, true);
|
assert.strictEqual(hasAlpha, true);
|
||||||
})
|
})
|
||||||
@@ -320,7 +322,7 @@ describe('Image metadata', function () {
|
|||||||
assert.strictEqual(isProgressive, false);
|
assert.strictEqual(isProgressive, false);
|
||||||
assert.strictEqual(pages, 10);
|
assert.strictEqual(pages, 10);
|
||||||
assert.strictEqual(pageHeight, 285);
|
assert.strictEqual(pageHeight, 285);
|
||||||
assert.strictEqual(true, [2, 3].includes(loop)); // libvips 8.11.0 = 2
|
assert.strictEqual(loop, 2);
|
||||||
assert.deepStrictEqual(delay, [...Array(9).fill(3000), 15000]);
|
assert.deepStrictEqual(delay, [...Array(9).fill(3000), 15000]);
|
||||||
assert.strictEqual(hasProfile, false);
|
assert.strictEqual(hasProfile, false);
|
||||||
assert.strictEqual(hasAlpha, true);
|
assert.strictEqual(hasAlpha, true);
|
||||||
@@ -724,6 +726,25 @@ describe('Image metadata', function () {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
it('AVIF', async () => {
|
||||||
|
const metadata = await sharp(fixtures.inputAvif).metadata();
|
||||||
|
assert.deepStrictEqual(metadata, {
|
||||||
|
format: 'heif',
|
||||||
|
width: 2048,
|
||||||
|
height: 858,
|
||||||
|
space: 'srgb',
|
||||||
|
channels: 3,
|
||||||
|
depth: 'uchar',
|
||||||
|
isProgressive: false,
|
||||||
|
pages: 1,
|
||||||
|
pageHeight: 858,
|
||||||
|
pagePrimary: 0,
|
||||||
|
compression: 'av1',
|
||||||
|
hasProfile: false,
|
||||||
|
hasAlpha: false
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('File input with corrupt header fails gracefully', function (done) {
|
it('File input with corrupt header fails gracefully', function (done) {
|
||||||
sharp(fixtures.inputJpgWithCorruptHeader)
|
sharp(fixtures.inputJpgWithCorruptHeader)
|
||||||
.metadata(function (err) {
|
.metadata(function (err) {
|
||||||
|
|||||||
@@ -107,4 +107,88 @@ describe('Negate', function () {
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('negate ({alpha: true})', function (done) {
|
||||||
|
sharp(fixtures.inputJpg)
|
||||||
|
.resize(320, 240)
|
||||||
|
.negate({ alpha: true })
|
||||||
|
.toBuffer(function (err, data, info) {
|
||||||
|
if (err) throw err;
|
||||||
|
assert.strictEqual('jpeg', info.format);
|
||||||
|
assert.strictEqual(320, info.width);
|
||||||
|
assert.strictEqual(240, info.height);
|
||||||
|
fixtures.assertSimilar(fixtures.expected('negate.jpg'), data, done);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('negate non-alpha channels (png)', function (done) {
|
||||||
|
sharp(fixtures.inputPng)
|
||||||
|
.resize(320, 240)
|
||||||
|
.negate({ alpha: false })
|
||||||
|
.toBuffer(function (err, data, info) {
|
||||||
|
if (err) throw err;
|
||||||
|
assert.strictEqual('png', info.format);
|
||||||
|
assert.strictEqual(320, info.width);
|
||||||
|
assert.strictEqual(240, info.height);
|
||||||
|
fixtures.assertSimilar(fixtures.expected('negate-preserve-alpha.png'), data, done);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('negate non-alpha channels (png, trans)', function (done) {
|
||||||
|
sharp(fixtures.inputPngWithTransparency)
|
||||||
|
.resize(320, 240)
|
||||||
|
.negate({ alpha: false })
|
||||||
|
.toBuffer(function (err, data, info) {
|
||||||
|
if (err) throw err;
|
||||||
|
assert.strictEqual('png', info.format);
|
||||||
|
assert.strictEqual(320, info.width);
|
||||||
|
assert.strictEqual(240, info.height);
|
||||||
|
fixtures.assertSimilar(fixtures.expected('negate-preserve-alpha-trans.png'), data, done);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('negate non-alpha channels (png, alpha)', function (done) {
|
||||||
|
sharp(fixtures.inputPngWithGreyAlpha)
|
||||||
|
.resize(320, 240)
|
||||||
|
.negate({ alpha: false })
|
||||||
|
.toBuffer(function (err, data, info) {
|
||||||
|
if (err) throw err;
|
||||||
|
assert.strictEqual('png', info.format);
|
||||||
|
assert.strictEqual(320, info.width);
|
||||||
|
assert.strictEqual(240, info.height);
|
||||||
|
fixtures.assertSimilar(fixtures.expected('negate-preserve-alpha-grey.png'), data, done);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('negate non-alpha channels (webp)', function (done) {
|
||||||
|
sharp(fixtures.inputWebP)
|
||||||
|
.resize(320, 240)
|
||||||
|
.negate({ alpha: false })
|
||||||
|
.toBuffer(function (err, data, info) {
|
||||||
|
if (err) throw err;
|
||||||
|
assert.strictEqual('webp', info.format);
|
||||||
|
assert.strictEqual(320, info.width);
|
||||||
|
assert.strictEqual(240, info.height);
|
||||||
|
fixtures.assertSimilar(fixtures.expected('negate-preserve-alpha.webp'), data, done);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('negate non-alpha channels (webp, trans)', function (done) {
|
||||||
|
sharp(fixtures.inputWebPWithTransparency)
|
||||||
|
.resize(320, 240)
|
||||||
|
.negate({ alpha: false })
|
||||||
|
.toBuffer(function (err, data, info) {
|
||||||
|
if (err) throw err;
|
||||||
|
assert.strictEqual('webp', info.format);
|
||||||
|
assert.strictEqual(320, info.width);
|
||||||
|
assert.strictEqual(240, info.height);
|
||||||
|
fixtures.assertSimilar(fixtures.expected('negate-preserve-alpha-trans.webp'), data, done);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('invalid alpha value', function () {
|
||||||
|
assert.throws(function () {
|
||||||
|
sharp(fixtures.inputWebPWithTransparency).negate({ alpha: 'non-bool' });
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -179,7 +179,7 @@ describe('Raw pixel data', function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Ouput raw, uncompressed image data', function () {
|
describe('Output raw, uncompressed image data', function () {
|
||||||
it('1 channel greyscale image', function (done) {
|
it('1 channel greyscale image', function (done) {
|
||||||
sharp(fixtures.inputJpg)
|
sharp(fixtures.inputJpg)
|
||||||
.greyscale()
|
.greyscale()
|
||||||
@@ -227,7 +227,7 @@ describe('Raw pixel data', function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('extract A from RGBA', () =>
|
it('Extract A from RGBA', () =>
|
||||||
sharp(fixtures.inputPngWithTransparency)
|
sharp(fixtures.inputPngWithTransparency)
|
||||||
.resize(32, 24)
|
.resize(32, 24)
|
||||||
.extractChannel(3)
|
.extractChannel(3)
|
||||||
@@ -241,4 +241,41 @@ describe('Raw pixel data', function () {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('Raw pixel depths', function () {
|
||||||
|
it('Invalid depth', function () {
|
||||||
|
assert.throws(function () {
|
||||||
|
sharp(Buffer.alloc(3), { raw: { width: 1, height: 1, channels: 3 } })
|
||||||
|
.raw({ depth: 'zoinks' });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
for (const { constructor, depth, bits } of [
|
||||||
|
{ constructor: Uint8Array, depth: undefined, bits: 8 },
|
||||||
|
{ constructor: Uint8Array, depth: 'uchar', bits: 8 },
|
||||||
|
{ constructor: Uint8ClampedArray, depth: 'uchar', bits: 8 },
|
||||||
|
{ constructor: Int8Array, depth: 'char', bits: 8 },
|
||||||
|
{ constructor: Uint16Array, depth: 'ushort', bits: 16 },
|
||||||
|
{ constructor: Int16Array, depth: 'short', bits: 16 },
|
||||||
|
{ constructor: Uint32Array, depth: 'uint', bits: 32 },
|
||||||
|
{ constructor: Int32Array, depth: 'int', bits: 32 },
|
||||||
|
{ constructor: Float32Array, depth: 'float', bits: 32 },
|
||||||
|
{ constructor: Float64Array, depth: 'double', bits: 64 }
|
||||||
|
]) {
|
||||||
|
it(constructor.name, () =>
|
||||||
|
sharp(new constructor(3), { raw: { width: 1, height: 1, channels: 3 } })
|
||||||
|
.raw({ depth })
|
||||||
|
.toBuffer({ resolveWithObject: true })
|
||||||
|
.then(({ data, info }) => {
|
||||||
|
assert.strictEqual(1, info.width);
|
||||||
|
assert.strictEqual(1, info.height);
|
||||||
|
assert.strictEqual(3, info.channels);
|
||||||
|
if (depth !== undefined) {
|
||||||
|
assert.strictEqual(depth, info.depth);
|
||||||
|
}
|
||||||
|
assert.strictEqual(data.length / 3, bits / 8);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -423,20 +423,20 @@ describe('Image Stats', function () {
|
|||||||
assert.strictEqual(true, isInRange(stats.channels[0].maxY, 0, 1));
|
assert.strictEqual(true, isInRange(stats.channels[0].maxY, 0, 1));
|
||||||
|
|
||||||
// alpha channel
|
// alpha channel
|
||||||
assert.strictEqual(0, stats.channels[1].min);
|
assert.strictEqual(0, stats.channels[3].min);
|
||||||
assert.strictEqual(255, stats.channels[1].max);
|
assert.strictEqual(255, stats.channels[3].max);
|
||||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[1].sum, 255));
|
assert.strictEqual(true, isInAcceptableRange(stats.channels[3].sum, 255));
|
||||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[1].squaresSum, 65025));
|
assert.strictEqual(true, isInAcceptableRange(stats.channels[3].squaresSum, 65025));
|
||||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[1].mean, 127.5));
|
assert.strictEqual(true, isInAcceptableRange(stats.channels[3].mean, 127.5));
|
||||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[1].stdev, 180.31222920256963));
|
assert.strictEqual(true, isInAcceptableRange(stats.channels[3].stdev, 180.31222920256963));
|
||||||
assert.strictEqual(true, isInteger(stats.channels[1].minX));
|
assert.strictEqual(true, isInteger(stats.channels[3].minX));
|
||||||
assert.strictEqual(true, isInRange(stats.channels[1].minX, 0, 2));
|
assert.strictEqual(true, isInRange(stats.channels[3].minX, 0, 2));
|
||||||
assert.strictEqual(true, isInteger(stats.channels[1].minY));
|
assert.strictEqual(true, isInteger(stats.channels[3].minY));
|
||||||
assert.strictEqual(true, isInRange(stats.channels[1].minY, 0, 1));
|
assert.strictEqual(true, isInRange(stats.channels[3].minY, 0, 1));
|
||||||
assert.strictEqual(true, isInteger(stats.channels[1].maxX));
|
assert.strictEqual(true, isInteger(stats.channels[3].maxX));
|
||||||
assert.strictEqual(true, isInRange(stats.channels[1].maxX, 0, 2));
|
assert.strictEqual(true, isInRange(stats.channels[3].maxX, 0, 2));
|
||||||
assert.strictEqual(true, isInteger(stats.channels[1].maxY));
|
assert.strictEqual(true, isInteger(stats.channels[3].maxY));
|
||||||
assert.strictEqual(true, isInRange(stats.channels[1].maxY, 0, 1));
|
assert.strictEqual(true, isInRange(stats.channels[3].maxY, 0, 1));
|
||||||
|
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ describe('WebP', function () {
|
|||||||
|
|
||||||
it('should work for webp alpha quality', function (done) {
|
it('should work for webp alpha quality', function (done) {
|
||||||
sharp(fixtures.inputPngAlphaPremultiplicationSmall)
|
sharp(fixtures.inputPngAlphaPremultiplicationSmall)
|
||||||
.webp({ alphaQuality: 80 })
|
.webp({ alphaQuality: 80, reductionEffort: 0 })
|
||||||
.toBuffer(function (err, data, info) {
|
.toBuffer(function (err, data, info) {
|
||||||
if (err) throw err;
|
if (err) throw err;
|
||||||
assert.strictEqual(true, data.length > 0);
|
assert.strictEqual(true, data.length > 0);
|
||||||
@@ -46,7 +46,7 @@ describe('WebP', function () {
|
|||||||
|
|
||||||
it('should work for webp lossless', function (done) {
|
it('should work for webp lossless', function (done) {
|
||||||
sharp(fixtures.inputPngAlphaPremultiplicationSmall)
|
sharp(fixtures.inputPngAlphaPremultiplicationSmall)
|
||||||
.webp({ lossless: true })
|
.webp({ lossless: true, reductionEffort: 0 })
|
||||||
.toBuffer(function (err, data, info) {
|
.toBuffer(function (err, data, info) {
|
||||||
if (err) throw err;
|
if (err) throw err;
|
||||||
assert.strictEqual(true, data.length > 0);
|
assert.strictEqual(true, data.length > 0);
|
||||||
@@ -57,7 +57,7 @@ describe('WebP', function () {
|
|||||||
|
|
||||||
it('should work for webp near-lossless', function (done) {
|
it('should work for webp near-lossless', function (done) {
|
||||||
sharp(fixtures.inputPngAlphaPremultiplicationSmall)
|
sharp(fixtures.inputPngAlphaPremultiplicationSmall)
|
||||||
.webp({ nearLossless: true, quality: 50 })
|
.webp({ nearLossless: true, quality: 50, reductionEffort: 0 })
|
||||||
.toBuffer(function (err50, data50, info50) {
|
.toBuffer(function (err50, data50, info50) {
|
||||||
if (err50) throw err50;
|
if (err50) throw err50;
|
||||||
assert.strictEqual(true, data50.length > 0);
|
assert.strictEqual(true, data50.length > 0);
|
||||||
@@ -68,7 +68,7 @@ describe('WebP', function () {
|
|||||||
|
|
||||||
it('should use near-lossless when both lossless and nearLossless are specified', function (done) {
|
it('should use near-lossless when both lossless and nearLossless are specified', function (done) {
|
||||||
sharp(fixtures.inputPngAlphaPremultiplicationSmall)
|
sharp(fixtures.inputPngAlphaPremultiplicationSmall)
|
||||||
.webp({ nearLossless: true, quality: 50, lossless: true })
|
.webp({ nearLossless: true, quality: 50, lossless: true, reductionEffort: 0 })
|
||||||
.toBuffer(function (err50, data50, info50) {
|
.toBuffer(function (err50, data50, info50) {
|
||||||
if (err50) throw err50;
|
if (err50) throw err50;
|
||||||
assert.strictEqual(true, data50.length > 0);
|
assert.strictEqual(true, data50.length > 0);
|
||||||
@@ -189,7 +189,7 @@ describe('WebP', function () {
|
|||||||
it('should work with streams when only animated is set', function (done) {
|
it('should work with streams when only animated is set', function (done) {
|
||||||
fs.createReadStream(fixtures.inputWebPAnimated)
|
fs.createReadStream(fixtures.inputWebPAnimated)
|
||||||
.pipe(sharp({ animated: true }))
|
.pipe(sharp({ animated: true }))
|
||||||
.webp({ lossless: true })
|
.webp({ lossless: true, reductionEffort: 0 })
|
||||||
.toBuffer(function (err, data, info) {
|
.toBuffer(function (err, data, info) {
|
||||||
if (err) throw err;
|
if (err) throw err;
|
||||||
assert.strictEqual(true, data.length > 0);
|
assert.strictEqual(true, data.length > 0);
|
||||||
@@ -201,7 +201,7 @@ describe('WebP', function () {
|
|||||||
it('should work with streams when only pages is set', function (done) {
|
it('should work with streams when only pages is set', function (done) {
|
||||||
fs.createReadStream(fixtures.inputWebPAnimated)
|
fs.createReadStream(fixtures.inputWebPAnimated)
|
||||||
.pipe(sharp({ pages: -1 }))
|
.pipe(sharp({ pages: -1 }))
|
||||||
.webp({ lossless: true })
|
.webp({ lossless: true, reductionEffort: 0 })
|
||||||
.toBuffer(function (err, data, info) {
|
.toBuffer(function (err, data, info) {
|
||||||
if (err) throw err;
|
if (err) throw err;
|
||||||
assert.strictEqual(true, data.length > 0);
|
assert.strictEqual(true, data.length > 0);
|
||||||
|
|||||||