Compare commits

..

14 Commits

Author SHA1 Message Date
Lovell Fuller
e1bad5470e Remove install script, building from source is now opt-in
The vast majority of people don't need this. Package managers
are (correctly) starting to block install scripts by default,
so this change should reduce install-time warnings.
2025-12-21 12:36:40 +00:00
Lovell Fuller
1a2c1c8833 Add version to shared library filename to help avoid collision 2025-12-21 12:00:30 +00:00
Lovell Fuller
aaeded2b67 Add withGainMap to process HDR JPEGs with embedded gain map #4314 2025-12-19 15:41:09 +00:00
Lovell Fuller
f6cdd36559 Bump devDeps 2025-12-18 22:47:14 +00:00
Lovell Fuller
283c7d3f0c Drop Node.js 18, now requires Node.js >= 20.9.0 2025-12-17 15:08:34 +00:00
Lovell Fuller
34c39fa194 Upgrade to libvips v8.18.0-rc.2 2025-12-17 13:26:51 +00:00
Lovell Fuller
7b4c476243 CI: Update to latest FreeBSD 16 2025-12-16 19:59:31 +00:00
Lovell Fuller
084a30f8bf Docs: clarify metadata 'format' property #4483 2025-12-10 15:38:14 +00:00
Kleis Auke Wolthuizen
3609c61a22 Tests: fix JP2 suite with global libvips (#4477) 2025-11-15 10:55:58 +00:00
Jiralite
dc6820b49f TypeScript: tag deprecated constructor properties (#4474) 2025-11-10 16:41:22 +00:00
Sylvester Keil
f2a49d19c9 Fix invalid escape sequence (#4471) 2025-11-07 11:39:39 +00:00
Lovell Fuller
e062456868 Release v0.34.5 2025-11-06 14:06:31 +00:00
Lovell Fuller
6450c704a6 Prerelease v0.34.5-rc.1 2025-11-06 11:34:00 +00:00
Lovell Fuller
f7c95d1bf0 TypeScript: consolidate a few enum-like properties 2025-11-06 11:15:28 +00:00
51 changed files with 446 additions and 248 deletions

View File

@@ -1,5 +1,5 @@
freebsd_instance:
image_family: freebsd-15-0
image_family: freebsd-16-0-snap
task:
name: FreeBSD

View File

@@ -31,7 +31,7 @@ please open an issue against that package instead.
<!-- Please place an [x] in the relevant box to confirm. -->
- [ ] I am using Node.js with a version that satisfies `^18.17.0 || ^20.3.0 || >=21.0.0`
- [ ] I am using Node.js with a version that satisfies `>=20.9.0`
- [ ] I am using Deno
- [ ] I am using Bun

View File

@@ -9,8 +9,8 @@ jobs:
contents: read
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v5
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: "24"
- run: npm install --ignore-scripts
@@ -31,123 +31,129 @@ jobs:
- os: ubuntu-24.04
container: rockylinux:8
nodejs_arch: x64
nodejs_version: "^18.17.0"
nodejs_version_major: 18
nodejs_version: "^20.9.0"
nodejs_version_major: 20
platform: linux-x64
package: true
- os: ubuntu-24.04
container: rockylinux:8
nodejs_arch: x64
nodejs_version: "^20.3.0"
nodejs_version_major: 20
platform: linux-x64
- os: ubuntu-24.04
container: rockylinux:8
nodejs_arch: x64
nodejs_version: "^22.9.0"
nodejs_version: "^22"
nodejs_version_major: 22
platform: linux-x64
- os: ubuntu-24.04
container: node:18-alpine3.17
nodejs_version_major: 18
platform: linuxmusl-x64
package: true
container: rockylinux:8
nodejs_arch: x64
nodejs_version: "^24"
nodejs_version_major: 24
platform: linux-x64
- os: ubuntu-24.04
container: node:20-alpine3.18
nodejs_version_major: 20
platform: linuxmusl-x64
package: true
- os: ubuntu-24.04
container: node:22-alpine3.20
nodejs_version_major: 22
platform: linuxmusl-x64
- os: ubuntu-24.04
container: node:24-alpine3.22
nodejs_version_major: 24
platform: linuxmusl-x64
- os: ubuntu-24.04-arm
container: arm64v8/rockylinux:8
nodejs_arch: arm64
nodejs_version: "^18.17.0"
nodejs_version_major: 18
nodejs_version: "^20.9.0"
nodejs_version_major: 20
platform: linux-arm64
package: true
- os: ubuntu-24.04-arm
container: arm64v8/rockylinux:8
nodejs_arch: arm64
nodejs_version: "^20.3.0"
nodejs_version_major: 20
nodejs_version: "^22"
nodejs_version_major: 22
platform: linux-arm64
- os: ubuntu-24.04-arm
container: arm64v8/rockylinux:8
nodejs_arch: arm64
nodejs_version: "^24"
nodejs_version_major: 24
platform: linux-arm64
- os: macos-15-intel
nodejs_arch: x64
nodejs_version: "^18.17.0"
nodejs_version_major: 18
nodejs_version: "^20.9.0"
nodejs_version_major: 20
platform: darwin-x64
package: true
- os: macos-15-intel
nodejs_arch: x64
nodejs_version: "^20.3.0"
nodejs_version_major: 20
nodejs_version: "^22"
nodejs_version_major: 22
platform: darwin-x64
- os: macos-15-intel
nodejs_arch: x64
nodejs_version: "^22.9.0"
nodejs_version_major: 22
nodejs_version: "^24"
nodejs_version_major: 24
platform: darwin-x64
- os: macos-15
nodejs_arch: arm64
nodejs_version: "^18.17.0"
nodejs_version_major: 18
nodejs_version: "^20.9.0"
nodejs_version_major: 20
platform: darwin-arm64
package: true
- os: macos-15
nodejs_arch: arm64
nodejs_version: "^20.3.0"
nodejs_version_major: 20
nodejs_version: "^22"
nodejs_version_major: 22
platform: darwin-arm64
- os: macos-15
nodejs_arch: arm64
nodejs_version: "^22.9.0"
nodejs_version_major: 22
nodejs_version: "^24"
nodejs_version_major: 24
platform: darwin-arm64
- os: windows-2022
nodejs_arch: x86
nodejs_version: "18.18.2" # pinned to avoid 18.19.0 and npm 10
nodejs_version_major: 18
nodejs_version: "^20.9.0"
nodejs_version_major: 20
platform: win32-ia32
package: true
- os: windows-2022
nodejs_arch: x86
nodejs_version: "^20.3.0"
nodejs_version_major: 20
platform: win32-ia32
- os: windows-2022
nodejs_arch: x86
nodejs_version: "^22.9.0"
nodejs_version: "^22"
nodejs_version_major: 22
platform: win32-ia32
- os: windows-2022
nodejs_arch: x64
nodejs_version: "^18.17.0"
nodejs_version_major: 18
nodejs_version: "^20.9.0"
nodejs_version_major: 20
platform: win32-x64
package: true
- os: windows-2022
nodejs_arch: x64
nodejs_version: "^20.3.0"
nodejs_version_major: 20
nodejs_version: "^22"
nodejs_version_major: 22
platform: win32-x64
- os: windows-2022
nodejs_arch: x64
nodejs_version: "^22.9.0"
nodejs_version_major: 22
nodejs_version: "^24"
nodejs_version_major: 24
platform: win32-x64
- os: windows-11-arm
nodejs_arch: arm64
nodejs_version: "^20.3.0"
nodejs_version: "^20.9.0"
nodejs_version_major: 20
platform: win32-arm64
package: true
- os: windows-11-arm
nodejs_arch: arm64
nodejs_version: "^22.9.0"
nodejs_version: "^22"
nodejs_version_major: 22
platform: win32-arm64
- os: windows-11-arm
nodejs_arch: arm64
nodejs_version: "^24"
nodejs_version_major: 24
platform: win32-arm64
steps:
- name: Dependencies (Rocky Linux glibc)
if: contains(matrix.container, 'rockylinux')
@@ -159,22 +165,22 @@ jobs:
run: apk add build-base git python3 font-noto --update-cache
- name: Dependencies (Python 3.11 - macOS, Windows)
if: contains(matrix.os, 'macos') || contains(matrix.os, 'windows')
uses: actions/setup-python@v5
uses: actions/setup-python@v6
with:
python-version: "3.12"
- name: Dependencies (Node.js)
if: "!contains(matrix.platform, 'linuxmusl')"
uses: actions/setup-node@v5
uses: actions/setup-node@v6
with:
node-version: ${{ matrix.nodejs_version }}
architecture: ${{ matrix.nodejs_arch }}
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- run: npm install
- run: npm run build
- run: npm run test-unit
- if: matrix.package
run: npm run package-from-local-build
- uses: actions/upload-artifact@v4
- uses: actions/upload-artifact@v6
if: matrix.package
with:
name: ${{ matrix.platform }}
@@ -191,16 +197,18 @@ jobs:
image: ${{ matrix.container }}
volumes:
- /opt:/opt:rw,rshared
- /opt:/__e/node20:ro,rshared
- /opt:/__e/node24:ro,rshared
strategy:
fail-fast: false
matrix:
include:
- container: node:18-alpine3.17
nodejs_version_major: 18
package: true
- container: node:20-alpine3.18
- container: node:20-alpine3.20
nodejs_version_major: 20
package: true
- container: node:22-alpine3.20
nodejs_version_major: 22
- container: node:24-alpine3.22
nodejs_version_major: 24
steps:
- name: Allow Linux musl containers on ARM64 runners # https://github.com/actions/runner/issues/801#issuecomment-2394425757
shell: sh
@@ -211,13 +219,13 @@ jobs:
ln -s /usr/bin/node /opt/bin/node
- name: Dependencies
run: apk add build-base git python3 font-noto --update-cache
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- run: npm install
- run: npm run build
- run: npm run test-unit
- if: matrix.package
run: npm run package-from-local-build
- uses: actions/upload-artifact@v4
- uses: actions/upload-artifact@v6
if: matrix.package
with:
name: linuxmusl-arm64
@@ -238,20 +246,20 @@ jobs:
base_image: "balenalib/rpi-raspbian:bullseye"
nodejs_arch: armv6l
nodejs_hostname: unofficial-builds.nodejs.org
nodejs_version: "18.17.0"
nodejs_version_major: 18
nodejs_version: "20.9.0"
nodejs_version_major: 20
- platform: linux-s390x
base_image: "--platform=linux/s390x s390x/debian:bookworm"
nodejs_arch: s390x
nodejs_hostname: nodejs.org
nodejs_version: "18.17.0"
nodejs_version_major: 18
nodejs_version: "20.9.0"
nodejs_version_major: 20
- platform: linux-ppc64
base_image: "--platform=linux/ppc64le ppc64le/debian:bookworm"
nodejs_arch: ppc64le
nodejs_hostname: nodejs.org
nodejs_version: "18.17.0"
nodejs_version_major: 18
nodejs_version: "20.9.0"
nodejs_version_major: 20
- platform: linux-riscv64
base_image: "--platform=linux/riscv64 riscv64/debian:trixie"
compiler_flags: "-march=rv64gc"
@@ -260,7 +268,7 @@ jobs:
nodejs_version: "20.19.5"
nodejs_version_major: 20
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- uses: uraimo/run-on-arch-action@v3
with:
arch: none
@@ -279,7 +287,7 @@ jobs:
npm run build
node --test test/unit/io.js
npm run package-from-local-build
- uses: actions/upload-artifact@v4
- uses: actions/upload-artifact@v6
with:
name: ${{ matrix.platform }}
path: npm/${{ matrix.platform }}
@@ -291,7 +299,7 @@ jobs:
needs: lint
name: "build-wasm32 [package]"
runs-on: ubuntu-24.04
container: "emscripten/emsdk:4.0.18"
container: "emscripten/emsdk:4.0.21"
steps:
- uses: actions/checkout@v4
- name: Dependencies
@@ -311,7 +319,7 @@ jobs:
test "$EMSCRIPTEN_VERSION_LIBVIPS" = "$EMSCRIPTEN_VERSION_SHARP"
- run: emmake npm run test-unit
- run: emmake npm run package-from-local-build
- uses: actions/upload-artifact@v4
- uses: actions/upload-artifact@v6
with:
name: wasm32
path: npm/wasm32
@@ -329,12 +337,12 @@ jobs:
- build-emscripten
steps:
- uses: actions/checkout@v4
- uses: actions/download-artifact@v4
- uses: actions/download-artifact@v7
with:
path: npm
- name: Create npm workspace tarball
run: tar -vcaf npm-workspace.tar.xz --directory npm --exclude=from-local-build.js .
- uses: actions/setup-node@v5
- uses: actions/setup-node@v6
with:
node-version: '24'
- name: Create release notes

View File

@@ -96,7 +96,7 @@ jobs:
steps:
- name: Install Node.js
if: ${{ matrix.runtime == 'node' }}
uses: actions/setup-node@v5
uses: actions/setup-node@v6
with:
node-version: 20
- name: Install pnpm

2
.gitignore vendored
View File

@@ -1,7 +1,6 @@
src/build
src/node_modules
node_modules
/coverage
npm/*/*
!npm/*/package.json
test/bench/node_modules
@@ -9,7 +8,6 @@ test/fixtures/output*
test/fixtures/vips-properties.xml
test/leak/libvips.supp
.DS_Store
.nyc_output
.vscode/
package-lock.json
.idea

View File

@@ -8,7 +8,7 @@ smaller, web-friendly JPEG, PNG, WebP, GIF and AVIF images of varying dimensions
It can be used with all JavaScript runtimes
that provide support for Node-API v9, including
Node.js (^18.17.0 or >= 20.3.0), Deno and Bun.
Node.js (>= 20.9.0), Deno and Bun.
Resizing an image is typically 4x-5x faster than using the
quickest ImageMagick and GraphicsMagick settings

View File

@@ -1,5 +1,5 @@
{
"$schema": "https://biomejs.dev/schemas/2.3.4/schema.json",
"$schema": "https://biomejs.dev/schemas/2.3.10/schema.json",
"vcs": {
"enabled": true,
"clientKind": "git",

View File

@@ -17,7 +17,7 @@ Dimensions in the response will respect the `page` and `pages` properties of the
A `Promise` is returned when `callback` is not provided.
- `format`: Name of decoder used to decompress image data e.g. `jpeg`, `png`, `webp`, `gif`, `svg`
- `format`: Name of decoder used to parse image e.g. `jpeg`, `png`, `webp`, `gif`, `svg`, `heif`, `tiff`
- `size`: Total size of image in bytes, for Stream and Buffer input only
- `width`: Number of pixels wide (EXIF orientation is not taken into consideration, see example below)
- `height`: Number of pixels high (EXIF orientation is not taken into consideration, see example below)
@@ -50,6 +50,7 @@ A `Promise` is returned when `callback` is not provided.
- `tifftagPhotoshop`: Buffer containing raw TIFFTAG_PHOTOSHOP data, if present
- `formatMagick`: String containing format for images loaded via *magick
- `comments`: Array of keyword/text pairs representing PNG text blocks, if present.
- `gainMap.image`: HDR gain map, if present, as compressed JPEG image.

View File

@@ -250,6 +250,27 @@ const outputWithP3 = await sharp(input)
```
## withGainMap
> withGainMap() ⇒ <code>Sharp</code>
If the input contains gain map metadata, use it to convert the main image to HDR (High Dynamic Range) before further processing.
The input gain map is discarded.
If the output is JPEG, generate and attach a new ISO 21496-1 gain map.
JPEG output options other than `quality` are ignored.
This feature is experimental and the API may change.
**Since**: 0.35.0
**Example**
```js
const outputWithGainMap = await sharp(inputWithGainMap)
.withGainMap()
.toBuffer();
```
## keepXmp
> keepXmp() ⇒ <code>Sharp</code>

View File

@@ -1,5 +1,5 @@
---
title: v0.34.5 - TBD
title: v0.34.5 - 6th November 2025
slug: changelog/v0.34.5
---

View File

@@ -0,0 +1,14 @@
---
title: v0.35.0 - TBC
slug: changelog/v0.35.0
---
* Breaking: Drop support for Node.js 18, now requires Node.js >= 20.9.0.
* Breaking: Remove `install` script from `package.json` file.
Compiling from source is now opt-in via the `build` script.
* Upgrade to libvips v8.18.0 for upstream bug fixes.
* Add `withGainMap` to process HDR JPEG images with embedded gain maps.
[#4314](https://github.com/lovell/sharp/issues/4314)

View File

@@ -10,7 +10,7 @@ smaller, web-friendly JPEG, PNG, WebP, GIF and AVIF images of varying dimensions
It can be used with all JavaScript runtimes
that provide support for Node-API v9, including
Node.js >= 18.17.0, Deno and Bun.
Node.js >= 20.9.0, Deno and Bun.
Resizing an image is typically 4x-5x faster than using the
quickest ImageMagick and GraphicsMagick settings

View File

@@ -20,10 +20,6 @@ npm install sharp
pnpm add sharp
```
When using `pnpm`, add `sharp` to
[ignoredBuiltDependencies](https://pnpm.io/settings#ignoredbuiltdependencies)
to silence warnings.
```sh frame="none"
yarn add sharp
```
@@ -39,7 +35,7 @@ deno run --allow-env --allow-ffi --allow-read --allow-sys ...
## Prerequisites
* Node-API v9 compatible runtime e.g. Node.js ^18.17.0 or >=20.3.0.
* Node-API v9 compatible runtime e.g. Node.js >= 20.9.0.
## Prebuilt binaries
@@ -112,13 +108,13 @@ and on macOS when running Node.js under Rosetta.
## Building from source
This module will be compiled from source when:
```sh frame="none"
npm install sharp
npm explore sharp -- npm run build
```
* a globally-installed libvips is detected, or
* using `npm explore sharp -- npm run build`, or
* using the deprecated `npm run --build-from-source` at `npm install` time.
The logic to detect a globally-installed libvips can be skipped by setting the
The build process will search for a globally-installed libvips.
This detection logic can be skipped by setting the
`SHARP_IGNORE_GLOBAL_LIBVIPS` (never try to use it) or
`SHARP_FORCE_GLOBAL_LIBVIPS` (always try to use it, even when missing or outdated)
environment variables.
@@ -129,21 +125,12 @@ Building from source requires:
* [node-addon-api](https://www.npmjs.com/package/node-addon-api) version 7+
* [node-gyp](https://github.com/nodejs/node-gyp#installation) version 9+ and its dependencies
There is an install-time check for these dependencies.
If `node-addon-api` or `node-gyp` cannot be found, try adding them via:
```sh frame="none"
npm install --save node-addon-api node-gyp
```
When using `pnpm`, you may need to add `sharp` to
[onlyBuiltDependencies](https://pnpm.io/settings#onlybuiltdependencies)
to ensure the installation script can be run.
For cross-compiling, the `--platform`, `--arch` and `--libc` npm flags
(or the `npm_config_platform`, `npm_config_arch` and `npm_config_libc` environment variables)
can be used to configure the target environment.
## WebAssembly
Experimental support is provided for runtime environments that provide
@@ -166,10 +153,8 @@ as well as the additional [building from source](#building-from-source) dependen
```sh frame="none"
pkg install -y pkgconf vips
```
```sh frame="none"
cd /usr/ports/graphics/vips/ && make install clean
npm install sharp
npm explore sharp -- npm run build
```
## Linux memory allocator

View File

@@ -10,7 +10,7 @@ const {
spawnRebuild,
} = require('../lib/libvips');
log('Attempting to build from source via node-gyp');
log('Building from source');
log('See https://sharp.pixelplumbing.com/install#building-from-source');
try {
@@ -29,7 +29,7 @@ try {
}
if (useGlobalLibvips(log)) {
log(`Detected globally-installed libvips v${globalLibvipsVersion()}`);
log(`Found globally-installed libvips v${globalLibvipsVersion()}`);
}
const status = spawnRebuild();

View File

@@ -1,14 +0,0 @@
/*!
Copyright 2013 Lovell Fuller and others.
SPDX-License-Identifier: Apache-2.0
*/
try {
const { useGlobalLibvips } = require('../lib/libvips');
if (useGlobalLibvips() || process.env.npm_config_build_from_source) {
process.exit(1);
}
} catch (err) {
const summary = err.message.split(/\n/).slice(0, 1);
console.log(`sharp: skipping install check: ${summary}`);
}

View File

@@ -313,6 +313,7 @@ const Sharp = function (input, options) {
withExif: {},
withExifMerge: true,
withXmp: '',
withGainMap: false,
resolveWithObject: false,
loop: -1,
delay: [],

28
lib/index.d.ts vendored
View File

@@ -860,6 +860,7 @@ declare namespace sharp {
| JxlOptions
| GifOptions
| Jp2Options
| RawOptions
| TiffOptions,
): Sharp;
@@ -1027,11 +1028,11 @@ declare namespace sharp {
openSlide?: OpenSlideInputOptions | undefined;
/** JPEG 2000 specific input options */
jp2?: Jp2InputOptions | undefined;
/** Deprecated: use tiff.subifd instead */
/** @deprecated Use {@link SharpOptions.tiff} instead */
subifd?: number | undefined;
/** Deprecated: use pdf.background instead */
/** @deprecated Use {@link SharpOptions.pdf} instead */
pdfBackground?: Colour | Color | undefined;
/** Deprecated: use openSlide.level instead */
/** @deprecated Use {@link SharpOptions.openSlide} instead */
level?: number | undefined;
/** Set to `true` to read all frames/pages of an animated image (equivalent of setting `pages` to `-1`). (optional, default false) */
animated?: boolean | undefined;
@@ -1181,6 +1182,10 @@ declare namespace sharp {
'IFD3'?: ExifDir;
}
type HeifCompression = 'av1' | 'hevc';
type Unit = 'inch' | 'cm';
interface WriteableMetadata {
/** Number of pixels per inch (DPI) */
density?: number | undefined;
@@ -1259,7 +1264,7 @@ declare namespace sharp {
/** Buffer containing raw TIFFTAG_PHOTOSHOP data, if present */
tifftagPhotoshop?: Buffer | undefined;
/** The encoder used to compress an HEIF file, `av1` (AVIF) or `hevc` (HEIC) */
compression?: 'av1' | 'hevc';
compression?: HeifCompression | undefined;
/** Default background colour, if present, for PNG (bKGD) and GIF images */
background?: { r: number; g: number; b: number } | { gray: number };
/** Details of each level in a multi-level image provided as an array of objects, requires libvips compiled with support for OpenSlide */
@@ -1267,11 +1272,13 @@ declare namespace sharp {
/** Number of Sub Image File Directories in an OME-TIFF image */
subifds?: number | undefined;
/** The unit of resolution (density) */
resolutionUnit?: 'inch' | 'cm' | undefined;
resolutionUnit?: Unit | undefined;
/** String containing format for images loaded via *magick */
formatMagick?: string | undefined;
/** Array of keyword/text pairs representing PNG text blocks, if present. */
comments?: CommentsMetadata[] | undefined;
/** HDR gain map, if present */
gainMap?: GainMapMetadata | undefined;
}
interface LevelMetadata {
@@ -1284,6 +1291,11 @@ declare namespace sharp {
text: string;
}
interface GainMapMetadata {
/** JPEG image */
image: Buffer;
}
interface Stats {
/** Array of channel statistics for each channel in the image. */
channels: ChannelStats[];
@@ -1423,7 +1435,7 @@ declare namespace sharp {
/** quality, integer 1-100 (optional, default 50) */
quality?: number | undefined;
/** compression format: av1, hevc (optional, default 'av1') */
compression?: 'av1' | 'hevc' | undefined;
compression?: HeifCompression | undefined;
/** use lossless compression (optional, default false) */
lossless?: boolean | undefined;
/** Level of CPU effort to reduce file size, between 0 (fastest) and 9 (slowest) (optional, default 4) */
@@ -1481,7 +1493,7 @@ declare namespace sharp {
/** Write 1-bit images as miniswhite (optional, default false) */
miniswhite?: boolean | undefined;
/** Resolution unit options: inch, cm (optional, default 'inch') */
resolutionUnit?: 'inch' | 'cm' | undefined;
resolutionUnit?: Unit | undefined;
}
interface PngOptions extends OutputOptions {
@@ -1606,7 +1618,7 @@ declare namespace sharp {
}
interface RawOptions {
depth?: 'char' | 'uchar' | 'short' | 'ushort' | 'int' | 'uint' | 'float' | 'complex' | 'double' | 'dpcomplex';
depth?: keyof DepthEnum;
}
/** 1 for grayscale, 2 for grayscale + alpha, 3 for sRGB, 4 for CMYK or RGBA */

View File

@@ -574,7 +574,7 @@ function _isStreamInput () {
*
* A `Promise` is returned when `callback` is not provided.
*
* - `format`: Name of decoder used to decompress image data e.g. `jpeg`, `png`, `webp`, `gif`, `svg`
* - `format`: Name of decoder used to parse image e.g. `jpeg`, `png`, `webp`, `gif`, `svg`, `heif`, `tiff`
* - `size`: Total size of image in bytes, for Stream and Buffer input only
* - `width`: Number of pixels wide (EXIF orientation is not taken into consideration, see example below)
* - `height`: Number of pixels high (EXIF orientation is not taken into consideration, see example below)
@@ -607,6 +607,7 @@ function _isStreamInput () {
* - `tifftagPhotoshop`: Buffer containing raw TIFFTAG_PHOTOSHOP data, if present
* - `formatMagick`: String containing format for images loaded via *magick
* - `comments`: Array of keyword/text pairs representing PNG text blocks, if present.
* - `gainMap.image`: HDR gain map, if present, as compressed JPEG image.
*
* @example
* const metadata = await sharp(input).metadata();

View File

@@ -319,6 +319,30 @@ function withIccProfile (icc, options) {
return this;
}
/**
* If the input contains gain map metadata, use it to convert the main image to HDR (High Dynamic Range) before further processing.
* The input gain map is discarded.
*
* If the output is JPEG, generate and attach a new ISO 21496-1 gain map.
* JPEG output options other than `quality` are ignored.
*
* This feature is experimental and the API may change.
*
* @since 0.35.0
*
* @example
* const outputWithGainMap = await sharp(inputWithGainMap)
* .withGainMap()
* .toBuffer();
*
* @returns {Sharp}
*/
function withGainMap() {
this.options.withGainMap = true;
this.options.colourspace = 'scrgb';
return this;
}
/**
* Keep XMP metadata from the input image in the output image.
*
@@ -1640,6 +1664,7 @@ module.exports = (Sharp) => {
withExifMerge,
keepIccProfile,
withIccProfile,
withGainMap,
keepXmp,
withXmp,
keepMetadata,

View File

@@ -7,12 +7,13 @@
const { familySync, versionSync } = require('detect-libc');
const { version } = require('../package.json');
const { runtimePlatformArch, isUnsupportedNodeRuntime, prebuiltPlatforms, minimumLibvipsVersion } = require('./libvips');
const runtimePlatform = runtimePlatformArch();
const paths = [
`../src/build/Release/sharp-${runtimePlatform}.node`,
'../src/build/Release/sharp-wasm32.node',
`../src/build/Release/sharp-${runtimePlatform}-${version}.node`,
`../src/build/Release/sharp-wasm32-${version}.node`,
`@img/sharp-${runtimePlatform}/sharp.node`,
'@img/sharp-wasm32/sharp.node'
];
@@ -72,6 +73,7 @@ if (sharp) {
} else {
help.push(
`- Manually install libvips >= ${minimumLibvipsVersion}`,
' See https://sharp.pixelplumbing.com/install#building-from-source',
'- Add experimental WebAssembly-based dependencies:',
' npm install --cpu=wasm32 sharp',
' npm install @img/sharp-wasm32'

View File

@@ -1,6 +1,6 @@
{
"name": "@img/sharp-darwin-arm64",
"version": "0.34.5-rc.0",
"version": "0.34.5",
"description": "Prebuilt sharp for use with macOS 64-bit ARM",
"author": "Lovell Fuller <npm@lovell.info>",
"homepage": "https://sharp.pixelplumbing.com",
@@ -15,9 +15,10 @@
},
"preferUnplugged": true,
"optionalDependencies": {
"@img/sharp-libvips-darwin-arm64": "1.2.4"
"@img/sharp-libvips-darwin-arm64": "1.3.0-rc.1"
},
"files": [
"index.cjs",
"lib"
],
"publishConfig": {
@@ -25,11 +26,11 @@
},
"type": "commonjs",
"exports": {
"./sharp.node": "./lib/sharp-darwin-arm64.node",
"./sharp.node": "./index.cjs",
"./package": "./package.json"
},
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
"node": ">=20.9.0"
},
"os": [
"darwin"

View File

@@ -1,6 +1,6 @@
{
"name": "@img/sharp-darwin-x64",
"version": "0.34.5-rc.0",
"version": "0.34.5",
"description": "Prebuilt sharp for use with macOS x64",
"author": "Lovell Fuller <npm@lovell.info>",
"homepage": "https://sharp.pixelplumbing.com",
@@ -15,9 +15,10 @@
},
"preferUnplugged": true,
"optionalDependencies": {
"@img/sharp-libvips-darwin-x64": "1.2.4"
"@img/sharp-libvips-darwin-x64": "1.3.0-rc.1"
},
"files": [
"index.cjs",
"lib"
],
"publishConfig": {
@@ -25,11 +26,11 @@
},
"type": "commonjs",
"exports": {
"./sharp.node": "./lib/sharp-darwin-x64.node",
"./sharp.node": "./index.cjs",
"./package": "./package.json"
},
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
"node": ">=20.9.0"
},
"os": [
"darwin"

View File

@@ -44,9 +44,10 @@ cpSync(releaseDir, libDir, {
}
});
// Generate README
const { name, description } = require(`./${platform}/package.json`);
// Generate README and index.cjs
const { version, name, description } = require(`./${platform}/package.json`);
writeFileSync(join(destDir, 'README.md'), `# \`${name}\`\n\n${description}.\n${licensing}`);
writeFileSync(join(destDir, 'index.cjs'), `module.exports = require('./lib/sharp-${platform}-${version}.node');`);
// Copy Apache-2.0 LICENSE
copyFileSync(join(__dirname, '..', 'LICENSE'), join(destDir, 'LICENSE'));

View File

@@ -1,6 +1,6 @@
{
"name": "@img/sharp-linux-arm",
"version": "0.34.5-rc.0",
"version": "0.34.5",
"description": "Prebuilt sharp for use with Linux (glibc) ARM (32-bit)",
"author": "Lovell Fuller <npm@lovell.info>",
"homepage": "https://sharp.pixelplumbing.com",
@@ -15,9 +15,10 @@
},
"preferUnplugged": true,
"optionalDependencies": {
"@img/sharp-libvips-linux-arm": "1.2.4"
"@img/sharp-libvips-linux-arm": "1.3.0-rc.1"
},
"files": [
"index.cjs",
"lib"
],
"publishConfig": {
@@ -25,11 +26,11 @@
},
"type": "commonjs",
"exports": {
"./sharp.node": "./lib/sharp-linux-arm.node",
"./sharp.node": "./index.cjs",
"./package": "./package.json"
},
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
"node": ">=20.9.0"
},
"config": {
"glibc": ">=2.31"

View File

@@ -1,6 +1,6 @@
{
"name": "@img/sharp-linux-arm64",
"version": "0.34.5-rc.0",
"version": "0.34.5",
"description": "Prebuilt sharp for use with Linux (glibc) 64-bit ARM",
"author": "Lovell Fuller <npm@lovell.info>",
"homepage": "https://sharp.pixelplumbing.com",
@@ -15,9 +15,10 @@
},
"preferUnplugged": true,
"optionalDependencies": {
"@img/sharp-libvips-linux-arm64": "1.2.4"
"@img/sharp-libvips-linux-arm64": "1.3.0-rc.1"
},
"files": [
"index.cjs",
"lib"
],
"publishConfig": {
@@ -25,11 +26,11 @@
},
"type": "commonjs",
"exports": {
"./sharp.node": "./lib/sharp-linux-arm64.node",
"./sharp.node": "./index.cjs",
"./package": "./package.json"
},
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
"node": ">=20.9.0"
},
"config": {
"glibc": ">=2.26"

View File

@@ -1,6 +1,6 @@
{
"name": "@img/sharp-linux-ppc64",
"version": "0.34.5-rc.0",
"version": "0.34.5",
"description": "Prebuilt sharp for use with Linux (glibc) ppc64",
"author": "Lovell Fuller <npm@lovell.info>",
"homepage": "https://sharp.pixelplumbing.com",
@@ -15,9 +15,10 @@
},
"preferUnplugged": true,
"optionalDependencies": {
"@img/sharp-libvips-linux-ppc64": "1.2.4"
"@img/sharp-libvips-linux-ppc64": "1.3.0-rc.1"
},
"files": [
"index.cjs",
"lib"
],
"publishConfig": {
@@ -25,11 +26,11 @@
},
"type": "commonjs",
"exports": {
"./sharp.node": "./lib/sharp-linux-ppc64.node",
"./sharp.node": "./index.cjs",
"./package": "./package.json"
},
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
"node": ">=20.9.0"
},
"config": {
"glibc": ">=2.36"

View File

@@ -1,6 +1,6 @@
{
"name": "@img/sharp-linux-riscv64",
"version": "0.34.5-rc.0",
"version": "0.34.5",
"description": "Prebuilt sharp for use with Linux (glibc) RISC-V 64-bit",
"author": "Lovell Fuller <npm@lovell.info>",
"homepage": "https://sharp.pixelplumbing.com",
@@ -15,9 +15,10 @@
},
"preferUnplugged": true,
"optionalDependencies": {
"@img/sharp-libvips-linux-riscv64": "1.2.4"
"@img/sharp-libvips-linux-riscv64": "1.3.0-rc.1"
},
"files": [
"index.cjs",
"lib"
],
"publishConfig": {
@@ -25,11 +26,11 @@
},
"type": "commonjs",
"exports": {
"./sharp.node": "./lib/sharp-linux-riscv64.node",
"./sharp.node": "./index.cjs",
"./package": "./package.json"
},
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
"node": ">=20.9.0"
},
"config": {
"glibc": ">=2.41"

View File

@@ -1,6 +1,6 @@
{
"name": "@img/sharp-linux-s390x",
"version": "0.34.5-rc.0",
"version": "0.34.5",
"description": "Prebuilt sharp for use with Linux (glibc) s390x",
"author": "Lovell Fuller <npm@lovell.info>",
"homepage": "https://sharp.pixelplumbing.com",
@@ -15,9 +15,10 @@
},
"preferUnplugged": true,
"optionalDependencies": {
"@img/sharp-libvips-linux-s390x": "1.2.4"
"@img/sharp-libvips-linux-s390x": "1.3.0-rc.1"
},
"files": [
"index.cjs",
"lib"
],
"publishConfig": {
@@ -25,11 +26,11 @@
},
"type": "commonjs",
"exports": {
"./sharp.node": "./lib/sharp-linux-s390x.node",
"./sharp.node": "./index.cjs",
"./package": "./package.json"
},
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
"node": ">=20.9.0"
},
"config": {
"glibc": ">=2.36"

View File

@@ -1,6 +1,6 @@
{
"name": "@img/sharp-linux-x64",
"version": "0.34.5-rc.0",
"version": "0.34.5",
"description": "Prebuilt sharp for use with Linux (glibc) x64",
"author": "Lovell Fuller <npm@lovell.info>",
"homepage": "https://sharp.pixelplumbing.com",
@@ -15,9 +15,10 @@
},
"preferUnplugged": true,
"optionalDependencies": {
"@img/sharp-libvips-linux-x64": "1.2.4"
"@img/sharp-libvips-linux-x64": "1.3.0-rc.1"
},
"files": [
"index.cjs",
"lib"
],
"publishConfig": {
@@ -25,11 +26,11 @@
},
"type": "commonjs",
"exports": {
"./sharp.node": "./lib/sharp-linux-x64.node",
"./sharp.node": "./index.cjs",
"./package": "./package.json"
},
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
"node": ">=20.9.0"
},
"config": {
"glibc": ">=2.26"

View File

@@ -1,6 +1,6 @@
{
"name": "@img/sharp-linuxmusl-arm64",
"version": "0.34.5-rc.0",
"version": "0.34.5",
"description": "Prebuilt sharp for use with Linux (musl) 64-bit ARM",
"author": "Lovell Fuller <npm@lovell.info>",
"homepage": "https://sharp.pixelplumbing.com",
@@ -15,9 +15,10 @@
},
"preferUnplugged": true,
"optionalDependencies": {
"@img/sharp-libvips-linuxmusl-arm64": "1.2.4"
"@img/sharp-libvips-linuxmusl-arm64": "1.3.0-rc.1"
},
"files": [
"index.cjs",
"lib"
],
"publishConfig": {
@@ -25,11 +26,11 @@
},
"type": "commonjs",
"exports": {
"./sharp.node": "./lib/sharp-linuxmusl-arm64.node",
"./sharp.node": "./index.cjs",
"./package": "./package.json"
},
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
"node": ">=20.9.0"
},
"config": {
"musl": ">=1.2.2"

View File

@@ -1,6 +1,6 @@
{
"name": "@img/sharp-linuxmusl-x64",
"version": "0.34.5-rc.0",
"version": "0.34.5",
"description": "Prebuilt sharp for use with Linux (musl) x64",
"author": "Lovell Fuller <npm@lovell.info>",
"homepage": "https://sharp.pixelplumbing.com",
@@ -15,9 +15,10 @@
},
"preferUnplugged": true,
"optionalDependencies": {
"@img/sharp-libvips-linuxmusl-x64": "1.2.4"
"@img/sharp-libvips-linuxmusl-x64": "1.3.0-rc.1"
},
"files": [
"index.cjs",
"lib"
],
"publishConfig": {
@@ -25,11 +26,11 @@
},
"type": "commonjs",
"exports": {
"./sharp.node": "./lib/sharp-linuxmusl-x64.node",
"./sharp.node": "./index.cjs",
"./package": "./package.json"
},
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
"node": ">=20.9.0"
},
"config": {
"musl": ">=1.2.2"

View File

@@ -1,6 +1,6 @@
{
"name": "@img/sharp",
"version": "0.34.5-rc.0",
"version": "0.34.5",
"private": "true",
"workspaces": [
"darwin-arm64",
@@ -8,6 +8,7 @@
"linux-arm",
"linux-arm64",
"linux-ppc64",
"linux-riscv64",
"linux-s390x",
"linux-x64",
"linuxmusl-arm64",

View File

@@ -1,6 +1,6 @@
{
"name": "@img/sharp-wasm32",
"version": "0.34.5-rc.0",
"version": "0.34.5",
"description": "Prebuilt sharp for use with wasm32",
"author": "Lovell Fuller <npm@lovell.info>",
"homepage": "https://sharp.pixelplumbing.com",
@@ -23,15 +23,15 @@
},
"type": "commonjs",
"exports": {
"./sharp.node": "./lib/sharp-wasm32.node.js",
"./sharp.node": "./index.cjs",
"./package": "./package.json",
"./versions": "./versions.json"
},
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
"node": ">=20.9.0"
},
"dependencies": {
"@emnapi/runtime": "^1.7.0"
"@emnapi/runtime": "^1.7.1"
},
"cpu": [
"wasm32"

View File

@@ -1,6 +1,6 @@
{
"name": "@img/sharp-win32-arm64",
"version": "0.34.5-rc.0",
"version": "0.34.5",
"description": "Prebuilt sharp for use with Windows 64-bit ARM",
"author": "Lovell Fuller <npm@lovell.info>",
"homepage": "https://sharp.pixelplumbing.com",
@@ -15,6 +15,7 @@
},
"preferUnplugged": true,
"files": [
"index.cjs",
"lib",
"versions.json"
],
@@ -23,12 +24,12 @@
},
"type": "commonjs",
"exports": {
"./sharp.node": "./lib/sharp-win32-arm64.node",
"./sharp.node": "./index.cjs",
"./package": "./package.json",
"./versions": "./versions.json"
},
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
"node": ">=20.9.0"
},
"os": [
"win32"

View File

@@ -1,6 +1,6 @@
{
"name": "@img/sharp-win32-ia32",
"version": "0.34.5-rc.0",
"version": "0.34.5",
"description": "Prebuilt sharp for use with Windows x86 (32-bit)",
"author": "Lovell Fuller <npm@lovell.info>",
"homepage": "https://sharp.pixelplumbing.com",
@@ -15,6 +15,7 @@
},
"preferUnplugged": true,
"files": [
"index.cjs",
"lib",
"versions.json"
],
@@ -23,12 +24,12 @@
},
"type": "commonjs",
"exports": {
"./sharp.node": "./lib/sharp-win32-ia32.node",
"./sharp.node": "./index.cjs",
"./package": "./package.json",
"./versions": "./versions.json"
},
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
"node": ">=20.9.0"
},
"os": [
"win32"

View File

@@ -1,6 +1,6 @@
{
"name": "@img/sharp-win32-x64",
"version": "0.34.5-rc.0",
"version": "0.34.5",
"description": "Prebuilt sharp for use with Windows x64",
"author": "Lovell Fuller <npm@lovell.info>",
"homepage": "https://sharp.pixelplumbing.com",
@@ -15,6 +15,7 @@
},
"preferUnplugged": true,
"files": [
"index.cjs",
"lib",
"versions.json"
],
@@ -23,12 +24,12 @@
},
"type": "commonjs",
"exports": {
"./sharp.node": "./lib/sharp-win32-x64.node",
"./sharp.node": "./index.cjs",
"./package": "./package.json",
"./versions": "./versions.json"
},
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
"node": ">=20.9.0"
},
"os": [
"win32"

View File

@@ -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.34.5-rc.0",
"version": "0.34.5",
"author": "Lovell Fuller <npm@lovell.info>",
"homepage": "https://sharp.pixelplumbing.com",
"contributors": [
@@ -93,8 +93,7 @@
],
"scripts": {
"build": "node install/build.js",
"install": "node install/check.js || npm run build",
"clean": "rm -rf src/build/ .nyc_output/ coverage/ test/fixtures/output.*",
"clean": "rm -rf src/build/ test/fixtures/output.*",
"test": "npm run lint && npm run test-unit",
"lint": "npm run lint-cpp && npm run lint-js && npm run lint-types",
"lint-cpp": "cpplint --quiet src/*.h src/*.cc",
@@ -144,65 +143,59 @@
"semver": "^7.7.3"
},
"optionalDependencies": {
"@img/sharp-darwin-arm64": "0.34.5-rc.0",
"@img/sharp-darwin-x64": "0.34.5-rc.0",
"@img/sharp-libvips-darwin-arm64": "1.2.4",
"@img/sharp-libvips-darwin-x64": "1.2.4",
"@img/sharp-libvips-linux-arm": "1.2.4",
"@img/sharp-libvips-linux-arm64": "1.2.4",
"@img/sharp-libvips-linux-ppc64": "1.2.4",
"@img/sharp-libvips-linux-riscv64": "1.2.4",
"@img/sharp-libvips-linux-s390x": "1.2.4",
"@img/sharp-libvips-linux-x64": "1.2.4",
"@img/sharp-libvips-linuxmusl-arm64": "1.2.4",
"@img/sharp-libvips-linuxmusl-x64": "1.2.4",
"@img/sharp-linux-arm": "0.34.5-rc.0",
"@img/sharp-linux-arm64": "0.34.5-rc.0",
"@img/sharp-linux-ppc64": "0.34.5-rc.0",
"@img/sharp-linux-riscv64": "0.34.5-rc.0",
"@img/sharp-linux-s390x": "0.34.5-rc.0",
"@img/sharp-linux-x64": "0.34.5-rc.0",
"@img/sharp-linuxmusl-arm64": "0.34.5-rc.0",
"@img/sharp-linuxmusl-x64": "0.34.5-rc.0",
"@img/sharp-wasm32": "0.34.5-rc.0",
"@img/sharp-win32-arm64": "0.34.5-rc.0",
"@img/sharp-win32-ia32": "0.34.5-rc.0",
"@img/sharp-win32-x64": "0.34.5-rc.0"
"@img/sharp-darwin-arm64": "0.34.5",
"@img/sharp-darwin-x64": "0.34.5",
"@img/sharp-libvips-darwin-arm64": "1.3.0-rc.1",
"@img/sharp-libvips-darwin-x64": "1.3.0-rc.1",
"@img/sharp-libvips-linux-arm": "1.3.0-rc.1",
"@img/sharp-libvips-linux-arm64": "1.3.0-rc.1",
"@img/sharp-libvips-linux-ppc64": "1.3.0-rc.1",
"@img/sharp-libvips-linux-riscv64": "1.3.0-rc.1",
"@img/sharp-libvips-linux-s390x": "1.3.0-rc.1",
"@img/sharp-libvips-linux-x64": "1.3.0-rc.1",
"@img/sharp-libvips-linuxmusl-arm64": "1.3.0-rc.1",
"@img/sharp-libvips-linuxmusl-x64": "1.3.0-rc.1",
"@img/sharp-linux-arm": "0.34.5",
"@img/sharp-linux-arm64": "0.34.5",
"@img/sharp-linux-ppc64": "0.34.5",
"@img/sharp-linux-riscv64": "0.34.5",
"@img/sharp-linux-s390x": "0.34.5",
"@img/sharp-linux-x64": "0.34.5",
"@img/sharp-linuxmusl-arm64": "0.34.5",
"@img/sharp-linuxmusl-x64": "0.34.5",
"@img/sharp-wasm32": "0.34.5",
"@img/sharp-win32-arm64": "0.34.5",
"@img/sharp-win32-ia32": "0.34.5",
"@img/sharp-win32-x64": "0.34.5"
},
"devDependencies": {
"@biomejs/biome": "^2.3.4",
"@biomejs/biome": "^2.3.10",
"@cpplint/cli": "^0.1.0",
"@emnapi/runtime": "^1.7.0",
"@img/sharp-libvips-dev": "1.2.4",
"@img/sharp-libvips-dev-wasm32": "1.2.4",
"@img/sharp-libvips-win32-arm64": "1.2.4",
"@img/sharp-libvips-win32-ia32": "1.2.4",
"@img/sharp-libvips-win32-x64": "1.2.4",
"@emnapi/runtime": "^1.7.1",
"@img/sharp-libvips-dev": "1.3.0-rc.1",
"@img/sharp-libvips-dev-wasm32": "1.3.0-rc.1",
"@img/sharp-libvips-win32-arm64": "1.3.0-rc.1",
"@img/sharp-libvips-win32-ia32": "1.3.0-rc.1",
"@img/sharp-libvips-win32-x64": "1.3.0-rc.1",
"@types/node": "*",
"emnapi": "^1.7.0",
"exif-reader": "^2.0.2",
"emnapi": "^1.7.1",
"exif-reader": "^2.0.3",
"extract-zip": "^2.0.1",
"icc": "^3.0.0",
"jsdoc-to-markdown": "^9.1.3",
"node-addon-api": "^8.5.0",
"node-gyp": "^11.5.0",
"node-gyp": "^12.1.0",
"tar-fs": "^3.1.1",
"tsd": "^0.33.0"
},
"license": "Apache-2.0",
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
"node": ">=20.9.0"
},
"config": {
"libvips": ">=8.17.3"
"libvips": ">=8.18.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
},
"cc": {
"linelength": "120",
"filter": [
"build/include"
]
}
}

View File

@@ -5,6 +5,7 @@
'variables': {
'vips_version': '<!(node -p "require(\'../lib/libvips\').minimumLibvipsVersion")',
'platform_and_arch': '<!(node -p "require(\'../lib/libvips\').buildPlatformArch()")',
'sharp_version': '<!(node -p "require(\'../package.json\').version")',
'sharp_libvips_version': '<!(node -p "require(\'../package.json\').optionalDependencies[\'@img/sharp-libvips-<(platform_and_arch)\']")',
'sharp_libvips_yarn_locator': '<!(node -p "require(\'../lib/libvips\').yarnLocator()")',
'sharp_libvips_include_dir': '<!(node -p "require(\'../lib/libvips\').buildSharpLibvipsIncludeDir()")',
@@ -81,7 +82,7 @@
}]
]
}, {
'target_name': 'sharp-<(platform_and_arch)',
'target_name': 'sharp-<(platform_and_arch)-<(sharp_version)',
'defines': [
'G_DISABLE_ASSERT',
'G_DISABLE_CAST_CHECKS',
@@ -120,7 +121,7 @@
'conditions': [
['use_global_libvips == "true"', {
# 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)'],
'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'
@@ -282,7 +283,7 @@
'target_name': 'copy-dll',
'type': 'none',
'dependencies': [
'sharp-<(platform_and_arch)'
'sharp-<(platform_and_arch)-<(sharp_version)'
],
'conditions': [
['OS == "win"', {

View File

@@ -289,6 +289,7 @@ namespace sharp {
case ImageType::JXL: id = "jxl"; break;
case ImageType::RAD: id = "rad"; break;
case ImageType::DCRAW: id = "dcraw"; break;
case ImageType::UHDR: id = "uhdr"; break;
case ImageType::VIPS: id = "vips"; break;
case ImageType::RAW: id = "raw"; break;
case ImageType::UNKNOWN: id = "unknown"; break;
@@ -339,6 +340,9 @@ namespace sharp {
{ "VipsForeignLoadRadBuffer", ImageType::RAD },
{ "VipsForeignLoadDcRawFile", ImageType::DCRAW },
{ "VipsForeignLoadDcRawBuffer", ImageType::DCRAW },
{ "VipsForeignLoadUhdr", ImageType::UHDR },
{ "VipsForeignLoadUhdrFile", ImageType::UHDR },
{ "VipsForeignLoadUhdrBuffer", ImageType::UHDR },
{ "VipsForeignLoadVips", ImageType::VIPS },
{ "VipsForeignLoadVipsFile", ImageType::VIPS },
{ "VipsForeignLoadRaw", ImageType::RAW }
@@ -356,6 +360,9 @@ namespace sharp {
imageType = it->second;
}
}
if (imageType == ImageType::UHDR) {
imageType = ImageType::JPEG;
}
return imageType;
}
@@ -375,6 +382,9 @@ namespace sharp {
imageType = ImageType::MISSING;
}
}
if (imageType == ImageType::UHDR) {
imageType = ImageType::JPEG;
}
return imageType;
}
@@ -1127,4 +1137,20 @@ namespace sharp {
}
return image;
}
/*
Does this image have a gain map?
*/
bool HasGainMap(VImage image) {
return image.get_typeof("gainmap-data") == VIPS_TYPE_BLOB;
}
/*
Removes gain map, if any.
*/
VImage RemoveGainMap(VImage image) {
VImage copy = image.copy();
copy.remove("gainmap-data");
return copy;
}
} // namespace sharp

View File

@@ -18,9 +18,9 @@
// Verify platform and compiler compatibility
#if (VIPS_MAJOR_VERSION < 8) || \
(VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION < 17) || \
(VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION == 17 && VIPS_MICRO_VERSION < 3)
#error "libvips version 8.17.3+ is required - please see https://sharp.pixelplumbing.com/install"
(VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION < 18) || \
(VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION == 18 && VIPS_MICRO_VERSION < 0)
#error "libvips version 8.18.0+ is required - please see https://sharp.pixelplumbing.com/install"
#endif
#if defined(__has_include)
@@ -173,6 +173,7 @@ namespace sharp {
JXL,
RAD,
DCRAW,
UHDR,
VIPS,
RAW,
UNKNOWN,
@@ -397,6 +398,16 @@ namespace sharp {
*/
VImage StaySequential(VImage image, bool condition = true);
/*
Does this image have a gain map?
*/
bool HasGainMap(VImage image);
/*
Removes gain map, if any.
*/
VImage RemoveGainMap(VImage image);
} // namespace sharp
#endif // SRC_COMMON_H_

View File

@@ -141,6 +141,14 @@ class MetadataWorker : public Napi::AsyncWorker {
memcpy(baton->tifftagPhotoshop, tifftagPhotoshop, tifftagPhotoshopLength);
baton->tifftagPhotoshopLength = tifftagPhotoshopLength;
}
// Gain Map
if (image.get_typeof("gainmap-data") == VIPS_TYPE_BLOB) {
size_t gainMapLength;
void const *gainMap = image.get_blob("gainmap-data", &gainMapLength);
baton->gainMap = static_cast<char *>(g_malloc(gainMapLength));
memcpy(baton->gainMap, gainMap, gainMapLength);
baton->gainMapLength = gainMapLength;
}
// PNG comments
vips_image_map(image.get_image(), readPNGComment, &baton->comments);
}
@@ -276,6 +284,12 @@ class MetadataWorker : public Napi::AsyncWorker {
Napi::Buffer<char>::NewOrCopy(env, baton->tifftagPhotoshop,
baton->tifftagPhotoshopLength, sharp::FreeCallback));
}
if (baton->gainMapLength > 0) {
Napi::Object gainMap = Napi::Object::New(env);
info.Set("gainMap", gainMap);
gainMap.Set("image",
Napi::Buffer<char>::NewOrCopy(env, baton->gainMap, baton->gainMapLength, sharp::FreeCallback));
}
if (baton->comments.size() > 0) {
int i = 0;
Napi::Array comments = Napi::Array::New(env, baton->comments.size());

View File

@@ -53,6 +53,8 @@ struct MetadataBaton {
size_t xmpLength;
char *tifftagPhotoshop;
size_t tifftagPhotoshopLength;
char *gainMap;
size_t gainMapLength;
MetadataComments comments;
std::string err;
@@ -82,7 +84,9 @@ struct MetadataBaton {
xmp(nullptr),
xmpLength(0),
tifftagPhotoshop(nullptr),
tifftagPhotoshopLength(0) {}
tifftagPhotoshopLength(0),
gainMap(nullptr),
gainMapLength(0) {}
};
Napi::Value metadata(const Napi::CallbackInfo& info);

View File

@@ -296,6 +296,14 @@ class PipelineWorker : public Napi::AsyncWorker {
if (baton->input->autoOrient) {
image = sharp::RemoveExifOrientation(image);
}
if (sharp::HasGainMap(image)) {
if (baton->withGainMap) {
image = image.uhdr2scRGB();
}
image = sharp::RemoveGainMap(image);
} else {
baton->withGainMap = false;
}
// Any pre-shrinking may already have been done
inputWidth = image.width();
@@ -335,7 +343,7 @@ class PipelineWorker : public Napi::AsyncWorker {
image.interpretation() != VIPS_INTERPRETATION_LABS &&
image.interpretation() != VIPS_INTERPRETATION_GREY16 &&
baton->colourspacePipeline != VIPS_INTERPRETATION_CMYK &&
!baton->input->ignoreIcc
!baton->input->ignoreIcc && !baton->withGainMap
) {
// Convert to sRGB/P3 using embedded profile
try {
@@ -1706,6 +1714,7 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
}
baton->withExifMerge = sharp::AttrAsBool(options, "withExifMerge");
baton->withXmp = sharp::AttrAsStr(options, "withXmp");
baton->withGainMap = sharp::AttrAsBool(options, "withGainMap");
baton->timeoutSeconds = sharp::AttrAsUint32(options, "timeoutSeconds");
baton->loop = sharp::AttrAsUint32(options, "loop");
baton->delay = sharp::AttrAsInt32Vector(options, "delay");

View File

@@ -208,6 +208,7 @@ struct PipelineBaton {
std::unordered_map<std::string, std::string> withExif;
bool withExifMerge;
std::string withXmp;
bool withGainMap;
int timeoutSeconds;
std::vector<double> convKernel;
int convKernelWidth;
@@ -381,6 +382,7 @@ struct PipelineBaton {
withMetadataOrientation(-1),
withMetadataDensity(0.0),
withExifMerge(true),
withGainMap(false),
timeoutSeconds(0),
convKernelWidth(0),
convKernelHeight(0),

BIN
test/fixtures/gain-map.jpg vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

View File

@@ -70,6 +70,7 @@ module.exports = {
inputJpgRandom: getPath('random.jpg'), // convert -size 200x200 xc: +noise Random random.jpg
inputJpgThRandom: getPath('thRandom.jpg'), // convert random.jpg -channel G -threshold 5% -separate +channel -negate thRandom.jpg
inputJpgLossless: getPath('testimgl.jpg'), // Lossless JPEG from ftp://ftp.fu-berlin.de/unix/X11/graphics/ImageMagick/delegates/ljpeg-6b.tar.gz
inputJpgWithGainMap: getPath('gain-map.jpg'), // https://github.com/libvips/libvips/issues/3799
inputPng: getPath('50020484-00001.png'), // http://c.searspartsdirect.com/lis_png/PLDM/50020484-00001.png
inputPngGradients: getPath('gradients-rgb8.png'),

View File

@@ -321,7 +321,7 @@ sharp('input.gif')
// From https://sharp.pixelplumbing.com/api-output#examples-9
// Extract raw RGB pixel data from JPEG input
sharp('input.jpg')
.raw()
.raw({ depth: 'ushort' })
.toBuffer({ resolveWithObject: true })
.then(({ data, info }) => {
console.log(data);

69
test/unit/gain-map.js Normal file
View File

@@ -0,0 +1,69 @@
/*!
Copyright 2013 Lovell Fuller and others.
SPDX-License-Identifier: Apache-2.0
*/
const { describe, it } = require('node:test');
const sharp = require('../../');
const fixtures = require('../fixtures');
describe('Gain maps', () => {
it('Metadata contains gainMap', async (t) => {
t.plan(4);
const { format, gainMap } = await sharp(
fixtures.inputJpgWithGainMap,
).metadata();
t.assert.strictEqual(format, 'jpeg');
t.assert.strictEqual(typeof gainMap, 'object');
t.assert.ok(Buffer.isBuffer(gainMap.image));
t.assert.strictEqual(gainMap.image.length, 31738);
});
it('Can be regenerated', async (t) => {
t.plan(4);
const data = await sharp(fixtures.inputJpgWithGainMap)
.withGainMap()
.toBuffer();
const metadata = await sharp(data).metadata();
t.assert.strictEqual(metadata.format, 'jpeg');
t.assert.strictEqual(typeof metadata.gainMap, 'object');
t.assert.ok(Buffer.isBuffer(metadata.gainMap.image));
const {
format,
width,
height,
channels,
depth,
space,
hasProfile,
chromaSubsampling,
} = await sharp(metadata.gainMap.image).metadata();
t.assert.deepEqual(
{
format,
width,
height,
channels,
depth,
space,
hasProfile,
chromaSubsampling,
},
{
format: 'jpeg',
width: 1920,
height: 1080,
channels: 1,
depth: 'uchar',
space: 'b-w',
hasProfile: true,
chromaSubsampling: '4:4:4',
},
);
});
});

View File

@@ -45,11 +45,11 @@ describe('JP2 output', () => {
assert.strictEqual('png', info.format);
assert.strictEqual(8, info.width);
assert.strictEqual(15, info.height);
assert.strictEqual(4, info.channels);
assert.strictEqual(3, info.channels);
});
});
it('JP2 quality', (done) => {
it('JP2 quality', (_t, done) => {
sharp(fixtures.inputJp2)
.resize(320, 240)
.jp2({ quality: 70 })
@@ -65,7 +65,7 @@ describe('JP2 output', () => {
});
});
it('Without chroma subsampling generates larger file', (done) => {
it('Without chroma subsampling generates larger file', (_t, done) => {
// First generate with chroma subsampling (default)
sharp(fixtures.inputJp2)
.resize(320, 240)
@@ -111,7 +111,7 @@ describe('JP2 output', () => {
it('Invalid JP2 chromaSubsampling value throws error', () => {
assert.throws(
() => sharp().jp2({ chromaSubsampling: '4:2:2' }),
/Expected one of 4:2:0, 4:4:4 but received 4:2:2 of type string/
/Expected one of: 4:2:0, 4:4:4 for chromaSubsampling but received 4:2:2 of type string/
);
});
}

View File

@@ -180,7 +180,7 @@ describe('libvips binaries', () => {
process.env.npm_config_arch = 's390x';
process.env.npm_config_libc = '';
const locatorHash = libvips.yarnLocator();
assert.strictEqual(locatorHash, '4ab19140fd');
assert.strictEqual(locatorHash, '8cdba194cb');
delete process.env.npm_config_platform;
delete process.env.npm_config_arch;
delete process.env.npm_config_libc;

View File

@@ -226,12 +226,11 @@ describe('PNG', () => {
.png({ colours: 2, palette: false })
.toBuffer();
const { channels, isPalette, bitsPerSample, paletteBitDepth, size, space } = await sharp(data).metadata();
const { channels, isPalette, bitsPerSample, paletteBitDepth, space } = await sharp(data).metadata();
assert.strictEqual(channels, 1);
assert.strictEqual(isPalette, false);
assert.strictEqual(bitsPerSample, 1);
assert.strictEqual(paletteBitDepth, undefined);
assert.strictEqual(size, 89);
assert.strictEqual(space, 'b-w');
});