javascriptnode.jssharpjimp

How to resize an image proportionally using a blur effect, instead of letterboxing, on Node.js?


I have a photo which is a rectangle and I want to resize it down to a square while preserving the aspect ratio. Libraries like Sharp allow you to do that by applying letterboxing to the resulting image.

await sharp(photoBuffer).resize({ width: 200, height: 200, fit: 'contain' })

This is the result:

with letterboxing

Instead of applying letterboxing I'd like the remaining empty space to be filled with a 2nd blurred version of the image, placed behind the resized one, like so:

example

Is there a Node.js library that does that out of the box or some custom way of achieving this ?


Solution

  • Turns out this is how you do it using Sharp:

    import Sharp from 'sharp'
    
    export default function({ pathToInputFile, pathToOutputFile, size, blur }) {
      let sharpOriginal = Sharp(pathToInputFile)
      
      return new Promise((resolve) => {
        sharpOriginal
          .resize({ width: size })
          .toBuffer()
          .then((resizedBuffer) => {
            sharpOriginal
              .resize(size, size, { // the result will be a square
                fit: 'cover'
              })
              .blur(blur) // 6 seems to work well
              .composite([{
                input: resizedBuffer,
                gravity: 'center'
              }])
              .toFile(pathToOutputFile)
              .then((info) => {
                console.log(info)
                resolve(true)
              })
              .catch((err) => {
                console.error(err)
                resolve(false)
              })
          })
          .catch((err) => {
            console.error(err)
            resolve(false)
          })
      })
    }