From 2de435f43a2e75391a655e91a0cda251da776bcb Mon Sep 17 00:00:00 2001 From: Dan Ribbens Date: Fri, 23 Dec 2022 11:38:49 -0500 Subject: [PATCH] fix: #1738 save image dimensions to svg uploads --- src/uploads/generateFileData.ts | 46 +++++++++++++++++++++++---------- src/uploads/imageResizer.ts | 7 ++--- test/uploads/image.svg | 15 +++++++++++ test/uploads/int.spec.ts | 25 +++++++++++++++++- 4 files changed, 75 insertions(+), 18 deletions(-) create mode 100644 test/uploads/image.svg diff --git a/src/uploads/generateFileData.ts b/src/uploads/generateFileData.ts index a01e92649..e76e9b6ac 100644 --- a/src/uploads/generateFileData.ts +++ b/src/uploads/generateFileData.ts @@ -12,6 +12,7 @@ import getSafeFileName from './getSafeFilename'; import resizeAndSave from './imageResizer'; import { FileData, FileToSave } from './types'; import canResizeImage from './canResizeImage'; +import isImage from './isImage'; type Args = { config: SanitizedConfig, @@ -67,7 +68,12 @@ export const generateFileData = async ({ const shouldResize = canResizeImage(file.mimetype); let fsSafeName: string; let resized: Sharp | undefined; - let dimensions: ProbedImageSize; + let dimensions; + let fileBuffer; + let bufferInfo; + let ext; + let mime; + if (shouldResize) { if (resizeOptions) { resized = sharp(file.data) @@ -76,34 +82,46 @@ export const generateFileData = async ({ if (formatOptions) { resized = (resized ?? sharp(file.data)).toFormat(formatOptions.format, formatOptions.options); } + } + + if (isImage(file.mimetype)) { dimensions = await getImageSize(file); fileData.width = dimensions.width; fileData.height = dimensions.height; } - const fileBuffer = resized ? (await resized.toBuffer()) : file.data; - const bufferInfo = await fromBuffer(fileBuffer); - let mime = bufferInfo?.mime ?? file.mimetype; - const ext = resized ? bufferInfo.ext : file.name.split('.').pop(); - const fileSize = fileBuffer.length; + if (resized) { + fileBuffer = await resized.toBuffer({ resolveWithObject: true }); + bufferInfo = await fromBuffer(fileBuffer.data); + + mime = bufferInfo.mime; + ext = bufferInfo.ext; + fileData.width = fileBuffer.info.width; + fileData.height = fileBuffer.info.height; + fileData.filesize = fileBuffer.data.length; + } else { + mime = file.mimetype; + fileData.filesize = file.size; + ext = file.name.split('.').pop(); + } + + if (mime === 'application/xml' && ext === 'svg') mime = 'image/svg+xml'; + fileData.mimeType = mime; + const baseFilename = sanitize(file.name.substring(0, file.name.lastIndexOf('.')) || file.name); fsSafeName = `${baseFilename}.${ext}`; - if (mime === 'application/xml' && ext === 'svg') mime = 'image/svg+xml'; - if (!overwriteExistingFiles) { - fsSafeName = await getSafeFileName(Model, staticPath, fsSafeName); + fsSafeName = await getSafeFileName(Model, staticPath, `${baseFilename}.${ext}`); } + fileData.filename = fsSafeName; + filesToSave.push({ path: `${staticPath}/${fsSafeName}`, - buffer: fileBuffer, + buffer: fileBuffer?.data || file.data, }); - fileData.filename = fsSafeName || (!overwriteExistingFiles ? await getSafeFileName(Model, staticPath, file.name) : file.name); - fileData.filesize = fileSize || file.size; - fileData.mimeType = mime || (await fromBuffer(file.data)).mime; - if (Array.isArray(imageSizes) && shouldResize) { req.payloadUploadSizes = {}; const { sizeData, sizesToSave } = await resizeAndSave({ diff --git a/src/uploads/imageResizer.ts b/src/uploads/imageResizer.ts index 35b8f9c35..7b7a2568e 100644 --- a/src/uploads/imageResizer.ts +++ b/src/uploads/imageResizer.ts @@ -5,13 +5,14 @@ import sharp from 'sharp'; import { SanitizedCollectionConfig } from '../collections/config/types'; import { PayloadRequest } from '../express/types'; import fileExists from './fileExists'; -import { ProbedImageSize } from './getImageSize'; import { FileSizes, FileToSave, ImageSize } from './types'; +type Dimensions = { width?: number, height?: number } + type Args = { req: PayloadRequest file: Buffer - dimensions: ProbedImageSize + dimensions: Dimensions staticPath: string config: SanitizedCollectionConfig savedFilename: string @@ -118,7 +119,7 @@ function createImageName( return `${outputImage.name}-${bufferObject.info.width}x${bufferObject.info.height}.${extension}`; } -function needsResize(desiredSize: ImageSize, dimensions: ProbedImageSize): boolean { +function needsResize(desiredSize: ImageSize, dimensions: Dimensions): boolean { return (typeof desiredSize.width === 'number' && desiredSize.width <= dimensions.width) || (typeof desiredSize.height === 'number' && desiredSize.height <= dimensions.height); } diff --git a/test/uploads/image.svg b/test/uploads/image.svg new file mode 100644 index 000000000..42f36913c --- /dev/null +++ b/test/uploads/image.svg @@ -0,0 +1,15 @@ + + + + + diff --git a/test/uploads/int.spec.ts b/test/uploads/int.spec.ts index c223e6f49..ba986ebd2 100644 --- a/test/uploads/int.spec.ts +++ b/test/uploads/int.spec.ts @@ -26,7 +26,7 @@ describe('Collections - Uploads', () => { describe('REST', () => { describe('create', () => { - it('creates from form data', async () => { + it('creates from form data given a png', async () => { const formData = new FormData(); formData.append('file', fs.createReadStream(path.join(__dirname, './image.png'))); @@ -56,6 +56,29 @@ describe('Collections - Uploads', () => { expect(doc.sizes).toHaveProperty('mobile'); expect(doc.sizes).toHaveProperty('icon'); }); + + it('creates from form data given an svg', async () => { + const formData = new FormData(); + formData.append('file', fs.createReadStream(path.join(__dirname, './image.svg'))); + + const { status, doc } = await client.create({ + file: true, + data: formData, + auth: true, + headers: {}, + }); + + expect(status).toBe(201); + + // Check for files + expect(await fileExists(path.join(__dirname, './media', doc.filename))).toBe(true); + + // Check api response + expect(doc.mimeType).toEqual('image/svg+xml'); + expect(doc.sizes.maintainedAspectRatio.url).toBeUndefined(); + expect(doc.width).toBeDefined(); + expect(doc.height).toBeDefined(); + }); }); it('creates images that do not require all sizes', async () => {