Skip to content

keepGainMap(): extract() crops the base image but leaves the gain map uncropped #4606

Description

@gregbenz

Is this a possible bug in a feature of sharp, unrelated to installation?

  • [ x] Running npm install sharp completes without error.
  • [ x] Running node -e "import 'sharp'" completes without error.

Are you using the latest version of sharp?

  • [ x] I am using the latest version of sharp as reported by npm view sharp dist-tags.latest.
    Running 0.35.4

What is the output of running npx envinfo --binaries --system --npmPackages=sharp --npmGlobalPackages=sharp?

System:
OS: macOS 27.0
CPU: (18) arm64 Apple M5 Max
Memory: 6.47 GB / 128.00 GB
Shell: 3.2.57 - /bin/bash
Binaries:
Node: 24.18.0 - /Users/redacted/.nvm/versions/node/v24.18.0/bin/node
Yarn: 1.22.19 - /usr/local/bin/yarn
npm: 11.16.0 - /Users/redacted/.nvm/versions/node/v24.18.0/bin/npm

Does this problem relate to file caching?

  • [x ] Adding sharp.cache(false) does not fix this problem.

Does this problem relate to images appearing to have been rotated by 90 degrees?

  • [x ] Using rotate() or keepExif() does not fix this problem.

What are the steps to reproduce?

run code below

Tested against sharp main at commit 9dcb3dd (reports version 0.35.4), using libvips 8.18.6 and libultrahdr 2.0.2.

What is the expected behaviour?

The image should be cropped, but show no changes in the cropped area. However, when you view the output on an HDR-capable display, you'll see ghosting because the gain map was not cropped to stay aligned to the base image.

Expected result: both the base image and this source’s full-resolution gain map are cropped to 601 × 499.
Actual: the base becomes 601 × 499, but the gain map remains 1080 × 1080.

Please provide a minimal, standalone code sample, without other dependencies, that demonstrates this problem

node - "./ISO JPG - sRGB - transcoding test - Greg Benz.jpg" <<'NODE'
const sharp = require('sharp');
const path = require('node:path');

(async () => {
  const output = path.resolve('./crop-gainmap-issue.jpg');

  await sharp(process.argv[2])
    .keepGainMap()
    .extract({ left: 101, top: 153, width: 601, height: 499 }) // Both images should be cropped, but the gain map stays at its original size.
    .toFile(output);

  const base = await sharp(output).metadata();
  const map = await sharp(base.gainMap.image).metadata();

  console.log(`Base image: ${base.width} × ${base.height}`);
  console.log(`Gain map:   ${map.width} × ${map.height}`);
  console.log(`Saved: ${output}`);
})().catch(error => {
  console.error(error.message);
  process.exitCode = 1;
});
NODE

Please provide sample image(s) that help explain this problem

Source to test:
Image

The failed output:
Image

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions