Last active
January 9, 2021 05:19
-
-
Save chrisjhoughton/ce73112b59551f8f080d to your computer and use it in GitHub Desktop.
Given an image URL or path, crop and resize it to be exactly a specific size. Crops centrally to force enforce the correct aspect ratio, and then resizes as per normal. Depends on the `when` and `gm` NPM modules. Returns a promise that resolves with an image buffer in a .PNG format.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Given an image URL or path, crop and resize it to be exactly a specific size. | |
* Crops centrally to force enforce the correct aspect ratio, and then resizes as per normal. | |
* Depends on the `when` and `gm` NPM modules. | |
* Returns a promise that resolves with an image buffer in a .PNG format. | |
*/ | |
var when = require('when'); | |
var gm = require('gm'); | |
var im = gm.subClass({ imageMagick: true }); // use `im` in place of `gm` for heroku compatibility | |
/* | |
* Get the size of an image | |
*/ | |
var getImageSize = function (file) { | |
return when.promise(function (resolve, reject) { | |
im(file).size(function (err, size) { | |
if (err) { | |
reject(err); | |
} else { | |
resolve(size); | |
} | |
}); | |
}); | |
}; | |
/* | |
* Crop and resize an image to precisely the correct dimensions. | |
* Crops first to get to the correct aspect ratio, and then resizes | |
* accordingly. | |
* | |
* Works with either a URL, or a path. | |
*/ | |
module.exports = function (url, requiredWidth, requiredHeight) { | |
return when.promise(function (resolve, reject) { | |
// We need to resize and then crop. These dimensions | |
// help us choose how to do this. | |
var requiredRatio = requiredWidth / requiredHeight; | |
// Get the size of the image | |
getImageSize(url) | |
// Crop to required dimensions and then resize | |
.then(function (actualSize) { | |
// If the actual width or height are too small, then reject | |
if (actualSize.width < requiredWidth || actualSize.height < requiredHeight) { | |
reject('image_too_small'); | |
return; | |
} | |
var actualRatio = actualSize.width / actualSize.height; | |
// dimensions we'll crop to | |
var cropWidth; | |
var cropHeight; | |
// crop co-ordinates (top left) | |
var cropX; | |
var cropY; | |
// If actual ratio is too high, we need to crop the width | |
if (actualRatio > requiredRatio) { | |
cropWidth = actualSize.height * requiredRatio; | |
cropHeight = actualSize.height; // no change | |
cropX = (actualSize.width - cropWidth) / 2 | |
cropY = 0; | |
} | |
// If actual ratio is too low, we need to crop the height | |
else if (actualRatio < requiredRatio) { | |
cropWidth = actualSize.width | |
cropHeight = actualSize.width / requiredRatio; // no change | |
cropX = 0; | |
cropY = (actualSize.height - cropHeight) / 2; | |
} | |
// we're already the correct ratio | |
else { | |
cropWidth = 0; | |
cropHeight = 0; | |
cropX = 0; | |
cropY = 0; | |
} | |
// Crop and resize | |
im(url) | |
.crop(cropWidth, cropHeight, cropX, cropY) | |
.resize(requiredWidth, requiredHeight) | |
.toBuffer('PNG', function (err, buffer) { | |
if (err) { | |
reject(err); | |
} else { | |
resolve(buffer); | |
} | |
}); | |
}); | |
}); | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment