const Promise = require('bluebird'); const common = require('../common'); const fs = require('fs-extra'); /** * @NOTE: Sharp cannot operate on the same image path, that's why we have to use in & out paths. * * We currently can't enable compression or having more config options, because of * https://github.com/lovell/sharp/issues/1360. */ const unsafeProcess = (options = {}) => { return fs.readFile(options.in) .then((data) => { return unsafeResizeImage(data, { width: options.width }); }) .then((data) => { return fs.writeFile(options.out, data); }); }; const unsafeResizeImage = (originalBuffer, {width, height} = {}) => { const sharp = require('sharp'); return sharp(originalBuffer) .resize(width, height, { // CASE: dont make the image bigger than it was withoutEnlargement: true }) // CASE: Automatically remove metadata and rotate based on the orientation. .rotate() .toBuffer() .then((resizedBuffer) => { return resizedBuffer.length < originalBuffer.length ? resizedBuffer : originalBuffer; }); }; // NOTE: .gif optimization is currently not supported by sharp but will be soon // as there has been support added in underlying libvips library https://github.com/lovell/sharp/issues/1372 // As for .svg files, sharp only supports conversion to png, and this does not // play well with animated svg files const canTransformFileExtension = ext => !['.gif', '.svg', '.svgz', '.ico'].includes(ext); const makeSafe = fn => (...args) => { try { require('sharp'); } catch (err) { return Promise.reject(new common.errors.InternalServerError({ message: 'Sharp wasn\'t installed', code: 'SHARP_INSTALLATION', err: err })); } return fn(...args).catch((err) => { throw new common.errors.InternalServerError({ message: 'Unable to manipulate image.', err: err, code: 'IMAGE_PROCESSING' }); }); }; module.exports.canTransformFileExtension = canTransformFileExtension; module.exports.process = makeSafe(unsafeProcess); module.exports.resizeImage = makeSafe(unsafeResizeImage);