mirror of
				https://github.com/strapi/strapi.git
				synced 2025-11-04 11:54:10 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			155 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			155 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
'use strict';
 | 
						|
/**
 | 
						|
 * Image manipulation functions
 | 
						|
 */
 | 
						|
const sharp = require('sharp');
 | 
						|
 | 
						|
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)
 | 
						|
    .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 {
 | 
						|
        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 => {
 | 
						|
  const { sizeOptimization = false } = await strapi.plugins.upload.services.upload.getSettings();
 | 
						|
 | 
						|
  if (!sizeOptimization) return { buffer };
 | 
						|
 | 
						|
  if (!(await canBeProccessed(buffer))) {
 | 
						|
    return { buffer };
 | 
						|
  }
 | 
						|
 | 
						|
  return sharp(buffer)
 | 
						|
    .toBuffer({ resolveWithObject: true })
 | 
						|
    .then(({ data, info }) => ({
 | 
						|
      buffer: data,
 | 
						|
      info: {
 | 
						|
        width: info.width,
 | 
						|
        height: info.height,
 | 
						|
        size: bytesToKbytes(info.size),
 | 
						|
      },
 | 
						|
    }))
 | 
						|
    .catch(() => ({ buffer }));
 | 
						|
};
 | 
						|
 | 
						|
const BREAKPOINTS = {
 | 
						|
  large: 1000,
 | 
						|
  medium: 750,
 | 
						|
  small: 500,
 | 
						|
};
 | 
						|
 | 
						|
const generateResponsiveFormats = async file => {
 | 
						|
  const {
 | 
						|
    responsiveDimensions = false,
 | 
						|
  } = await strapi.plugins.upload.services.upload.getSettings();
 | 
						|
 | 
						|
  if (!responsiveDimensions) return [];
 | 
						|
 | 
						|
  if (!(await canBeProccessed(file.buffer))) {
 | 
						|
    return [];
 | 
						|
  }
 | 
						|
 | 
						|
  const originalDimensions = await getDimensions(file.buffer);
 | 
						|
 | 
						|
  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: {
 | 
						|
        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);
 | 
						|
};
 | 
						|
 | 
						|
module.exports = {
 | 
						|
  getDimensions,
 | 
						|
  generateResponsiveFormats,
 | 
						|
  generateThumbnail,
 | 
						|
  bytesToKbytes,
 | 
						|
  optimize,
 | 
						|
};
 |