Sharp Image Resizing

These samples will explore image resizing and cropping actions.

Resize using 300 width only

const sharp = require("sharp");

const logDimensions = (json) => { console.log({width: json.width, height: json.height}) }

const resizeImageWidthOnly = async () => {
  const image = await sharp("./cat1.jpg")
  const metadata = await image.metadata()
  logDimensions(metadata)

  await image.resize({ width: 300}).toFile("./cat1-300w.jpg")
  const imageNew = await sharp("./cat1-300w.jpg")
  const newImageMetadata = await imageNew.metadata()
  logDimensions(newImageMetadata)
}

Resize using 300 height only

const resizeImageHeightOnly = async () => {
    const image = await sharp("./cat1.jpg")
    const metadata = await image.metadata()
    logDimensions(metadata)
  
    await image.resize({ height: 300}).toFile("./cat1-300h.jpg")
    const imageNew = await sharp("./cat1-300h.jpg")
    const newImageMetadata = await imageNew.metadata()
    logDimensions(newImageMetadata)
}
resizeImageHeightOnly()
Width set to 300. Height stays proportional
{ width: 300, height: 187 }
Height set to 300. Width stays proportional
{ width: 480, height: 300 }

Image resize fit strategies when using both width and height

The following diagram is used on the sharp site to explain fit. The subsequent examples should make this clearer.

const resizeImageFits = async () => {
  const image = await sharp("./cat1.jpg")

  await image.resize({ width: 300, height: 100, fit: "cover" }).toFile("./cat1-cover.jpg")
  await image.resize({ width: 300, height: 100, fit: "contain" }).toFile("./cat1-contain.jpg")
  await image.resize({ width: 300, height: 100, fit: "fill" }).toFile("./cat1-fill.jpg")
  await image.resize({ width: 300, height: 100, fit: "inside" }).toFile("./cat1-inside.jpg")
  await image.resize({ width: 300, height: 100, fit: "outside" }).toFile("./cat1-outside.jpg")
}

resizeImageFits()

Original

Cover

Contain

Fill

Inside

Outside

Image resize fit strategies when resizing larger than the original

First make a small image. This one has 200 pixel width.

const resizeImageSmall = async () => {
  await sharp("./cat1.jpg").resize({ width: 200 }).toFile("./cat1-small.jpg")
}
resizeImageSmall()
const resizeImageFitsLarger = async () => {
  const image = await sharp("./cat1-small.jpg")

  await image
    .resize({ width: 300, height: 100, fit: "cover" })
    .toFile("./cat1-cover-large.jpg")
  await image
    .resize({ width: 300, height: 100, fit: "contain" })
    .toFile("./cat1-contain-large.jpg")
  await image
    .resize({ width: 300, height: 100, fit: "fill" })
    .toFile("./cat1-fill-large.jpg")
  await image
    .resize({ width: 300, height: 100, fit: "inside" })
    .toFile("./cat1-inside-large.jpg")
  await image
    .resize({ width: 300, height: 100, fit: "outside" })
    .toFile("./cat1-outside-large.jpg")
};
resizeImageFitsLarger()

Get size info so we can confirm new dimensions

const getSizes = async () => {
    const fits = 'cover_contain_fill_inside_outside'.split('_')
    const commands = [
        await sharp('./cat1-cover-large.jpg').metadata(),
        await sharp('./cat1-contain-large.jpg').metadata(),
        await sharp('./cat1-fill-large.jpg').metadata(),
        await sharp('./cat1-inside-large.jpg').metadata(),
        await sharp('./cat1-outside-large.jpg').metadata(),
    ]
    Promise.all(commands).then(metadata => {
        const filteredData = metadata.map((m, index) => {
            return { fit: fits[index], width: m.width, height: m.height }
        })
        console.log(filteredData)
    })
}
getSizes()
[
  { fit: 'cover', width: 300, height: 100 },
  { fit: 'contain', width: 300, height: 100 },
  { fit: 'fill', width: 300, height: 100 },
  { fit: 'inside', width: 160, height: 100 },
  { fit: 'outside', width: 300, height: 188 }
]

Original Small

Cover

{ fit: 'cover', width: 300, height: 100 }

Contain

{ fit: 'contain', width: 300, height: 100 }

Fill

{ fit: 'fill', width: 300, height: 100 }

Inside

{ fit: 'inside', width: 160, height: 100 }

Outside

{ fit: 'outside', width: 300, height: 188 }