Sharp: Is it possible to crop with coordinates provided from the front-end?

Created on 25 Apr 2017  路  6Comments  路  Source: lovell/sharp

I am using a cropping tool on the front-end with react.js called react-avatar-editor. It can crop the image on the front-end, but long story short, I will be cropping and manipulating very large images so I need to do it on the server. The package provides certain coordinates and parameters below which I can use on the server.

Is it easy to achieve accurate cropping with sharp package when I have a list of coordinates that I am provided below?

The 'x' and 'y' coordinates tell me at which point to start cropping from bottom left corner and 'height' and 'width' parameters tell me how far the top right corner is where to end the cropping.

Any help would be greatly appreciated!

{
   height: 1,
   width: 0.5979381443298969,
   x: 0.24318114874815838,
   y: 0
}

To give more context on numbers above, let's say we have a 400px (h) x 600px (w) image. 'x' and 'y' tell me to start cropping at bottom left proportionally so around 125px (24%) to the right and 0px (0%) from the bottom. the height tells me to crop until to the very top of the image 400px (1 in height) and 0.59 (or 59%) to the right which around 300px.

question

Most helpful comment

Hello, perhaps try something like the following (untested):

const image = sharp(input);
image.metadata()
  .then(metadata => {
    // perform your calculations based on metadata.width and metadata.height
    const left = ?, top = ?, width = ?, height = ?;
    return image
      .extract({ left, top, width, height })
      .toBuffer();
  })
  .then(data => {
    // data is a Buffer containing your extracted image
  });

All 6 comments

Hello, perhaps try something like the following (untested):

const image = sharp(input);
image.metadata()
  .then(metadata => {
    // perform your calculations based on metadata.width and metadata.height
    const left = ?, top = ?, width = ?, height = ?;
    return image
      .extract({ left, top, width, height })
      .toBuffer();
  })
  .then(data => {
    // data is a Buffer containing your extracted image
  });

Hopefully my answer was useful, please re-open if more help is required.

Worked perfectly; thanks @lovell!

You forgot to put the property names in extract left: left, top: top, width: width, height: height, but very useful :-)

Here's what I'm using. You can chain extract() with resize() without any intermediate buffer. Note I'm using await to get the promise.

// load image from disk
var resizedImage = sharp(physicalPath);

// original size from metadata
var metadata = await resizedImage.metadata();
var originalSize = { width: metadata.width, height: metadata.height };

// I've made crop a relative fraction from left, top, right, bottom
// crop = [.3, .1, .2, 0];   // crop 30% off the left, 10% off the top, 20% off the right
if (crop) {
    var cropLeft = Math.round(originalSize.width * crop[0]);
    var cropTop = Math.round(originalSize.height * crop[1]);
    var cropRight = Math.round(originalSize.width * crop[2]);
    var cropBottom = Math.round(originalSize.height * crop[3]);

    var cropWidth = originalSize.width - cropLeft - cropRight;
    var cropHeight = originalSize.height - cropTop - cropBottom;

    resizedImage = resizedImage.extract({ left: cropLeft, top: cropTop, width: cropWidth, height: cropHeight });
}

// resize the image after cropping it. I like to 'embed' it with a background during testing
resizedImage = resizedImage
    .resize(maxWidth || null, maxHeight || null)
    .embed()
    .background('hotpink');

@simeyla in 2015 a new version of Javascript came out that allows you to create objects with that syntax. If the property name and variable being set as the value have the same name you can write it without duplicating the value each time.

{ 
  top: top, 
  left: left 
}

is exactly equivalent to

{
  top,
  left
}

Hey @lovell, How can I work with blob image? I've a blob image to crop.. Thanks for your help.

Was this page helpful?
0 / 5 - 0 ratings