/* * 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); } }); }); }); };