diff --git a/README.md b/README.md index 253fa36..4826924 100644 --- a/README.md +++ b/README.md @@ -110,6 +110,7 @@ try { - __fit__ [string] - method by which the image should fit the width/height. Default = contain ([details](https://sharp.pixelplumbing.com/api-resize)) - __failOnError__ [boolean] - Set to false to avoid read problems for images from some phones (i.e Samsung) in the sharp lib. Default = true ([details](https://github.com/lovell/sharp/issues/1578)) - __withMetaData__ [boolean] - Keep metadata in the thumbnail (will increase file size) + - __flattenBackgroundColor__ [background colour] - parsed by the color module, defaults to #ffffff. ### Examples ```js diff --git a/src/index.js b/src/index.js index b0bce22..a371eed 100644 --- a/src/index.js +++ b/src/index.js @@ -12,10 +12,10 @@ const { fail } = require('assert'); const PERCENTAGE = 10; const RESPONSE_TYPE = 'buffer'; -const fromBase64 = async (source, percentage, width, height, responseType, jpegOptions, fit, failOnError, withMetaData) => { +const fromBase64 = async (source, percentage, width, height, responseType, jpegOptions, fit, failOnError, withMetaData, flattenBackgroundColor) => { const imageBuffer = Buffer.from(source, 'base64'); const dimensions = getDimensions(imageBuffer, percentage, { width, height }); - const thumbnailBuffer = await sharpResize(imageBuffer, dimensions, jpegOptions, fit, failOnError, withMetaData); + const thumbnailBuffer = await sharpResize(imageBuffer, dimensions, jpegOptions, fit, failOnError, withMetaData, flattenBackgroundColor); if (responseType === 'base64') { return thumbnailBuffer.toString('base64'); @@ -24,13 +24,12 @@ const fromBase64 = async (source, percentage, width, height, responseType, jpegO return thumbnailBuffer; }; -const fromUri = async (source, percentage, width, height, responseType, jpegOptions, fit, failOnError, withMetaData) => { +const fromUri = async (source, percentage, width, height, responseType, jpegOptions, fit, failOnError, withMetaData, flattenBackgroundColor) => { const response = await axios.get(source.uri, { responseType: 'arraybuffer' }); const imageBuffer = Buffer.from(response.data, 'binary'); const dimensions = getDimensions(imageBuffer, percentage, { width, height }); - const thumbnailBuffer = await sharpResize(imageBuffer, dimensions, jpegOptions, fit, failOnError, withMetaData); - + const thumbnailBuffer = await sharpResize(imageBuffer, dimensions, jpegOptions, fit, failOnError, withMetaData, flattenBackgroundColor); if (responseType === 'base64') { return thumbnailBuffer.toString('base64'); @@ -39,11 +38,11 @@ const fromUri = async (source, percentage, width, height, responseType, jpegOpti return thumbnailBuffer; }; -const fromPath = async (source, percentage, width, height, responseType, jpegOptions, fit, failOnError, withMetaData) => { +const fromPath = async (source, percentage, width, height, responseType, jpegOptions, fit, failOnError, withMetaData, flattenBackgroundColor) => { const imageBuffer = fs.readFileSync(source); const dimensions = getDimensions(imageBuffer, percentage, { width, height }); - const thumbnailBuffer = await sharpResize(imageBuffer, dimensions, jpegOptions, fit, failOnError, withMetaData); + const thumbnailBuffer = await sharpResize(imageBuffer, dimensions, jpegOptions, fit, failOnError, withMetaData, flattenBackgroundColor); if (responseType === 'base64') { return thumbnailBuffer.toString('base64'); @@ -52,10 +51,21 @@ const fromPath = async (source, percentage, width, height, responseType, jpegOpt return thumbnailBuffer; }; -const fromReadStream = async (source, percentage, width, height, responseType, jpegOptions, fit, failOnError, withMetaData) => { +const fromReadStream = async ( + source, + percentage, + width, + height, + responseType, + jpegOptions, + fit, + failOnError, + withMetaData, + flattenBackgroundColor, +) => { const imageBuffer = await util.streamToBuffer(source); const dimensions = getDimensions(imageBuffer, percentage, { width, height }); - const thumbnailBuffer = await sharpResize(imageBuffer, dimensions, jpegOptions, fit, failOnError, withMetaData); + const thumbnailBuffer = await sharpResize(imageBuffer, dimensions, jpegOptions, fit, failOnError, withMetaData, flattenBackgroundColor); if (responseType === 'base64') { return thumbnailBuffer.toString('base64'); @@ -64,11 +74,10 @@ const fromReadStream = async (source, percentage, width, height, responseType, j return thumbnailBuffer; }; -const fromBuffer = async (source, percentage, width, height, responseType, jpegOptions, fit, failOnError, withMetaData) => { +const fromBuffer = async (source, percentage, width, height, responseType, jpegOptions, fit, failOnError, withMetaData, flattenBackgroundColor) => { const imageBuffer = source; - const dimensions = getDimensions(imageBuffer, percentage, { width, height }); - const thumbnailBuffer = await sharpResize(imageBuffer, dimensions, jpegOptions, fit, failOnError, withMetaData); + const thumbnailBuffer = await sharpResize(imageBuffer, dimensions, jpegOptions, fit, failOnError, withMetaData, flattenBackgroundColor); if (responseType === 'base64') { return thumbnailBuffer.toString('base64'); @@ -84,26 +93,82 @@ module.exports = async (source, options) => { const responseType = options && options.responseType ? options.responseType : RESPONSE_TYPE; const jpegOptions = options && options.jpegOptions ? options.jpegOptions : undefined; const fit = options && options.fit ? options.fit : undefined; - const failOnError = options && typeof(options.failOnError) !== 'undefined' ? options.failOnError : true; - const withMetaData = options && typeof(options.withMetaData) !== 'undefined' ? options.withMetaData : false; + const failOnError = options && typeof options.failOnError !== 'undefined' ? options.failOnError : true; + const withMetaData = options && typeof options.withMetaData !== 'undefined' ? options.withMetaData : false; + const flattenBackgroundColor = options && typeof options.flattenBackgroundColor !== 'undefined' ? options.flattenBackgroundColor : '#ffffff'; try { switch (typeof source) { case 'object': let response; if (source instanceof fs.ReadStream || source instanceof stream.PassThrough) { - response = await fromReadStream(source, percentage, width, height, responseType, jpegOptions, fit, failOnError, withMetaData); + response = await fromReadStream( + source, + percentage, + width, + height, + responseType, + jpegOptions, + fit, + failOnError, + withMetaData, + flattenBackgroundColor, + ); } else if (source instanceof Buffer) { - response = await fromBuffer(source, percentage, width, height, responseType, jpegOptions, fit, failOnError, withMetaData); + response = await fromBuffer( + source, + percentage, + width, + height, + responseType, + jpegOptions, + fit, + failOnError, + withMetaData, + flattenBackgroundColor, + ); } else { - response = await fromUri(source, percentage, width, height, responseType, jpegOptions, fit, failOnError, withMetaData); + response = await fromUri( + source, + percentage, + width, + height, + responseType, + jpegOptions, + fit, + failOnError, + withMetaData, + flattenBackgroundColor, + ); } return response; case 'string': if (validator.isBase64(source)) { - return await fromBase64(source, percentage, width, height, responseType, jpegOptions, fit, failOnError, withMetaData); + return await fromBase64( + source, + percentage, + width, + height, + responseType, + jpegOptions, + fit, + failOnError, + withMetaData, + flattenBackgroundColor, + ); } else { - return await fromPath(source, percentage, width, height, responseType, jpegOptions, fit, failOnError, withMetaData); + return await fromPath( + source, + percentage, + width, + height, + responseType, + jpegOptions, + fit, + failOnError, + withMetaData, + flattenBackgroundColor, + ); } default: throw new Error('unsupported source type'); @@ -124,26 +189,28 @@ const getDimensions = (imageBuffer, percentageOfImage, dimensions) => { const height = parseInt((originalDimensions.height * (percentageOfImage / 100)).toFixed(0)); return { width, height }; -} +}; -const sharpResize = (imageBuffer, dimensions, jpegOptions, fit, failOnError, withMetadata) => { +const sharpResize = (imageBuffer, dimensions, jpegOptions, fit, failOnError, withMetadata, flattenBackgroundColor) => { return new Promise((resolve, reject) => { let result = sharp(imageBuffer, { failOnError }) .resize({ - ...dimensions, withoutEnlargement: true, fit: fit ? fit : 'contain', + ...dimensions, + withoutEnlargement: true, + fit: fit ? fit : 'contain', }) + .flatten({ background: flattenBackgroundColor }); - if(withMetadata){ - result.withMetadata() - } + if (withMetadata) { + result.withMetadata(); + } - result.jpeg(jpegOptions ? jpegOptions : { force: false }) - .toBuffer((err, data) => { - if (err) { - reject(err); - } else { - resolve(data); - } - }); + result.jpeg(jpegOptions ? jpegOptions : { force: false }).toBuffer((err, data) => { + if (err) { + reject(err); + } else { + resolve(data); + } + }); }); };