sharp
sharp copied to clipboard
Enhancement: add support to extend feature for width and height
Hello,
is there a way to pad an image if it's smaller than required dimensions?
For example:
desired dimensions | actual dimensions | expected result |
---|---|---|
1000x1000 | 200x200 | 1000x1000 image with 200x200 centered inside |
300x300 | 350x350 | downscaled to 300x300 |
Original
Desired output
I ended up with something like this:
async function resize(width, height) {
const image = sharp(imgBuffer).resize(width, height).withoutEnlargement();
const { info, data } = await image.jpeg({ quality: 100 }).toBuffer({ resolveWithObject: true });
if (info.width < width || info.height < height) {
const bg = sharp({
create: {
height,
width,
background: 'white',
},
});
bg.overlayWith(data);
return bg.jpeg({ quality: 100 }).toBuffer();
}
return data;
}
But could this be achieved with the Sharp's api?
Hello, did you see the extend operation?
@lovell yeah I saw it, but in order to use extend
I need to know dimensions of image after resize so I can calculate params for extend
. So at the end I will have to calculate the exact pixels to add to the sides.
Maybe something like extend
with desired width
and height
could be great. So my question stays the same, could this be achieved with the sharp's api ? :)
Maybe something like this:
image.resize(width, height).withoutEnlargement().extend({ width, height })
Providing target dimensions to extend
is not currently supported but would make a good addition, thanks for the suggestion. PRs always welcome.
For now two pipelines are required to achieve what you want. You could use raw pixel data to avoid the compression/decompression round-trip in the middle.
@lovell Thanks for suggesting raw
but when I replaced jpeg({ quality: 100 })
in the middle with raw()
I got the error Input buffer contains unsupported image format
.
Here is a failing test code I used:
import sharp from 'sharp';
import { resolve as resolvePath } from 'path';
import { readFileSync } from 'fs';
describe('test', () => {
const width = 1000;
const height = 1000;
it('works with buffer from an image file', async () => {
const img = readFileSync(resolvePath(__dirname, '../../__tests__/fixture.jpeg'));
const buf = await sharp(img)
.resize(width, height)
.withoutEnlargement()
.raw()
.toBuffer();
await sharp({ create: { width, height, background: 'white', channels: 3 } })
.overlayWith(buf)
.jpeg({ quality: 100 })
.toBuffer();
});
it('works with an output from another sharp instance', async () => {
const buf = await sharp({ create: { width, height, background: 'white', channels: 4 } })
.raw()
.toBuffer();
await sharp({ create: { width, height, background: 'white', channels: 4 } })
.overlayWith(buf)
.jpeg({ quality: 100 })
.toBuffer();
});
});
When I replace raw
with jpeg
in test, it passes just fine.
Raw pixel data Buffer objects need their dimensions and channel count described, something like:
- .overlayWith(buf)
+ .overlayWith(buf, { raw: { width, height, channels: 3 }})
https://sharp.pixelplumbing.com/en/stable/api-composite/#overlaywith
@lovell oh sorry I completely oversaw this, thank you very much. Great library :)
Any word on this enhancement being merged in?
@schematis Happy to accept a PR if you're able.