mirror of
https://github.com/lovell/sharp.git
synced 2026-02-04 05:36:18 +01:00
Compare commits
58 Commits
v0.33.0-al
...
v0.33.0-al
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7c1551bdc9 | ||
|
|
bdcf02695f | ||
|
|
d206fd5392 | ||
|
|
0bd1715f36 | ||
|
|
2e7c60675b | ||
|
|
7caaa8e22b | ||
|
|
839c92bf3d | ||
|
|
28aa176957 | ||
|
|
0f24f0f214 | ||
|
|
655da113c8 | ||
|
|
159b986cdd | ||
|
|
069d1786f5 | ||
|
|
f43829a16a | ||
|
|
65e61ad001 | ||
|
|
0107a4de81 | ||
|
|
337ce7b1c2 | ||
|
|
3719f79065 | ||
|
|
8d1747aa6a | ||
|
|
de9bdcba0a | ||
|
|
f8b6cb6d5b | ||
|
|
e6942805b4 | ||
|
|
47e76c9981 | ||
|
|
68fa84ef6f | ||
|
|
ff2fb18c76 | ||
|
|
28a9b1e9fa | ||
|
|
6377d5a73a | ||
|
|
80e4707af1 | ||
|
|
ab00e34d0d | ||
|
|
7c2f883b67 | ||
|
|
9b5eecba8f | ||
|
|
4b028edfe9 | ||
|
|
7e25dd7be1 | ||
|
|
09460d7af4 | ||
|
|
3b22640077 | ||
|
|
946976ba8f | ||
|
|
29a83250a4 | ||
|
|
3f54ef7525 | ||
|
|
4dc2467f49 | ||
|
|
f54ceb0973 | ||
|
|
8d033ae341 | ||
|
|
f7da2e5970 | ||
|
|
51e56f994c | ||
|
|
68ac12292c | ||
|
|
a9aa7339ce | ||
|
|
08108f5fad | ||
|
|
58e3c4c70e | ||
|
|
f8cf25ca56 | ||
|
|
ca95979ecc | ||
|
|
392f6afb5e | ||
|
|
7c97aabaf8 | ||
|
|
fcc7e84bee | ||
|
|
226a9a13ef | ||
|
|
4d3c9ae3d1 | ||
|
|
f31011d759 | ||
|
|
7cf4ae5648 | ||
|
|
9161c605e1 | ||
|
|
70ac6905c7 | ||
|
|
265d70111a |
@@ -38,11 +38,11 @@ jobs:
|
||||
- run: sudo docker exec sharp sh -c "npm test"
|
||||
- run: |
|
||||
sudo docker exec sharp sh -c "npm run package-from-local-build"
|
||||
sudo docker exec sharp sh -c "npm pkg set \"optionalDependencies.@sharpen/sharp-linux-arm64=file:./npm/linux-arm64\""
|
||||
sudo docker exec sharp sh -c "npm pkg set \"optionalDependencies.@img/sharp-linux-arm64=file:./npm/linux-arm64\""
|
||||
sudo docker exec sharp sh -c "npm run clean"
|
||||
sudo docker exec sharp sh -c "npm install --ignore-scripts"
|
||||
sudo docker exec sharp sh -c "npm test"
|
||||
- run: "[[ -n $CIRCLE_TAG ]] && sudo docker exec --env prebuild_upload sharp sh -c \"npx prebuild --upload=$prebuild_upload\" || true"
|
||||
- run: "[[ -n $CIRCLE_TAG ]] && sudo docker exec --env prebuild_upload sharp sh -c \"cd src && ln -s ../package.json && npx prebuild --upload=$prebuild_upload\" || true"
|
||||
linux-arm64-glibc-node-20:
|
||||
resource_class: arm.medium
|
||||
machine:
|
||||
@@ -62,7 +62,7 @@ jobs:
|
||||
- run: sudo docker exec sharp sh -c "npm test"
|
||||
- run: |
|
||||
sudo docker exec sharp sh -c "npm run package-from-local-build"
|
||||
sudo docker exec sharp sh -c "npm pkg set \"optionalDependencies.@sharpen/sharp-linux-arm64=file:./npm/linux-arm64\""
|
||||
sudo docker exec sharp sh -c "npm pkg set \"optionalDependencies.@img/sharp-linux-arm64=file:./npm/linux-arm64\""
|
||||
sudo docker exec sharp sh -c "npm run clean"
|
||||
sudo docker exec sharp sh -c "npm install --ignore-scripts"
|
||||
sudo docker exec sharp sh -c "npm test"
|
||||
@@ -79,11 +79,11 @@ jobs:
|
||||
- run: sudo docker exec sharp sh -c "npm test"
|
||||
- run: |
|
||||
sudo docker exec sharp sh -c "npm run package-from-local-build"
|
||||
sudo docker exec sharp sh -c "npm pkg set \"optionalDependencies.@sharpen/sharp-linuxmusl-arm64=file:./npm/linuxmusl-arm64\""
|
||||
sudo docker exec sharp sh -c "npm pkg set \"optionalDependencies.@img/sharp-linuxmusl-arm64=file:./npm/linuxmusl-arm64\""
|
||||
sudo docker exec sharp sh -c "npm run clean"
|
||||
sudo docker exec sharp sh -c "npm install --ignore-scripts"
|
||||
sudo docker exec sharp sh -c "npm test"
|
||||
- run: "[[ -n $CIRCLE_TAG ]] && sudo docker exec --env prebuild_upload sharp sh -c \"npx prebuild --upload=$prebuild_upload\" || true"
|
||||
- run: "[[ -n $CIRCLE_TAG ]] && sudo docker exec --env prebuild_upload sharp sh -c \"cd src && ln -s ../package.json && npx prebuild --upload=$prebuild_upload\" || true"
|
||||
linux-arm64-musl-node-20:
|
||||
resource_class: arm.medium
|
||||
machine:
|
||||
@@ -99,7 +99,7 @@ jobs:
|
||||
- run: sudo docker exec sharp sh -c "npm test"
|
||||
- run: |
|
||||
sudo docker exec sharp sh -c "npm run package-from-local-build"
|
||||
sudo docker exec sharp sh -c "npm pkg set \"optionalDependencies.@sharpen/sharp-linuxmusl-arm64=file:./npm/linuxmusl-arm64\""
|
||||
sudo docker exec sharp sh -c "npm pkg set \"optionalDependencies.@img/sharp-linuxmusl-arm64=file:./npm/linuxmusl-arm64\""
|
||||
sudo docker exec sharp sh -c "npm run clean"
|
||||
sudo docker exec sharp sh -c "npm install --ignore-scripts"
|
||||
sudo docker exec sharp sh -c "npm test"
|
||||
|
||||
1
.gitattributes
vendored
1
.gitattributes
vendored
@@ -1 +0,0 @@
|
||||
src/libvips/* linguist-vendored
|
||||
44
.github/workflows/ci.yml
vendored
44
.github/workflows/ci.yml
vendored
@@ -106,7 +106,7 @@ jobs:
|
||||
- name: Test packaging
|
||||
run: |
|
||||
npm run package-from-local-build
|
||||
npm pkg set "optionalDependencies.@sharpen/sharp-${{ matrix.platform }}=file:./npm/${{ matrix.platform }}"
|
||||
npm pkg set "optionalDependencies.@img/sharp-${{ matrix.platform }}=file:./npm/${{ matrix.platform }}"
|
||||
npm run clean
|
||||
npm install --ignore-scripts
|
||||
npm test
|
||||
@@ -114,35 +114,53 @@ jobs:
|
||||
if: matrix.prebuild && startsWith(github.ref, 'refs/tags/')
|
||||
env:
|
||||
prebuild_upload: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: npx prebuild
|
||||
run: |
|
||||
node -e "require('fs').cpSync('package.json', 'src/package.json')"
|
||||
cd src
|
||||
npx prebuild
|
||||
github-runner-qemu:
|
||||
permissions:
|
||||
contents: write
|
||||
name: linux-arm - Node.js 18 - prebuild
|
||||
name: ${{ matrix.platform }} - Node.js ${{ matrix.nodejs_version_major }} - prebuild
|
||||
runs-on: ubuntu-22.04
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- platform: linux-arm
|
||||
run_on_arch: armv6
|
||||
nodejs_arch: armv6l
|
||||
nodejs_hostname: unofficial-builds.nodejs.org
|
||||
nodejs_version: "18.17.0"
|
||||
nodejs_version_major: 18
|
||||
- platform: linux-s390x
|
||||
run_on_arch: s390x
|
||||
nodejs_arch: s390x
|
||||
nodejs_hostname: nodejs.org
|
||||
nodejs_version: "18.17.0"
|
||||
nodejs_version_major: 18
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: uraimo/run-on-arch-action@v2
|
||||
with:
|
||||
arch: armv6
|
||||
arch: ${{ matrix.run_on_arch }}
|
||||
distro: buster
|
||||
env: |
|
||||
nodejs_version: "18.17.0"
|
||||
prebuild_upload: "${{ startsWith(github.ref, 'refs/tags/') && secrets.GITHUB_TOKEN || '' }}"
|
||||
run: |
|
||||
apt-get update
|
||||
apt-get install -y fontconfig fonts-noto-core g++ git libatomic1 make python3 xz-utils
|
||||
apt-get install -y curl g++ git libatomic1 make python3 xz-utils
|
||||
mkdir /opt/nodejs
|
||||
curl --silent https://unofficial-builds.nodejs.org/download/release/v${nodejs_version}/node-v${nodejs_version}-linux-armv6l.tar.xz | tar xJC /opt/nodejs --strip-components=1
|
||||
curl --silent https://${{ matrix.nodejs_hostname }}/download/release/v${{ matrix.nodejs_version}}/node-v${{ matrix.nodejs_version}}-linux-${{ matrix.nodejs_arch }}.tar.xz | tar xJC /opt/nodejs --strip-components=1
|
||||
export PATH=$PATH:/opt/nodejs/bin
|
||||
npm install --build-from-source
|
||||
npx mocha --no-config --spec=test/unit/io.js
|
||||
npx mocha --no-config --spec=test/unit/io.js --timeout=30000
|
||||
npm run package-from-local-build
|
||||
npm pkg set "optionalDependencies.@sharpen/sharp-linux-arm=file:./npm/linux-arm"
|
||||
npm pkg set "optionalDependencies.@img/sharp-${{ matrix.platform }}=file:./npm/${{ matrix.platform }}"
|
||||
npm run clean
|
||||
npm install --ignore-scripts
|
||||
npx mocha --no-config --spec=test/unit/io.js
|
||||
[[ -n $prebuild_upload ]] && npx prebuild || true
|
||||
npx mocha --no-config --spec=test/unit/io.js --timeout=30000
|
||||
[[ -n $prebuild_upload ]] && cd src && ln -s ../package.json && npx prebuild || true
|
||||
macstadium-runner:
|
||||
permissions:
|
||||
contents: write
|
||||
@@ -179,7 +197,7 @@ jobs:
|
||||
- name: Test packaging
|
||||
run: |
|
||||
npm run package-from-local-build
|
||||
npm pkg set "optionalDependencies.@sharpen/sharp-${{ matrix.platform }}=file:./npm/${{ matrix.platform }}"
|
||||
npm pkg set "optionalDependencies.@img/sharp-${{ matrix.platform }}=file:./npm/${{ matrix.platform }}"
|
||||
npm run clean
|
||||
npm install --ignore-scripts
|
||||
npm test
|
||||
@@ -187,4 +205,4 @@ jobs:
|
||||
if: matrix.prebuild && startsWith(github.ref, 'refs/tags/')
|
||||
env:
|
||||
prebuild_upload: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: npx prebuild
|
||||
run: cd src && ln -s ../package.json && npx prebuild
|
||||
|
||||
152
.github/workflows/npm.yml
vendored
Normal file
152
.github/workflows/npm.yml
vendored
Normal file
@@ -0,0 +1,152 @@
|
||||
name: "CI: npm smoke test"
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "v**"
|
||||
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
release-smoke-test:
|
||||
name: "${{ github.ref_name }} ${{ matrix.name }}"
|
||||
runs-on: ${{ matrix.runs-on }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- name: linux-x64-node-npm
|
||||
runs-on: ubuntu-22.04
|
||||
runtime: node
|
||||
package-manager: npm
|
||||
- name: linux-x64-node-pnpm
|
||||
runs-on: ubuntu-22.04
|
||||
runtime: node
|
||||
package-manager: pnpm
|
||||
- name: linux-x64-node-yarn
|
||||
runs-on: ubuntu-22.04
|
||||
runtime: node
|
||||
package-manager: yarn
|
||||
- name: linux-x64-deno
|
||||
runs-on: ubuntu-22.04
|
||||
runtime: deno
|
||||
- name: linux-x64-bun
|
||||
runs-on: ubuntu-22.04
|
||||
runtime: bun
|
||||
|
||||
- name: darwin-x64-node-npm
|
||||
runs-on: macos-11
|
||||
runtime: node
|
||||
package-manager: npm
|
||||
- name: darwin-x64-node-pnpm
|
||||
runs-on: macos-11
|
||||
runtime: node
|
||||
package-manager: pnpm
|
||||
- name: darwin-x64-node-yarn
|
||||
runs-on: macos-11
|
||||
runtime: node
|
||||
package-manager: yarn
|
||||
- name: darwin-x64-deno
|
||||
runs-on: macos-11
|
||||
runtime: deno
|
||||
- name: darwin-x64-bun
|
||||
runs-on: macos-11
|
||||
runtime: bun
|
||||
|
||||
- name: win32-x64-node-npm
|
||||
runs-on: windows-2019
|
||||
runtime: node
|
||||
package-manager: npm
|
||||
- name: win32-x64-node-pnpm
|
||||
runs-on: windows-2019
|
||||
runtime: node
|
||||
package-manager: pnpm
|
||||
- name: win32-x64-node-yarn
|
||||
runs-on: windows-2019
|
||||
runtime: node
|
||||
package-manager: yarn
|
||||
- name: win32-x64-deno
|
||||
runs-on: windows-2019
|
||||
runtime: deno
|
||||
|
||||
steps:
|
||||
- name: Install Node.js
|
||||
if: ${{ matrix.runtime == 'node' }}
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 20
|
||||
- name: Install pnpm
|
||||
if: ${{ matrix.package-manager == 'pnpm' }}
|
||||
uses: pnpm/action-setup@v2
|
||||
with:
|
||||
version: 8
|
||||
- name: Install Deno
|
||||
if: ${{ matrix.runtime == 'deno' }}
|
||||
uses: denoland/setup-deno@v1
|
||||
with:
|
||||
deno-version: v1.x
|
||||
- name: Install Bun
|
||||
if: ${{ matrix.runtime == 'bun' }}
|
||||
uses: oven-sh/setup-bun@v1
|
||||
with:
|
||||
bun-version: latest
|
||||
|
||||
- name: Version
|
||||
id: version
|
||||
uses: actions/github-script@v6
|
||||
with:
|
||||
script: |
|
||||
core.setOutput('semver', context.ref.replace('refs/tags/v',''))
|
||||
- name: Create package.json
|
||||
uses: DamianReeves/write-file-action@v1.2
|
||||
with:
|
||||
path: package.json
|
||||
contents: |
|
||||
{
|
||||
"dependencies": {
|
||||
"sharp": "${{ steps.version.outputs.semver }}"
|
||||
}
|
||||
}
|
||||
- name: Create release.mjs
|
||||
uses: DamianReeves/write-file-action@v1.2
|
||||
with:
|
||||
path: release.mjs
|
||||
contents: |
|
||||
import { createRequire } from 'node:module';
|
||||
import { deepStrictEqual } from 'node:assert';
|
||||
const require = createRequire(import.meta.url);
|
||||
const sharp = require('sharp');
|
||||
deepStrictEqual(['.jpg', '.jpeg', '.jpe'], sharp.format.jpeg.input.fileSuffix);
|
||||
|
||||
- name: Run with Node.js + npm
|
||||
if: ${{ matrix.runtime == 'node' && matrix.package-manager == 'npm' }}
|
||||
run: |
|
||||
npm install --ignore-scripts
|
||||
node release.mjs
|
||||
|
||||
- name: Run with Node.js + pnpm
|
||||
if: ${{ matrix.runtime == 'node' && matrix.package-manager == 'pnpm' }}
|
||||
run: |
|
||||
pnpm install --ignore-scripts
|
||||
node release.mjs
|
||||
|
||||
- name: Run with Node.js + yarn
|
||||
if: ${{ matrix.runtime == 'node' && matrix.package-manager == 'yarn' }}
|
||||
run: |
|
||||
corepack enable
|
||||
yarn set version stable
|
||||
yarn config set enableImmutableInstalls false
|
||||
yarn config set enableScripts false
|
||||
yarn config set nodeLinker node-modules
|
||||
yarn install
|
||||
node release.mjs
|
||||
|
||||
- name: Run with Deno
|
||||
if: ${{ matrix.runtime == 'deno' }}
|
||||
run: deno run --allow-read --allow-ffi release.mjs
|
||||
|
||||
- name: Run with Bun
|
||||
if: ${{ matrix.runtime == 'bun' }}
|
||||
run: |
|
||||
bun install --ignore-scripts
|
||||
bun release.mjs
|
||||
8
.gitignore
vendored
8
.gitignore
vendored
@@ -1,4 +1,5 @@
|
||||
build
|
||||
src/build
|
||||
src/node_modules
|
||||
node_modules
|
||||
/coverage
|
||||
npm/*/*
|
||||
@@ -7,11 +8,6 @@ test/bench/node_modules
|
||||
test/fixtures/output*
|
||||
test/fixtures/vips-properties.xml
|
||||
test/leak/libvips.supp
|
||||
test/saliency/report.json
|
||||
test/saliency/Image*
|
||||
test/saliency/[Uu]serData*
|
||||
!test/saliency/userData.js
|
||||
.gitattributes
|
||||
.DS_Store
|
||||
.nyc_output
|
||||
.vscode/
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"runtime": "napi",
|
||||
"include-regex": "(sharp-.+\\.node|libvips-.+\\.dll|libglib-.+\\.dll|libgobject-.+\\.dll)",
|
||||
"include-regex": "(sharp-.+\\.node|libvips-.+\\.dll)",
|
||||
"prerelease": true,
|
||||
"strip": true
|
||||
}
|
||||
|
||||
@@ -2,10 +2,14 @@
|
||||
|
||||
<img src="https://cdn.jsdelivr.net/gh/lovell/sharp@main/docs/image/sharp-logo.svg" width="160" height="160" alt="sharp logo" align="right">
|
||||
|
||||
The typical use case for this high speed Node.js module
|
||||
The typical use case for this high speed Node-API module
|
||||
is to convert large images in common formats to
|
||||
smaller, web-friendly JPEG, PNG, WebP, GIF and AVIF images of varying dimensions.
|
||||
|
||||
It can be used with all JavaScript runtimes
|
||||
that provide support for Node-API v9, including
|
||||
Node.js >= 18.17.0, Deno and Bun.
|
||||
|
||||
Resizing an image is typically 4x-5x faster than using the
|
||||
quickest ImageMagick and GraphicsMagick settings
|
||||
due to its use of [libvips](https://github.com/libvips/libvips).
|
||||
@@ -16,7 +20,7 @@ Lanczos resampling ensures quality is not sacrificed for speed.
|
||||
As well as image resizing, operations such as
|
||||
rotation, extraction, compositing and gamma correction are available.
|
||||
|
||||
Most modern macOS, Windows and Linux systems running Node.js >= 18.17.0
|
||||
Most modern macOS, Windows and Linux systems
|
||||
do not require any additional install or runtime dependencies.
|
||||
|
||||
## Documentation
|
||||
|
||||
@@ -2,10 +2,14 @@
|
||||
|
||||
<img src="https://cdn.jsdelivr.net/gh/lovell/sharp@main/docs/image/sharp-logo.svg" width="160" height="160" alt="sharp logo" align="right">
|
||||
|
||||
The typical use case for this high speed Node.js module
|
||||
The typical use case for this high speed Node-API module
|
||||
is to convert large images in common formats to
|
||||
smaller, web-friendly JPEG, PNG, WebP, GIF and AVIF images of varying dimensions.
|
||||
|
||||
It can be used with all JavaScript runtimes
|
||||
that provide support for Node-API v9, including
|
||||
Node.js >= 18.17.0, Deno and Bun.
|
||||
|
||||
Resizing an image is typically 4x-5x faster than using the
|
||||
quickest ImageMagick and GraphicsMagick settings
|
||||
due to its use of [libvips](https://github.com/libvips/libvips).
|
||||
@@ -16,7 +20,7 @@ Lanczos resampling ensures quality is not sacrificed for speed.
|
||||
As well as image resizing, operations such as
|
||||
rotation, extraction, compositing and gamma correction are available.
|
||||
|
||||
Most modern macOS, Windows and Linux systems running Node.js >= 14.15.0
|
||||
Most modern macOS, Windows and Linux systems
|
||||
do not require any additional install or runtime dependencies.
|
||||
|
||||
### Formats
|
||||
|
||||
@@ -26,7 +26,7 @@ Implements the [stream.Duplex](http://nodejs.org/api/stream.html#stream_class_st
|
||||
| --- | --- | --- | --- |
|
||||
| [input] | <code>Buffer</code> \| <code>ArrayBuffer</code> \| <code>Uint8Array</code> \| <code>Uint8ClampedArray</code> \| <code>Int8Array</code> \| <code>Uint16Array</code> \| <code>Int16Array</code> \| <code>Uint32Array</code> \| <code>Int32Array</code> \| <code>Float32Array</code> \| <code>Float64Array</code> \| <code>string</code> | | if present, can be a Buffer / ArrayBuffer / 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. JPEG, PNG, WebP, AVIF, GIF, SVG, TIFF or raw pixel image data can be streamed into the object when not present. |
|
||||
| [options] | <code>Object</code> | | if present, is an Object with optional attributes. |
|
||||
| [options.failOn] | <code>string</code> | <code>"'warning'"</code> | when to abort processing of invalid pixel data, one of (in order of sensitivity): 'none' (least), 'truncated', 'error' or 'warning' (most), higher levels imply lower levels, invalid metadata will always abort. |
|
||||
| [options.failOn] | <code>string</code> | <code>"'warning'"</code> | When to abort processing of invalid pixel data, one of (in order of sensitivity, least to most): 'none', 'truncated', 'error', 'warning'. Higher levels imply lower levels. Invalid metadata will always abort. |
|
||||
| [options.limitInputPixels] | <code>number</code> \| <code>boolean</code> | <code>268402689</code> | 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. An integral Number of pixels, zero or false to remove limit, true to use default limit of 268402689 (0x3FFF x 0x3FFF). |
|
||||
| [options.unlimited] | <code>boolean</code> | <code>false</code> | Set this to `true` to remove safety features that help prevent memory exhaustion (JPEG, PNG, SVG, HEIF). |
|
||||
| [options.sequentialRead] | <code>boolean</code> | <code>true</code> | Set this to `false` to use random access rather than sequential read. Some operations will do this automatically. |
|
||||
|
||||
@@ -466,6 +466,7 @@ instead of providing `xres` and `yres` in pixels/mm.
|
||||
| [options.yres] | <code>number</code> | <code>1.0</code> | vertical resolution in pixels/mm |
|
||||
| [options.resolutionUnit] | <code>string</code> | <code>"'inch'"</code> | resolution unit options: inch, cm |
|
||||
| [options.bitdepth] | <code>number</code> | <code>8</code> | reduce bitdepth to 1, 2 or 4 bit |
|
||||
| [options.miniswhite] | <code>boolean</code> | <code>false</code> | write 1-bit images as miniswhite |
|
||||
|
||||
**Example**
|
||||
```js
|
||||
|
||||
@@ -214,7 +214,7 @@ Extract/crop a region of the image.
|
||||
|
||||
- Use `extract` before `resize` for pre-resize extraction.
|
||||
- Use `extract` after `resize` for post-resize extraction.
|
||||
- Use `extract` before and after for both.
|
||||
- Use `extract` twice and `resize` once for extract-then-resize-then-extract in a fixed operation order.
|
||||
|
||||
|
||||
**Throws**:
|
||||
@@ -251,7 +251,7 @@ sharp(input)
|
||||
|
||||
|
||||
## trim
|
||||
> trim(trim) ⇒ <code>Sharp</code>
|
||||
> trim([options]) ⇒ <code>Sharp</code>
|
||||
|
||||
Trim pixels from all edges that contain values similar to the given background colour, which defaults to that of the top-left pixel.
|
||||
|
||||
@@ -259,8 +259,7 @@ Images with an alpha channel will use the combined bounding box of alpha and non
|
||||
|
||||
If the result of this operation would trim an image to nothing then no change is made.
|
||||
|
||||
The `info` response Object, obtained from callback of `.toFile()` or `.toBuffer()`,
|
||||
will contain `trimOffsetLeft` and `trimOffsetTop` properties.
|
||||
The `info` response Object will contain `trimOffsetLeft` and `trimOffsetTop` properties.
|
||||
|
||||
|
||||
**Throws**:
|
||||
@@ -270,46 +269,44 @@ will contain `trimOffsetLeft` and `trimOffsetTop` properties.
|
||||
|
||||
| Param | Type | Default | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| trim | <code>string</code> \| <code>number</code> \| <code>Object</code> | | the specific background colour to trim, the threshold for doing so or an Object with both. |
|
||||
| [trim.background] | <code>string</code> \| <code>Object</code> | <code>"'top-left pixel'"</code> | background colour, parsed by the [color](https://www.npmjs.org/package/color) module, defaults to that of the top-left pixel. |
|
||||
| [trim.threshold] | <code>number</code> | <code>10</code> | the allowed difference from the above colour, a positive number. |
|
||||
| [options] | <code>Object</code> | | |
|
||||
| [options.background] | <code>string</code> \| <code>Object</code> | <code>"'top-left pixel'"</code> | Background colour, parsed by the [color](https://www.npmjs.org/package/color) module, defaults to that of the top-left pixel. |
|
||||
| [options.threshold] | <code>number</code> | <code>10</code> | Allowed difference from the above colour, a positive number. |
|
||||
| [options.lineArt] | <code>boolean</code> | <code>false</code> | Does the input more closely resemble line art (e.g. vector) rather than being photographic? |
|
||||
|
||||
**Example**
|
||||
```js
|
||||
// Trim pixels with a colour similar to that of the top-left pixel.
|
||||
sharp(input)
|
||||
await sharp(input)
|
||||
.trim()
|
||||
.toFile(output, function(err, info) {
|
||||
...
|
||||
});
|
||||
.toFile(output);
|
||||
```
|
||||
**Example**
|
||||
```js
|
||||
// Trim pixels with the exact same colour as that of the top-left pixel.
|
||||
sharp(input)
|
||||
.trim(0)
|
||||
.toFile(output, function(err, info) {
|
||||
...
|
||||
});
|
||||
await sharp(input)
|
||||
.trim({
|
||||
threshold: 0
|
||||
})
|
||||
.toFile(output);
|
||||
```
|
||||
**Example**
|
||||
```js
|
||||
// Trim only pixels with a similar colour to red.
|
||||
sharp(input)
|
||||
.trim("#FF0000")
|
||||
.toFile(output, function(err, info) {
|
||||
...
|
||||
});
|
||||
// Assume input is line art and trim only pixels with a similar colour to red.
|
||||
const output = await sharp(input)
|
||||
.trim({
|
||||
background: "#FF0000",
|
||||
lineArt: true
|
||||
})
|
||||
.toBuffer();
|
||||
```
|
||||
**Example**
|
||||
```js
|
||||
// Trim all "yellow-ish" pixels, being more lenient with the higher threshold.
|
||||
sharp(input)
|
||||
const output = await sharp(input)
|
||||
.trim({
|
||||
background: "yellow",
|
||||
threshold: 42,
|
||||
})
|
||||
.toFile(output, function(err, info) {
|
||||
...
|
||||
});
|
||||
.toBuffer();
|
||||
```
|
||||
@@ -1,7 +1,8 @@
|
||||
## versions
|
||||
> versions
|
||||
|
||||
An Object containing the version numbers of sharp, libvips and its dependencies.
|
||||
An Object containing the version numbers of sharp, libvips
|
||||
and (when using prebuilt binaries) its dependencies.
|
||||
|
||||
|
||||
**Example**
|
||||
|
||||
@@ -2,17 +2,41 @@
|
||||
|
||||
## v0.33 - *gauge*
|
||||
|
||||
Requires libvips v8.14.5
|
||||
Requires libvips v8.15.0
|
||||
|
||||
### v0.33.0 - TBD
|
||||
|
||||
* Drop support for Node.js 14 and 16, now requires Node.js >= 18.17.0
|
||||
|
||||
* Prebuilt binaries distributed via npm registry and installed via package manager.
|
||||
|
||||
* Building from source requires dependency on `node-addon-api`.
|
||||
|
||||
* Remove `sharp.vendor`.
|
||||
|
||||
* Options for `trim` operation must be an Object, add new `lineArt` option.
|
||||
[#2363](https://github.com/lovell/sharp/issues/2363)
|
||||
|
||||
* Ensure all `Error` objects contain a `stack` property.
|
||||
[#3653](https://github.com/lovell/sharp/issues/3653)
|
||||
|
||||
* Make `compression` option of `heif` mandatory to help reduce HEIF vs HEIC confusion.
|
||||
[#3740](https://github.com/lovell/sharp/issues/3740)
|
||||
|
||||
* Ensure correct interpretation of 16-bit raw input.
|
||||
[#3808](https://github.com/lovell/sharp/issues/3808)
|
||||
|
||||
* Add support for `miniswhite` when using TIFF output.
|
||||
[#3812](https://github.com/lovell/sharp/pull/3812)
|
||||
[@dnsbty](https://github.com/dnsbty)
|
||||
|
||||
* TypeScript: add missing definition for `withMetadata` boolean.
|
||||
[#3823](https://github.com/lovell/sharp/pull/3823)
|
||||
[@uhthomas](https://github.com/uhthomas)
|
||||
|
||||
* Ensure multi-page extract remains sequential.
|
||||
[#3837](https://github.com/lovell/sharp/issues/3837)
|
||||
|
||||
## v0.32 - *flow*
|
||||
|
||||
Requires libvips v8.14.5
|
||||
|
||||
@@ -275,3 +275,6 @@ GitHub: https://github.com/LachlanNewman
|
||||
|
||||
Name: BJJ
|
||||
GitHub: https://github.com/bianjunjie1981
|
||||
|
||||
Name: Dennis Beatty
|
||||
GitHub: https://github.com/dnsbty
|
||||
|
||||
@@ -1,20 +1,30 @@
|
||||
# Installation
|
||||
|
||||
Works with your choice of JavaScript package manager.
|
||||
|
||||
```sh
|
||||
npm install sharp
|
||||
```
|
||||
|
||||
```sh
|
||||
yarn add sharp
|
||||
pnpm add sharp
|
||||
```
|
||||
|
||||
```sh
|
||||
pnpm add sharp
|
||||
yarn add sharp # v3 recommended, Plug'n'Play unsupported
|
||||
```
|
||||
|
||||
```sh
|
||||
bun add sharp
|
||||
```
|
||||
|
||||
```sh
|
||||
deno run --allow-ffi ...
|
||||
```
|
||||
|
||||
## Prerequisites
|
||||
|
||||
* Node.js >= 18.17.0
|
||||
* Node-API v9 compatible runtime e.g. Node.js >= 18.17.0
|
||||
|
||||
## Prebuilt binaries
|
||||
|
||||
@@ -22,9 +32,10 @@ Ready-compiled sharp and libvips binaries are provided for use on the most commo
|
||||
|
||||
* macOS x64 (>= 10.13)
|
||||
* macOS ARM64
|
||||
* Linux x64 (glibc >= 2.26, musl >= 1.2.2, CPU with SSE4.2)
|
||||
* Linux ARM64 (glibc >= 2.26, musl >= 1.2.2)
|
||||
* Linux ARM (glibc >= 2.28)
|
||||
* Linux ARM64 (glibc >= 2.26, musl >= 1.2.2)
|
||||
* Linux s390x (glibc >= 2.28)
|
||||
* Linux x64 (glibc >= 2.26, musl >= 1.2.2, CPU with SSE4.2)
|
||||
* Windows x64
|
||||
* Windows x86
|
||||
|
||||
@@ -53,9 +64,15 @@ This module will be compiled from source at `npm install` time when:
|
||||
Building from source requires:
|
||||
|
||||
* C++11 compiler
|
||||
* [node-addon-api](https://www.npmjs.com/package/node-addon-api)
|
||||
* [node-gyp](https://github.com/nodejs/node-gyp#installation) and its dependencies
|
||||
|
||||
If `node-gyp` cannot be found, try adding it to `devDependencies`.
|
||||
There is an install-time check for these dependencies.
|
||||
If `node-addon-api` or `node-gyp` cannot be found, try adding them via:
|
||||
|
||||
```sh
|
||||
npm install --save node-addon-api node-gyp
|
||||
```
|
||||
|
||||
For cross-compiling, the `--platform`, `--arch` and `--libc` npm flags
|
||||
(or the `npm_config_platform`, `npm_config_arch` and `npm_config_libc` environment variables)
|
||||
@@ -98,14 +115,14 @@ must include binaries for either the linux-x64 or linux-arm64 platforms
|
||||
depending on the chosen architecture.
|
||||
|
||||
When building your deployment package on a machine that differs from the target architecture,
|
||||
you will need to install either `@sharpen/sharp-linux-x64` or `@sharpen/sharp-linux-arm64` package.
|
||||
you will need to install either `@img/sharp-linux-x64` or `@img/sharp-linux-arm64` package.
|
||||
|
||||
```sh
|
||||
npm install --force @sharpen/sharp-linux-x64
|
||||
npm install --force @img/sharp-linux-x64
|
||||
```
|
||||
|
||||
```sh
|
||||
npm install --force @sharpen/sharp-linux-arm64
|
||||
npm install --force @img/sharp-linux-arm64
|
||||
```
|
||||
|
||||
To get the best performance select the largest memory available.
|
||||
@@ -157,7 +174,7 @@ custom:
|
||||
- sharp
|
||||
packagerOptions:
|
||||
scripts:
|
||||
- npm install --force @sharpen/sharp-linux-x64
|
||||
- npm install --force @img/sharp-linux-x64
|
||||
```
|
||||
|
||||
## TypeScript
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -3,18 +3,27 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
const { useGlobalLibvips, globalLibvipsVersion, log, gypRebuild } = require('../lib/libvips');
|
||||
const { useGlobalLibvips, globalLibvipsVersion, log, spawnRebuild } = require('../lib/libvips');
|
||||
|
||||
const buildFromSource = (msg) => {
|
||||
log(msg);
|
||||
log('Attempting to build from source via node-gyp');
|
||||
try {
|
||||
require('node-gyp');
|
||||
require('node-addon-api');
|
||||
log('Found node-addon-api');
|
||||
} catch (err) {
|
||||
log('You might need to install node-gyp');
|
||||
log('Please add node-addon-api to your dependencies');
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const gyp = require('node-gyp');
|
||||
log(`Found node-gyp version ${gyp().version}`);
|
||||
} catch (err) {
|
||||
log('Please add node-gyp to your dependencies');
|
||||
return;
|
||||
}
|
||||
log('See https://sharp.pixelplumbing.com/install#building-from-source');
|
||||
const status = gypRebuild();
|
||||
const status = spawnRebuild();
|
||||
if (status !== 0) {
|
||||
process.exit(status);
|
||||
}
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
const util = require('util');
|
||||
const stream = require('stream');
|
||||
const util = require('node:util');
|
||||
const stream = require('node:stream');
|
||||
const is = require('./is');
|
||||
|
||||
require('./sharp');
|
||||
@@ -121,7 +121,7 @@ const debuglog = util.debuglog('sharp');
|
||||
* 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.
|
||||
* @param {Object} [options] - if present, is an Object with optional attributes.
|
||||
* @param {string} [options.failOn='warning'] - when to abort processing of invalid pixel data, one of (in order of sensitivity): 'none' (least), 'truncated', 'error' or 'warning' (most), higher levels imply lower levels, invalid metadata will always abort.
|
||||
* @param {string} [options.failOn='warning'] - When to abort processing of invalid pixel data, one of (in order of sensitivity, least to most): 'none', 'truncated', 'error', 'warning'. Higher levels imply lower levels. Invalid metadata will always abort.
|
||||
* @param {number|boolean} [options.limitInputPixels=268402689] - 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.
|
||||
* An integral Number of pixels, zero or false to remove limit, true to use default limit of 268402689 (0x3FFF x 0x3FFF).
|
||||
@@ -230,7 +230,8 @@ const Sharp = function (input, options) {
|
||||
threshold: 0,
|
||||
thresholdGrayscale: true,
|
||||
trimBackground: [],
|
||||
trimThreshold: 0,
|
||||
trimThreshold: -1,
|
||||
trimLineArt: false,
|
||||
gamma: 0,
|
||||
gammaOut: 0,
|
||||
greyscale: false,
|
||||
@@ -305,6 +306,7 @@ const Sharp = function (input, options) {
|
||||
tiffCompression: 'jpeg',
|
||||
tiffPredictor: 'horizontal',
|
||||
tiffPyramid: false,
|
||||
tiffMiniswhite: false,
|
||||
tiffBitdepth: 8,
|
||||
tiffTile: false,
|
||||
tiffTileHeight: 256,
|
||||
|
||||
22
lib/index.d.ts
vendored
22
lib/index.d.ts
vendored
@@ -640,7 +640,7 @@ declare namespace sharp {
|
||||
* @param withMetadata
|
||||
* @throws {Error} Invalid parameters.
|
||||
*/
|
||||
withMetadata(withMetadata?: WriteableMetadata): Sharp;
|
||||
withMetadata(withMetadata?: boolean | WriteableMetadata): Sharp;
|
||||
|
||||
/**
|
||||
* Use these JPEG options for output image.
|
||||
@@ -847,11 +847,11 @@ declare namespace sharp {
|
||||
* Trim pixels from all edges that contain values similar to the given background colour, which defaults to that of the top-left pixel.
|
||||
* Images with an alpha channel will use the combined bounding box of alpha and non-alpha channels.
|
||||
* The info response Object will contain trimOffsetLeft and trimOffsetTop properties.
|
||||
* @param trim The specific background colour to trim, the threshold for doing so or an Object with both.
|
||||
* @param options trim options
|
||||
* @throws {Error} Invalid parameters
|
||||
* @returns A sharp instance that can be used to chain operations
|
||||
*/
|
||||
trim(trim?: string | number | TrimOptions): Sharp;
|
||||
trim(options?: TrimOptions): Sharp;
|
||||
|
||||
//#endregion
|
||||
}
|
||||
@@ -1234,6 +1234,8 @@ declare namespace sharp {
|
||||
yres?: number | undefined;
|
||||
/** Reduce bitdepth to 1, 2 or 4 bit (optional, default 8) */
|
||||
bitdepth?: 1 | 2 | 4 | 8 | undefined;
|
||||
/** Write 1-bit images as miniswhite (optional, default false) */
|
||||
miniswhite?: boolean | undefined;
|
||||
/** Resolution unit options: inch, cm (optional, default 'inch') */
|
||||
resolutionUnit?: 'inch' | 'cm' | undefined;
|
||||
}
|
||||
@@ -1275,10 +1277,10 @@ declare namespace sharp {
|
||||
}
|
||||
|
||||
interface NormaliseOptions {
|
||||
/** Percentile below which luminance values will be underexposed. */
|
||||
lower?: number | undefined;
|
||||
/** Percentile above which luminance values will be overexposed. */
|
||||
upper?: number | undefined;
|
||||
/** Percentile below which luminance values will be underexposed. */
|
||||
lower?: number | undefined;
|
||||
/** Percentile above which luminance values will be overexposed. */
|
||||
upper?: number | undefined;
|
||||
}
|
||||
|
||||
interface ResizeOptions {
|
||||
@@ -1340,10 +1342,12 @@ declare namespace sharp {
|
||||
}
|
||||
|
||||
interface TrimOptions {
|
||||
/** background colour, parsed by the color module, defaults to that of the top-left pixel. (optional) */
|
||||
/** Background colour, parsed by the color module, defaults to that of the top-left pixel. (optional) */
|
||||
background?: Color | undefined;
|
||||
/** the allowed difference from the above colour, a positive number. (optional, default `10`) */
|
||||
/** Allowed difference from the above colour, a positive number. (optional, default 10) */
|
||||
threshold?: number | undefined;
|
||||
/** Does the input more closely resemble line art (e.g. vector) rather than being photographic? (optional, default false) */
|
||||
lineArt?: boolean | undefined;
|
||||
}
|
||||
|
||||
interface RawOptions {
|
||||
|
||||
42
lib/input.js
42
lib/input.js
@@ -483,14 +483,27 @@ function _isStreamInput () {
|
||||
* @returns {Promise<Object>|Sharp}
|
||||
*/
|
||||
function metadata (callback) {
|
||||
const stack = Error();
|
||||
if (is.fn(callback)) {
|
||||
if (this._isStreamInput()) {
|
||||
this.on('finish', () => {
|
||||
this._flattenBufferIn();
|
||||
sharp.metadata(this.options, callback);
|
||||
sharp.metadata(this.options, (err, metadata) => {
|
||||
if (err) {
|
||||
callback(is.nativeError(err, stack));
|
||||
} else {
|
||||
callback(null, metadata);
|
||||
}
|
||||
});
|
||||
});
|
||||
} else {
|
||||
sharp.metadata(this.options, callback);
|
||||
sharp.metadata(this.options, (err, metadata) => {
|
||||
if (err) {
|
||||
callback(is.nativeError(err, stack));
|
||||
} else {
|
||||
callback(null, metadata);
|
||||
}
|
||||
});
|
||||
}
|
||||
return this;
|
||||
} else {
|
||||
@@ -500,7 +513,7 @@ function metadata (callback) {
|
||||
this._flattenBufferIn();
|
||||
sharp.metadata(this.options, (err, metadata) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
reject(is.nativeError(err, stack));
|
||||
} else {
|
||||
resolve(metadata);
|
||||
}
|
||||
@@ -516,7 +529,7 @@ function metadata (callback) {
|
||||
return new Promise((resolve, reject) => {
|
||||
sharp.metadata(this.options, (err, metadata) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
reject(is.nativeError(err, stack));
|
||||
} else {
|
||||
resolve(metadata);
|
||||
}
|
||||
@@ -572,14 +585,27 @@ function metadata (callback) {
|
||||
* @returns {Promise<Object>}
|
||||
*/
|
||||
function stats (callback) {
|
||||
const stack = Error();
|
||||
if (is.fn(callback)) {
|
||||
if (this._isStreamInput()) {
|
||||
this.on('finish', () => {
|
||||
this._flattenBufferIn();
|
||||
sharp.stats(this.options, callback);
|
||||
sharp.stats(this.options, (err, stats) => {
|
||||
if (err) {
|
||||
callback(is.nativeError(err, stack));
|
||||
} else {
|
||||
callback(null, stats);
|
||||
}
|
||||
});
|
||||
});
|
||||
} else {
|
||||
sharp.stats(this.options, callback);
|
||||
sharp.stats(this.options, (err, stats) => {
|
||||
if (err) {
|
||||
callback(is.nativeError(err, stack));
|
||||
} else {
|
||||
callback(null, stats);
|
||||
}
|
||||
});
|
||||
}
|
||||
return this;
|
||||
} else {
|
||||
@@ -589,7 +615,7 @@ function stats (callback) {
|
||||
this._flattenBufferIn();
|
||||
sharp.stats(this.options, (err, stats) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
reject(is.nativeError(err, stack));
|
||||
} else {
|
||||
resolve(stats);
|
||||
}
|
||||
@@ -600,7 +626,7 @@ function stats (callback) {
|
||||
return new Promise((resolve, reject) => {
|
||||
sharp.stats(this.options, (err, stats) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
reject(is.nativeError(err, stack));
|
||||
} else {
|
||||
resolve(stats);
|
||||
}
|
||||
|
||||
16
lib/is.js
16
lib/is.js
@@ -137,6 +137,19 @@ const invalidParameterError = function (name, expected, actual) {
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Ensures an Error from C++ contains a JS stack.
|
||||
*
|
||||
* @param {Error} native - Error with message from C++.
|
||||
* @param {Error} context - Error with stack from JS.
|
||||
* @returns {Error} Error with message and stack.
|
||||
* @private
|
||||
*/
|
||||
const nativeError = function (native, context) {
|
||||
context.message = native.message;
|
||||
return context;
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
defined,
|
||||
object,
|
||||
@@ -151,5 +164,6 @@ module.exports = {
|
||||
integer,
|
||||
inRange,
|
||||
inArray,
|
||||
invalidParameterError
|
||||
invalidParameterError,
|
||||
nativeError
|
||||
};
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
const spawnSync = require('child_process').spawnSync;
|
||||
const { spawnSync } = require('node:child_process');
|
||||
const semverCoerce = require('semver/functions/coerce');
|
||||
const semverGreaterThanOrEqualTo = require('semver/functions/gte');
|
||||
const detectLibc = require('detect-libc');
|
||||
@@ -48,7 +48,7 @@ const buildPlatformArch = () => {
|
||||
|
||||
const buildSharpLibvipsIncludeDir = () => {
|
||||
try {
|
||||
return require('@sharpen/sharp-libvips-dev/include');
|
||||
return require('@img/sharp-libvips-dev/include');
|
||||
} catch {}
|
||||
/* istanbul ignore next */
|
||||
return '';
|
||||
@@ -56,7 +56,7 @@ const buildSharpLibvipsIncludeDir = () => {
|
||||
|
||||
const buildSharpLibvipsCPlusPlusDir = () => {
|
||||
try {
|
||||
return require('@sharpen/sharp-libvips-dev/cplusplus');
|
||||
return require('@img/sharp-libvips-dev/cplusplus');
|
||||
} catch {}
|
||||
/* istanbul ignore next */
|
||||
return '';
|
||||
@@ -64,7 +64,7 @@ const buildSharpLibvipsCPlusPlusDir = () => {
|
||||
|
||||
const buildSharpLibvipsLibDir = () => {
|
||||
try {
|
||||
return require(`@sharpen/sharp-libvips-${buildPlatformArch()}/lib`);
|
||||
return require(`@img/sharp-libvips-${buildPlatformArch()}/lib`);
|
||||
} catch {}
|
||||
/* istanbul ignore next */
|
||||
return '';
|
||||
@@ -80,8 +80,8 @@ const isRosetta = () => {
|
||||
};
|
||||
|
||||
/* istanbul ignore next */
|
||||
const gypRebuild = () =>
|
||||
spawnSync('node-gyp rebuild', {
|
||||
const spawnRebuild = () =>
|
||||
spawnSync('node-gyp rebuild --directory=src', {
|
||||
...spawnSyncOptions,
|
||||
stdio: 'inherit'
|
||||
}).status;
|
||||
@@ -146,7 +146,7 @@ module.exports = {
|
||||
buildSharpLibvipsLibDir,
|
||||
runtimePlatformArch,
|
||||
log,
|
||||
gypRebuild,
|
||||
spawnRebuild,
|
||||
globalLibvipsVersion,
|
||||
pkgConfigPath,
|
||||
useGlobalLibvips
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
const path = require('path');
|
||||
const path = require('node:path');
|
||||
const is = require('./is');
|
||||
const sharp = require('./sharp');
|
||||
|
||||
@@ -86,7 +86,8 @@ function toFile (fileOut, callback) {
|
||||
}
|
||||
} else {
|
||||
this.options.fileOut = fileOut;
|
||||
return this._pipeline(callback);
|
||||
const stack = Error();
|
||||
return this._pipeline(callback, stack);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
@@ -157,7 +158,8 @@ function toBuffer (options, callback) {
|
||||
this.options.resolveWithObject = false;
|
||||
}
|
||||
this.options.fileOut = '';
|
||||
return this._pipeline(is.fn(options) ? options : callback);
|
||||
const stack = Error();
|
||||
return this._pipeline(is.fn(options) ? options : callback, stack);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -780,6 +782,7 @@ function trySetAnimationOptions (source, target) {
|
||||
* @param {number} [options.yres=1.0] - vertical resolution in pixels/mm
|
||||
* @param {string} [options.resolutionUnit='inch'] - resolution unit options: inch, cm
|
||||
* @param {number} [options.bitdepth=8] - reduce bitdepth to 1, 2 or 4 bit
|
||||
* @param {boolean} [options.miniswhite=false] - write 1-bit images as miniswhite
|
||||
* @returns {Sharp}
|
||||
* @throws {Error} Invalid options
|
||||
*/
|
||||
@@ -817,6 +820,10 @@ function tiff (options) {
|
||||
throw is.invalidParameterError('tileHeight', 'integer greater than zero', options.tileHeight);
|
||||
}
|
||||
}
|
||||
// miniswhite
|
||||
if (is.defined(options.miniswhite)) {
|
||||
this._setBooleanOption('tiffMiniswhite', options.miniswhite);
|
||||
}
|
||||
// pyramid
|
||||
if (is.defined(options.pyramid)) {
|
||||
this._setBooleanOption('tiffPyramid', options.pyramid);
|
||||
@@ -1282,7 +1289,8 @@ function _read () {
|
||||
/* istanbul ignore else */
|
||||
if (!this.options.streamOut) {
|
||||
this.options.streamOut = true;
|
||||
this._pipeline();
|
||||
const stack = Error();
|
||||
this._pipeline(undefined, stack);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1291,18 +1299,30 @@ function _read () {
|
||||
* Supports callback, stream and promise variants
|
||||
* @private
|
||||
*/
|
||||
function _pipeline (callback) {
|
||||
function _pipeline (callback, stack) {
|
||||
if (typeof callback === 'function') {
|
||||
// output=file/buffer
|
||||
if (this._isStreamInput()) {
|
||||
// output=file/buffer, input=stream
|
||||
this.on('finish', () => {
|
||||
this._flattenBufferIn();
|
||||
sharp.pipeline(this.options, callback);
|
||||
sharp.pipeline(this.options, (err, data, info) => {
|
||||
if (err) {
|
||||
callback(is.nativeError(err, stack));
|
||||
} else {
|
||||
callback(null, data, info);
|
||||
}
|
||||
});
|
||||
});
|
||||
} else {
|
||||
// output=file/buffer, input=file/buffer
|
||||
sharp.pipeline(this.options, callback);
|
||||
sharp.pipeline(this.options, (err, data, info) => {
|
||||
if (err) {
|
||||
callback(is.nativeError(err, stack));
|
||||
} else {
|
||||
callback(null, data, info);
|
||||
}
|
||||
});
|
||||
}
|
||||
return this;
|
||||
} else if (this.options.streamOut) {
|
||||
@@ -1313,7 +1333,7 @@ function _pipeline (callback) {
|
||||
this._flattenBufferIn();
|
||||
sharp.pipeline(this.options, (err, data, info) => {
|
||||
if (err) {
|
||||
this.emit('error', err);
|
||||
this.emit('error', is.nativeError(err, stack));
|
||||
} else {
|
||||
this.emit('info', info);
|
||||
this.push(data);
|
||||
@@ -1329,7 +1349,7 @@ function _pipeline (callback) {
|
||||
// output=stream, input=file/buffer
|
||||
sharp.pipeline(this.options, (err, data, info) => {
|
||||
if (err) {
|
||||
this.emit('error', err);
|
||||
this.emit('error', is.nativeError(err, stack));
|
||||
} else {
|
||||
this.emit('info', info);
|
||||
this.push(data);
|
||||
@@ -1348,7 +1368,7 @@ function _pipeline (callback) {
|
||||
this._flattenBufferIn();
|
||||
sharp.pipeline(this.options, (err, data, info) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
reject(is.nativeError(err, stack));
|
||||
} else {
|
||||
if (this.options.resolveWithObject) {
|
||||
resolve({ data, info });
|
||||
@@ -1364,7 +1384,7 @@ function _pipeline (callback) {
|
||||
return new Promise((resolve, reject) => {
|
||||
sharp.pipeline(this.options, (err, data, info) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
reject(is.nativeError(err, stack));
|
||||
} else {
|
||||
if (this.options.resolveWithObject) {
|
||||
resolve({ data, info });
|
||||
|
||||
@@ -250,6 +250,9 @@ function resize (widthOrOptions, height, options) {
|
||||
if (isResizeExpected(this.options)) {
|
||||
this.options.debuglog('ignoring previous resize options');
|
||||
}
|
||||
if (this.options.widthPost !== -1) {
|
||||
this.options.debuglog('operation order will be: extract, resize, extract');
|
||||
}
|
||||
if (is.defined(widthOrOptions)) {
|
||||
if (is.object(widthOrOptions) && !is.defined(options)) {
|
||||
options = widthOrOptions;
|
||||
@@ -437,7 +440,7 @@ function extend (extend) {
|
||||
*
|
||||
* - Use `extract` before `resize` for pre-resize extraction.
|
||||
* - Use `extract` after `resize` for post-resize extraction.
|
||||
* - Use `extract` before and after for both.
|
||||
* - Use `extract` twice and `resize` once for extract-then-resize-then-extract in a fixed operation order.
|
||||
*
|
||||
* @example
|
||||
* sharp(input)
|
||||
@@ -491,70 +494,67 @@ function extract (options) {
|
||||
*
|
||||
* If the result of this operation would trim an image to nothing then no change is made.
|
||||
*
|
||||
* The `info` response Object, obtained from callback of `.toFile()` or `.toBuffer()`,
|
||||
* will contain `trimOffsetLeft` and `trimOffsetTop` properties.
|
||||
* The `info` response Object will contain `trimOffsetLeft` and `trimOffsetTop` properties.
|
||||
*
|
||||
* @example
|
||||
* // Trim pixels with a colour similar to that of the top-left pixel.
|
||||
* sharp(input)
|
||||
* await sharp(input)
|
||||
* .trim()
|
||||
* .toFile(output, function(err, info) {
|
||||
* ...
|
||||
* });
|
||||
* .toFile(output);
|
||||
*
|
||||
* @example
|
||||
* // Trim pixels with the exact same colour as that of the top-left pixel.
|
||||
* sharp(input)
|
||||
* .trim(0)
|
||||
* .toFile(output, function(err, info) {
|
||||
* ...
|
||||
* });
|
||||
* await sharp(input)
|
||||
* .trim({
|
||||
* threshold: 0
|
||||
* })
|
||||
* .toFile(output);
|
||||
*
|
||||
* @example
|
||||
* // Trim only pixels with a similar colour to red.
|
||||
* sharp(input)
|
||||
* .trim("#FF0000")
|
||||
* .toFile(output, function(err, info) {
|
||||
* ...
|
||||
* });
|
||||
* // Assume input is line art and trim only pixels with a similar colour to red.
|
||||
* const output = await sharp(input)
|
||||
* .trim({
|
||||
* background: "#FF0000",
|
||||
* lineArt: true
|
||||
* })
|
||||
* .toBuffer();
|
||||
*
|
||||
* @example
|
||||
* // Trim all "yellow-ish" pixels, being more lenient with the higher threshold.
|
||||
* sharp(input)
|
||||
* const output = await sharp(input)
|
||||
* .trim({
|
||||
* background: "yellow",
|
||||
* threshold: 42,
|
||||
* })
|
||||
* .toFile(output, function(err, info) {
|
||||
* ...
|
||||
* });
|
||||
* .toBuffer();
|
||||
*
|
||||
* @param {string|number|Object} trim - the specific background colour to trim, the threshold for doing so or an Object with both.
|
||||
* @param {string|Object} [trim.background='top-left pixel'] - background colour, parsed by the [color](https://www.npmjs.org/package/color) module, defaults to that of the top-left pixel.
|
||||
* @param {number} [trim.threshold=10] - the allowed difference from the above colour, a positive number.
|
||||
* @param {Object} [options]
|
||||
* @param {string|Object} [options.background='top-left pixel'] - Background colour, parsed by the [color](https://www.npmjs.org/package/color) module, defaults to that of the top-left pixel.
|
||||
* @param {number} [options.threshold=10] - Allowed difference from the above colour, a positive number.
|
||||
* @param {boolean} [options.lineArt=false] - Does the input more closely resemble line art (e.g. vector) rather than being photographic?
|
||||
* @returns {Sharp}
|
||||
* @throws {Error} Invalid parameters
|
||||
*/
|
||||
function trim (trim) {
|
||||
if (!is.defined(trim)) {
|
||||
this.options.trimThreshold = 10;
|
||||
} else if (is.string(trim)) {
|
||||
this._setBackgroundColourOption('trimBackground', trim);
|
||||
this.options.trimThreshold = 10;
|
||||
} else if (is.number(trim)) {
|
||||
if (trim >= 0) {
|
||||
this.options.trimThreshold = trim;
|
||||
function trim (options) {
|
||||
this.options.trimThreshold = 10;
|
||||
if (is.defined(options)) {
|
||||
if (is.object(options)) {
|
||||
if (is.defined(options.background)) {
|
||||
this._setBackgroundColourOption('trimBackground', options.background);
|
||||
}
|
||||
if (is.defined(options.threshold)) {
|
||||
if (is.number(options.threshold) && options.threshold >= 0) {
|
||||
this.options.trimThreshold = options.threshold;
|
||||
} else {
|
||||
throw is.invalidParameterError('threshold', 'positive number', options.threshold);
|
||||
}
|
||||
}
|
||||
if (is.defined(options.lineArt)) {
|
||||
this._setBooleanOption('trimLineArt', options.lineArt);
|
||||
}
|
||||
} else {
|
||||
throw is.invalidParameterError('threshold', 'positive number', trim);
|
||||
throw is.invalidParameterError('trim', 'object', options);
|
||||
}
|
||||
} else if (is.object(trim)) {
|
||||
this._setBackgroundColourOption('trimBackground', trim.background);
|
||||
if (!is.defined(trim.threshold)) {
|
||||
this.options.trimThreshold = 10;
|
||||
} else if (is.number(trim.threshold) && trim.threshold >= 0) {
|
||||
this.options.trimThreshold = trim.threshold;
|
||||
} else {
|
||||
throw is.invalidParameterError('threshold', 'positive number', trim);
|
||||
}
|
||||
} else {
|
||||
throw is.invalidParameterError('trim', 'string, number or object', trim);
|
||||
}
|
||||
if (isRotationExpected(this.options)) {
|
||||
this.options.rotateBeforePreExtract = true;
|
||||
|
||||
29
lib/sharp.js
29
lib/sharp.js
@@ -9,15 +9,16 @@ const { familySync, versionSync } = require('detect-libc');
|
||||
|
||||
const { runtimePlatformArch, prebuiltPlatforms, minimumLibvipsVersion } = require('./libvips');
|
||||
const runtimePlatform = runtimePlatformArch();
|
||||
const [isLinux, isMacOs, isWindows] = ['linux', 'darwin', 'win32'].map(os => runtimePlatform.startsWith(os));
|
||||
|
||||
/* istanbul ignore next */
|
||||
try {
|
||||
// Check for local build
|
||||
module.exports = require(`../build/Release/sharp-${runtimePlatform}.node`);
|
||||
module.exports = require(`../src/build/Release/sharp-${runtimePlatform}.node`);
|
||||
} catch (errLocal) {
|
||||
try {
|
||||
// Check for runtime package
|
||||
module.exports = require(`@sharpen/sharp-${runtimePlatform}/sharp.node`);
|
||||
module.exports = require(`@img/sharp-${runtimePlatform}/sharp.node`);
|
||||
} catch (errPackage) {
|
||||
const help = ['Could not load the "sharp" module at runtime'];
|
||||
if (errLocal.code !== 'MODULE_NOT_FOUND') {
|
||||
@@ -29,28 +30,36 @@ try {
|
||||
help.push('Possible solutions:');
|
||||
// Common error messages
|
||||
if (prebuiltPlatforms.includes(runtimePlatform)) {
|
||||
help.push(`- Add an explicit dependency for the runtime platform: "npm install --force @sharpen/sharp-${runtimePlatform}"`);
|
||||
help.push('- Add an explicit dependency for the runtime platform:');
|
||||
help.push(` npm install --force @img/sharp-${runtimePlatform}`);
|
||||
} else {
|
||||
help.push(`- The ${runtimePlatform} platform requires manual installation of libvips >= ${minimumLibvipsVersion}`);
|
||||
}
|
||||
if (runtimePlatform.startsWith('linux') && /symbol not found/i.test(errPackage)) {
|
||||
if (isLinux && /symbol not found/i.test(errPackage)) {
|
||||
try {
|
||||
const { engines } = require(`@sharpen/sharp-libvips-${runtimePlatform}/package`);
|
||||
const { engines } = require(`@img/sharp-libvips-${runtimePlatform}/package`);
|
||||
const libcFound = `${familySync()} ${versionSync()}`;
|
||||
const libcRequires = `${engines.musl ? 'musl' : 'glibc'} ${engines.musl || engines.glibc}`;
|
||||
help.push(`- Update your OS: found ${libcFound}, requires ${libcRequires}`);
|
||||
help.push('- Update your OS:');
|
||||
help.push(` Found ${libcFound}`);
|
||||
help.push(` Requires ${libcRequires}`);
|
||||
} catch (errEngines) {}
|
||||
}
|
||||
if (runtimePlatform.startsWith('darwin') && /Incompatible library version/.test(errLocal.message)) {
|
||||
help.push('- Update Homebrew: "brew update && brew upgrade vips"');
|
||||
if (isMacOs && /Incompatible library version/.test(errLocal.message)) {
|
||||
help.push('- Update Homebrew:');
|
||||
help.push(' brew update && brew upgrade vips');
|
||||
}
|
||||
if (errPackage.code === 'ERR_DLOPEN_DISABLED') {
|
||||
help.push('- Run Node.js without using the --no-addons flag');
|
||||
}
|
||||
if (process.versions.pnp) {
|
||||
help.push('- Use a supported yarn linker, either pnpm or node-modules:');
|
||||
help.push(' yarn config set nodeLinker node-modules');
|
||||
}
|
||||
// Link to installation docs
|
||||
if (runtimePlatform.startsWith('linux') && /Module did not self-register/.test(errLocal.message + errPackage.message)) {
|
||||
if (isLinux && /Module did not self-register/.test(errLocal.message + errPackage.message)) {
|
||||
help.push('- Using worker threads on Linux? See https://sharp.pixelplumbing.com/install#worker-threads');
|
||||
} else if (runtimePlatform.startsWith('win32') && /The specified procedure could not be found/.test(errPackage.message)) {
|
||||
} else if (isWindows && /The specified procedure could not be found/.test(errPackage.message)) {
|
||||
help.push('- Using the canvas package on Windows? See https://sharp.pixelplumbing.com/install#canvas-and-windows');
|
||||
} else {
|
||||
help.push('- Consult the installation documentation: https://sharp.pixelplumbing.com/install');
|
||||
|
||||
@@ -3,13 +3,16 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
const events = require('events');
|
||||
const events = require('node:events');
|
||||
const detectLibc = require('detect-libc');
|
||||
|
||||
const is = require('./is');
|
||||
const { runtimePlatformArch } = require('./libvips');
|
||||
const sharp = require('./sharp');
|
||||
|
||||
const runtimePlatform = runtimePlatformArch();
|
||||
const libvipsVersion = sharp.libvipsVersion();
|
||||
|
||||
/**
|
||||
* An Object containing nested boolean values representing the available input and output formats/methods.
|
||||
* @member
|
||||
@@ -44,20 +47,25 @@ const interpolators = {
|
||||
};
|
||||
|
||||
/**
|
||||
* An Object containing the version numbers of sharp, libvips and its dependencies.
|
||||
* An Object containing the version numbers of sharp, libvips
|
||||
* and (when using prebuilt binaries) its dependencies.
|
||||
*
|
||||
* @member
|
||||
* @example
|
||||
* console.log(sharp.versions);
|
||||
*/
|
||||
let versions = {
|
||||
vips: sharp.libvipsVersion()
|
||||
vips: libvipsVersion.semver
|
||||
};
|
||||
try {
|
||||
versions = require(`@sharpen/sharp-${runtimePlatformArch()}/versions`);
|
||||
} catch (_) {
|
||||
/* istanbul ignore next */
|
||||
if (!libvipsVersion.isGlobal) {
|
||||
try {
|
||||
versions = require(`@sharpen/sharp-libvips-${runtimePlatformArch()}/versions`);
|
||||
} catch (_) {}
|
||||
versions = require(`@img/sharp-${runtimePlatform}/versions`);
|
||||
} catch (_) {
|
||||
try {
|
||||
versions = require(`@img/sharp-libvips-${runtimePlatform}/versions`);
|
||||
} catch (_) {}
|
||||
}
|
||||
}
|
||||
versions.sharp = require('../package.json').version;
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
{
|
||||
"name": "@sharpen/sharp-darwin-arm64",
|
||||
"version": "0.0.1-alpha.1",
|
||||
"description": "Prebuilt sharp for use with macOS ARM64",
|
||||
"name": "@img/sharp-darwin-arm64",
|
||||
"version": "0.33.0-alpha.10",
|
||||
"description": "Prebuilt sharp for use with macOS 64-bit ARM",
|
||||
"author": "Lovell Fuller <npm@lovell.info>",
|
||||
"homepage": "https://sharp.pixelplumbing.com",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -14,7 +15,7 @@
|
||||
},
|
||||
"preferUnplugged": true,
|
||||
"optionalDependencies": {
|
||||
"@sharpen/sharp-libvips-darwin-arm64": "0.0.1-alpha.1"
|
||||
"@img/sharp-libvips-darwin-arm64": "0.0.3"
|
||||
},
|
||||
"files": [
|
||||
"lib"
|
||||
@@ -22,6 +23,7 @@
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"type": "commonjs",
|
||||
"exports": {
|
||||
"./sharp.node": "./lib/sharp-darwin-arm64.node",
|
||||
"./package": "./package.json"
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
{
|
||||
"name": "@sharpen/sharp-darwin-x64",
|
||||
"version": "0.0.1-alpha.1",
|
||||
"name": "@img/sharp-darwin-x64",
|
||||
"version": "0.33.0-alpha.10",
|
||||
"description": "Prebuilt sharp for use with macOS x64",
|
||||
"author": "Lovell Fuller <npm@lovell.info>",
|
||||
"homepage": "https://sharp.pixelplumbing.com",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -14,11 +15,15 @@
|
||||
},
|
||||
"preferUnplugged": true,
|
||||
"optionalDependencies": {
|
||||
"@sharpen/sharp-libvips-darwin-x64": "0.0.1-alpha.1"
|
||||
"@img/sharp-libvips-darwin-x64": "0.0.3"
|
||||
},
|
||||
"files": [
|
||||
"lib"
|
||||
],
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"type": "commonjs",
|
||||
"exports": {
|
||||
"./sharp.node": "./lib/sharp-darwin-x64.node",
|
||||
"./package": "./package.json"
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
// Populate contents of all packages with the current GitHub release
|
||||
|
||||
const { writeFile, copyFile } = require('node:fs/promises');
|
||||
const { readFile, writeFile, appendFile, copyFile, rm } = require('node:fs/promises');
|
||||
const path = require('node:path');
|
||||
const { Readable } = require('node:stream');
|
||||
const { pipeline } = require('node:stream/promises');
|
||||
@@ -20,8 +20,25 @@ const mapTarballEntry = (header) => {
|
||||
return header;
|
||||
};
|
||||
|
||||
const licensing = `
|
||||
## Licensing
|
||||
|
||||
Copyright 2013 Lovell Fuller and others.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
[https://www.apache.org/licenses/LICENSE-2.0](https://www.apache.org/licenses/LICENSE-2.0)
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
`;
|
||||
|
||||
workspaces.map(async platform => {
|
||||
const url = `https://github.com/lovell/sharp/releases/download/v${version}/sharp-v${version}-napi-v7-${platform}.tar.gz`;
|
||||
const url = `https://github.com/lovell/sharp/releases/download/v${version}/sharp-v${version}-napi-v9-${platform}.tar.gz`;
|
||||
const dir = path.join(__dirname, platform);
|
||||
const response = await fetch(url);
|
||||
if (!response.ok) {
|
||||
@@ -29,23 +46,26 @@ workspaces.map(async platform => {
|
||||
return;
|
||||
}
|
||||
// Extract prebuild tarball
|
||||
const lib = path.join(dir, 'lib');
|
||||
await rm(lib, { recursive: true });
|
||||
await pipeline(
|
||||
Readable.fromWeb(response.body),
|
||||
createGunzip(),
|
||||
extract(path.join(dir, 'lib'), { map: mapTarballEntry })
|
||||
extract(lib, { map: mapTarballEntry })
|
||||
);
|
||||
// Generate README
|
||||
const { name, description } = require(`./${platform}/package.json`);
|
||||
await writeFile(path.join(dir, 'README.md'), `# ${name}\n${description}`);
|
||||
await writeFile(path.join(dir, 'README.md'), `# \`${name}\`\n\n${description}.\n${licensing}`);
|
||||
// Copy Apache-2.0 LICENSE
|
||||
await copyFile(path.join(__dirname, '..', 'LICENSE'), path.join(dir, 'LICENSE'));
|
||||
// Copy Windows-specific files
|
||||
if (platform.startsWith('win32-')) {
|
||||
const sharpLibvipsDir = path.join(require(`@sharpen/sharp-libvips-${platform}/lib`), '..');
|
||||
await Promise.all(
|
||||
['versions.json', 'THIRD-PARTY-NOTICES.md'].map(
|
||||
filename => copyFile(path.join(sharpLibvipsDir, filename), path.join(dir, filename))
|
||||
)
|
||||
);
|
||||
const sharpLibvipsDir = path.join(require(`@img/sharp-libvips-${platform}/lib`), '..');
|
||||
// Copy versions.json
|
||||
await copyFile(path.join(sharpLibvipsDir, 'versions.json'), path.join(dir, 'versions.json'));
|
||||
// Append third party licensing to README
|
||||
const readme = await readFile(path.join(sharpLibvipsDir, 'README.md'), { encoding: 'utf-8' });
|
||||
const thirdParty = readme.substring(readme.indexOf('\nThis software contains'));
|
||||
appendFile(path.join(dir, 'README.md'), thirdParty);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -14,7 +14,7 @@ const platform = buildPlatformArch();
|
||||
const dest = path.join(__dirname, platform);
|
||||
|
||||
// Use same config as prebuild to copy binary files
|
||||
const release = path.join(__dirname, '..', 'build', 'Release');
|
||||
const release = path.join(__dirname, '..', 'src', 'build', 'Release');
|
||||
const prebuildrc = JSON.parse(fs.readFileSync(path.join(__dirname, '..', '.prebuildrc'), 'utf8'));
|
||||
const include = new RegExp(prebuildrc['include-regex'], 'i');
|
||||
fs.cpSync(release, path.join(dest, 'lib'), {
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
{
|
||||
"name": "@sharpen/sharp-linux-arm",
|
||||
"version": "0.0.1-alpha.1",
|
||||
"name": "@img/sharp-linux-arm",
|
||||
"version": "0.33.0-alpha.10",
|
||||
"description": "Prebuilt sharp for use with Linux (glibc) ARM (32-bit)",
|
||||
"author": "Lovell Fuller <npm@lovell.info>",
|
||||
"homepage": "https://sharp.pixelplumbing.com",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -14,7 +15,7 @@
|
||||
},
|
||||
"preferUnplugged": true,
|
||||
"optionalDependencies": {
|
||||
"@sharpen/sharp-libvips-linux-arm": "0.0.1-alpha.1"
|
||||
"@img/sharp-libvips-linux-arm": "0.0.3"
|
||||
},
|
||||
"files": [
|
||||
"lib"
|
||||
@@ -22,6 +23,7 @@
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"type": "commonjs",
|
||||
"exports": {
|
||||
"./sharp.node": "./lib/sharp-linux-arm.node",
|
||||
"./package": "./package.json"
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
{
|
||||
"name": "@sharpen/sharp-linux-arm64",
|
||||
"version": "0.0.1-alpha.1",
|
||||
"description": "Prebuilt sharp for use with Linux (glibc) ARM64",
|
||||
"name": "@img/sharp-linux-arm64",
|
||||
"version": "0.33.0-alpha.10",
|
||||
"description": "Prebuilt sharp for use with Linux (glibc) 64-bit ARM",
|
||||
"author": "Lovell Fuller <npm@lovell.info>",
|
||||
"homepage": "https://sharp.pixelplumbing.com",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -14,7 +15,7 @@
|
||||
},
|
||||
"preferUnplugged": true,
|
||||
"optionalDependencies": {
|
||||
"@sharpen/sharp-libvips-linux-arm64": "0.0.1-alpha.1"
|
||||
"@img/sharp-libvips-linux-arm64": "0.0.3"
|
||||
},
|
||||
"files": [
|
||||
"lib"
|
||||
@@ -22,6 +23,7 @@
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"type": "commonjs",
|
||||
"exports": {
|
||||
"./sharp.node": "./lib/sharp-linux-arm64.node",
|
||||
"./package": "./package.json"
|
||||
|
||||
47
npm/linux-s390x/package.json
Normal file
47
npm/linux-s390x/package.json
Normal file
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"name": "@img/sharp-linux-s390x",
|
||||
"version": "0.33.0-alpha.10",
|
||||
"description": "Prebuilt sharp for use with Linux (glibc) s390x",
|
||||
"author": "Lovell Fuller <npm@lovell.info>",
|
||||
"homepage": "https://sharp.pixelplumbing.com",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/lovell/sharp.git",
|
||||
"directory": "npm/linux-s390x"
|
||||
},
|
||||
"license": "Apache-2.0",
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
},
|
||||
"preferUnplugged": true,
|
||||
"optionalDependencies": {
|
||||
"@img/sharp-libvips-linux-s390x": "0.0.3"
|
||||
},
|
||||
"files": [
|
||||
"lib"
|
||||
],
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"type": "commonjs",
|
||||
"exports": {
|
||||
"./sharp.node": "./lib/sharp-linux-s390x.node",
|
||||
"./package": "./package.json"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0",
|
||||
"npm": ">=9.6.5",
|
||||
"yarn": ">=3.2.0",
|
||||
"pnpm": ">=7.1.0",
|
||||
"glibc": ">=2.28"
|
||||
},
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"libc": [
|
||||
"glibc"
|
||||
],
|
||||
"cpu": [
|
||||
"s390x"
|
||||
]
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
{
|
||||
"name": "@sharpen/sharp-linux-x64",
|
||||
"version": "0.0.1-alpha.1",
|
||||
"name": "@img/sharp-linux-x64",
|
||||
"version": "0.33.0-alpha.10",
|
||||
"description": "Prebuilt sharp for use with Linux (glibc) x64",
|
||||
"author": "Lovell Fuller <npm@lovell.info>",
|
||||
"homepage": "https://sharp.pixelplumbing.com",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -14,7 +15,7 @@
|
||||
},
|
||||
"preferUnplugged": true,
|
||||
"optionalDependencies": {
|
||||
"@sharpen/sharp-libvips-linux-x64": "0.0.1-alpha.1"
|
||||
"@img/sharp-libvips-linux-x64": "0.0.3"
|
||||
},
|
||||
"files": [
|
||||
"lib"
|
||||
@@ -22,6 +23,7 @@
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"type": "commonjs",
|
||||
"exports": {
|
||||
"./sharp.node": "./lib/sharp-linux-x64.node",
|
||||
"./package": "./package.json"
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
{
|
||||
"name": "@sharpen/sharp-linuxmusl-arm64",
|
||||
"version": "0.0.1-alpha.1",
|
||||
"description": "Prebuilt sharp for use with Linux (musl) ARM64",
|
||||
"name": "@img/sharp-linuxmusl-arm64",
|
||||
"version": "0.33.0-alpha.10",
|
||||
"description": "Prebuilt sharp for use with Linux (musl) 64-bit ARM",
|
||||
"author": "Lovell Fuller <npm@lovell.info>",
|
||||
"homepage": "https://sharp.pixelplumbing.com",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -14,7 +15,7 @@
|
||||
},
|
||||
"preferUnplugged": true,
|
||||
"optionalDependencies": {
|
||||
"@sharpen/sharp-libvips-linuxmusl-arm64": "0.0.1-alpha.1"
|
||||
"@img/sharp-libvips-linuxmusl-arm64": "0.0.3"
|
||||
},
|
||||
"files": [
|
||||
"lib"
|
||||
@@ -22,6 +23,7 @@
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"type": "commonjs",
|
||||
"exports": {
|
||||
"./sharp.node": "./lib/sharp-linuxmusl-arm64.node",
|
||||
"./package": "./package.json"
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
{
|
||||
"name": "@sharpen/sharp-linuxmusl-x64",
|
||||
"version": "0.0.1-alpha.1",
|
||||
"name": "@img/sharp-linuxmusl-x64",
|
||||
"version": "0.33.0-alpha.10",
|
||||
"description": "Prebuilt sharp for use with Linux (musl) x64",
|
||||
"author": "Lovell Fuller <npm@lovell.info>",
|
||||
"homepage": "https://sharp.pixelplumbing.com",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -14,7 +15,7 @@
|
||||
},
|
||||
"preferUnplugged": true,
|
||||
"optionalDependencies": {
|
||||
"@sharpen/sharp-libvips-linuxmusl-x64": "0.0.1-alpha.1"
|
||||
"@img/sharp-libvips-linuxmusl-x64": "0.0.3"
|
||||
},
|
||||
"files": [
|
||||
"lib"
|
||||
@@ -22,6 +23,7 @@
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"type": "commonjs",
|
||||
"exports": {
|
||||
"./sharp.node": "./lib/sharp-linuxmusl-x64.node",
|
||||
"./package": "./package.json"
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
{
|
||||
"name": "@sharpen/sharp",
|
||||
"version": "0.0.1-alpha.1",
|
||||
"name": "@img/sharp",
|
||||
"version": "0.33.0-alpha.10",
|
||||
"private": "true",
|
||||
"workspaces": [
|
||||
"darwin-x64",
|
||||
"darwin-arm64",
|
||||
"darwin-x64",
|
||||
"linux-arm",
|
||||
"linux-arm64",
|
||||
"linux-s390x",
|
||||
"linux-x64",
|
||||
"linuxmusl-arm64",
|
||||
"linuxmusl-x64",
|
||||
"linux-x64",
|
||||
"win32-ia32",
|
||||
"win32-x64"
|
||||
]
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
{
|
||||
"name": "@sharpen/sharp-win32-ia32",
|
||||
"version": "0.0.1-alpha.1",
|
||||
"name": "@img/sharp-win32-ia32",
|
||||
"version": "0.33.0-alpha.10",
|
||||
"description": "Prebuilt sharp for use with Windows x86 (32-bit)",
|
||||
"author": "Lovell Fuller <npm@lovell.info>",
|
||||
"homepage": "https://sharp.pixelplumbing.com",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -13,18 +14,18 @@
|
||||
"url": "https://opencollective.com/libvips"
|
||||
},
|
||||
"preferUnplugged": true,
|
||||
"optionalDependencies": {
|
||||
"@sharpen/sharp-libvips-win32-ia32": "0.0.1-alpha.1"
|
||||
},
|
||||
"files": [
|
||||
"lib"
|
||||
"lib",
|
||||
"versions.json"
|
||||
],
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"type": "commonjs",
|
||||
"exports": {
|
||||
"./sharp.node": "./lib/sharp-win32-ia32.node",
|
||||
"./package": "./package.json"
|
||||
"./package": "./package.json",
|
||||
"./versions": "./versions.json"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0",
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
{
|
||||
"name": "@sharpen/sharp-win32-x64",
|
||||
"version": "0.0.1-alpha.1",
|
||||
"name": "@img/sharp-win32-x64",
|
||||
"version": "0.33.0-alpha.10",
|
||||
"description": "Prebuilt sharp for use with Windows x64",
|
||||
"author": "Lovell Fuller <npm@lovell.info>",
|
||||
"homepage": "https://sharp.pixelplumbing.com",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -13,18 +14,18 @@
|
||||
"url": "https://opencollective.com/libvips"
|
||||
},
|
||||
"preferUnplugged": true,
|
||||
"optionalDependencies": {
|
||||
"@sharpen/sharp-libvips-win32-x64": "0.0.1-alpha.1"
|
||||
},
|
||||
"files": [
|
||||
"lib"
|
||||
"lib",
|
||||
"versions.json"
|
||||
],
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"type": "commonjs",
|
||||
"exports": {
|
||||
"./sharp.node": "./lib/sharp-win32-x64.node",
|
||||
"./package": "./package.json"
|
||||
"./package": "./package.json",
|
||||
"./versions": "./versions.json"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0",
|
||||
|
||||
59
package.json
59
package.json
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "sharp",
|
||||
"description": "High performance Node.js image processing, the fastest module to resize JPEG, PNG, WebP, GIF, AVIF and TIFF images",
|
||||
"version": "0.33.0-alpha.1",
|
||||
"version": "0.33.0-alpha.10",
|
||||
"author": "Lovell Fuller <npm@lovell.info>",
|
||||
"homepage": "https://github.com/lovell/sharp",
|
||||
"contributors": [
|
||||
@@ -86,11 +86,12 @@
|
||||
"Ankur Parihar <ankur.github@gmail.com>",
|
||||
"Brahim Ait elhaj <brahima@gmail.com>",
|
||||
"Mart Jansink <m.jansink@gmail.com>",
|
||||
"Lachlan Newman <lachnewman007@gmail.com>"
|
||||
"Lachlan Newman <lachnewman007@gmail.com>",
|
||||
"Dennis Beatty <dennis@dcbeatty.com>"
|
||||
],
|
||||
"scripts": {
|
||||
"install": "node install/check",
|
||||
"clean": "rm -rf build/ .nyc_output/ coverage/ test/fixtures/output.*",
|
||||
"clean": "rm -rf src/build/ .nyc_output/ coverage/ test/fixtures/output.*",
|
||||
"test": "npm run test-lint && npm run test-unit && npm run test-licensing && npm run test-types",
|
||||
"test-lint": "semistandard && cpplint",
|
||||
"test-unit": "nyc --reporter=lcov --reporter=text --check-coverage --branches=100 mocha",
|
||||
@@ -103,13 +104,13 @@
|
||||
"docs-serve": "cd docs && npx serve",
|
||||
"docs-publish": "cd docs && npx firebase-tools deploy --project pixelplumbing --only hosting:pixelplumbing-sharp"
|
||||
},
|
||||
"type": "commonjs",
|
||||
"main": "lib/index.js",
|
||||
"types": "lib/index.d.ts",
|
||||
"files": [
|
||||
"binding.gyp",
|
||||
"install/**",
|
||||
"lib/**",
|
||||
"src/**"
|
||||
"install",
|
||||
"lib",
|
||||
"src/*.{cc,h,gyp}"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -136,31 +137,32 @@
|
||||
"dependencies": {
|
||||
"color": "^4.2.3",
|
||||
"detect-libc": "^2.0.2",
|
||||
"node-addon-api": "^7.0.0",
|
||||
"semver": "^7.5.4"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@sharpen/sharp-darwin-arm64": "0.0.1-alpha.1",
|
||||
"@sharpen/sharp-darwin-x64": "0.0.1-alpha.1",
|
||||
"@sharpen/sharp-linux-arm": "0.0.1-alpha.1",
|
||||
"@sharpen/sharp-linux-arm64": "0.0.1-alpha.1",
|
||||
"@sharpen/sharp-linux-x64": "0.0.1-alpha.1",
|
||||
"@sharpen/sharp-linuxmusl-arm64": "0.0.1-alpha.1",
|
||||
"@sharpen/sharp-linuxmusl-x64": "0.0.1-alpha.1",
|
||||
"@sharpen/sharp-win32-ia32": "0.0.1-alpha.1",
|
||||
"@sharpen/sharp-win32-x64": "0.0.1-alpha.1"
|
||||
"@img/sharp-darwin-arm64": "0.33.0-alpha.10",
|
||||
"@img/sharp-darwin-x64": "0.33.0-alpha.10",
|
||||
"@img/sharp-libvips-darwin-arm64": "0.0.3",
|
||||
"@img/sharp-libvips-darwin-x64": "0.0.3",
|
||||
"@img/sharp-libvips-linux-arm": "0.0.3",
|
||||
"@img/sharp-libvips-linux-arm64": "0.0.3",
|
||||
"@img/sharp-libvips-linux-s390x": "0.0.3",
|
||||
"@img/sharp-libvips-linux-x64": "0.0.3",
|
||||
"@img/sharp-libvips-linuxmusl-arm64": "0.0.3",
|
||||
"@img/sharp-libvips-linuxmusl-x64": "0.0.3",
|
||||
"@img/sharp-linux-arm": "0.33.0-alpha.10",
|
||||
"@img/sharp-linux-arm64": "0.33.0-alpha.10",
|
||||
"@img/sharp-linux-s390x": "0.33.0-alpha.10",
|
||||
"@img/sharp-linux-x64": "0.33.0-alpha.10",
|
||||
"@img/sharp-linuxmusl-arm64": "0.33.0-alpha.10",
|
||||
"@img/sharp-linuxmusl-x64": "0.33.0-alpha.10",
|
||||
"@img/sharp-win32-ia32": "0.33.0-alpha.10",
|
||||
"@img/sharp-win32-x64": "0.33.0-alpha.10"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@sharpen/sharp-libvips-darwin-arm64": "0.0.1-alpha.1",
|
||||
"@sharpen/sharp-libvips-darwin-x64": "0.0.1-alpha.1",
|
||||
"@sharpen/sharp-libvips-dev": "0.0.1-alpha.1",
|
||||
"@sharpen/sharp-libvips-linux-arm": "0.0.1-alpha.1",
|
||||
"@sharpen/sharp-libvips-linux-arm64": "0.0.1-alpha.1",
|
||||
"@sharpen/sharp-libvips-linux-x64": "0.0.1-alpha.1",
|
||||
"@sharpen/sharp-libvips-linuxmusl-arm64": "0.0.1-alpha.1",
|
||||
"@sharpen/sharp-libvips-linuxmusl-x64": "0.0.1-alpha.1",
|
||||
"@sharpen/sharp-libvips-win32-ia32": "0.0.1-alpha.1",
|
||||
"@sharpen/sharp-libvips-win32-x64": "0.0.1-alpha.1",
|
||||
"@img/sharp-libvips-dev": "0.0.3",
|
||||
"@img/sharp-libvips-win32-ia32": "0.0.3",
|
||||
"@img/sharp-libvips-win32-x64": "0.0.3",
|
||||
"@types/node": "*",
|
||||
"async": "^3.2.4",
|
||||
"cc": "^3.0.1",
|
||||
@@ -170,6 +172,7 @@
|
||||
"jsdoc-to-markdown": "^8.0.0",
|
||||
"license-checker": "^25.0.1",
|
||||
"mocha": "^10.2.0",
|
||||
"node-addon-api": "^7.0.0",
|
||||
"nyc": "^15.1.0",
|
||||
"prebuild": "^12.1.0",
|
||||
"semistandard": "^17.0.0",
|
||||
@@ -179,7 +182,7 @@
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0",
|
||||
"libvips": ">=8.14.5"
|
||||
"libvips": ">=8.15.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
|
||||
@@ -3,14 +3,15 @@
|
||||
|
||||
{
|
||||
'variables': {
|
||||
'vips_version': '<!(node -p "require(\'./lib/libvips\').minimumLibvipsVersion")',
|
||||
'platform_and_arch': '<!(node -p "require(\'./lib/libvips\').buildPlatformArch()")',
|
||||
'sharp_libvips_include_dir': '<!(node -p "require(\'./lib/libvips\').buildSharpLibvipsIncludeDir()")',
|
||||
'sharp_libvips_cplusplus_dir': '<!(node -p "require(\'./lib/libvips\').buildSharpLibvipsCPlusPlusDir()")',
|
||||
'sharp_libvips_lib_dir': '<!(node -p "require(\'./lib/libvips\').buildSharpLibvipsLibDir()")'
|
||||
'vips_version': '<!(node -p "require(\'../lib/libvips\').minimumLibvipsVersion")',
|
||||
'platform_and_arch': '<!(node -p "require(\'../lib/libvips\').buildPlatformArch()")',
|
||||
'sharp_libvips_version': '<!(node -p "require(\'../package.json\').optionalDependencies[\'@img/sharp-libvips-<(platform_and_arch)\']")',
|
||||
'sharp_libvips_include_dir': '<!(node -p "require(\'../lib/libvips\').buildSharpLibvipsIncludeDir()")',
|
||||
'sharp_libvips_cplusplus_dir': '<!(node -p "require(\'../lib/libvips\').buildSharpLibvipsCPlusPlusDir()")',
|
||||
'sharp_libvips_lib_dir': '<!(node -p "require(\'../lib/libvips\').buildSharpLibvipsLibDir()")'
|
||||
},
|
||||
'targets': [{
|
||||
'target_name': 'win-libvips-cpp',
|
||||
'target_name': 'libvips-cpp',
|
||||
'conditions': [
|
||||
['OS == "win"', {
|
||||
# Build libvips C++ binding for Windows due to MSVC std library ABI changes
|
||||
@@ -32,11 +33,11 @@
|
||||
'<(sharp_libvips_lib_dir)/glib-2.0/include'
|
||||
],
|
||||
'link_settings': {
|
||||
'library_dirs': ['<(sharp_libvips_lib_dir)'],
|
||||
'library_dirs': [
|
||||
'<(sharp_libvips_lib_dir)'
|
||||
],
|
||||
'libraries': [
|
||||
'libvips.lib',
|
||||
'libglib-2.0.lib',
|
||||
'libgobject-2.0.lib'
|
||||
'libvips.lib'
|
||||
],
|
||||
},
|
||||
'configurations': {
|
||||
@@ -81,13 +82,13 @@
|
||||
],
|
||||
'dependencies': [
|
||||
'<!(node -p "require(\'node-addon-api\').gyp")',
|
||||
'win-libvips-cpp'
|
||||
'libvips-cpp'
|
||||
],
|
||||
'variables': {
|
||||
'conditions': [
|
||||
['OS != "win"', {
|
||||
'pkg_config_path': '<!(node -p "require(\'./lib/libvips\').pkgConfigPath()")',
|
||||
'use_global_libvips': '<!(node -p "Boolean(require(\'./lib/libvips\').useGlobalLibvips()).toString()")'
|
||||
'pkg_config_path': '<!(node -p "require(\'../lib/libvips\').pkgConfigPath()")',
|
||||
'use_global_libvips': '<!(node -p "Boolean(require(\'../lib/libvips\').useGlobalLibvips()).toString()")'
|
||||
}, {
|
||||
'pkg_config_path': '',
|
||||
'use_global_libvips': ''
|
||||
@@ -95,13 +96,13 @@
|
||||
]
|
||||
},
|
||||
'sources': [
|
||||
'src/common.cc',
|
||||
'src/metadata.cc',
|
||||
'src/stats.cc',
|
||||
'src/operations.cc',
|
||||
'src/pipeline.cc',
|
||||
'src/utilities.cc',
|
||||
'src/sharp.cc'
|
||||
'common.cc',
|
||||
'metadata.cc',
|
||||
'stats.cc',
|
||||
'operations.cc',
|
||||
'pipeline.cc',
|
||||
'utilities.cc',
|
||||
'sharp.cc'
|
||||
],
|
||||
'include_dirs': [
|
||||
'<!(node -p "require(\'node-addon-api\').include_dir")',
|
||||
@@ -111,6 +112,9 @@
|
||||
# Use pkg-config for include and lib
|
||||
'include_dirs': ['<!@(PKG_CONFIG_PATH="<(pkg_config_path)" pkg-config --cflags-only-I vips-cpp vips glib-2.0 | sed s\/-I//g)'],
|
||||
'libraries': ['<!@(PKG_CONFIG_PATH="<(pkg_config_path)" pkg-config --libs vips-cpp)'],
|
||||
'defines': [
|
||||
'SHARP_USE_GLOBAL_LIBVIPS'
|
||||
],
|
||||
'conditions': [
|
||||
['OS == "linux"', {
|
||||
'defines': [
|
||||
@@ -126,6 +130,9 @@
|
||||
'<(sharp_libvips_include_dir)/glib-2.0',
|
||||
'<(sharp_libvips_lib_dir)/glib-2.0/include'
|
||||
],
|
||||
'library_dirs': [
|
||||
'<(sharp_libvips_lib_dir)'
|
||||
],
|
||||
'conditions': [
|
||||
['OS == "win"', {
|
||||
'defines': [
|
||||
@@ -133,19 +140,13 @@
|
||||
'_FILE_OFFSET_BITS=64'
|
||||
],
|
||||
'link_settings': {
|
||||
'library_dirs': ['<(sharp_libvips_lib_dir)'],
|
||||
'libraries': [
|
||||
'libvips.lib',
|
||||
'libglib-2.0.lib',
|
||||
'libgobject-2.0.lib'
|
||||
'libvips.lib'
|
||||
]
|
||||
}
|
||||
}],
|
||||
['OS == "mac"', {
|
||||
'link_settings': {
|
||||
'library_dirs': [
|
||||
'<(sharp_libvips_lib_dir)'
|
||||
],
|
||||
'libraries': [
|
||||
'libvips-cpp.42.dylib'
|
||||
]
|
||||
@@ -154,8 +155,9 @@
|
||||
'OTHER_LDFLAGS': [
|
||||
# Ensure runtime linking is relative to sharp.node
|
||||
'-Wl,-rpath,\'@loader_path/../../sharp-libvips-<(platform_and_arch)/lib\'',
|
||||
'-Wl,-rpath,\'@loader_path/../../node_modules/@sharpen/sharp-libvips-<(platform_and_arch)/lib\'',
|
||||
'-Wl,-rpath,\'@loader_path/../../../node_modules/@sharpen/sharp-libvips-<(platform_and_arch)/lib\''
|
||||
'-Wl,-rpath,\'@loader_path/../../../<(sharp_libvips_version)/sharp-libvips-<(platform_and_arch)/lib\'',
|
||||
'-Wl,-rpath,\'@loader_path/../../node_modules/@img/sharp-libvips-<(platform_and_arch)/lib\'',
|
||||
'-Wl,-rpath,\'@loader_path/../../../node_modules/@img/sharp-libvips-<(platform_and_arch)/lib\''
|
||||
]
|
||||
}
|
||||
}],
|
||||
@@ -164,9 +166,6 @@
|
||||
'_GLIBCXX_USE_CXX11_ABI=1'
|
||||
],
|
||||
'link_settings': {
|
||||
'library_dirs': [
|
||||
'<(sharp_libvips_lib_dir)'
|
||||
],
|
||||
'libraries': [
|
||||
'-l:libvips-cpp.so.42'
|
||||
],
|
||||
@@ -175,8 +174,9 @@
|
||||
'-Wl,-s',
|
||||
'-Wl,--disable-new-dtags',
|
||||
'-Wl,-rpath=\'$$ORIGIN/../../sharp-libvips-<(platform_and_arch)/lib\'',
|
||||
'-Wl,-rpath=\'$$ORIGIN/../../node_modules/@sharpen/sharp-libvips-<(platform_and_arch)/lib\'',
|
||||
'-Wl,-rpath=\'$$ORIGIN/../../../node_modules/@sharpen/sharp-libvips-<(platform_and_arch)/lib\''
|
||||
'-Wl,-rpath=\'$$ORIGIN/../../../<(sharp_libvips_version)/sharp-libvips-<(platform_and_arch)/lib\'',
|
||||
'-Wl,-rpath=\'$$ORIGIN/../../node_modules/@img/sharp-libvips-<(platform_and_arch)/lib\'',
|
||||
'-Wl,-rpath=\'$$ORIGIN/../../../node_modules/@img/sharp-libvips-<(platform_and_arch)/lib\''
|
||||
]
|
||||
}
|
||||
}]
|
||||
@@ -243,7 +243,7 @@
|
||||
}
|
||||
},
|
||||
}, {
|
||||
'target_name': 'win-copy-dlls',
|
||||
'target_name': 'copy-dll',
|
||||
'type': 'none',
|
||||
'dependencies': [
|
||||
'sharp-<(platform_and_arch)'
|
||||
@@ -253,9 +253,7 @@
|
||||
'copies': [{
|
||||
'destination': 'build/Release',
|
||||
'files': [
|
||||
'<(sharp_libvips_lib_dir)/libvips-42.dll',
|
||||
'<(sharp_libvips_lib_dir)/libglib-2.0-0.dll',
|
||||
'<(sharp_libvips_lib_dir)/libgobject-2.0-0.dll'
|
||||
'<(sharp_libvips_lib_dir)/libvips-42.dll'
|
||||
]
|
||||
}]
|
||||
}]
|
||||
@@ -166,10 +166,10 @@ namespace sharp {
|
||||
}
|
||||
|
||||
// How many tasks are in the queue?
|
||||
volatile int counterQueue = 0;
|
||||
std::atomic<int> counterQueue{0};
|
||||
|
||||
// How many tasks are being processed?
|
||||
volatile int counterProcess = 0;
|
||||
std::atomic<int> counterProcess{0};
|
||||
|
||||
// Filename extension checkers
|
||||
static bool EndsWith(std::string const &str, std::string const &end) {
|
||||
@@ -363,12 +363,13 @@ namespace sharp {
|
||||
if (descriptor->isBuffer) {
|
||||
if (descriptor->rawChannels > 0) {
|
||||
// Raw, uncompressed pixel data
|
||||
bool const is8bit = vips_band_format_is8bit(descriptor->rawDepth);
|
||||
image = VImage::new_from_memory(descriptor->buffer, descriptor->bufferLength,
|
||||
descriptor->rawWidth, descriptor->rawHeight, descriptor->rawChannels, descriptor->rawDepth);
|
||||
if (descriptor->rawChannels < 3) {
|
||||
image.get_image()->Type = VIPS_INTERPRETATION_B_W;
|
||||
image.get_image()->Type = is8bit ? VIPS_INTERPRETATION_B_W : VIPS_INTERPRETATION_GREY16;
|
||||
} else {
|
||||
image.get_image()->Type = VIPS_INTERPRETATION_sRGB;
|
||||
image.get_image()->Type = is8bit ? VIPS_INTERPRETATION_sRGB : VIPS_INTERPRETATION_RGB16;
|
||||
}
|
||||
if (descriptor->rawPremultiplied) {
|
||||
image = image.unpremultiply();
|
||||
|
||||
11
src/common.h
11
src/common.h
@@ -7,6 +7,7 @@
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
#include <atomic>
|
||||
|
||||
#include <napi.h>
|
||||
#include <vips/vips8>
|
||||
@@ -14,9 +15,9 @@
|
||||
// Verify platform and compiler compatibility
|
||||
|
||||
#if (VIPS_MAJOR_VERSION < 8) || \
|
||||
(VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION < 14) || \
|
||||
(VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION == 14 && VIPS_MICRO_VERSION < 5)
|
||||
#error "libvips version 8.14.5+ is required - please see https://sharp.pixelplumbing.com/install"
|
||||
(VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION < 15) || \
|
||||
(VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION == 15 && VIPS_MICRO_VERSION < 0)
|
||||
#error "libvips version 8.15.0+ is required - please see https://sharp.pixelplumbing.com/install"
|
||||
#endif
|
||||
|
||||
#if ((!defined(__clang__)) && defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 6)))
|
||||
@@ -161,10 +162,10 @@ namespace sharp {
|
||||
};
|
||||
|
||||
// How many tasks are in the queue?
|
||||
extern volatile int counterQueue;
|
||||
extern std::atomic<int> counterQueue;
|
||||
|
||||
// How many tasks are being processed?
|
||||
extern volatile int counterProcess;
|
||||
extern std::atomic<int> counterProcess;
|
||||
|
||||
// Filename extension checkers
|
||||
bool IsJpeg(std::string const &str);
|
||||
|
||||
@@ -18,7 +18,7 @@ class MetadataWorker : public Napi::AsyncWorker {
|
||||
|
||||
void Execute() {
|
||||
// Decrement queued task counter
|
||||
g_atomic_int_dec_and_test(&sharp::counterQueue);
|
||||
sharp::counterQueue--;
|
||||
|
||||
vips::VImage image;
|
||||
sharp::ImageType imageType = sharp::ImageType::UNKNOWN;
|
||||
@@ -145,7 +145,7 @@ class MetadataWorker : public Napi::AsyncWorker {
|
||||
// Handle warnings
|
||||
std::string warning = sharp::VipsWarningPop();
|
||||
while (!warning.empty()) {
|
||||
debuglog.MakeCallback(Receiver().Value(), { Napi::String::New(env, warning) });
|
||||
debuglog.Call(Receiver().Value(), { Napi::String::New(env, warning) });
|
||||
warning = sharp::VipsWarningPop();
|
||||
}
|
||||
|
||||
@@ -246,9 +246,9 @@ class MetadataWorker : public Napi::AsyncWorker {
|
||||
Napi::Buffer<char>::NewOrCopy(env, baton->tifftagPhotoshop,
|
||||
baton->tifftagPhotoshopLength, sharp::FreeCallback));
|
||||
}
|
||||
Callback().MakeCallback(Receiver().Value(), { env.Null(), info });
|
||||
Callback().Call(Receiver().Value(), { env.Null(), info });
|
||||
} else {
|
||||
Callback().MakeCallback(Receiver().Value(), { Napi::Error::New(env, sharp::TrimEnd(baton->err)).Value() });
|
||||
Callback().Call(Receiver().Value(), { Napi::Error::New(env, sharp::TrimEnd(baton->err)).Value() });
|
||||
}
|
||||
|
||||
delete baton->input;
|
||||
@@ -281,7 +281,7 @@ Napi::Value metadata(const Napi::CallbackInfo& info) {
|
||||
worker->Queue();
|
||||
|
||||
// Increment queued task counter
|
||||
g_atomic_int_inc(&sharp::counterQueue);
|
||||
sharp::counterQueue++;
|
||||
|
||||
return info.Env().Undefined();
|
||||
}
|
||||
|
||||
@@ -141,7 +141,7 @@ namespace sharp {
|
||||
return image.conv(blur);
|
||||
} else {
|
||||
// Slower, accurate Gaussian blur
|
||||
return image.gaussblur(sigma);
|
||||
return StaySequential(image, VIPS_ACCESS_SEQUENTIAL).gaussblur(sigma);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -265,7 +265,7 @@ namespace sharp {
|
||||
/*
|
||||
Trim an image
|
||||
*/
|
||||
VImage Trim(VImage image, std::vector<double> background, double threshold) {
|
||||
VImage Trim(VImage image, std::vector<double> background, double threshold, bool const lineArt) {
|
||||
if (image.width() < 3 && image.height() < 3) {
|
||||
throw VError("Image to trim must be at least 3x3 pixels");
|
||||
}
|
||||
@@ -287,6 +287,7 @@ namespace sharp {
|
||||
int left, top, width, height;
|
||||
left = image.find_trim(&top, &width, &height, VImage::option()
|
||||
->set("background", background)
|
||||
->set("line_art", lineArt)
|
||||
->set("threshold", threshold));
|
||||
if (HasAlpha(image)) {
|
||||
// Search alpha channel (A)
|
||||
@@ -294,6 +295,7 @@ namespace sharp {
|
||||
VImage alpha = image[image.bands() - 1];
|
||||
leftA = alpha.find_trim(&topA, &widthA, &heightA, VImage::option()
|
||||
->set("background", backgroundAlpha)
|
||||
->set("line_art", lineArt)
|
||||
->set("threshold", threshold));
|
||||
if (widthA > 0 && heightA > 0) {
|
||||
if (width > 0 && height > 0) {
|
||||
@@ -370,6 +372,7 @@ namespace sharp {
|
||||
pages.reserve(nPages);
|
||||
|
||||
// Split the image into cropped frames
|
||||
image = StaySequential(image, VIPS_ACCESS_SEQUENTIAL);
|
||||
for (int i = 0; i < nPages; i++) {
|
||||
pages.push_back(
|
||||
image.extract_area(left, *pageHeight * i + top, width, height));
|
||||
|
||||
@@ -79,7 +79,7 @@ namespace sharp {
|
||||
/*
|
||||
Trim an image
|
||||
*/
|
||||
VImage Trim(VImage image, std::vector<double> background, double const threshold);
|
||||
VImage Trim(VImage image, std::vector<double> background, double threshold, bool const lineArt);
|
||||
|
||||
/*
|
||||
* Linear adjustment (a * in + b)
|
||||
|
||||
@@ -44,9 +44,9 @@ class PipelineWorker : public Napi::AsyncWorker {
|
||||
// libuv worker
|
||||
void Execute() {
|
||||
// Decrement queued task counter
|
||||
g_atomic_int_dec_and_test(&sharp::counterQueue);
|
||||
sharp::counterQueue--;
|
||||
// Increment processing task counter
|
||||
g_atomic_int_inc(&sharp::counterProcess);
|
||||
sharp::counterProcess++;
|
||||
|
||||
try {
|
||||
// Open input
|
||||
@@ -126,10 +126,10 @@ class PipelineWorker : public Napi::AsyncWorker {
|
||||
}
|
||||
|
||||
// Trim
|
||||
if (baton->trimThreshold > 0.0) {
|
||||
if (baton->trimThreshold >= 0.0) {
|
||||
MultiPageUnsupported(nPages, "Trim");
|
||||
image = sharp::StaySequential(image, access);
|
||||
image = sharp::Trim(image, baton->trimBackground, baton->trimThreshold);
|
||||
image = sharp::Trim(image, baton->trimBackground, baton->trimThreshold, baton->trimLineArt);
|
||||
baton->trimOffsetLeft = image.xoffset();
|
||||
baton->trimOffsetTop = image.yoffset();
|
||||
}
|
||||
@@ -182,7 +182,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
||||
// - trimming or pre-resize extract isn't required;
|
||||
// - input colourspace is not specified;
|
||||
bool const shouldPreShrink = (targetResizeWidth > 0 || targetResizeHeight > 0) &&
|
||||
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 && !shouldRotateBefore;
|
||||
|
||||
if (shouldPreShrink) {
|
||||
@@ -485,9 +485,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
||||
image = sharp::StaySequential(image, access);
|
||||
image = image.smartcrop(baton->width, baton->height, VImage::option()
|
||||
->set("interesting", baton->position == 16 ? VIPS_INTERESTING_ENTROPY : VIPS_INTERESTING_ATTENTION)
|
||||
#if (VIPS_MAJOR_VERSION >= 8 && VIPS_MINOR_VERSION >= 15)
|
||||
->set("premultiplied", shouldPremultiplyAlpha)
|
||||
#endif
|
||||
->set("attention_x", &attention_x)
|
||||
->set("attention_y", &attention_y));
|
||||
baton->hasCropOffset = true;
|
||||
@@ -940,6 +938,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
||||
->set("Q", baton->tiffQuality)
|
||||
->set("bitdepth", baton->tiffBitdepth)
|
||||
->set("compression", baton->tiffCompression)
|
||||
->set("miniswhite", baton->tiffMiniswhite)
|
||||
->set("predictor", baton->tiffPredictor)
|
||||
->set("pyramid", baton->tiffPyramid)
|
||||
->set("tile", baton->tiffTile)
|
||||
@@ -1136,6 +1135,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
||||
->set("Q", baton->tiffQuality)
|
||||
->set("bitdepth", baton->tiffBitdepth)
|
||||
->set("compression", baton->tiffCompression)
|
||||
->set("miniswhite", baton->tiffMiniswhite)
|
||||
->set("predictor", baton->tiffPredictor)
|
||||
->set("pyramid", baton->tiffPyramid)
|
||||
->set("tile", baton->tiffTile)
|
||||
@@ -1215,7 +1215,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
||||
// Handle warnings
|
||||
std::string warning = sharp::VipsWarningPop();
|
||||
while (!warning.empty()) {
|
||||
debuglog.MakeCallback(Receiver().Value(), { Napi::String::New(env, warning) });
|
||||
debuglog.Call(Receiver().Value(), { Napi::String::New(env, warning) });
|
||||
warning = sharp::VipsWarningPop();
|
||||
}
|
||||
|
||||
@@ -1248,11 +1248,10 @@ class PipelineWorker : public Napi::AsyncWorker {
|
||||
info.Set("attentionX", static_cast<int32_t>(baton->attentionX));
|
||||
info.Set("attentionY", static_cast<int32_t>(baton->attentionY));
|
||||
}
|
||||
if (baton->trimThreshold > 0.0) {
|
||||
if (baton->trimThreshold >= 0.0) {
|
||||
info.Set("trimOffsetLeft", static_cast<int32_t>(baton->trimOffsetLeft));
|
||||
info.Set("trimOffsetTop", static_cast<int32_t>(baton->trimOffsetTop));
|
||||
}
|
||||
|
||||
if (baton->input->textAutofitDpi) {
|
||||
info.Set("textAutofitDpi", static_cast<uint32_t>(baton->input->textAutofitDpi));
|
||||
}
|
||||
@@ -1263,17 +1262,17 @@ class PipelineWorker : public Napi::AsyncWorker {
|
||||
// Pass ownership of output data to Buffer instance
|
||||
Napi::Buffer<char> data = Napi::Buffer<char>::NewOrCopy(env, static_cast<char*>(baton->bufferOut),
|
||||
baton->bufferOutLength, sharp::FreeCallback);
|
||||
Callback().MakeCallback(Receiver().Value(), { env.Null(), data, info });
|
||||
Callback().Call(Receiver().Value(), { env.Null(), data, info });
|
||||
} else {
|
||||
// Add file size to info
|
||||
struct STAT64_STRUCT st;
|
||||
if (STAT64_FUNCTION(baton->fileOut.data(), &st) == 0) {
|
||||
info.Set("size", static_cast<uint32_t>(st.st_size));
|
||||
}
|
||||
Callback().MakeCallback(Receiver().Value(), { env.Null(), info });
|
||||
Callback().Call(Receiver().Value(), { env.Null(), info });
|
||||
}
|
||||
} else {
|
||||
Callback().MakeCallback(Receiver().Value(), { Napi::Error::New(env, sharp::TrimEnd(baton->err)).Value() });
|
||||
Callback().Call(Receiver().Value(), { Napi::Error::New(env, sharp::TrimEnd(baton->err)).Value() });
|
||||
}
|
||||
|
||||
// Delete baton
|
||||
@@ -1289,9 +1288,9 @@ class PipelineWorker : public Napi::AsyncWorker {
|
||||
delete baton;
|
||||
|
||||
// Decrement processing task counter
|
||||
g_atomic_int_dec_and_test(&sharp::counterProcess);
|
||||
Napi::Number queueLength = Napi::Number::New(env, static_cast<double>(sharp::counterQueue));
|
||||
queueListener.MakeCallback(Receiver().Value(), { queueLength });
|
||||
sharp::counterProcess--;
|
||||
Napi::Number queueLength = Napi::Number::New(env, static_cast<int>(sharp::counterQueue));
|
||||
queueListener.Call(Receiver().Value(), { queueLength });
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -1519,6 +1518,7 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
||||
baton->thresholdGrayscale = sharp::AttrAsBool(options, "thresholdGrayscale");
|
||||
baton->trimBackground = sharp::AttrAsVectorOfDouble(options, "trimBackground");
|
||||
baton->trimThreshold = sharp::AttrAsDouble(options, "trimThreshold");
|
||||
baton->trimLineArt = sharp::AttrAsBool(options, "trimLineArt");
|
||||
baton->gamma = sharp::AttrAsDouble(options, "gamma");
|
||||
baton->gammaOut = sharp::AttrAsDouble(options, "gammaOut");
|
||||
baton->linearA = sharp::AttrAsVectorOfDouble(options, "linearA");
|
||||
@@ -1647,6 +1647,7 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
||||
baton->gifProgressive = sharp::AttrAsBool(options, "gifProgressive");
|
||||
baton->tiffQuality = sharp::AttrAsUint32(options, "tiffQuality");
|
||||
baton->tiffPyramid = sharp::AttrAsBool(options, "tiffPyramid");
|
||||
baton->tiffMiniswhite = sharp::AttrAsBool(options, "tiffMiniswhite");
|
||||
baton->tiffBitdepth = sharp::AttrAsUint32(options, "tiffBitdepth");
|
||||
baton->tiffTile = sharp::AttrAsBool(options, "tiffTile");
|
||||
baton->tiffTileWidth = sharp::AttrAsUint32(options, "tiffTileWidth");
|
||||
@@ -1707,9 +1708,8 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
||||
worker->Queue();
|
||||
|
||||
// Increment queued task counter
|
||||
g_atomic_int_inc(&sharp::counterQueue);
|
||||
Napi::Number queueLength = Napi::Number::New(info.Env(), static_cast<double>(sharp::counterQueue));
|
||||
queueListener.MakeCallback(info.This(), { queueLength });
|
||||
Napi::Number queueLength = Napi::Number::New(info.Env(), static_cast<int>(++sharp::counterQueue));
|
||||
queueListener.Call(info.This(), { queueLength });
|
||||
|
||||
return info.Env().Undefined();
|
||||
}
|
||||
|
||||
@@ -92,6 +92,7 @@ struct PipelineBaton {
|
||||
bool thresholdGrayscale;
|
||||
std::vector<double> trimBackground;
|
||||
double trimThreshold;
|
||||
bool trimLineArt;
|
||||
int trimOffsetLeft;
|
||||
int trimOffsetTop;
|
||||
std::vector<double> linearA;
|
||||
@@ -169,6 +170,7 @@ struct PipelineBaton {
|
||||
VipsForeignTiffPredictor tiffPredictor;
|
||||
bool tiffPyramid;
|
||||
int tiffBitdepth;
|
||||
bool tiffMiniswhite;
|
||||
bool tiffTile;
|
||||
int tiffTileHeight;
|
||||
int tiffTileWidth;
|
||||
@@ -259,7 +261,8 @@ struct PipelineBaton {
|
||||
threshold(0),
|
||||
thresholdGrayscale(true),
|
||||
trimBackground{},
|
||||
trimThreshold(0.0),
|
||||
trimThreshold(-1.0),
|
||||
trimLineArt(false),
|
||||
trimOffsetLeft(0),
|
||||
trimOffsetTop(0),
|
||||
linearA{},
|
||||
@@ -335,6 +338,7 @@ struct PipelineBaton {
|
||||
tiffPredictor(VIPS_FOREIGN_TIFF_PREDICTOR_HORIZONTAL),
|
||||
tiffPyramid(false),
|
||||
tiffBitdepth(8),
|
||||
tiffMiniswhite(false),
|
||||
tiffTile(false),
|
||||
tiffTileHeight(256),
|
||||
tiffTileWidth(256),
|
||||
|
||||
13
src/sharp.cc
13
src/sharp.cc
@@ -1,6 +1,8 @@
|
||||
// Copyright 2013 Lovell Fuller and others.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#include <mutex> // NOLINT(build/c++11)
|
||||
|
||||
#include <napi.h>
|
||||
#include <vips/vips8>
|
||||
|
||||
@@ -10,14 +12,11 @@
|
||||
#include "utilities.h"
|
||||
#include "stats.h"
|
||||
|
||||
static void* sharp_vips_init(void*) {
|
||||
vips_init("sharp");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Napi::Object init(Napi::Env env, Napi::Object exports) {
|
||||
static GOnce sharp_vips_init_once = G_ONCE_INIT;
|
||||
g_once(&sharp_vips_init_once, static_cast<GThreadFunc>(sharp_vips_init), nullptr);
|
||||
static std::once_flag sharp_vips_init_once;
|
||||
std::call_once(sharp_vips_init_once, []() {
|
||||
vips_init("sharp");
|
||||
});
|
||||
|
||||
g_log_set_handler("VIPS", static_cast<GLogLevelFlags>(G_LOG_LEVEL_WARNING),
|
||||
static_cast<GLogFunc>(sharp::VipsWarningCallback), nullptr);
|
||||
|
||||
10
src/stats.cc
10
src/stats.cc
@@ -30,7 +30,7 @@ class StatsWorker : public Napi::AsyncWorker {
|
||||
|
||||
void Execute() {
|
||||
// Decrement queued task counter
|
||||
g_atomic_int_dec_and_test(&sharp::counterQueue);
|
||||
sharp::counterQueue--;
|
||||
|
||||
vips::VImage image;
|
||||
sharp::ImageType imageType = sharp::ImageType::UNKNOWN;
|
||||
@@ -106,7 +106,7 @@ class StatsWorker : public Napi::AsyncWorker {
|
||||
// Handle warnings
|
||||
std::string warning = sharp::VipsWarningPop();
|
||||
while (!warning.empty()) {
|
||||
debuglog.MakeCallback(Receiver().Value(), { Napi::String::New(env, warning) });
|
||||
debuglog.Call(Receiver().Value(), { Napi::String::New(env, warning) });
|
||||
warning = sharp::VipsWarningPop();
|
||||
}
|
||||
|
||||
@@ -141,9 +141,9 @@ class StatsWorker : public Napi::AsyncWorker {
|
||||
dominant.Set("g", baton->dominantGreen);
|
||||
dominant.Set("b", baton->dominantBlue);
|
||||
info.Set("dominant", dominant);
|
||||
Callback().MakeCallback(Receiver().Value(), { env.Null(), info });
|
||||
Callback().Call(Receiver().Value(), { env.Null(), info });
|
||||
} else {
|
||||
Callback().MakeCallback(Receiver().Value(), { Napi::Error::New(env, sharp::TrimEnd(baton->err)).Value() });
|
||||
Callback().Call(Receiver().Value(), { Napi::Error::New(env, sharp::TrimEnd(baton->err)).Value() });
|
||||
}
|
||||
|
||||
delete baton->input;
|
||||
@@ -177,7 +177,7 @@ Napi::Value stats(const Napi::CallbackInfo& info) {
|
||||
worker->Queue();
|
||||
|
||||
// Increment queued task counter
|
||||
g_atomic_int_inc(&sharp::counterQueue);
|
||||
sharp::counterQueue++;
|
||||
|
||||
return info.Env().Undefined();
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include <cmath>
|
||||
#include <string>
|
||||
#include <cstdio>
|
||||
|
||||
#include <napi.h>
|
||||
#include <vips/vips8>
|
||||
@@ -70,8 +71,8 @@ Napi::Value concurrency(const Napi::CallbackInfo& info) {
|
||||
*/
|
||||
Napi::Value counters(const Napi::CallbackInfo& info) {
|
||||
Napi::Object counters = Napi::Object::New(info.Env());
|
||||
counters.Set("queue", sharp::counterQueue);
|
||||
counters.Set("process", sharp::counterProcess);
|
||||
counters.Set("queue", static_cast<int>(sharp::counterQueue));
|
||||
counters.Set("process", static_cast<int>(sharp::counterProcess));
|
||||
return counters;
|
||||
}
|
||||
|
||||
@@ -91,9 +92,18 @@ Napi::Value simd(const Napi::CallbackInfo& info) {
|
||||
Get libvips version
|
||||
*/
|
||||
Napi::Value libvipsVersion(const Napi::CallbackInfo& info) {
|
||||
char version[9];
|
||||
g_snprintf(version, sizeof(version), "%d.%d.%d", vips_version(0), vips_version(1), vips_version(2));
|
||||
return Napi::String::New(info.Env(), version);
|
||||
Napi::Env env = info.Env();
|
||||
Napi::Object version = Napi::Object::New(env);
|
||||
|
||||
char semver[9];
|
||||
std::snprintf(semver, sizeof(semver), "%d.%d.%d", vips_version(0), vips_version(1), vips_version(2));
|
||||
version.Set("semver", Napi::String::New(env, semver));
|
||||
#ifdef SHARP_USE_GLOBAL_LIBVIPS
|
||||
version.Set("isGlobal", Napi::Boolean::New(env, true));
|
||||
#else
|
||||
version.Set("isGlobal", Napi::Boolean::New(env, false));
|
||||
#endif
|
||||
return version;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -572,8 +572,8 @@ const nohalo: string = sharp.interpolators.nohalo;
|
||||
const vertexSplitQuadraticBasisSpline: string = sharp.interpolators.vertexSplitQuadraticBasisSpline;
|
||||
|
||||
// Triming
|
||||
sharp(input).trim('#000').toBuffer();
|
||||
sharp(input).trim(10).toBuffer();
|
||||
sharp(input).trim({ background: '#000' }).toBuffer();
|
||||
sharp(input).trim({ threshold: 10, lineArt: true }).toBuffer();
|
||||
sharp(input).trim({ background: '#bf1942', threshold: 30 }).toBuffer();
|
||||
|
||||
// Text input
|
||||
@@ -659,3 +659,6 @@ sharp('input.tiff').webp({ preset: 'drawing' }).toFile('out.webp');
|
||||
sharp('input.tiff').webp({ preset: 'text' }).toFile('out.webp');
|
||||
sharp('input.tiff').webp({ preset: 'default' }).toFile('out.webp');
|
||||
|
||||
// Allow a boolean or an object for metadata options.
|
||||
// https://github.com/lovell/sharp/issues/3822
|
||||
sharp(input).withMetadata().withMetadata({}).withMetadata(false);
|
||||
|
||||
@@ -246,7 +246,7 @@ describe('composite', () => {
|
||||
sharp(fixtures.inputJpg)
|
||||
.resize(300, 300)
|
||||
.composite([{
|
||||
input: Buffer.from('<svg width="200" height="200"><rect x="0" y="0" width="200" height="200" rx="50" ry="50"/></svg>'),
|
||||
input: Buffer.from('<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200"><rect x="0" y="0" width="200" height="200" rx="50" ry="50"/></svg>'),
|
||||
density: 96,
|
||||
blend: 'dest-in',
|
||||
cutout: true
|
||||
|
||||
@@ -319,5 +319,16 @@ describe('Partial image extraction', function () {
|
||||
s.extract(options);
|
||||
assert.strictEqual(warningMessage, 'ignoring previous extract options');
|
||||
});
|
||||
|
||||
it('Multiple extract+resize emits warning', () => {
|
||||
let warningMessage = '';
|
||||
const s = sharp();
|
||||
s.on('warning', function (msg) { warningMessage = msg; });
|
||||
const options = { top: 0, left: 0, width: 1, height: 1 };
|
||||
s.extract(options).extract(options);
|
||||
assert.strictEqual(warningMessage, '');
|
||||
s.resize(1);
|
||||
assert.strictEqual(warningMessage, 'operation order will be: extract, resize, extract');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -459,27 +459,29 @@ describe('Input/output', function () {
|
||||
});
|
||||
});
|
||||
|
||||
it('Fail when input is invalid Buffer', function (done) {
|
||||
sharp(Buffer.from([0x1, 0x2, 0x3, 0x4])).toBuffer().then(function () {
|
||||
assert(false);
|
||||
done();
|
||||
}).catch(function (err) {
|
||||
assert(err instanceof Error);
|
||||
assert.strictEqual('Input buffer contains unsupported image format', err.message);
|
||||
done();
|
||||
});
|
||||
});
|
||||
it('Fail when input is invalid Buffer', async () =>
|
||||
assert.rejects(
|
||||
() => sharp(Buffer.from([0x1, 0x2, 0x3, 0x4])).toBuffer(),
|
||||
(err) => {
|
||||
assert.strictEqual(err.message, 'Input buffer contains unsupported image format');
|
||||
assert(err.stack.includes('at Sharp.toBuffer'));
|
||||
assert(err.stack.includes(__filename));
|
||||
return true;
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
it('Fail when input file path is missing', function (done) {
|
||||
sharp('does-not-exist').toBuffer().then(function () {
|
||||
assert(false);
|
||||
done();
|
||||
}).catch(function (err) {
|
||||
assert(err instanceof Error);
|
||||
assert.strictEqual('Input file is missing: does-not-exist', err.message);
|
||||
done();
|
||||
});
|
||||
});
|
||||
it('Fail when input file path is missing', async () =>
|
||||
assert.rejects(
|
||||
() => sharp('does-not-exist').toFile('fail'),
|
||||
(err) => {
|
||||
assert.strictEqual(err.message, 'Input file is missing: does-not-exist');
|
||||
assert(err.stack.includes('at Sharp.toFile'));
|
||||
assert(err.stack.includes(__filename));
|
||||
return true;
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
describe('Fail for unsupported input', function () {
|
||||
it('Undefined', function () {
|
||||
|
||||
@@ -6,43 +6,44 @@
|
||||
const assert = require('assert');
|
||||
|
||||
const sharp = require('../../');
|
||||
const fixtures = require('../fixtures');
|
||||
|
||||
describe('Median filter', () => {
|
||||
it('1x1 window', async () => {
|
||||
const [r, g, b] = await sharp(fixtures.inputSvgSmallViewBox)
|
||||
.median(1)
|
||||
const row = [0, 3, 15, 63, 127, 255];
|
||||
const input = Buffer.from(Array.from(row, () => row).flat());
|
||||
const raw = {
|
||||
width: 6,
|
||||
height: 6,
|
||||
channels: 1
|
||||
};
|
||||
|
||||
describe('Median filter', function () {
|
||||
it('default window (3x3)', async () => {
|
||||
const data = await sharp(input, { raw })
|
||||
.median()
|
||||
.toColourspace('b-w')
|
||||
.raw()
|
||||
.toBuffer();
|
||||
|
||||
assert.deepStrictEqual({ r: 0, g: 0, b: 0 }, { r, g, b });
|
||||
assert.deepStrictEqual(data.subarray(0, 6), Buffer.from(row));
|
||||
});
|
||||
|
||||
it('3x3 window', async () => {
|
||||
const [r, g, b] = await sharp(fixtures.inputSvgSmallViewBox)
|
||||
const data = await sharp(input, { raw })
|
||||
.median(3)
|
||||
.toColourspace('b-w')
|
||||
.raw()
|
||||
.toBuffer();
|
||||
|
||||
assert.deepStrictEqual({ r: 255, g: 0, b: 127 }, { r, g, b });
|
||||
assert.deepStrictEqual(data.subarray(0, 6), Buffer.from(row));
|
||||
});
|
||||
|
||||
it('7x7 window', async () => {
|
||||
const [r, g, b] = await sharp(fixtures.inputSvgSmallViewBox)
|
||||
.median(7)
|
||||
it('5x5 window', async () => {
|
||||
const data = await sharp(input, { raw })
|
||||
.median(5)
|
||||
.toColourspace('b-w')
|
||||
.raw()
|
||||
.toBuffer();
|
||||
|
||||
assert.deepStrictEqual({ r: 255, g: 19, b: 146 }, { r, g, b });
|
||||
});
|
||||
|
||||
it('default window (3x3)', async () => {
|
||||
const [r, g, b] = await sharp(fixtures.inputSvgSmallViewBox)
|
||||
.median()
|
||||
.raw()
|
||||
.toBuffer();
|
||||
|
||||
assert.deepStrictEqual({ r: 255, g: 0, b: 127 }, { r, g, b });
|
||||
assert.deepStrictEqual(data.subarray(0, 6), Buffer.from([0, 3, 15, 15, 63, 127]));
|
||||
});
|
||||
|
||||
it('invalid radius', () => {
|
||||
|
||||
@@ -395,13 +395,27 @@ describe('Image metadata', function () {
|
||||
});
|
||||
});
|
||||
|
||||
it('Non-existent file in, Promise out', function (done) {
|
||||
sharp('fail').metadata().then(function (metadata) {
|
||||
throw new Error('Non-existent file');
|
||||
}, function (err) {
|
||||
assert.ok(!!err);
|
||||
done();
|
||||
});
|
||||
it('Non-existent file in, Promise out', async () =>
|
||||
assert.rejects(
|
||||
() => sharp('fail').metadata(),
|
||||
(err) => {
|
||||
assert.strictEqual(err.message, 'Input file is missing: fail');
|
||||
assert(err.stack.includes('at Sharp.metadata'));
|
||||
assert(err.stack.includes(__filename));
|
||||
return true;
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
it('Invalid stream in, callback out', (done) => {
|
||||
fs.createReadStream(__filename).pipe(
|
||||
sharp().metadata((err) => {
|
||||
assert.strictEqual(err.message, 'Input buffer contains unsupported image format');
|
||||
assert(err.stack.includes('at Sharp.metadata'));
|
||||
assert(err.stack.includes(__filename));
|
||||
done();
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it('Stream in, Promise out', function (done) {
|
||||
|
||||
@@ -284,4 +284,42 @@ describe('Raw pixel data', function () {
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
describe('16-bit roundtrip', () => {
|
||||
it('grey', async () => {
|
||||
const grey = 42000;
|
||||
const png = await sharp(
|
||||
Uint16Array.from([grey]),
|
||||
{ raw: { width: 1, height: 1, channels: 1 } }
|
||||
)
|
||||
.toColourspace('grey16')
|
||||
.png({ compressionLevel: 0 })
|
||||
.toBuffer();
|
||||
const raw = await sharp(png)
|
||||
.toColourspace('grey16')
|
||||
.raw({ depth: 'ushort' })
|
||||
.toBuffer();
|
||||
|
||||
assert.strictEqual(raw.readUint16LE(0), grey);
|
||||
});
|
||||
|
||||
it('RGB', async () => {
|
||||
const rgb = [10946, 28657, 46368];
|
||||
const png = await sharp(
|
||||
Uint16Array.from(rgb),
|
||||
{ raw: { width: 1, height: 1, channels: 3 } }
|
||||
)
|
||||
.toColourspace('rgb16')
|
||||
.png({ compressionLevel: 0 })
|
||||
.toBuffer();
|
||||
const raw = await sharp(png)
|
||||
.toColourspace('rgb16')
|
||||
.raw({ depth: 'ushort' })
|
||||
.toBuffer();
|
||||
|
||||
assert.strictEqual(raw.readUint16LE(0), rgb[0]);
|
||||
assert.strictEqual(raw.readUint16LE(2), rgb[1]);
|
||||
assert.strictEqual(raw.readUint16LE(4), rgb[2]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -690,11 +690,25 @@ describe('Image Stats', function () {
|
||||
it('File input with corrupt header fails gracefully', function (done) {
|
||||
sharp(fixtures.inputJpgWithCorruptHeader)
|
||||
.stats(function (err) {
|
||||
assert.strictEqual(true, !!err);
|
||||
assert(err.message.includes('Input file has corrupt header'));
|
||||
assert(err.stack.includes('at Sharp.stats'));
|
||||
assert(err.stack.includes(__filename));
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('Stream input with corrupt header fails gracefully', function (done) {
|
||||
fs.createReadStream(fixtures.inputJpgWithCorruptHeader).pipe(
|
||||
sharp()
|
||||
.stats(function (err) {
|
||||
assert(err.message.includes('Input buffer has corrupt header'));
|
||||
assert(err.stack.includes('at Sharp.stats'));
|
||||
assert(err.stack.includes(__filename));
|
||||
done();
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it('File input with corrupt header fails gracefully, Promise out', function () {
|
||||
return sharp(fixtures.inputJpgWithCorruptHeader)
|
||||
.stats().then(function (stats) {
|
||||
|
||||
@@ -141,21 +141,21 @@ describe('SVG input', function () {
|
||||
|
||||
it('Fails to render SVG larger than 32767x32767', () =>
|
||||
assert.rejects(
|
||||
() => sharp(Buffer.from('<svg width="32768" height="1" />')).toBuffer(),
|
||||
() => sharp(Buffer.from('<svg xmlns="http://www.w3.org/2000/svg" width="32768" height="1" />')).toBuffer(),
|
||||
/Input SVG image exceeds 32767x32767 pixel limit/
|
||||
)
|
||||
);
|
||||
|
||||
it('Fails to render scaled SVG larger than 32767x32767', () =>
|
||||
assert.rejects(
|
||||
() => sharp(Buffer.from('<svg width="32767" height="1" />')).resize(32768).toBuffer(),
|
||||
() => sharp(Buffer.from('<svg xmlns="http://www.w3.org/2000/svg" width="32767" height="1" />')).resize(32768).toBuffer(),
|
||||
/Input SVG image will exceed 32767x32767 pixel limit when scaled/
|
||||
)
|
||||
);
|
||||
|
||||
it('Detects SVG passed as a string', () =>
|
||||
assert.rejects(
|
||||
() => sharp('<svg></svg>').toBuffer(),
|
||||
() => sharp('<svg xmlns="http://www.w3.org/2000/svg"></svg>').toBuffer(),
|
||||
/Input file is missing, did you mean/
|
||||
)
|
||||
);
|
||||
|
||||
@@ -7,17 +7,21 @@ const assert = require('assert');
|
||||
|
||||
const sharp = require('../../');
|
||||
const fixtures = require('../fixtures');
|
||||
const { inRange } = require('../../lib/is');
|
||||
|
||||
describe('Text to image', function () {
|
||||
this.retries(3);
|
||||
|
||||
it('text with default values', async () => {
|
||||
it('text with default values', async function () {
|
||||
const output = fixtures.path('output.text-default.png');
|
||||
const text = sharp({
|
||||
text: {
|
||||
text: 'Hello, world !'
|
||||
}
|
||||
});
|
||||
if (!sharp.versions.pango) {
|
||||
return this.skip();
|
||||
}
|
||||
const info = await text.png().toFile(output);
|
||||
assert.strictEqual('png', info.format);
|
||||
assert.strictEqual(3, info.channels);
|
||||
@@ -40,22 +44,23 @@ describe('Text to image', function () {
|
||||
|
||||
it('text with width and height', function (done) {
|
||||
const output = fixtures.path('output.text-width-height.png');
|
||||
const maxWidth = 500;
|
||||
const maxHeight = 500;
|
||||
const text = sharp({
|
||||
text: {
|
||||
text: 'Hello, world!',
|
||||
width: maxWidth,
|
||||
height: maxHeight
|
||||
width: 500,
|
||||
height: 400
|
||||
}
|
||||
});
|
||||
if (!sharp.versions.pango) {
|
||||
return this.skip();
|
||||
}
|
||||
text.toFile(output, function (err, info) {
|
||||
if (err) throw err;
|
||||
assert.strictEqual('png', info.format);
|
||||
assert.strictEqual(3, info.channels);
|
||||
assert.ok(info.width <= maxWidth);
|
||||
assert.ok(info.height <= maxHeight);
|
||||
assert.ok(info.textAutofitDpi > 0);
|
||||
assert.ok(inRange(info.width, 450, 550), `Actual width ${info.width}`);
|
||||
assert.ok(inRange(info.height, 300, 450), `Actual height ${info.height}`);
|
||||
assert.ok(inRange(info.textAutofitDpi, 900, 1200), `Actual textAutofitDpi ${info.textAutofitDpi}`);
|
||||
done();
|
||||
});
|
||||
});
|
||||
@@ -69,6 +74,9 @@ describe('Text to image', function () {
|
||||
dpi
|
||||
}
|
||||
});
|
||||
if (!sharp.versions.pango) {
|
||||
return this.skip();
|
||||
}
|
||||
text.toFile(output, function (err, info) {
|
||||
if (err) throw err;
|
||||
assert.strictEqual('png', info.format);
|
||||
@@ -90,6 +98,9 @@ describe('Text to image', function () {
|
||||
dpi
|
||||
}
|
||||
});
|
||||
if (!sharp.versions.pango) {
|
||||
return this.skip();
|
||||
}
|
||||
text.toFile(output, function (err, info) {
|
||||
if (err) throw err;
|
||||
assert.strictEqual('png', info.format);
|
||||
@@ -112,6 +123,9 @@ describe('Text to image', function () {
|
||||
font: 'sans 100'
|
||||
}
|
||||
});
|
||||
if (!sharp.versions.pango) {
|
||||
return this.skip();
|
||||
}
|
||||
text.toFile(output, function (err, info) {
|
||||
if (err) throw err;
|
||||
assert.strictEqual('png', info.format);
|
||||
@@ -122,7 +136,7 @@ describe('Text to image', function () {
|
||||
});
|
||||
});
|
||||
|
||||
it('text with justify and composite', done => {
|
||||
it('text with justify and composite', function (done) {
|
||||
const output = fixtures.path('output.text-composite.png');
|
||||
const width = 500;
|
||||
const dpi = 300;
|
||||
@@ -153,6 +167,9 @@ describe('Text to image', function () {
|
||||
left: 30,
|
||||
top: 250
|
||||
}]);
|
||||
if (!sharp.versions.pango) {
|
||||
return this.skip();
|
||||
}
|
||||
text.toFile(output, function (err, info) {
|
||||
if (err) throw err;
|
||||
assert.strictEqual('png', info.format);
|
||||
|
||||
@@ -462,6 +462,18 @@ describe('TIFF', function () {
|
||||
});
|
||||
});
|
||||
|
||||
it('TIFF miniswhite true value does not throw error', function () {
|
||||
assert.doesNotThrow(function () {
|
||||
sharp().tiff({ miniswhite: true });
|
||||
});
|
||||
});
|
||||
|
||||
it('Invalid TIFF miniswhite value throws error', function () {
|
||||
assert.throws(function () {
|
||||
sharp().tiff({ miniswhite: 'true' });
|
||||
});
|
||||
});
|
||||
|
||||
it('Invalid TIFF tile value throws error', function () {
|
||||
assert.throws(function () {
|
||||
sharp().tiff({ tile: 'true' });
|
||||
|
||||
@@ -741,28 +741,6 @@ describe('Tile', function () {
|
||||
});
|
||||
});
|
||||
|
||||
it('Google layout with depth onepixel', function (done) {
|
||||
const directory = fixtures.path('output.google_depth_onepixel.dzi');
|
||||
fs.rm(directory, { recursive: true }, function () {
|
||||
sharp(fixtures.inputJpg)
|
||||
.tile({
|
||||
layout: 'google',
|
||||
depth: 'onepixel',
|
||||
size: 256
|
||||
})
|
||||
.toFile(directory, function (err, info) {
|
||||
if (err) throw err;
|
||||
assert.strictEqual('dz', info.format);
|
||||
assert.strictEqual(2725, info.width);
|
||||
assert.strictEqual(2225, info.height);
|
||||
assert.strictEqual(3, info.channels);
|
||||
assert.strictEqual('number', typeof info.size);
|
||||
|
||||
assertGoogleTiles(directory, 256, 13, done);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('Google layout with depth onetile', function (done) {
|
||||
const directory = fixtures.path('output.google_depth_onetile.dzi');
|
||||
fs.rm(directory, { recursive: true }, function () {
|
||||
|
||||
@@ -11,7 +11,7 @@ const fixtures = require('../fixtures');
|
||||
describe('Timeout', function () {
|
||||
it('Will timeout after 1s when performing slow blur operation', () => assert.rejects(
|
||||
() => sharp(fixtures.inputJpg)
|
||||
.blur(100)
|
||||
.blur(200)
|
||||
.timeout({ seconds: 1 })
|
||||
.toBuffer(),
|
||||
/timeout: [0-9]+% complete/
|
||||
|
||||
@@ -49,7 +49,7 @@ describe('Tint', function () {
|
||||
});
|
||||
|
||||
it('tints rgb image with sepia tone', function (done) {
|
||||
const output = fixtures.path('output.tint-sepia.jpg');
|
||||
const output = fixtures.path('output.tint-sepia-hex.jpg');
|
||||
sharp(fixtures.inputJpg)
|
||||
.resize(320, 240, { fastShrinkOnLoad: false })
|
||||
.tint('#704214')
|
||||
@@ -63,7 +63,7 @@ describe('Tint', function () {
|
||||
});
|
||||
|
||||
it('tints rgb image with sepia tone with rgb colour', function (done) {
|
||||
const output = fixtures.path('output.tint-sepia.jpg');
|
||||
const output = fixtures.path('output.tint-sepia-rgb.jpg');
|
||||
sharp(fixtures.inputJpg)
|
||||
.resize(320, 240, { fastShrinkOnLoad: false })
|
||||
.tint([112, 66, 20])
|
||||
|
||||
@@ -46,7 +46,9 @@ describe('Trim borders', function () {
|
||||
it('16-bit PNG with alpha channel', function (done) {
|
||||
sharp(fixtures.inputPngWithTransparency16bit)
|
||||
.resize(32, 32)
|
||||
.trim(20)
|
||||
.trim({
|
||||
threshold: 20
|
||||
})
|
||||
.toBuffer(function (err, data, info) {
|
||||
if (err) throw err;
|
||||
assert.strictEqual(true, data.length > 0);
|
||||
@@ -96,7 +98,9 @@ describe('Trim borders', function () {
|
||||
.then(rotated30 =>
|
||||
sharp(rotated30)
|
||||
.rotate(-30)
|
||||
.trim(128)
|
||||
.trim({
|
||||
threshold: 128
|
||||
})
|
||||
.toBuffer({ resolveWithObject: true })
|
||||
.then(({ info }) => {
|
||||
assert.strictEqual(20, info.width);
|
||||
@@ -198,49 +202,26 @@ describe('Trim borders', function () {
|
||||
assert.strictEqual(trimOffsetLeft, 0);
|
||||
});
|
||||
|
||||
describe('Valid parameters', function () {
|
||||
const expected = fixtures.expected('alpha-layer-1-fill-trim-resize.png');
|
||||
Object.entries({
|
||||
'Background and threshold default': undefined,
|
||||
'Background string': '#00000000',
|
||||
'Background option': {
|
||||
background: '#00000000'
|
||||
},
|
||||
'Threshold number': 10,
|
||||
'Threshold option': {
|
||||
threshold: 10
|
||||
}
|
||||
}).forEach(function ([description, parameter]) {
|
||||
it(description, function (done) {
|
||||
sharp(fixtures.inputPngOverlayLayer1)
|
||||
.resize(450, 322)
|
||||
.trim(parameter)
|
||||
.toBuffer(function (err, data, info) {
|
||||
if (err) throw err;
|
||||
assert.strictEqual('png', info.format);
|
||||
assert.strictEqual(450, info.width);
|
||||
assert.strictEqual(322, info.height);
|
||||
assert.strictEqual(-204, info.trimOffsetLeft);
|
||||
assert.strictEqual(0, info.trimOffsetTop);
|
||||
fixtures.assertSimilar(expected, data, done);
|
||||
});
|
||||
});
|
||||
});
|
||||
it('Works with line-art', async () => {
|
||||
const { info } = await sharp(fixtures.inputJpgOverlayLayer2)
|
||||
.trim({ lineArt: true })
|
||||
.toBuffer({ resolveWithObject: true });
|
||||
|
||||
assert.strictEqual(info.trimOffsetTop, -552);
|
||||
});
|
||||
|
||||
describe('Invalid parameters', function () {
|
||||
Object.entries({
|
||||
'Invalid background string': 'fail',
|
||||
'Invalid string': 'fail',
|
||||
'Invalid background option': {
|
||||
background: 'fail'
|
||||
},
|
||||
|
||||
'Negative threshold number': -1,
|
||||
'Negative threshold option': {
|
||||
threshold: -1
|
||||
},
|
||||
|
||||
Boolean: false
|
||||
'Invalid lineArt': {
|
||||
lineArt: 'fail'
|
||||
}
|
||||
}).forEach(function ([description, parameter]) {
|
||||
it(description, function () {
|
||||
assert.throws(function () {
|
||||
@@ -253,7 +234,9 @@ describe('Trim borders', function () {
|
||||
describe('Specific background colour', function () {
|
||||
it('Doesn\'t trim at all', async () => {
|
||||
const { info } = await sharp(fixtures.inputPngTrimSpecificColour)
|
||||
.trim('yellow')
|
||||
.trim({
|
||||
background: 'yellow'
|
||||
})
|
||||
.toBuffer({ resolveWithObject: true });
|
||||
|
||||
const { width, height, trimOffsetTop, trimOffsetLeft } = info;
|
||||
@@ -265,7 +248,9 @@ describe('Trim borders', function () {
|
||||
|
||||
it('Only trims the bottom', async () => {
|
||||
const { info } = await sharp(fixtures.inputPngTrimSpecificColour)
|
||||
.trim('#21468B')
|
||||
.trim({
|
||||
background: '#21468B'
|
||||
})
|
||||
.toBuffer({ resolveWithObject: true });
|
||||
|
||||
const { width, height, trimOffsetTop, trimOffsetLeft } = info;
|
||||
@@ -277,7 +262,9 @@ describe('Trim borders', function () {
|
||||
|
||||
it('Only trims the bottom, in 16-bit', async () => {
|
||||
const { info } = await sharp(fixtures.inputPngTrimSpecificColour16bit)
|
||||
.trim('#21468B')
|
||||
.trim({
|
||||
background: '#21468B'
|
||||
})
|
||||
.toBuffer({ resolveWithObject: true });
|
||||
|
||||
const { width, height, trimOffsetTop, trimOffsetLeft } = info;
|
||||
@@ -289,7 +276,9 @@ describe('Trim borders', function () {
|
||||
|
||||
it('Only trims the bottom, including alpha', async () => {
|
||||
const { info } = await sharp(fixtures.inputPngTrimSpecificColourIncludeAlpha)
|
||||
.trim('#21468B80')
|
||||
.trim({
|
||||
background: '#21468B80'
|
||||
})
|
||||
.toBuffer({ resolveWithObject: true });
|
||||
|
||||
const { width, height, trimOffsetTop, trimOffsetLeft } = info;
|
||||
|
||||
Reference in New Issue
Block a user