Compare commits

...

7 Commits

Author SHA1 Message Date
Lovell Fuller
de9bdcba0a Prerelease 0.33.0-alpha.9 2023-10-13 14:32:21 +01:00
Lovell Fuller
f8b6cb6d5b Update package names to use 'img' npm organisation 2023-10-12 17:03:37 +01:00
Thomas
e6942805b4 TypeScript: withMetadata accepts boolean (#3823) 2023-10-11 20:38:13 +01:00
Lovell Fuller
47e76c9981 Ensure all Error objects contain a stack prop #3653 2023-10-11 14:59:21 +01:00
Lovell Fuller
68fa84ef6f Remove unused gitattributes 2023-10-11 14:48:40 +01:00
Lovell Fuller
ff2fb18c76 Remove extranous quote from help text 2023-10-11 10:03:07 +01:00
Lovell Fuller
28a9b1e9fa CI: Split npm package smoke tests into a matrix 2023-10-11 10:02:20 +01:00
31 changed files with 300 additions and 154 deletions

View File

@@ -38,7 +38,7 @@ jobs:
- run: sudo docker exec sharp sh -c "npm test" - run: sudo docker exec sharp sh -c "npm test"
- run: | - run: |
sudo docker exec sharp sh -c "npm run package-from-local-build" 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 run clean"
sudo docker exec sharp sh -c "npm install --ignore-scripts" sudo docker exec sharp sh -c "npm install --ignore-scripts"
sudo docker exec sharp sh -c "npm test" sudo docker exec sharp sh -c "npm test"
@@ -62,7 +62,7 @@ jobs:
- run: sudo docker exec sharp sh -c "npm test" - run: sudo docker exec sharp sh -c "npm test"
- run: | - run: |
sudo docker exec sharp sh -c "npm run package-from-local-build" 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 run clean"
sudo docker exec sharp sh -c "npm install --ignore-scripts" sudo docker exec sharp sh -c "npm install --ignore-scripts"
sudo docker exec sharp sh -c "npm test" sudo docker exec sharp sh -c "npm test"
@@ -79,7 +79,7 @@ jobs:
- run: sudo docker exec sharp sh -c "npm test" - run: sudo docker exec sharp sh -c "npm test"
- run: | - run: |
sudo docker exec sharp sh -c "npm run package-from-local-build" 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 run clean"
sudo docker exec sharp sh -c "npm install --ignore-scripts" sudo docker exec sharp sh -c "npm install --ignore-scripts"
sudo docker exec sharp sh -c "npm test" sudo docker exec sharp sh -c "npm test"
@@ -99,7 +99,7 @@ jobs:
- run: sudo docker exec sharp sh -c "npm test" - run: sudo docker exec sharp sh -c "npm test"
- run: | - run: |
sudo docker exec sharp sh -c "npm run package-from-local-build" 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 run clean"
sudo docker exec sharp sh -c "npm install --ignore-scripts" sudo docker exec sharp sh -c "npm install --ignore-scripts"
sudo docker exec sharp sh -c "npm test" sudo docker exec sharp sh -c "npm test"

1
.gitattributes vendored
View File

@@ -1 +0,0 @@
src/libvips/* linguist-vendored

View File

@@ -106,7 +106,7 @@ jobs:
- name: Test packaging - name: Test packaging
run: | run: |
npm run package-from-local-build 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 run clean
npm install --ignore-scripts npm install --ignore-scripts
npm test npm test
@@ -141,7 +141,7 @@ jobs:
npm install --build-from-source npm install --build-from-source
npx mocha --no-config --spec=test/unit/io.js npx mocha --no-config --spec=test/unit/io.js
npm run package-from-local-build npm run package-from-local-build
npm pkg set "optionalDependencies.@sharpen/sharp-linux-arm=file:./npm/linux-arm" npm pkg set "optionalDependencies.@img/sharp-linux-arm=file:./npm/linux-arm"
npm run clean npm run clean
npm install --ignore-scripts npm install --ignore-scripts
npx mocha --no-config --spec=test/unit/io.js --timeout=30000 npx mocha --no-config --spec=test/unit/io.js --timeout=30000
@@ -182,7 +182,7 @@ jobs:
- name: Test packaging - name: Test packaging
run: | run: |
npm run package-from-local-build 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 run clean
npm install --ignore-scripts npm install --ignore-scripts
npm test npm test

View File

@@ -9,33 +9,84 @@ permissions: {}
jobs: jobs:
release-smoke-test: release-smoke-test:
name: "${{ github.ref }} ${{ matrix.name }}" name: "${{ github.ref_name }} ${{ matrix.name }}"
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.runs-on }}
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
include: include:
- name: linux-x64 - name: linux-x64-node-npm
os: ubuntu-22.04 runs-on: ubuntu-22.04
- name: darwin-x64 runtime: node
os: macos-11 package-manager: npm
- name: win32-x64 - name: linux-x64-node-pnpm
os: windows-2019 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: steps:
- name: Install Node.js - name: Install Node.js
if: ${{ matrix.runtime == 'node' }}
uses: actions/setup-node@v3 uses: actions/setup-node@v3
with: with:
node-version: 20 node-version: 20
- name: Install pnpm - name: Install pnpm
if: ${{ matrix.package-manager == 'pnpm' }}
uses: pnpm/action-setup@v2 uses: pnpm/action-setup@v2
with: with:
version: 8 version: 8
- name: Install Deno - name: Install Deno
if: ${{ matrix.runtime == 'deno' }}
uses: denoland/setup-deno@v1 uses: denoland/setup-deno@v1
with: with:
deno-version: v1.x deno-version: v1.x
- name: Install Bun - name: Install Bun
if: ${{ !contains(matrix.os, 'windows') }} if: ${{ matrix.runtime == 'bun' }}
uses: oven-sh/setup-bun@v1 uses: oven-sh/setup-bun@v1
with: with:
bun-version: latest bun-version: latest
@@ -68,33 +119,34 @@ jobs:
deepStrictEqual(['.jpg', '.jpeg', '.jpe'], sharp.format.jpeg.input.fileSuffix); deepStrictEqual(['.jpg', '.jpeg', '.jpe'], sharp.format.jpeg.input.fileSuffix);
- name: Run with Node.js + npm - name: Run with Node.js + npm
if: ${{ matrix.runtime == 'node' && matrix.package-manager == 'npm' }}
run: | run: |
npm install --ignore-scripts npm install --ignore-scripts
node release.mjs node release.mjs
rm -r node_modules/ package-lock.json
- name: Run with Node.js + pnpm - name: Run with Node.js + pnpm
if: ${{ matrix.runtime == 'node' && matrix.package-manager == 'pnpm' }}
run: | run: |
pnpm install --ignore-scripts pnpm install --ignore-scripts
node release.mjs node release.mjs
rm -r node_modules/ pnpm-lock.yaml
- name: Run with Node.js + yarn - name: Run with Node.js + yarn
if: ${{ matrix.runtime == 'node' && matrix.package-manager == 'yarn' }}
run: | run: |
corepack enable corepack enable
yarn set version stable yarn set version stable
yarn config set enableImmutableInstalls false
yarn config set enableScripts false yarn config set enableScripts false
yarn config set nodeLinker node-modules yarn config set nodeLinker node-modules
yarn install yarn install
node release.mjs node release.mjs
rm -r node_modules/ .yarn/ yarn.lock .yarnrc.yml
corepack disable
- name: Run with Deno - name: Run with Deno
if: ${{ matrix.runtime == 'deno' }}
run: deno run --allow-read --allow-ffi release.mjs run: deno run --allow-read --allow-ffi release.mjs
- name: Run with Bun - name: Run with Bun
if: ${{ !contains(matrix.os, 'windows') }} if: ${{ matrix.runtime == 'bun' }}
run: | run: |
bun install --ignore-scripts bun install --ignore-scripts
bun release.mjs bun release.mjs

5
.gitignore vendored
View File

@@ -8,11 +8,6 @@ test/bench/node_modules
test/fixtures/output* test/fixtures/output*
test/fixtures/vips-properties.xml test/fixtures/vips-properties.xml
test/leak/libvips.supp test/leak/libvips.supp
test/saliency/report.json
test/saliency/Image*
test/saliency/[Uu]serData*
!test/saliency/userData.js
.gitattributes
.DS_Store .DS_Store
.nyc_output .nyc_output
.vscode/ .vscode/

View File

@@ -14,6 +14,9 @@ Requires libvips v8.14.5
* Remove `sharp.vendor`. * Remove `sharp.vendor`.
* 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. * Make `compression` option of `heif` mandatory to help reduce HEIF vs HEIC confusion.
[#3740](https://github.com/lovell/sharp/issues/3740) [#3740](https://github.com/lovell/sharp/issues/3740)

View File

@@ -106,14 +106,14 @@ must include binaries for either the linux-x64 or linux-arm64 platforms
depending on the chosen architecture. depending on the chosen architecture.
When building your deployment package on a machine that differs from the target 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 ```sh
npm install --force @sharpen/sharp-linux-x64 npm install --force @img/sharp-linux-x64
``` ```
```sh ```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. To get the best performance select the largest memory available.
@@ -165,7 +165,7 @@ custom:
- sharp - sharp
packagerOptions: packagerOptions:
scripts: scripts:
- npm install --force @sharpen/sharp-linux-x64 - npm install --force @img/sharp-linux-x64
``` ```
## TypeScript ## TypeScript

10
lib/index.d.ts vendored
View File

@@ -640,7 +640,7 @@ declare namespace sharp {
* @param withMetadata * @param withMetadata
* @throws {Error} Invalid parameters. * @throws {Error} Invalid parameters.
*/ */
withMetadata(withMetadata?: WriteableMetadata): Sharp; withMetadata(withMetadata?: boolean | WriteableMetadata): Sharp;
/** /**
* Use these JPEG options for output image. * Use these JPEG options for output image.
@@ -1275,10 +1275,10 @@ declare namespace sharp {
} }
interface NormaliseOptions { interface NormaliseOptions {
/** Percentile below which luminance values will be underexposed. */ /** Percentile below which luminance values will be underexposed. */
lower?: number | undefined; lower?: number | undefined;
/** Percentile above which luminance values will be overexposed. */ /** Percentile above which luminance values will be overexposed. */
upper?: number | undefined; upper?: number | undefined;
} }
interface ResizeOptions { interface ResizeOptions {

View File

@@ -483,14 +483,27 @@ function _isStreamInput () {
* @returns {Promise<Object>|Sharp} * @returns {Promise<Object>|Sharp}
*/ */
function metadata (callback) { function metadata (callback) {
const stack = Error();
if (is.fn(callback)) { if (is.fn(callback)) {
if (this._isStreamInput()) { if (this._isStreamInput()) {
this.on('finish', () => { this.on('finish', () => {
this._flattenBufferIn(); 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 { } 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; return this;
} else { } else {
@@ -500,7 +513,7 @@ function metadata (callback) {
this._flattenBufferIn(); this._flattenBufferIn();
sharp.metadata(this.options, (err, metadata) => { sharp.metadata(this.options, (err, metadata) => {
if (err) { if (err) {
reject(err); reject(is.nativeError(err, stack));
} else { } else {
resolve(metadata); resolve(metadata);
} }
@@ -516,7 +529,7 @@ function metadata (callback) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
sharp.metadata(this.options, (err, metadata) => { sharp.metadata(this.options, (err, metadata) => {
if (err) { if (err) {
reject(err); reject(is.nativeError(err, stack));
} else { } else {
resolve(metadata); resolve(metadata);
} }
@@ -572,14 +585,27 @@ function metadata (callback) {
* @returns {Promise<Object>} * @returns {Promise<Object>}
*/ */
function stats (callback) { function stats (callback) {
const stack = Error();
if (is.fn(callback)) { if (is.fn(callback)) {
if (this._isStreamInput()) { if (this._isStreamInput()) {
this.on('finish', () => { this.on('finish', () => {
this._flattenBufferIn(); 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 { } 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; return this;
} else { } else {
@@ -589,7 +615,7 @@ function stats (callback) {
this._flattenBufferIn(); this._flattenBufferIn();
sharp.stats(this.options, (err, stats) => { sharp.stats(this.options, (err, stats) => {
if (err) { if (err) {
reject(err); reject(is.nativeError(err, stack));
} else { } else {
resolve(stats); resolve(stats);
} }
@@ -600,7 +626,7 @@ function stats (callback) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
sharp.stats(this.options, (err, stats) => { sharp.stats(this.options, (err, stats) => {
if (err) { if (err) {
reject(err); reject(is.nativeError(err, stack));
} else { } else {
resolve(stats); resolve(stats);
} }

View File

@@ -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 = { module.exports = {
defined, defined,
object, object,
@@ -151,5 +164,6 @@ module.exports = {
integer, integer,
inRange, inRange,
inArray, inArray,
invalidParameterError invalidParameterError,
nativeError
}; };

View File

@@ -48,7 +48,7 @@ const buildPlatformArch = () => {
const buildSharpLibvipsIncludeDir = () => { const buildSharpLibvipsIncludeDir = () => {
try { try {
return require('@sharpen/sharp-libvips-dev/include'); return require('@img/sharp-libvips-dev/include');
} catch {} } catch {}
/* istanbul ignore next */ /* istanbul ignore next */
return ''; return '';
@@ -56,7 +56,7 @@ const buildSharpLibvipsIncludeDir = () => {
const buildSharpLibvipsCPlusPlusDir = () => { const buildSharpLibvipsCPlusPlusDir = () => {
try { try {
return require('@sharpen/sharp-libvips-dev/cplusplus'); return require('@img/sharp-libvips-dev/cplusplus');
} catch {} } catch {}
/* istanbul ignore next */ /* istanbul ignore next */
return ''; return '';
@@ -64,7 +64,7 @@ const buildSharpLibvipsCPlusPlusDir = () => {
const buildSharpLibvipsLibDir = () => { const buildSharpLibvipsLibDir = () => {
try { try {
return require(`@sharpen/sharp-libvips-${buildPlatformArch()}/lib`); return require(`@img/sharp-libvips-${buildPlatformArch()}/lib`);
} catch {} } catch {}
/* istanbul ignore next */ /* istanbul ignore next */
return ''; return '';

View File

@@ -86,7 +86,8 @@ function toFile (fileOut, callback) {
} }
} else { } else {
this.options.fileOut = fileOut; this.options.fileOut = fileOut;
return this._pipeline(callback); const stack = Error();
return this._pipeline(callback, stack);
} }
return this; return this;
} }
@@ -157,7 +158,8 @@ function toBuffer (options, callback) {
this.options.resolveWithObject = false; this.options.resolveWithObject = false;
} }
this.options.fileOut = ''; this.options.fileOut = '';
return this._pipeline(is.fn(options) ? options : callback); const stack = Error();
return this._pipeline(is.fn(options) ? options : callback, stack);
} }
/** /**
@@ -1282,7 +1284,8 @@ function _read () {
/* istanbul ignore else */ /* istanbul ignore else */
if (!this.options.streamOut) { if (!this.options.streamOut) {
this.options.streamOut = true; this.options.streamOut = true;
this._pipeline(); const stack = Error();
this._pipeline(undefined, stack);
} }
} }
@@ -1291,18 +1294,30 @@ function _read () {
* Supports callback, stream and promise variants * Supports callback, stream and promise variants
* @private * @private
*/ */
function _pipeline (callback) { function _pipeline (callback, stack) {
if (typeof callback === 'function') { if (typeof callback === 'function') {
// output=file/buffer // output=file/buffer
if (this._isStreamInput()) { if (this._isStreamInput()) {
// output=file/buffer, input=stream // output=file/buffer, input=stream
this.on('finish', () => { this.on('finish', () => {
this._flattenBufferIn(); 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 { } else {
// output=file/buffer, input=file/buffer // 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; return this;
} else if (this.options.streamOut) { } else if (this.options.streamOut) {
@@ -1313,7 +1328,7 @@ function _pipeline (callback) {
this._flattenBufferIn(); this._flattenBufferIn();
sharp.pipeline(this.options, (err, data, info) => { sharp.pipeline(this.options, (err, data, info) => {
if (err) { if (err) {
this.emit('error', err); this.emit('error', is.nativeError(err, stack));
} else { } else {
this.emit('info', info); this.emit('info', info);
this.push(data); this.push(data);
@@ -1329,7 +1344,7 @@ function _pipeline (callback) {
// output=stream, input=file/buffer // output=stream, input=file/buffer
sharp.pipeline(this.options, (err, data, info) => { sharp.pipeline(this.options, (err, data, info) => {
if (err) { if (err) {
this.emit('error', err); this.emit('error', is.nativeError(err, stack));
} else { } else {
this.emit('info', info); this.emit('info', info);
this.push(data); this.push(data);
@@ -1348,7 +1363,7 @@ function _pipeline (callback) {
this._flattenBufferIn(); this._flattenBufferIn();
sharp.pipeline(this.options, (err, data, info) => { sharp.pipeline(this.options, (err, data, info) => {
if (err) { if (err) {
reject(err); reject(is.nativeError(err, stack));
} else { } else {
if (this.options.resolveWithObject) { if (this.options.resolveWithObject) {
resolve({ data, info }); resolve({ data, info });
@@ -1364,7 +1379,7 @@ function _pipeline (callback) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
sharp.pipeline(this.options, (err, data, info) => { sharp.pipeline(this.options, (err, data, info) => {
if (err) { if (err) {
reject(err); reject(is.nativeError(err, stack));
} else { } else {
if (this.options.resolveWithObject) { if (this.options.resolveWithObject) {
resolve({ data, info }); resolve({ data, info });

View File

@@ -18,7 +18,7 @@ try {
} catch (errLocal) { } catch (errLocal) {
try { try {
// Check for runtime package // Check for runtime package
module.exports = require(`@sharpen/sharp-${runtimePlatform}/sharp.node`); module.exports = require(`@img/sharp-${runtimePlatform}/sharp.node`);
} catch (errPackage) { } catch (errPackage) {
const help = ['Could not load the "sharp" module at runtime']; const help = ['Could not load the "sharp" module at runtime'];
if (errLocal.code !== 'MODULE_NOT_FOUND') { if (errLocal.code !== 'MODULE_NOT_FOUND') {
@@ -31,13 +31,13 @@ try {
// Common error messages // Common error messages
if (prebuiltPlatforms.includes(runtimePlatform)) { if (prebuiltPlatforms.includes(runtimePlatform)) {
help.push('- Add an explicit dependency for the runtime platform:'); help.push('- Add an explicit dependency for the runtime platform:');
help.push(` npm install --force @sharpen/sharp-${runtimePlatform}"`); help.push(` npm install --force @img/sharp-${runtimePlatform}`);
} else { } else {
help.push(`- The ${runtimePlatform} platform requires manual installation of libvips >= ${minimumLibvipsVersion}`); help.push(`- The ${runtimePlatform} platform requires manual installation of libvips >= ${minimumLibvipsVersion}`);
} }
if (isLinux && /symbol not found/i.test(errPackage)) { if (isLinux && /symbol not found/i.test(errPackage)) {
try { try {
const { engines } = require(`@sharpen/sharp-libvips-${runtimePlatform}/package`); const { engines } = require(`@img/sharp-libvips-${runtimePlatform}/package`);
const libcFound = `${familySync()} ${versionSync()}`; const libcFound = `${familySync()} ${versionSync()}`;
const libcRequires = `${engines.musl ? 'musl' : 'glibc'} ${engines.musl || engines.glibc}`; const libcRequires = `${engines.musl ? 'musl' : 'glibc'} ${engines.musl || engines.glibc}`;
help.push('- Update your OS:'); help.push('- Update your OS:');

View File

@@ -60,10 +60,10 @@ let versions = {
/* istanbul ignore next */ /* istanbul ignore next */
if (!libvipsVersion.isGlobal) { if (!libvipsVersion.isGlobal) {
try { try {
versions = require(`@sharpen/sharp-${runtimePlatform}/versions`); versions = require(`@img/sharp-${runtimePlatform}/versions`);
} catch (_) { } catch (_) {
try { try {
versions = require(`@sharpen/sharp-libvips-${runtimePlatform}/versions`); versions = require(`@img/sharp-libvips-${runtimePlatform}/versions`);
} catch (_) {} } catch (_) {}
} }
} }

View File

@@ -1,7 +1,8 @@
{ {
"name": "@sharpen/sharp-darwin-arm64", "name": "@img/sharp-darwin-arm64",
"version": "0.0.1-alpha.8", "version": "0.33.0-alpha.9",
"description": "Prebuilt sharp for use with macOS ARM64", "description": "Prebuilt sharp for use with macOS ARM64",
"author": "Lovell Fuller <npm@lovell.info>",
"homepage": "https://sharp.pixelplumbing.com", "homepage": "https://sharp.pixelplumbing.com",
"repository": { "repository": {
"type": "git", "type": "git",
@@ -14,7 +15,7 @@
}, },
"preferUnplugged": true, "preferUnplugged": true,
"optionalDependencies": { "optionalDependencies": {
"@sharpen/sharp-libvips-darwin-arm64": "0.0.1-alpha.2" "@img/sharp-libvips-darwin-arm64": "0.0.1"
}, },
"files": [ "files": [
"lib" "lib"

View File

@@ -1,7 +1,8 @@
{ {
"name": "@sharpen/sharp-darwin-x64", "name": "@img/sharp-darwin-x64",
"version": "0.0.1-alpha.8", "version": "0.33.0-alpha.9",
"description": "Prebuilt sharp for use with macOS x64", "description": "Prebuilt sharp for use with macOS x64",
"author": "Lovell Fuller <npm@lovell.info>",
"homepage": "https://sharp.pixelplumbing.com", "homepage": "https://sharp.pixelplumbing.com",
"repository": { "repository": {
"type": "git", "type": "git",
@@ -14,7 +15,7 @@
}, },
"preferUnplugged": true, "preferUnplugged": true,
"optionalDependencies": { "optionalDependencies": {
"@sharpen/sharp-libvips-darwin-x64": "0.0.1-alpha.2" "@img/sharp-libvips-darwin-x64": "0.0.1"
}, },
"files": [ "files": [
"lib" "lib"

View File

@@ -5,7 +5,7 @@
// Populate contents of all packages with the current GitHub release // Populate contents of all packages with the current GitHub release
const { writeFile, copyFile, rm } = require('node:fs/promises'); const { readFile, writeFile, appendFile, copyFile, rm } = require('node:fs/promises');
const path = require('node:path'); const path = require('node:path');
const { Readable } = require('node:stream'); const { Readable } = require('node:stream');
const { pipeline } = require('node:stream/promises'); const { pipeline } = require('node:stream/promises');
@@ -60,11 +60,12 @@ workspaces.map(async platform => {
await copyFile(path.join(__dirname, '..', 'LICENSE'), path.join(dir, 'LICENSE')); await copyFile(path.join(__dirname, '..', 'LICENSE'), path.join(dir, 'LICENSE'));
// Copy Windows-specific files // Copy Windows-specific files
if (platform.startsWith('win32-')) { if (platform.startsWith('win32-')) {
const sharpLibvipsDir = path.join(require(`@sharpen/sharp-libvips-${platform}/lib`), '..'); const sharpLibvipsDir = path.join(require(`@img/sharp-libvips-${platform}/lib`), '..');
await Promise.all( // Copy versions.json
['versions.json', 'THIRD-PARTY-NOTICES.md'].map( await copyFile(path.join(sharpLibvipsDir, 'versions.json'), path.join(dir, 'versions.json'));
filename => copyFile(path.join(sharpLibvipsDir, filename), path.join(dir, filename)) // 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);
} }
}); });

View File

@@ -1,7 +1,8 @@
{ {
"name": "@sharpen/sharp-linux-arm", "name": "@img/sharp-linux-arm",
"version": "0.0.1-alpha.8", "version": "0.33.0-alpha.9",
"description": "Prebuilt sharp for use with Linux (glibc) ARM (32-bit)", "description": "Prebuilt sharp for use with Linux (glibc) ARM (32-bit)",
"author": "Lovell Fuller <npm@lovell.info>",
"homepage": "https://sharp.pixelplumbing.com", "homepage": "https://sharp.pixelplumbing.com",
"repository": { "repository": {
"type": "git", "type": "git",
@@ -14,7 +15,7 @@
}, },
"preferUnplugged": true, "preferUnplugged": true,
"optionalDependencies": { "optionalDependencies": {
"@sharpen/sharp-libvips-linux-arm": "0.0.1-alpha.2" "@img/sharp-libvips-linux-arm": "0.0.1"
}, },
"files": [ "files": [
"lib" "lib"

View File

@@ -1,7 +1,8 @@
{ {
"name": "@sharpen/sharp-linux-arm64", "name": "@img/sharp-linux-arm64",
"version": "0.0.1-alpha.8", "version": "0.33.0-alpha.9",
"description": "Prebuilt sharp for use with Linux (glibc) ARM64", "description": "Prebuilt sharp for use with Linux (glibc) ARM64",
"author": "Lovell Fuller <npm@lovell.info>",
"homepage": "https://sharp.pixelplumbing.com", "homepage": "https://sharp.pixelplumbing.com",
"repository": { "repository": {
"type": "git", "type": "git",
@@ -14,7 +15,7 @@
}, },
"preferUnplugged": true, "preferUnplugged": true,
"optionalDependencies": { "optionalDependencies": {
"@sharpen/sharp-libvips-linux-arm64": "0.0.1-alpha.2" "@img/sharp-libvips-linux-arm64": "0.0.1"
}, },
"files": [ "files": [
"lib" "lib"

View File

@@ -1,7 +1,8 @@
{ {
"name": "@sharpen/sharp-linux-x64", "name": "@img/sharp-linux-x64",
"version": "0.0.1-alpha.8", "version": "0.33.0-alpha.9",
"description": "Prebuilt sharp for use with Linux (glibc) x64", "description": "Prebuilt sharp for use with Linux (glibc) x64",
"author": "Lovell Fuller <npm@lovell.info>",
"homepage": "https://sharp.pixelplumbing.com", "homepage": "https://sharp.pixelplumbing.com",
"repository": { "repository": {
"type": "git", "type": "git",
@@ -14,7 +15,7 @@
}, },
"preferUnplugged": true, "preferUnplugged": true,
"optionalDependencies": { "optionalDependencies": {
"@sharpen/sharp-libvips-linux-x64": "0.0.1-alpha.2" "@img/sharp-libvips-linux-x64": "0.0.1"
}, },
"files": [ "files": [
"lib" "lib"

View File

@@ -1,7 +1,8 @@
{ {
"name": "@sharpen/sharp-linuxmusl-arm64", "name": "@img/sharp-linuxmusl-arm64",
"version": "0.0.1-alpha.8", "version": "0.33.0-alpha.9",
"description": "Prebuilt sharp for use with Linux (musl) ARM64", "description": "Prebuilt sharp for use with Linux (musl) ARM64",
"author": "Lovell Fuller <npm@lovell.info>",
"homepage": "https://sharp.pixelplumbing.com", "homepage": "https://sharp.pixelplumbing.com",
"repository": { "repository": {
"type": "git", "type": "git",
@@ -14,7 +15,7 @@
}, },
"preferUnplugged": true, "preferUnplugged": true,
"optionalDependencies": { "optionalDependencies": {
"@sharpen/sharp-libvips-linuxmusl-arm64": "0.0.1-alpha.2" "@img/sharp-libvips-linuxmusl-arm64": "0.0.1"
}, },
"files": [ "files": [
"lib" "lib"

View File

@@ -1,7 +1,8 @@
{ {
"name": "@sharpen/sharp-linuxmusl-x64", "name": "@img/sharp-linuxmusl-x64",
"version": "0.0.1-alpha.8", "version": "0.33.0-alpha.9",
"description": "Prebuilt sharp for use with Linux (musl) x64", "description": "Prebuilt sharp for use with Linux (musl) x64",
"author": "Lovell Fuller <npm@lovell.info>",
"homepage": "https://sharp.pixelplumbing.com", "homepage": "https://sharp.pixelplumbing.com",
"repository": { "repository": {
"type": "git", "type": "git",
@@ -14,7 +15,7 @@
}, },
"preferUnplugged": true, "preferUnplugged": true,
"optionalDependencies": { "optionalDependencies": {
"@sharpen/sharp-libvips-linuxmusl-x64": "0.0.1-alpha.2" "@img/sharp-libvips-linuxmusl-x64": "0.0.1"
}, },
"files": [ "files": [
"lib" "lib"

View File

@@ -1,6 +1,6 @@
{ {
"name": "@sharpen/sharp", "name": "@img/sharp",
"version": "0.0.1-alpha.8", "version": "0.33.0-alpha.9",
"private": "true", "private": "true",
"workspaces": [ "workspaces": [
"darwin-x64", "darwin-x64",

View File

@@ -1,7 +1,8 @@
{ {
"name": "@sharpen/sharp-win32-ia32", "name": "@img/sharp-win32-ia32",
"version": "0.0.1-alpha.8", "version": "0.33.0-alpha.9",
"description": "Prebuilt sharp for use with Windows x86 (32-bit)", "description": "Prebuilt sharp for use with Windows x86 (32-bit)",
"author": "Lovell Fuller <npm@lovell.info>",
"homepage": "https://sharp.pixelplumbing.com", "homepage": "https://sharp.pixelplumbing.com",
"repository": { "repository": {
"type": "git", "type": "git",
@@ -15,8 +16,7 @@
"preferUnplugged": true, "preferUnplugged": true,
"files": [ "files": [
"lib", "lib",
"versions.json", "versions.json"
"THIRD-PARTY-NOTICES.md"
], ],
"publishConfig": { "publishConfig": {
"access": "public" "access": "public"

View File

@@ -1,7 +1,8 @@
{ {
"name": "@sharpen/sharp-win32-x64", "name": "@img/sharp-win32-x64",
"version": "0.0.1-alpha.8", "version": "0.33.0-alpha.9",
"description": "Prebuilt sharp for use with Windows x64", "description": "Prebuilt sharp for use with Windows x64",
"author": "Lovell Fuller <npm@lovell.info>",
"homepage": "https://sharp.pixelplumbing.com", "homepage": "https://sharp.pixelplumbing.com",
"repository": { "repository": {
"type": "git", "type": "git",
@@ -15,8 +16,7 @@
"preferUnplugged": true, "preferUnplugged": true,
"files": [ "files": [
"lib", "lib",
"versions.json", "versions.json"
"THIRD-PARTY-NOTICES.md"
], ],
"publishConfig": { "publishConfig": {
"access": "public" "access": "public"
@@ -24,7 +24,8 @@
"type": "commonjs", "type": "commonjs",
"exports": { "exports": {
"./sharp.node": "./lib/sharp-win32-x64.node", "./sharp.node": "./lib/sharp-win32-x64.node",
"./package": "./package.json" "./package": "./package.json",
"./versions": "./versions.json"
}, },
"engines": { "engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0", "node": "^18.17.0 || ^20.3.0 || >=21.0.0",

View File

@@ -1,7 +1,7 @@
{ {
"name": "sharp", "name": "sharp",
"description": "High performance Node.js image processing, the fastest module to resize JPEG, PNG, WebP, GIF, AVIF and TIFF images", "description": "High performance Node.js image processing, the fastest module to resize JPEG, PNG, WebP, GIF, AVIF and TIFF images",
"version": "0.33.0-alpha.8", "version": "0.33.0-alpha.9",
"author": "Lovell Fuller <npm@lovell.info>", "author": "Lovell Fuller <npm@lovell.info>",
"homepage": "https://github.com/lovell/sharp", "homepage": "https://github.com/lovell/sharp",
"contributors": [ "contributors": [
@@ -139,27 +139,27 @@
"semver": "^7.5.4" "semver": "^7.5.4"
}, },
"optionalDependencies": { "optionalDependencies": {
"@sharpen/sharp-darwin-arm64": "0.0.1-alpha.8", "@img/sharp-darwin-arm64": "0.33.0-alpha.9",
"@sharpen/sharp-darwin-x64": "0.0.1-alpha.8", "@img/sharp-darwin-x64": "0.33.0-alpha.9",
"@sharpen/sharp-libvips-darwin-arm64": "0.0.1-alpha.2", "@img/sharp-libvips-darwin-arm64": "0.0.1",
"@sharpen/sharp-libvips-darwin-x64": "0.0.1-alpha.2", "@img/sharp-libvips-darwin-x64": "0.0.1",
"@sharpen/sharp-libvips-linux-arm": "0.0.1-alpha.2", "@img/sharp-libvips-linux-arm": "0.0.1",
"@sharpen/sharp-libvips-linux-arm64": "0.0.1-alpha.2", "@img/sharp-libvips-linux-arm64": "0.0.1",
"@sharpen/sharp-libvips-linux-x64": "0.0.1-alpha.2", "@img/sharp-libvips-linux-x64": "0.0.1",
"@sharpen/sharp-libvips-linuxmusl-arm64": "0.0.1-alpha.2", "@img/sharp-libvips-linuxmusl-arm64": "0.0.1",
"@sharpen/sharp-libvips-linuxmusl-x64": "0.0.1-alpha.2", "@img/sharp-libvips-linuxmusl-x64": "0.0.1",
"@sharpen/sharp-linux-arm": "0.0.1-alpha.8", "@img/sharp-linux-arm": "0.33.0-alpha.9",
"@sharpen/sharp-linux-arm64": "0.0.1-alpha.8", "@img/sharp-linux-arm64": "0.33.0-alpha.9",
"@sharpen/sharp-linux-x64": "0.0.1-alpha.8", "@img/sharp-linux-x64": "0.33.0-alpha.9",
"@sharpen/sharp-linuxmusl-arm64": "0.0.1-alpha.8", "@img/sharp-linuxmusl-arm64": "0.33.0-alpha.9",
"@sharpen/sharp-linuxmusl-x64": "0.0.1-alpha.8", "@img/sharp-linuxmusl-x64": "0.33.0-alpha.9",
"@sharpen/sharp-win32-ia32": "0.0.1-alpha.8", "@img/sharp-win32-ia32": "0.33.0-alpha.9",
"@sharpen/sharp-win32-x64": "0.0.1-alpha.8" "@img/sharp-win32-x64": "0.33.0-alpha.9"
}, },
"devDependencies": { "devDependencies": {
"@sharpen/sharp-libvips-dev": "0.0.1-alpha.2", "@img/sharp-libvips-dev": "0.0.1",
"@sharpen/sharp-libvips-win32-ia32": "0.0.1-alpha.2", "@img/sharp-libvips-win32-ia32": "0.0.1",
"@sharpen/sharp-libvips-win32-x64": "0.0.1-alpha.2", "@img/sharp-libvips-win32-x64": "0.0.1",
"@types/node": "*", "@types/node": "*",
"async": "^3.2.4", "async": "^3.2.4",
"cc": "^3.0.1", "cc": "^3.0.1",

View File

@@ -157,8 +157,8 @@
'OTHER_LDFLAGS': [ 'OTHER_LDFLAGS': [
# Ensure runtime linking is relative to sharp.node # Ensure runtime linking is relative to sharp.node
'-Wl,-rpath,\'@loader_path/../../sharp-libvips-<(platform_and_arch)/lib\'', '-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/@img/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/@img/sharp-libvips-<(platform_and_arch)/lib\''
] ]
} }
}], }],
@@ -178,8 +178,8 @@
'-Wl,-s', '-Wl,-s',
'-Wl,--disable-new-dtags', '-Wl,--disable-new-dtags',
'-Wl,-rpath=\'$$ORIGIN/../../sharp-libvips-<(platform_and_arch)/lib\'', '-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/@img/sharp-libvips-<(platform_and_arch)/lib\'',
'-Wl,-rpath=\'$$ORIGIN/../../../node_modules/@sharpen/sharp-libvips-<(platform_and_arch)/lib\'' '-Wl,-rpath=\'$$ORIGIN/../../../node_modules/@img/sharp-libvips-<(platform_and_arch)/lib\''
] ]
} }
}] }]

View File

@@ -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: 'text' }).toFile('out.webp');
sharp('input.tiff').webp({ preset: 'default' }).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);

View File

@@ -459,27 +459,29 @@ describe('Input/output', function () {
}); });
}); });
it('Fail when input is invalid Buffer', function (done) { it('Fail when input is invalid Buffer', async () =>
sharp(Buffer.from([0x1, 0x2, 0x3, 0x4])).toBuffer().then(function () { assert.rejects(
assert(false); () => sharp(Buffer.from([0x1, 0x2, 0x3, 0x4])).toBuffer(),
done(); (err) => {
}).catch(function (err) { assert.strictEqual(err.message, 'Input buffer contains unsupported image format');
assert(err instanceof Error); assert(err.stack.includes('at Sharp.toBuffer'));
assert.strictEqual('Input buffer contains unsupported image format', err.message); assert(err.stack.includes(__filename));
done(); return true;
}); }
}); )
);
it('Fail when input file path is missing', function (done) { it('Fail when input file path is missing', async () =>
sharp('does-not-exist').toBuffer().then(function () { assert.rejects(
assert(false); () => sharp('does-not-exist').toFile('fail'),
done(); (err) => {
}).catch(function (err) { assert.strictEqual(err.message, 'Input file is missing: does-not-exist');
assert(err instanceof Error); assert(err.stack.includes('at Sharp.toFile'));
assert.strictEqual('Input file is missing: does-not-exist', err.message); assert(err.stack.includes(__filename));
done(); return true;
}); }
}); )
);
describe('Fail for unsupported input', function () { describe('Fail for unsupported input', function () {
it('Undefined', function () { it('Undefined', function () {

View File

@@ -395,13 +395,27 @@ describe('Image metadata', function () {
}); });
}); });
it('Non-existent file in, Promise out', function (done) { it('Non-existent file in, Promise out', async () =>
sharp('fail').metadata().then(function (metadata) { assert.rejects(
throw new Error('Non-existent file'); () => sharp('fail').metadata(),
}, function (err) { (err) => {
assert.ok(!!err); assert.strictEqual(err.message, 'Input file is missing: fail');
done(); 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) { it('Stream in, Promise out', function (done) {

View File

@@ -690,11 +690,25 @@ describe('Image Stats', function () {
it('File input with corrupt header fails gracefully', function (done) { it('File input with corrupt header fails gracefully', function (done) {
sharp(fixtures.inputJpgWithCorruptHeader) sharp(fixtures.inputJpgWithCorruptHeader)
.stats(function (err) { .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(); 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 () { it('File input with corrupt header fails gracefully, Promise out', function () {
return sharp(fixtures.inputJpgWithCorruptHeader) return sharp(fixtures.inputJpgWithCorruptHeader)
.stats().then(function (stats) { .stats().then(function (stats) {