Sharp: Add the ability to `pad` an image

Created on 27 Nov 2014  Â·  29Comments  Â·  Source: lovell/sharp

It would be great to see something much like the implementation here
https://github.com/EyalAr/lwip#user-content-pad

enhancement

Most helpful comment

I think extend is the right name for this behaviour.

An example of this, when used in conjunction with existing resize and background methods, might be:

sharp(input)
  .resize(180)
  .background({r: 100, g: 0, b: 0})
  .extend({top: 10, left: 10, bottom: 20, right: 10})
  .toBuffer( ... )

The resultant image would be 200 pixels wide (by whatever high). It would have a dark red border of 10 pixels to the top and sides and 20 pixels to the bottom.

All 29 comments

Would you be using this in a web context, i.e. producing an image that is part of an HTML document? If so, could CSS provide what you're looking for?

Not quite, you could potentially read the pixel color from the image, and pad the image with this color.
There are of course other use cases.

"you could potentially read the pixel color from the image"

Which pixel(s) does this refer to? Would a method that returned the dominant/average colour of an image help?

From what I understand of the lwip docs, its pad method defaults to transparent if no colour is provided. Is this the behaviour you need?

Which pixel(s) does this refer to? Would a method that returned the dominant/average colour of an image help?

Ultimately I'm just looking for the ability to pad an image, in my case where I may want to specify a color I may opt to use another library to retreive / calculate the color

From what I understand of the lwip docs, its pad method defaults to transparent if no colour is provided. Is this the behaviour you need?

That would be great

I am also in need of the pad functionality. I'd like to make square image tiles from rectangular images, adding transparent pixels for padding where necessary (i.e. to pad the shorter of the two dimensions). Is there a work-around with the current API?

@bennlich you should be able to to do with the existing API via a combination of the embed and background methods. https://github.com/lovell/sharp/blob/master/test/unit/embed.js#L32-L37 provides an example of this.

Ah! Awesome, thanks a bunch for the quick reply.

Is there a way to specify where the image is embedded in the larger image (bottom left, top right, etc.)? Kind of like a gravity option for embed?

@bennlich Reusing gravity to apply to the embed operation also would make a good addition, thanks for the idea.

@blowsie Does any of what @bennlich and I are discussing meet your needs, or should I move this new suggestion to a separate task?

I'm not sure without testing, which I don't have time to do right now.
I personally would love to see .pad(10,10,10,10) or similar as some sort of mixin rather than combining various other functions.

The embed function however does look useful for one of my use cases, which matches @bennlich s requirements of fitting rectangles in squares.

I'm trying to achieve something similar, where I have a "zoom" or "crop" feature that lets the user specify how to process their image.

To embed a smaller image on a larger background, resorting to below. Wondering if it can be reduced to 1 pipeline instead of 2?

So, starting with a 50x50 image, i want to center it in a 256x256 background:

sharp(in)
.resize(50, 256)
.embed()
.pipe(sharp().resize(256, 256).embed())
.pipe(out)

The first resize essentially centers the image vertically on a 50x256 background, then a second pass centers it in the 256x256 background. Inefficient, but gets the job done. hoping for better alternative...

ideally works like drawing on a canvas where we specify source rectangle on the image and destination rectangle on the background.

So after testing, using embed in combination with background; this caters for @bennlich s use case, however it doesnt let you add some padding / whitespace to the image, as desired

Because of the lack of something like a "centered" gravity option?

On Thu, May 7, 2015 at 7:57 AM, Sam Blowes [email protected] wrote:

So after testing, using embed in combination with background caters for
@bennlich https://github.com/bennlich s use case, however it doesnt let
you add some padding / whitespace to the image, as desired

—
Reply to this email directly or view it on GitHub
https://github.com/lovell/sharp/issues/128#issuecomment-99898371.

Well, as far as I know, you can only resize, and not extend / pad. Perhaps you can do this with embed somehow? I'm not sure

Gravity is not enough control to embed an image on a specific area of a background. For example, I want to embed a 50x50 image on the lower left corner of a 256x256 background, or any other specific position on the background. Imagine an image cropper use case where you allow the user to place an avatar in a region.

Would also love to see a padding function. My use case involves a square avatar image that is to be overlaid with a square having a round transparent area in the center (thus creating the illusion of a round avatar). Problem is since source and dest images in overlay function need to be the same size I am losing part of the original image and would love to resize it down a few pixels and adding the same as padding to accommodate for overlay function's requirement.

@masimakopoulos The existing embed option may provide some of what you're looking for.

Assuming you have a transparent overlay image of 300x300px, the following will create a 300x300 white image with input.jpg embedded then round.png overlaid.

sharp('input.jpg')
  .resize(300, 300)
  .background({r: 255, g: 255, b: 255})
  .embed()
  .overlayWith('round.png')
  .toFile( ... )

@lovell thanks for the response. I tried the above but it does not pad the image it just makes everything the size of the overlay (stretches the target image). Not sure if it make as difference but the target image ('input.jpg') is a stream passed through some other sharp manipulations.

Here is what I am doing:

    getAvatar() // Get an image stream from a remote source
   .pipe(sharp().resize(size, size).withoutEnlargement()) //resize the retrieved image to a predefined size
   // later on (optionally) trying to add overlay with padding
   .pipe(sharp()
        .png() //need to convert to png first, otherwise result looks really weird from jpg target
        .resize(54, 54) //image was already 54x54 by previous manipulation
        .background({r: 255, g: 255, b: 255})
        .embed()
        .overlayWith('lib/assets/overlay_s54.png'));  // overlay is 54x54px

Note the above is a simplification of my process. The first resize can be done without an overlay being added, thus the duplication in logic in this example.

I am also using the latest version 0.11.3

"stretches the target image"

The only time stretching should occur is with the use of ignoreAspectRatio - perhaps we've unearthed a bug here - let me investigate.

No, what I meant was it enlarged the target image, instead of adding padding to it (both axis, so not ignoring aspect ratio). I apologize for the confusion.

@masimakopoulos No worries, thanks for confirming :relieved:

I think extend is the right name for this behaviour.

An example of this, when used in conjunction with existing resize and background methods, might be:

sharp(input)
  .resize(180)
  .background({r: 100, g: 0, b: 0})
  .extend({top: 10, left: 10, bottom: 20, right: 10})
  .toBuffer( ... )

The resultant image would be 200 pixels wide (by whatever high). It would have a dark red border of 10 pixels to the top and sides and 20 pixels to the bottom.

Commit f950294 on the needle branch adds the new extend feature, which will be in v0.14.0.

Great news! Looking forward to this release.

++ Many thanks!

v0.14.0 now available via npm, thanks again for all the comments and help here.

Thanks for this. You are a saviour!

Why do I always read these threads from start to finish!? Because sometimes they get exciting, like little mini stories putting me on the edge of my seat. Happy to see this had a good ending :-) I needed this functionality to be able to put a css rounded border (to make the image a circle) so needed to extend it.

However @lovell I think you have this in the wrong place in the documentation. It is currently under image operations 'http://sharp.pixelplumbing.com/en/stable/api-operation/#extend'.

It would be really helpful to add this under resizing images where I think people are much more likely to be looking. http://sharp.pixelplumbing.com/en/stable/api-resize/ Same maybe goes for trim.

@simeyla I've added a note about this to #1135

Was this page helpful?
0 / 5 - 0 ratings

Related issues

AVVS picture AVVS  Â·  3Comments

janaz picture janaz  Â·  3Comments

jaekunchoi picture jaekunchoi  Â·  3Comments

vermin1337 picture vermin1337  Â·  3Comments

emmtte picture emmtte  Â·  3Comments