lovell / lovell/sharp

keepGainMap(): valid crop throws "extract_area: bad extract area" after resizing a reduced-resolution gain map

Open
#4,607 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

triage
Dominant language
JavaScript
Stars
32.7k
Forks
1.4k
Avg merge
1d 14h
Merged PRs (30d)
5

Description

### 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, will show error: "**extract_area: bad extract area**"

Tested against sharp main at commit https://github.com/lovell/sharp/commit/9dcb3ddf27d99b160d1aadafc980c8e42bc4cd1a (reports version 0.35.4), using libvips 8.18.6 and libultrahdr 2.0.2.

### What is the expected behaviour?
Expected: the valid crop should save a 30 × 25 JPEG with its gain map preserved and aligned.
Actual: the same crop succeeds without keepGainMap(), but with it throws extract_area: bad extract area and produces no usable output image.

### Please provide a minimal, standalone code sample, without other dependencies, that demonstrates this problem
```
node - "../source images to test/ISO JPG - sRGB - transcoding test - Greg Benz.jpg" <<'NODE'
const sharp = require('sharp');

(async () => {
// Make a smaller gain map, then save an image with odd dimensions.
const reduced = await sharp(process.argv[2]).withGainMap().toBuffer();
const input = './reduced-map-input.jpg';

await sharp(reduced).keepGainMap()
.resize(129, 97, { fit: 'fill' })
.toFile(input);

// Resize first so sharp crops afterward. The crop fits inside the image.
const crop = image => image
.resize(129, 97, { fit: 'fill' })
.extract({ left: 90, top: 60, width: 30, height: 25 });

await crop(sharp(input)).toFile('./crop-without-gainmap.jpg');
console.log('Without keepGainMap: crop succeeds.');

await crop(sharp(input).keepGainMap())
.toFile('./crop-with-gainmap.jpg'); // BUG: should save the crop, but throws "extract_area: bad extract area" and produces no usable output image.
})().catch(error => {
console.error(error.message);
process.exitCode = 1;
});
NODE
```

### Please provide sample image(s) that help explain this problem
Source to test:
Image

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by running the standalone Node.js reproduction with the provided source image, comparing the resize-then-extract pipeline with and without keepGainMap(). Trace the keepGainMap(), resize(), and extract() entry points to identify where the reduced-resolution gain map makes the valid crop fail. Done means the 30 × 25 JPEG is written successfully with its gain map preserved and aligned.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, node.js
Domain
computer-graphics
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
58/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.