sharp
sharp copied to clipboard
Ensure combination of resize and rotate operations is ordered (to match extract and rotate)
Possible bug
- [x] Running
npm install sharp
completes without error. - [x] Running
node -e "require('sharp')"
completes without error. - [x] I am using the latest version of
sharp
as reported bynpm view sharp dist-tags.latest
.
System:
OS: Windows 10 10.0.16299
CPU: (4) x64 Intel(R) Core(TM) i5-6500 CPU @ 3.20GHz
Memory: 10.08 GB / 15.95 GB
Binaries:
Node: 18.7.0 - C:\Program Files\nodejs\node.EXE
npm: 8.15.0 - C:\Program Files\nodejs\npm.CMD
npmPackages:
sharp: ^0.30.7 => 0.30.7
What are the steps to reproduce?
Resize an image into specific dimensions with fill fit mode, then try to rotate it 90 degrees.
What is the expected behavior?
Result image should be rotated, and have {oldHeight}x{oldWidth}
dimensions, instead, it IS rotated, but somehow retained {oldWidth}x{oldHeight}
dimensions.
Code sample
import sharp from 'sharp';
const image = sharp('./in.jpg');
image.resize({width: 400, height: 500, fit: 'fill'});
image.rotate(90);
await image.toFile('./out.jpg');
Sample image
Happens for contain
and cover
fit modes as well.
I currently have to do this intermediate step in between resize and rotate to "fix" it by I guess resetting whatever is being mangled internally:
image = sharp(await image.png().toBuffer());
As you've seen, you'll currently need to break this operation into two pipelines - see #1922, #2086 and related issues.
This has come up a few times, and I've been meaning to modify sharp to ensure that the combination of resize+rotate is also "ordered" to match the behaviour of extract+rotate.
https://sharp.pixelplumbing.com/api-operation#rotate
Method order is important when both rotating and extracting regions, for example
rotate(x).extract(y)
will produce a different result toextract(y).rotate(x)
.
Let's use this issue to track that enhancement.
I'm running into more and more chaining issues where sharp produces unexpected results. For example:
image.extract(...).rotate(90).extract(...);
The result is a completely different region than expected. I guess the second extract overwrites the first one?
So what I currently have to do is, similar to the above workaround, I made this flush function:
const flush = async () => {
const {data, info} = await image.raw().toBuffer({resolveWithObject: true});
image = sharp(data, {raw: info});
};
And I call it in between every operation just to be sure sharp chaining issues don't break something.
If sharp doesn't really support chaining operations, it shouldn't encourage it via it's API design 😞. Or have some big warnings everywhere that only one operation type per chain is allowed, and only certain orders are supported, and all other quirks and limitations I'm currently not aware of.
Please see the discussion at #241
Commit https://github.com/lovell/sharp/commit/212a6e7519413e69d6eb2e875ca750b5f76771b0 improves the situation slightly, adding examples and test cases, as well as emitting warnings when previous calls in the same pipeline will be ignored. This will be in v0.31.0.
v0.31.0 is now available with these improvements. Let's continue the other parts of this discussion at #241