keepGainMap(): valid crop throws "extract_area: bad extract area" after resizing a reduced-resolution gain map
Nobody has claimed this yet.
- 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:
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- 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