strapi/packages/core/upload/server/services/image-manipulation.js

166 lines
3.9 KiB
JavaScript
Raw Normal View History

'use strict';
/**
* Image manipulation functions
*/
const sharp = require('sharp');
2021-08-19 22:27:00 +02:00
const { getService } = require('../utils');
const { bytesToKbytes } = require('../utils/file');
const getMetadatas = buffer =>
sharp(buffer)
.metadata()
.catch(() => ({})); // ignore errors
const getDimensions = buffer =>
getMetadatas(buffer)
.then(({ width = null, height = null }) => ({ width, height }))
.catch(() => ({})); // ignore errors
const THUMBNAIL_RESIZE_OPTIONS = {
width: 245,
height: 156,
fit: 'inside',
};
const resizeTo = (buffer, options) =>
sharp(buffer)
.withMetadata()
.resize(options)
.toBuffer()
.catch(() => null);
const generateThumbnail = async file => {
if (!(await canBeProccessed(file.buffer))) {
return null;
}
const { width, height } = await getDimensions(file.buffer);
if (width > THUMBNAIL_RESIZE_OPTIONS.width || height > THUMBNAIL_RESIZE_OPTIONS.height) {
const newBuff = await resizeTo(file.buffer, THUMBNAIL_RESIZE_OPTIONS);
if (newBuff) {
const { width, height, size } = await getMetadatas(newBuff);
return {
name: `thumbnail_${file.name}`,
hash: `thumbnail_${file.hash}`,
ext: file.ext,
mime: file.mime,
width,
height,
size: bytesToKbytes(size),
buffer: newBuff,
path: file.path ? file.path : null,
};
}
}
return null;
};
const optimize = async buffer => {
2021-08-19 22:27:00 +02:00
const { sizeOptimization = false, autoOrientation = false } = await getService(
'upload'
).getSettings();
if (!sizeOptimization || !(await canBeProccessed(buffer))) {
return { buffer };
}
const sharpInstance = autoOrientation ? sharp(buffer).rotate() : sharp(buffer);
return sharpInstance
.toBuffer({ resolveWithObject: true })
.then(({ data, info }) => {
const output = buffer.length < data.length ? buffer : data;
return {
buffer: output,
info: {
width: info.width,
height: info.height,
size: bytesToKbytes(output.length),
},
};
})
.catch(() => ({ buffer }));
};
const DEFAULT_BREAKPOINTS = {
large: 1000,
medium: 750,
small: 500,
};
2021-08-06 18:09:49 +02:00
const getBreakpoints = () => strapi.config.get('plugin.upload.breakpoints', DEFAULT_BREAKPOINTS);
const generateResponsiveFormats = async file => {
2021-08-19 22:27:00 +02:00
const { responsiveDimensions = false } = await getService('upload').getSettings();
if (!responsiveDimensions) return [];
if (!(await canBeProccessed(file.buffer))) {
return [];
}
const originalDimensions = await getDimensions(file.buffer);
const breakpoints = getBreakpoints();
return Promise.all(
Object.keys(breakpoints).map(key => {
const breakpoint = breakpoints[key];
if (breakpointSmallerThan(breakpoint, originalDimensions)) {
return generateBreakpoint(key, { file, breakpoint, originalDimensions });
}
})
);
};
const generateBreakpoint = async (key, { file, breakpoint }) => {
const newBuff = await resizeTo(file.buffer, {
width: breakpoint,
height: breakpoint,
fit: 'inside',
});
if (newBuff) {
const { width, height, size } = await getMetadatas(newBuff);
return {
key,
file: {
name: `${key}_${file.name}`,
hash: `${key}_${file.hash}`,
ext: file.ext,
mime: file.mime,
width,
height,
size: bytesToKbytes(size),
buffer: newBuff,
path: file.path ? file.path : null,
},
};
}
};
const breakpointSmallerThan = (breakpoint, { width, height }) => {
return breakpoint < width || breakpoint < height;
};
const formatsToProccess = ['jpeg', 'png', 'webp', 'tiff'];
const canBeProccessed = async buffer => {
const { format } = await getMetadatas(buffer);
return format && formatsToProccess.includes(format);
};
2021-07-08 11:20:13 +02:00
module.exports = () => ({
getDimensions,
generateResponsiveFormats,
generateThumbnail,
bytesToKbytes,
optimize,
2021-07-08 11:20:13 +02:00
});