payload 3.0.0-beta.66 → 3.0.0-beta.67

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,8 +1,21 @@
1
+ import type { SanitizedConfig } from '../config/types.js';
2
+ import type { PayloadRequest } from '../types/index.js';
3
+ import type { UploadEdits } from './types.js';
1
4
  export declare const percentToPixel: (value: any, dimension: any) => number;
2
- export declare function cropImage({ cropData, dimensions, file, sharp }: {
3
- cropData: any;
4
- dimensions: any;
5
- file: any;
6
- sharp: any;
7
- }): Promise<any>;
5
+ type CropImageArgs = {
6
+ cropData: UploadEdits['crop'];
7
+ dimensions: {
8
+ height: number;
9
+ width: number;
10
+ };
11
+ file: PayloadRequest['file'];
12
+ heightInPixels: number;
13
+ sharp: SanitizedConfig['sharp'];
14
+ widthInPixels: number;
15
+ };
16
+ export declare function cropImage({ cropData, dimensions, file, heightInPixels, sharp, widthInPixels, }: CropImageArgs): Promise<{
17
+ data: Buffer;
18
+ info: import("sharp").OutputInfo;
19
+ }>;
20
+ export {};
8
21
  //# sourceMappingURL=cropImage.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"cropImage.d.ts","sourceRoot":"","sources":["../../src/uploads/cropImage.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,cAAc,wCAE1B,CAAA;AAED,wBAAsB,SAAS,CAAC,EAAE,QAAQ,EAAE,UAAU,EAAE,IAAI,EAAE,KAAK,EAAE;;;;;CAAA,gBA0BpE"}
1
+ {"version":3,"file":"cropImage.d.ts","sourceRoot":"","sources":["../../src/uploads/cropImage.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AACzD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AACvD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAE7C,eAAO,MAAM,cAAc,wCAE1B,CAAA;AAED,KAAK,aAAa,GAAG;IACnB,QAAQ,EAAE,WAAW,CAAC,MAAM,CAAC,CAAA;IAC7B,UAAU,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAA;IAC7C,IAAI,EAAE,cAAc,CAAC,MAAM,CAAC,CAAA;IAC5B,cAAc,EAAE,MAAM,CAAA;IACtB,KAAK,EAAE,eAAe,CAAC,OAAO,CAAC,CAAA;IAC/B,aAAa,EAAE,MAAM,CAAA;CACtB,CAAA;AACD,wBAAsB,SAAS,CAAC,EAC9B,QAAQ,EACR,UAAU,EACV,IAAI,EACJ,cAAc,EACd,KAAK,EACL,aAAa,GACd,EAAE,aAAa;;;GA0Bf"}
@@ -1,9 +1,9 @@
1
1
  export const percentToPixel = (value, dimension)=>{
2
2
  return Math.floor(parseFloat(value) / 100 * dimension);
3
3
  };
4
- export async function cropImage({ cropData, dimensions, file, sharp }) {
4
+ export async function cropImage({ cropData, dimensions, file, heightInPixels, sharp, widthInPixels }) {
5
5
  try {
6
- const { heightPixels, widthPixels, x, y } = cropData;
6
+ const { x, y } = cropData;
7
7
  const fileIsAnimatedType = [
8
8
  'image/avif',
9
9
  'image/gif',
@@ -12,10 +12,10 @@ export async function cropImage({ cropData, dimensions, file, sharp }) {
12
12
  const sharpOptions = {};
13
13
  if (fileIsAnimatedType) sharpOptions.animated = true;
14
14
  const formattedCropData = {
15
- height: Number(heightPixels),
15
+ height: Number(heightInPixels),
16
16
  left: percentToPixel(x, dimensions.width),
17
17
  top: percentToPixel(y, dimensions.height),
18
- width: Number(widthPixels)
18
+ width: Number(widthInPixels)
19
19
  };
20
20
  const cropped = sharp(file.tempFilePath || file.data, sharpOptions).extract(formattedCropData);
21
21
  return await cropped.toBuffer({
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/uploads/cropImage.ts"],"sourcesContent":["import type { SharpOptions } from 'sharp'\n\nexport const percentToPixel = (value, dimension) => {\n return Math.floor((parseFloat(value) / 100) * dimension)\n}\n\nexport async function cropImage({ cropData, dimensions, file, sharp }) {\n try {\n const { heightPixels, widthPixels, x, y } = cropData\n\n const fileIsAnimatedType = ['image/avif', 'image/gif', 'image/webp'].includes(file.mimetype)\n\n const sharpOptions: SharpOptions = {}\n\n if (fileIsAnimatedType) sharpOptions.animated = true\n\n const formattedCropData = {\n height: Number(heightPixels),\n left: percentToPixel(x, dimensions.width),\n top: percentToPixel(y, dimensions.height),\n width: Number(widthPixels),\n }\n\n const cropped = sharp(file.tempFilePath || file.data, sharpOptions).extract(formattedCropData)\n\n return await cropped.toBuffer({\n resolveWithObject: true,\n })\n } catch (error) {\n console.error(`Error cropping image:`, error)\n throw error\n }\n}\n"],"names":["percentToPixel","value","dimension","Math","floor","parseFloat","cropImage","cropData","dimensions","file","sharp","heightPixels","widthPixels","x","y","fileIsAnimatedType","includes","mimetype","sharpOptions","animated","formattedCropData","height","Number","left","width","top","cropped","tempFilePath","data","extract","toBuffer","resolveWithObject","error","console"],"mappings":"AAEA,OAAO,MAAMA,iBAAiB,CAACC,OAAOC;IACpC,OAAOC,KAAKC,KAAK,CAAC,AAACC,WAAWJ,SAAS,MAAOC;AAChD,EAAC;AAED,OAAO,eAAeI,UAAU,EAAEC,QAAQ,EAAEC,UAAU,EAAEC,IAAI,EAAEC,KAAK,EAAE;IACnE,IAAI;QACF,MAAM,EAAEC,YAAY,EAAEC,WAAW,EAAEC,CAAC,EAAEC,CAAC,EAAE,GAAGP;QAE5C,MAAMQ,qBAAqB;YAAC;YAAc;YAAa;SAAa,CAACC,QAAQ,CAACP,KAAKQ,QAAQ;QAE3F,MAAMC,eAA6B,CAAC;QAEpC,IAAIH,oBAAoBG,aAAaC,QAAQ,GAAG;QAEhD,MAAMC,oBAAoB;YACxBC,QAAQC,OAAOX;YACfY,MAAMvB,eAAea,GAAGL,WAAWgB,KAAK;YACxCC,KAAKzB,eAAec,GAAGN,WAAWa,MAAM;YACxCG,OAAOF,OAAOV;QAChB;QAEA,MAAMc,UAAUhB,MAAMD,KAAKkB,YAAY,IAAIlB,KAAKmB,IAAI,EAAEV,cAAcW,OAAO,CAACT;QAE5E,OAAO,MAAMM,QAAQI,QAAQ,CAAC;YAC5BC,mBAAmB;QACrB;IACF,EAAE,OAAOC,OAAO;QACdC,QAAQD,KAAK,CAAC,CAAC,qBAAqB,CAAC,EAAEA;QACvC,MAAMA;IACR;AACF"}
1
+ {"version":3,"sources":["../../src/uploads/cropImage.ts"],"sourcesContent":["import type { SharpOptions } from 'sharp'\n\nimport type { SanitizedConfig } from '../config/types.js'\nimport type { PayloadRequest } from '../types/index.js'\nimport type { UploadEdits } from './types.js'\n\nexport const percentToPixel = (value, dimension) => {\n return Math.floor((parseFloat(value) / 100) * dimension)\n}\n\ntype CropImageArgs = {\n cropData: UploadEdits['crop']\n dimensions: { height: number; width: number }\n file: PayloadRequest['file']\n heightInPixels: number\n sharp: SanitizedConfig['sharp']\n widthInPixels: number\n}\nexport async function cropImage({\n cropData,\n dimensions,\n file,\n heightInPixels,\n sharp,\n widthInPixels,\n}: CropImageArgs) {\n try {\n const { x, y } = cropData\n\n const fileIsAnimatedType = ['image/avif', 'image/gif', 'image/webp'].includes(file.mimetype)\n\n const sharpOptions: SharpOptions = {}\n\n if (fileIsAnimatedType) sharpOptions.animated = true\n\n const formattedCropData = {\n height: Number(heightInPixels),\n left: percentToPixel(x, dimensions.width),\n top: percentToPixel(y, dimensions.height),\n width: Number(widthInPixels),\n }\n\n const cropped = sharp(file.tempFilePath || file.data, sharpOptions).extract(formattedCropData)\n\n return await cropped.toBuffer({\n resolveWithObject: true,\n })\n } catch (error) {\n console.error(`Error cropping image:`, error)\n throw error\n }\n}\n"],"names":["percentToPixel","value","dimension","Math","floor","parseFloat","cropImage","cropData","dimensions","file","heightInPixels","sharp","widthInPixels","x","y","fileIsAnimatedType","includes","mimetype","sharpOptions","animated","formattedCropData","height","Number","left","width","top","cropped","tempFilePath","data","extract","toBuffer","resolveWithObject","error","console"],"mappings":"AAMA,OAAO,MAAMA,iBAAiB,CAACC,OAAOC;IACpC,OAAOC,KAAKC,KAAK,CAAC,AAACC,WAAWJ,SAAS,MAAOC;AAChD,EAAC;AAUD,OAAO,eAAeI,UAAU,EAC9BC,QAAQ,EACRC,UAAU,EACVC,IAAI,EACJC,cAAc,EACdC,KAAK,EACLC,aAAa,EACC;IACd,IAAI;QACF,MAAM,EAAEC,CAAC,EAAEC,CAAC,EAAE,GAAGP;QAEjB,MAAMQ,qBAAqB;YAAC;YAAc;YAAa;SAAa,CAACC,QAAQ,CAACP,KAAKQ,QAAQ;QAE3F,MAAMC,eAA6B,CAAC;QAEpC,IAAIH,oBAAoBG,aAAaC,QAAQ,GAAG;QAEhD,MAAMC,oBAAoB;YACxBC,QAAQC,OAAOZ;YACfa,MAAMvB,eAAea,GAAGL,WAAWgB,KAAK;YACxCC,KAAKzB,eAAec,GAAGN,WAAWa,MAAM;YACxCG,OAAOF,OAAOV;QAChB;QAEA,MAAMc,UAAUf,MAAMF,KAAKkB,YAAY,IAAIlB,KAAKmB,IAAI,EAAEV,cAAcW,OAAO,CAACT;QAE5E,OAAO,MAAMM,QAAQI,QAAQ,CAAC;YAC5BC,mBAAmB;QACrB;IACF,EAAE,OAAOC,OAAO;QACdC,QAAQD,KAAK,CAAC,CAAC,qBAAqB,CAAC,EAAEA;QACvC,MAAMA;IACR;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"generateFileData.d.ts","sourceRoot":"","sources":["../../src/uploads/generateFileData.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAA;AAChE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AACzD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AACvD,OAAO,KAAK,EAAY,UAAU,EAAgC,MAAM,YAAY,CAAA;AAYpF,KAAK,IAAI,CAAC,CAAC,IAAI;IACb,UAAU,EAAE,UAAU,CAAA;IACtB,MAAM,EAAE,eAAe,CAAA;IACvB,IAAI,EAAE,CAAC,CAAA;IACP,SAAS,EAAE,QAAQ,GAAG,QAAQ,CAAA;IAC9B,WAAW,CAAC,EAAE,CAAC,CAAA;IACf,sBAAsB,CAAC,EAAE,OAAO,CAAA;IAChC,GAAG,EAAE,cAAc,CAAA;IACnB,kBAAkB,CAAC,EAAE,OAAO,CAAA;CAC7B,CAAA;AAED,KAAK,MAAM,CAAC,CAAC,IAAI,OAAO,CAAC;IACvB,IAAI,EAAE,CAAC,CAAA;IACP,KAAK,EAAE,UAAU,EAAE,CAAA;CACpB,CAAC,CAAA;AAEF,eAAO,MAAM,gBAAgB,GAAU,CAAC,gIAQrC,IAAI,CAAC,CAAC,CAAC,KAAG,MAAM,CAAC,CAAC,CAoPpB,CAAA"}
1
+ {"version":3,"file":"generateFileData.d.ts","sourceRoot":"","sources":["../../src/uploads/generateFileData.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAA;AAChE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AACzD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AACvD,OAAO,KAAK,EAAY,UAAU,EAAgC,MAAM,YAAY,CAAA;AAYpF,KAAK,IAAI,CAAC,CAAC,IAAI;IACb,UAAU,EAAE,UAAU,CAAA;IACtB,MAAM,EAAE,eAAe,CAAA;IACvB,IAAI,EAAE,CAAC,CAAA;IACP,SAAS,EAAE,QAAQ,GAAG,QAAQ,CAAA;IAC9B,WAAW,CAAC,EAAE,CAAC,CAAA;IACf,sBAAsB,CAAC,EAAE,OAAO,CAAA;IAChC,GAAG,EAAE,cAAc,CAAA;IACnB,kBAAkB,CAAC,EAAE,OAAO,CAAA;CAC7B,CAAA;AAED,KAAK,MAAM,CAAC,CAAC,IAAI,OAAO,CAAC;IACvB,IAAI,EAAE,CAAC,CAAA;IACP,KAAK,EAAE,UAAU,EAAE,CAAA;CACpB,CAAC,CAAA;AAEF,eAAO,MAAM,gBAAgB,GAAU,CAAC,gIAQrC,IAAI,CAAC,CAAC,CAAC,KAAG,MAAM,CAAC,CAAC,CA2PpB,CAAA"}
@@ -149,7 +149,9 @@ export const generateFileData = async ({ collection: { config: collectionConfig
149
149
  cropData,
150
150
  dimensions,
151
151
  file,
152
- sharp
152
+ heightInPixels: uploadEdits.heightInPixels,
153
+ sharp,
154
+ widthInPixels: uploadEdits.widthInPixels
153
155
  });
154
156
  filesToSave.push({
155
157
  buffer: croppedImage,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/uploads/generateFileData.ts"],"sourcesContent":["import type { OutputInfo, Sharp, SharpOptions } from 'sharp'\n\nimport { fileTypeFromBuffer } from 'file-type'\nimport fs from 'fs'\nimport { mkdirSync } from 'node:fs'\nimport sanitize from 'sanitize-filename'\n\nimport type { Collection } from '../collections/config/types.js'\nimport type { SanitizedConfig } from '../config/types.js'\nimport type { PayloadRequest } from '../types/index.js'\nimport type { FileData, FileToSave, ProbedImageSize, UploadEdits } from './types.js'\n\nimport { FileRetrievalError, FileUploadError, MissingFile } from '../errors/index.js'\nimport { canResizeImage } from './canResizeImage.js'\nimport { cropImage } from './cropImage.js'\nimport { getExternalFile } from './getExternalFile.js'\nimport { getFileByPath } from './getFileByPath.js'\nimport { getImageSize } from './getImageSize.js'\nimport { getSafeFileName } from './getSafeFilename.js'\nimport { resizeAndTransformImageSizes } from './imageResizer.js'\nimport { isImage } from './isImage.js'\n\ntype Args<T> = {\n collection: Collection\n config: SanitizedConfig\n data: T\n operation: 'create' | 'update'\n originalDoc?: T\n overwriteExistingFiles?: boolean\n req: PayloadRequest\n throwOnMissingFile?: boolean\n}\n\ntype Result<T> = Promise<{\n data: T\n files: FileToSave[]\n}>\n\nexport const generateFileData = async <T>({\n collection: { config: collectionConfig },\n data,\n operation,\n originalDoc,\n overwriteExistingFiles,\n req,\n throwOnMissingFile,\n}: Args<T>): Result<T> => {\n if (!collectionConfig.upload) {\n return {\n data,\n files: [],\n }\n }\n\n const { sharp } = req.payload.config\n\n let file = req.file\n\n const uploadEdits = parseUploadEditsFromReqOrIncomingData({\n data,\n operation,\n originalDoc,\n req,\n })\n\n const {\n disableLocalStorage,\n focalPoint: focalPointEnabled = true,\n formatOptions,\n imageSizes,\n resizeOptions,\n staticDir,\n trimOptions,\n } = collectionConfig.upload\n\n const staticPath = staticDir\n\n if (!file && uploadEdits && data) {\n const { filename, url } = data as FileData\n\n try {\n if (url && url.startsWith('/') && !disableLocalStorage) {\n const filePath = `${staticPath}/${filename}`\n const response = await getFileByPath(filePath)\n file = response\n overwriteExistingFiles = true\n } else if (filename && url) {\n file = await getExternalFile({\n data: data as FileData,\n req,\n uploadConfig: collectionConfig.upload,\n })\n overwriteExistingFiles = true\n }\n } catch (err: unknown) {\n throw new FileRetrievalError(req.t, err instanceof Error ? err.message : undefined)\n }\n }\n\n if (!file) {\n if (throwOnMissingFile) throw new MissingFile(req.t)\n\n return {\n data,\n files: [],\n }\n }\n\n if (!disableLocalStorage) {\n mkdirSync(staticPath, { recursive: true })\n }\n\n let newData = data\n const filesToSave: FileToSave[] = []\n const fileData: Partial<FileData> = {}\n const fileIsAnimatedType = ['image/avif', 'image/gif', 'image/webp'].includes(file.mimetype)\n const cropData =\n typeof uploadEdits === 'object' && 'crop' in uploadEdits ? uploadEdits.crop : undefined\n\n try {\n const fileSupportsResize = canResizeImage(file.mimetype)\n let fsSafeName: string\n let sharpFile: Sharp | undefined\n let dimensions: ProbedImageSize | undefined\n let fileBuffer: { data: Buffer; info: OutputInfo }\n let ext\n let mime: string\n const fileHasAdjustments =\n fileSupportsResize &&\n Boolean(resizeOptions || formatOptions || imageSizes || trimOptions || file.tempFilePath)\n\n const sharpOptions: SharpOptions = {}\n\n if (fileIsAnimatedType) sharpOptions.animated = true\n\n if (sharp && (fileIsAnimatedType || fileHasAdjustments)) {\n if (file.tempFilePath) {\n sharpFile = sharp(file.tempFilePath, sharpOptions).rotate() // pass rotate() to auto-rotate based on EXIF data. https://github.com/payloadcms/payload/pull/3081\n } else {\n sharpFile = sharp(file.data, sharpOptions).rotate() // pass rotate() to auto-rotate based on EXIF data. https://github.com/payloadcms/payload/pull/3081\n }\n\n if (fileHasAdjustments) {\n if (resizeOptions) {\n sharpFile = sharpFile.resize(resizeOptions)\n }\n if (formatOptions) {\n sharpFile = sharpFile.toFormat(formatOptions.format, formatOptions.options)\n }\n if (trimOptions) {\n sharpFile = sharpFile.trim(trimOptions)\n }\n }\n }\n\n if (fileSupportsResize || isImage(file.mimetype)) {\n dimensions = await getImageSize(file)\n fileData.width = dimensions.width\n fileData.height = dimensions.height\n }\n\n if (sharpFile) {\n const metadata = await sharpFile.metadata()\n fileBuffer = await sharpFile.toBuffer({ resolveWithObject: true })\n ;({ ext, mime } = await fileTypeFromBuffer(fileBuffer.data)) // This is getting an incorrect gif height back.\n fileData.width = fileBuffer.info.width\n fileData.height = fileBuffer.info.height\n fileData.filesize = fileBuffer.info.size\n\n // Animated GIFs + WebP aggregate the height from every frame, so we need to use divide by number of pages\n if (metadata.pages) {\n fileData.height = fileBuffer.info.height / metadata.pages\n fileData.filesize = fileBuffer.data.length\n }\n } else {\n mime = file.mimetype\n fileData.filesize = file.size\n\n if (file.name.includes('.')) {\n ext = file.name.split('.').pop().split('?')[0]\n } else {\n ext = ''\n }\n }\n\n // Adjust SVG mime type. fromBuffer modifies it.\n if (mime === 'application/xml' && ext === 'svg') mime = 'image/svg+xml'\n fileData.mimeType = mime\n\n const baseFilename = sanitize(file.name.substring(0, file.name.lastIndexOf('.')) || file.name)\n fsSafeName = `${baseFilename}${ext ? `.${ext}` : ''}`\n\n if (!overwriteExistingFiles) {\n fsSafeName = await getSafeFileName({\n collectionSlug: collectionConfig.slug,\n desiredFilename: fsSafeName,\n req,\n staticPath,\n })\n }\n\n fileData.filename = fsSafeName\n let fileForResize = file\n\n if (cropData && sharp) {\n const { data: croppedImage, info } = await cropImage({ cropData, dimensions, file, sharp })\n\n filesToSave.push({\n buffer: croppedImage,\n path: `${staticPath}/${fsSafeName}`,\n })\n\n fileForResize = {\n ...file,\n data: croppedImage,\n size: info.size,\n }\n fileData.width = info.width\n fileData.height = info.height\n if (fileIsAnimatedType) {\n const metadata = await sharpFile.metadata()\n fileData.height = metadata.pages ? info.height / metadata.pages : info.height\n }\n fileData.filesize = info.size\n\n if (file.tempFilePath) {\n await fs.promises.writeFile(file.tempFilePath, croppedImage) // write fileBuffer to the temp path\n } else {\n req.file = fileForResize\n }\n } else {\n filesToSave.push({\n buffer: fileBuffer?.data || file.data,\n path: `${staticPath}/${fsSafeName}`,\n })\n\n // If using temp files and the image is being resized, write the file to the temp path\n if (fileBuffer?.data || file.data.length > 0) {\n if (file.tempFilePath) {\n await fs.promises.writeFile(file.tempFilePath, fileBuffer?.data || file.data) // write fileBuffer to the temp path\n } else {\n // Assign the _possibly modified_ file to the request object\n req.file = {\n ...file,\n data: fileBuffer?.data || file.data,\n size: fileBuffer?.info.size,\n }\n }\n }\n }\n\n if (fileSupportsResize && (Array.isArray(imageSizes) || focalPointEnabled !== false)) {\n req.payloadUploadSizes = {}\n const { focalPoint, sizeData, sizesToSave } = await resizeAndTransformImageSizes({\n config: collectionConfig,\n dimensions: !cropData\n ? dimensions\n : {\n ...dimensions,\n height: fileData.height,\n width: fileData.width,\n },\n file: fileForResize,\n mimeType: fileData.mimeType,\n req,\n savedFilename: fsSafeName || file.name,\n sharp,\n staticPath,\n uploadEdits,\n })\n\n fileData.sizes = sizeData\n fileData.focalX = focalPoint?.x\n fileData.focalY = focalPoint?.y\n filesToSave.push(...sizesToSave)\n }\n } catch (err) {\n req.payload.logger.error(err)\n throw new FileUploadError(req.t)\n }\n\n newData = {\n ...newData,\n ...fileData,\n }\n\n return {\n data: newData,\n files: filesToSave,\n }\n}\n\n/**\n * Parse upload edits from req or incoming data\n */\nfunction parseUploadEditsFromReqOrIncomingData(args: {\n data: unknown\n operation: 'create' | 'update'\n originalDoc: unknown\n req: PayloadRequest\n}): UploadEdits {\n const { data, operation, originalDoc, req } = args\n\n // Get intended focal point change from query string or incoming data\n const uploadEdits =\n req.query?.uploadEdits && typeof req.query.uploadEdits === 'object'\n ? (req.query.uploadEdits as UploadEdits)\n : {}\n\n if (uploadEdits.focalPoint) return uploadEdits\n\n const incomingData = data as FileData\n const origDoc = originalDoc as FileData\n\n // If no change in focal point, return undefined.\n // This prevents a refocal operation triggered from admin, because it always sends the focal point.\n if (origDoc && incomingData.focalX === origDoc.focalX && incomingData.focalY === origDoc.focalY) {\n return undefined\n }\n\n if (incomingData?.focalX && incomingData?.focalY) {\n uploadEdits.focalPoint = {\n x: incomingData.focalX,\n y: incomingData.focalY,\n }\n return uploadEdits\n }\n\n // If no focal point is set, default to center\n if (operation === 'create') {\n uploadEdits.focalPoint = {\n x: 50,\n y: 50,\n }\n }\n return uploadEdits\n}\n"],"names":["fileTypeFromBuffer","fs","mkdirSync","sanitize","FileRetrievalError","FileUploadError","MissingFile","canResizeImage","cropImage","getExternalFile","getFileByPath","getImageSize","getSafeFileName","resizeAndTransformImageSizes","isImage","generateFileData","collection","config","collectionConfig","data","operation","originalDoc","overwriteExistingFiles","req","throwOnMissingFile","upload","files","sharp","payload","file","uploadEdits","parseUploadEditsFromReqOrIncomingData","disableLocalStorage","focalPoint","focalPointEnabled","formatOptions","imageSizes","resizeOptions","staticDir","trimOptions","staticPath","filename","url","startsWith","filePath","response","uploadConfig","err","t","Error","message","undefined","recursive","newData","filesToSave","fileData","fileIsAnimatedType","includes","mimetype","cropData","crop","fileSupportsResize","fsSafeName","sharpFile","dimensions","fileBuffer","ext","mime","fileHasAdjustments","Boolean","tempFilePath","sharpOptions","animated","rotate","resize","toFormat","format","options","trim","width","height","metadata","toBuffer","resolveWithObject","info","filesize","size","pages","length","name","split","pop","mimeType","baseFilename","substring","lastIndexOf","collectionSlug","slug","desiredFilename","fileForResize","croppedImage","push","buffer","path","promises","writeFile","Array","isArray","payloadUploadSizes","sizeData","sizesToSave","savedFilename","sizes","focalX","x","focalY","y","logger","error","args","query","incomingData","origDoc"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/uploads/generateFileData.ts"],"sourcesContent":["import type { OutputInfo, Sharp, SharpOptions } from 'sharp'\n\nimport { fileTypeFromBuffer } from 'file-type'\nimport fs from 'fs'\nimport { mkdirSync } from 'node:fs'\nimport sanitize from 'sanitize-filename'\n\nimport type { Collection } from '../collections/config/types.js'\nimport type { SanitizedConfig } from '../config/types.js'\nimport type { PayloadRequest } from '../types/index.js'\nimport type { FileData, FileToSave, ProbedImageSize, UploadEdits } from './types.js'\n\nimport { FileRetrievalError, FileUploadError, MissingFile } from '../errors/index.js'\nimport { canResizeImage } from './canResizeImage.js'\nimport { cropImage } from './cropImage.js'\nimport { getExternalFile } from './getExternalFile.js'\nimport { getFileByPath } from './getFileByPath.js'\nimport { getImageSize } from './getImageSize.js'\nimport { getSafeFileName } from './getSafeFilename.js'\nimport { resizeAndTransformImageSizes } from './imageResizer.js'\nimport { isImage } from './isImage.js'\n\ntype Args<T> = {\n collection: Collection\n config: SanitizedConfig\n data: T\n operation: 'create' | 'update'\n originalDoc?: T\n overwriteExistingFiles?: boolean\n req: PayloadRequest\n throwOnMissingFile?: boolean\n}\n\ntype Result<T> = Promise<{\n data: T\n files: FileToSave[]\n}>\n\nexport const generateFileData = async <T>({\n collection: { config: collectionConfig },\n data,\n operation,\n originalDoc,\n overwriteExistingFiles,\n req,\n throwOnMissingFile,\n}: Args<T>): Result<T> => {\n if (!collectionConfig.upload) {\n return {\n data,\n files: [],\n }\n }\n\n const { sharp } = req.payload.config\n\n let file = req.file\n\n const uploadEdits = parseUploadEditsFromReqOrIncomingData({\n data,\n operation,\n originalDoc,\n req,\n })\n\n const {\n disableLocalStorage,\n focalPoint: focalPointEnabled = true,\n formatOptions,\n imageSizes,\n resizeOptions,\n staticDir,\n trimOptions,\n } = collectionConfig.upload\n\n const staticPath = staticDir\n\n if (!file && uploadEdits && data) {\n const { filename, url } = data as FileData\n\n try {\n if (url && url.startsWith('/') && !disableLocalStorage) {\n const filePath = `${staticPath}/${filename}`\n const response = await getFileByPath(filePath)\n file = response\n overwriteExistingFiles = true\n } else if (filename && url) {\n file = await getExternalFile({\n data: data as FileData,\n req,\n uploadConfig: collectionConfig.upload,\n })\n overwriteExistingFiles = true\n }\n } catch (err: unknown) {\n throw new FileRetrievalError(req.t, err instanceof Error ? err.message : undefined)\n }\n }\n\n if (!file) {\n if (throwOnMissingFile) throw new MissingFile(req.t)\n\n return {\n data,\n files: [],\n }\n }\n\n if (!disableLocalStorage) {\n mkdirSync(staticPath, { recursive: true })\n }\n\n let newData = data\n const filesToSave: FileToSave[] = []\n const fileData: Partial<FileData> = {}\n const fileIsAnimatedType = ['image/avif', 'image/gif', 'image/webp'].includes(file.mimetype)\n const cropData =\n typeof uploadEdits === 'object' && 'crop' in uploadEdits ? uploadEdits.crop : undefined\n\n try {\n const fileSupportsResize = canResizeImage(file.mimetype)\n let fsSafeName: string\n let sharpFile: Sharp | undefined\n let dimensions: ProbedImageSize | undefined\n let fileBuffer: { data: Buffer; info: OutputInfo }\n let ext\n let mime: string\n const fileHasAdjustments =\n fileSupportsResize &&\n Boolean(resizeOptions || formatOptions || imageSizes || trimOptions || file.tempFilePath)\n\n const sharpOptions: SharpOptions = {}\n\n if (fileIsAnimatedType) sharpOptions.animated = true\n\n if (sharp && (fileIsAnimatedType || fileHasAdjustments)) {\n if (file.tempFilePath) {\n sharpFile = sharp(file.tempFilePath, sharpOptions).rotate() // pass rotate() to auto-rotate based on EXIF data. https://github.com/payloadcms/payload/pull/3081\n } else {\n sharpFile = sharp(file.data, sharpOptions).rotate() // pass rotate() to auto-rotate based on EXIF data. https://github.com/payloadcms/payload/pull/3081\n }\n\n if (fileHasAdjustments) {\n if (resizeOptions) {\n sharpFile = sharpFile.resize(resizeOptions)\n }\n if (formatOptions) {\n sharpFile = sharpFile.toFormat(formatOptions.format, formatOptions.options)\n }\n if (trimOptions) {\n sharpFile = sharpFile.trim(trimOptions)\n }\n }\n }\n\n if (fileSupportsResize || isImage(file.mimetype)) {\n dimensions = await getImageSize(file)\n fileData.width = dimensions.width\n fileData.height = dimensions.height\n }\n\n if (sharpFile) {\n const metadata = await sharpFile.metadata()\n fileBuffer = await sharpFile.toBuffer({ resolveWithObject: true })\n ;({ ext, mime } = await fileTypeFromBuffer(fileBuffer.data)) // This is getting an incorrect gif height back.\n fileData.width = fileBuffer.info.width\n fileData.height = fileBuffer.info.height\n fileData.filesize = fileBuffer.info.size\n\n // Animated GIFs + WebP aggregate the height from every frame, so we need to use divide by number of pages\n if (metadata.pages) {\n fileData.height = fileBuffer.info.height / metadata.pages\n fileData.filesize = fileBuffer.data.length\n }\n } else {\n mime = file.mimetype\n fileData.filesize = file.size\n\n if (file.name.includes('.')) {\n ext = file.name.split('.').pop().split('?')[0]\n } else {\n ext = ''\n }\n }\n\n // Adjust SVG mime type. fromBuffer modifies it.\n if (mime === 'application/xml' && ext === 'svg') mime = 'image/svg+xml'\n fileData.mimeType = mime\n\n const baseFilename = sanitize(file.name.substring(0, file.name.lastIndexOf('.')) || file.name)\n fsSafeName = `${baseFilename}${ext ? `.${ext}` : ''}`\n\n if (!overwriteExistingFiles) {\n fsSafeName = await getSafeFileName({\n collectionSlug: collectionConfig.slug,\n desiredFilename: fsSafeName,\n req,\n staticPath,\n })\n }\n\n fileData.filename = fsSafeName\n let fileForResize = file\n\n if (cropData && sharp) {\n const { data: croppedImage, info } = await cropImage({\n cropData,\n dimensions,\n file,\n heightInPixels: uploadEdits.heightInPixels,\n sharp,\n widthInPixels: uploadEdits.widthInPixels,\n })\n\n filesToSave.push({\n buffer: croppedImage,\n path: `${staticPath}/${fsSafeName}`,\n })\n\n fileForResize = {\n ...file,\n data: croppedImage,\n size: info.size,\n }\n fileData.width = info.width\n fileData.height = info.height\n if (fileIsAnimatedType) {\n const metadata = await sharpFile.metadata()\n fileData.height = metadata.pages ? info.height / metadata.pages : info.height\n }\n fileData.filesize = info.size\n\n if (file.tempFilePath) {\n await fs.promises.writeFile(file.tempFilePath, croppedImage) // write fileBuffer to the temp path\n } else {\n req.file = fileForResize\n }\n } else {\n filesToSave.push({\n buffer: fileBuffer?.data || file.data,\n path: `${staticPath}/${fsSafeName}`,\n })\n\n // If using temp files and the image is being resized, write the file to the temp path\n if (fileBuffer?.data || file.data.length > 0) {\n if (file.tempFilePath) {\n await fs.promises.writeFile(file.tempFilePath, fileBuffer?.data || file.data) // write fileBuffer to the temp path\n } else {\n // Assign the _possibly modified_ file to the request object\n req.file = {\n ...file,\n data: fileBuffer?.data || file.data,\n size: fileBuffer?.info.size,\n }\n }\n }\n }\n\n if (fileSupportsResize && (Array.isArray(imageSizes) || focalPointEnabled !== false)) {\n req.payloadUploadSizes = {}\n const { focalPoint, sizeData, sizesToSave } = await resizeAndTransformImageSizes({\n config: collectionConfig,\n dimensions: !cropData\n ? dimensions\n : {\n ...dimensions,\n height: fileData.height,\n width: fileData.width,\n },\n file: fileForResize,\n mimeType: fileData.mimeType,\n req,\n savedFilename: fsSafeName || file.name,\n sharp,\n staticPath,\n uploadEdits,\n })\n\n fileData.sizes = sizeData\n fileData.focalX = focalPoint?.x\n fileData.focalY = focalPoint?.y\n filesToSave.push(...sizesToSave)\n }\n } catch (err) {\n req.payload.logger.error(err)\n throw new FileUploadError(req.t)\n }\n\n newData = {\n ...newData,\n ...fileData,\n }\n\n return {\n data: newData,\n files: filesToSave,\n }\n}\n\n/**\n * Parse upload edits from req or incoming data\n */\nfunction parseUploadEditsFromReqOrIncomingData(args: {\n data: unknown\n operation: 'create' | 'update'\n originalDoc: unknown\n req: PayloadRequest\n}): UploadEdits {\n const { data, operation, originalDoc, req } = args\n\n // Get intended focal point change from query string or incoming data\n const uploadEdits =\n req.query?.uploadEdits && typeof req.query.uploadEdits === 'object'\n ? (req.query.uploadEdits as UploadEdits)\n : {}\n\n if (uploadEdits.focalPoint) return uploadEdits\n\n const incomingData = data as FileData\n const origDoc = originalDoc as FileData\n\n // If no change in focal point, return undefined.\n // This prevents a refocal operation triggered from admin, because it always sends the focal point.\n if (origDoc && incomingData.focalX === origDoc.focalX && incomingData.focalY === origDoc.focalY) {\n return undefined\n }\n\n if (incomingData?.focalX && incomingData?.focalY) {\n uploadEdits.focalPoint = {\n x: incomingData.focalX,\n y: incomingData.focalY,\n }\n return uploadEdits\n }\n\n // If no focal point is set, default to center\n if (operation === 'create') {\n uploadEdits.focalPoint = {\n x: 50,\n y: 50,\n }\n }\n return uploadEdits\n}\n"],"names":["fileTypeFromBuffer","fs","mkdirSync","sanitize","FileRetrievalError","FileUploadError","MissingFile","canResizeImage","cropImage","getExternalFile","getFileByPath","getImageSize","getSafeFileName","resizeAndTransformImageSizes","isImage","generateFileData","collection","config","collectionConfig","data","operation","originalDoc","overwriteExistingFiles","req","throwOnMissingFile","upload","files","sharp","payload","file","uploadEdits","parseUploadEditsFromReqOrIncomingData","disableLocalStorage","focalPoint","focalPointEnabled","formatOptions","imageSizes","resizeOptions","staticDir","trimOptions","staticPath","filename","url","startsWith","filePath","response","uploadConfig","err","t","Error","message","undefined","recursive","newData","filesToSave","fileData","fileIsAnimatedType","includes","mimetype","cropData","crop","fileSupportsResize","fsSafeName","sharpFile","dimensions","fileBuffer","ext","mime","fileHasAdjustments","Boolean","tempFilePath","sharpOptions","animated","rotate","resize","toFormat","format","options","trim","width","height","metadata","toBuffer","resolveWithObject","info","filesize","size","pages","length","name","split","pop","mimeType","baseFilename","substring","lastIndexOf","collectionSlug","slug","desiredFilename","fileForResize","croppedImage","heightInPixels","widthInPixels","push","buffer","path","promises","writeFile","Array","isArray","payloadUploadSizes","sizeData","sizesToSave","savedFilename","sizes","focalX","x","focalY","y","logger","error","args","query","incomingData","origDoc"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"imageResizer.d.ts","sourceRoot":"","sources":["../../src/uploads/imageResizer.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,gCAAgC,CAAA;AAC/E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AACzD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AACvD,OAAO,KAAK,EAEV,SAAS,EACT,UAAU,EAEV,eAAe,EACf,WAAW,EACZ,MAAM,YAAY,CAAA;AAKnB,KAAK,UAAU,GAAG;IAChB,MAAM,EAAE,yBAAyB,CAAA;IACjC,UAAU,EAAE,eAAe,CAAA;IAC3B,IAAI,EAAE,cAAc,CAAC,MAAM,CAAC,CAAA;IAC5B,QAAQ,EAAE,MAAM,CAAA;IAChB,GAAG,EAAE,cAAc,CAAA;IACnB,aAAa,EAAE,MAAM,CAAA;IACrB,KAAK,CAAC,EAAE,eAAe,CAAA;IACvB,UAAU,EAAE,MAAM,CAAA;IAClB,WAAW,CAAC,EAAE,WAAW,CAAA;CAC1B,CAAA;AAED,sEAAsE;AACtE,KAAK,gBAAgB,GAAG;IACtB,UAAU,CAAC,EAAE,WAAW,CAAC,YAAY,CAAC,CAAA;IACtC,QAAQ,EAAE,SAAS,CAAA;IACnB,WAAW,EAAE,UAAU,EAAE,CAAA;CAC1B,CAAA;AA6KD;;;;;;;;;;;;;GAaG;AACH,wBAAsB,4BAA4B,CAAC,EACjD,MAAM,EACN,UAAU,EACV,IAAI,EACJ,QAAQ,EACR,GAAG,EACH,aAAa,EACb,KAAK,EACL,UAAU,EACV,WAAW,GACZ,EAAE,UAAU,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAmKxC"}
1
+ {"version":3,"file":"imageResizer.d.ts","sourceRoot":"","sources":["../../src/uploads/imageResizer.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,gCAAgC,CAAA;AAC/E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AACzD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AACvD,OAAO,KAAK,EAEV,SAAS,EACT,UAAU,EAEV,eAAe,EACf,WAAW,EACZ,MAAM,YAAY,CAAA;AAKnB,KAAK,UAAU,GAAG;IAChB,MAAM,EAAE,yBAAyB,CAAA;IACjC,UAAU,EAAE,eAAe,CAAA;IAC3B,IAAI,EAAE,cAAc,CAAC,MAAM,CAAC,CAAA;IAC5B,QAAQ,EAAE,MAAM,CAAA;IAChB,GAAG,EAAE,cAAc,CAAA;IACnB,aAAa,EAAE,MAAM,CAAA;IACrB,KAAK,CAAC,EAAE,eAAe,CAAA;IACvB,UAAU,EAAE,MAAM,CAAA;IAClB,WAAW,CAAC,EAAE,WAAW,CAAA;CAC1B,CAAA;AAED,sEAAsE;AACtE,KAAK,gBAAgB,GAAG;IACtB,UAAU,CAAC,EAAE,WAAW,CAAC,YAAY,CAAC,CAAA;IACtC,QAAQ,EAAE,SAAS,CAAA;IACnB,WAAW,EAAE,UAAU,EAAE,CAAA;CAC1B,CAAA;AAyLD;;;;;;;;;;;;;GAaG;AACH,wBAAsB,4BAA4B,CAAC,EACjD,MAAM,EACN,UAAU,EACV,IAAI,EACJ,QAAQ,EACR,GAAG,EACH,aAAa,EACb,KAAK,EACL,UAAU,EACV,WAAW,GACZ,EAAE,UAAU,GAAG,OAAO,CAAC,gBAAgB,CAAC,CA8LxC"}
@@ -16,19 +16,9 @@ import fileExists from './fileExists.js';
16
16
  ext: extension
17
17
  };
18
18
  };
19
- /**
20
- * Create a new image name based on the output image name, the dimensions and
21
- * the extension.
22
- *
23
- * Ignore the fact that duplicate names could happen if the there is one
24
- * size with `width AND height` and one with only `height OR width`. Because
25
- * space is expensive, we will reuse the same image for both sizes.
26
- *
27
- * @param outputImageName - the sanitized image name
28
- * @param bufferInfo - the buffer info
29
- * @param extension - the extension to use
30
- * @returns the new image name that is not taken
31
- */ const createImageName = (outputImageName, { height, width }, extension)=>`${outputImageName}-${width}x${height}.${extension}`;
19
+ const createImageName = ({ extension, height, outputImageName, width })=>{
20
+ return `${outputImageName}-${width}x${height}.${extension}`;
21
+ };
32
22
  /**
33
23
  * Create the result object for the image resize operation based on the
34
24
  * provided parameters. If the name is not provided, an empty result object
@@ -57,60 +47,40 @@ import fileExists from './fileExists.js';
57
47
  };
58
48
  };
59
49
  /**
60
- * Check if the image needs to be resized according to the requested dimensions
61
- * and the original image size. If the resize options withoutEnlargement or withoutReduction are provided,
62
- * the image will be resized regardless of the requested dimensions, given that the
63
- * width or height to be resized is provided.
50
+ * Determine whether or not to resize the image.
51
+ * - resize using image config
52
+ * - resize using image config with focal adjustments
53
+ * - do not resize at all
64
54
  *
65
- * @param resizeConfig - object containing the requested dimensions and resize options
66
- * @param original - the original image size
67
- * @returns true if resizing is not needed, false otherwise
68
- */ const preventResize = ({ height: desiredHeight, width: desiredWidth, withoutEnlargement, withoutReduction }, original)=>{
69
- // default is to allow reduction
70
- if (withoutReduction !== undefined) {
71
- return false // needs resize
72
- ;
73
- }
74
- // default is to prevent enlargement
75
- if (withoutEnlargement !== undefined) {
76
- return false // needs resize
77
- ;
78
- }
79
- const isWidthOrHeightNotDefined = !desiredHeight || !desiredWidth;
80
- if (isWidthOrHeightNotDefined) {
81
- // If width and height are not defined, it means there is a format conversion
82
- // and the image needs to be "resized" (transformed).
83
- return false // needs resize
84
- ;
85
- }
86
- const hasInsufficientWidth = desiredWidth > original.width;
87
- const hasInsufficientHeight = desiredHeight > original.height;
88
- if (hasInsufficientWidth && hasInsufficientHeight) {
89
- // doesn't need resize - prevent enlargement. This should only happen if both width and height are insufficient.
90
- // if only one dimension is insufficient and the other is sufficient, resizing needs to happen, as the image
91
- // should be resized to the sufficient dimension.
92
- return true // do not create a new size
93
- ;
94
- }
95
- return false // needs resize
96
- ;
97
- };
98
- /**
99
- * Check if the image should be passed directly to sharp without payload adjusting properties.
55
+ * `imageResizeConfig.withoutEnlargement`:
56
+ * - undefined [default]: uploading images with smaller width AND height than the image size will return null
57
+ * - false: always enlarge images to the image size
58
+ * - true: if the image is smaller than the image size, return the original image
59
+ *
60
+ * `imageResizeConfig.withoutReduction`:
61
+ * - false [default]: always enlarge images to the image size
62
+ * - true: if the image is smaller than the image size, return the original image
100
63
  *
101
- * @param resizeConfig - object containing the requested dimensions and resize options
102
- * @param original - the original image size
103
- * @returns true if the image should passed directly to sharp
104
- */ const applyPayloadAdjustments = ({ fit, height, width, withoutEnlargement, withoutReduction }, original)=>{
105
- if (fit === 'contain' || fit === 'inside') return false;
106
- if (!isNumber(height) && !isNumber(width)) return false;
107
- const targetAspectRatio = width / height;
108
- const originalAspectRatio = original.width / original.height;
109
- if (originalAspectRatio === targetAspectRatio) return false;
110
- const skipEnlargement = withoutEnlargement && (original.height < height || original.width < width);
111
- const skipReduction = withoutReduction && (original.height > height || original.width > width);
112
- if (skipEnlargement || skipReduction) return false;
113
- return true;
64
+ * @return 'omit' | 'resize' | 'resizeWithFocalPoint'
65
+ */ const getImageResizeAction = ({ dimensions: originalImage, hasFocalPoint, imageResizeConfig })=>{
66
+ const { fit, height: targetHeight, width: targetWidth, withoutEnlargement, withoutReduction } = imageResizeConfig;
67
+ // prevent upscaling by default when x and y are both smaller than target image size
68
+ if (targetHeight && targetWidth) {
69
+ const originalImageIsSmallerXAndY = originalImage.width < targetWidth && originalImage.height < targetHeight;
70
+ if (withoutEnlargement === undefined && originalImageIsSmallerXAndY) {
71
+ return 'omit' // prevent image size from being enlarged
72
+ ;
73
+ }
74
+ }
75
+ const originalImageIsSmallerXOrY = originalImage.width < targetWidth || originalImage.height < targetHeight;
76
+ if (fit === 'contain' || fit === 'inside') return 'resize';
77
+ if (!isNumber(targetHeight) && !isNumber(targetWidth)) return 'resize';
78
+ const targetAspectRatio = targetWidth / targetHeight;
79
+ const originalAspectRatio = originalImage.width / originalImage.height;
80
+ if (originalAspectRatio === targetAspectRatio) return 'resize';
81
+ if (withoutEnlargement && originalImageIsSmallerXOrY) return 'resize';
82
+ if (withoutReduction && !originalImageIsSmallerXOrY) return 'resize';
83
+ return hasFocalPoint ? 'resizeWithFocalPoint' : 'resize';
114
84
  };
115
85
  /**
116
86
  * Sanitize the resize config. If the resize config has the `withoutReduction`
@@ -130,6 +100,17 @@ import fileExists from './fileExists.js';
130
100
  }
131
101
  return resizeConfig;
132
102
  };
103
+ /**
104
+ * Used to extract height from images, animated or not.
105
+ *
106
+ * @param sharpMetadata - the sharp metadata
107
+ * @returns the height of the image
108
+ */ function extractHeightFromImage(sharpMetadata) {
109
+ if (sharpMetadata?.pages) {
110
+ return sharpMetadata.height / sharpMetadata.pages;
111
+ }
112
+ return sharpMetadata.height;
113
+ }
133
114
  /**
134
115
  * For the provided image sizes, handle the resizing and the transforms
135
116
  * (format, trim, etc.) of each requested image size and return the result object.
@@ -170,20 +151,24 @@ import fileExists from './fileExists.js';
170
151
  if (fileIsAnimatedType) sharpOptions.animated = true;
171
152
  const sharpBase = sharp(file.tempFilePath || file.data, sharpOptions).rotate() // pass rotate() to auto-rotate based on EXIF data. https://github.com/payloadcms/payload/pull/3081
172
153
  ;
154
+ const originalImageMeta = await sharpBase.metadata();
155
+ const resizeImageMeta = {
156
+ height: extractHeightFromImage(originalImageMeta),
157
+ width: originalImageMeta.width
158
+ };
173
159
  const results = await Promise.all(imageSizes.map(async (imageResizeConfig)=>{
174
160
  imageResizeConfig = sanitizeResizeConfig(imageResizeConfig);
175
- // This checks if a resize should happen. If not, the resized image will be
176
- // skipped COMPLETELY and thus will not be included in the resulting images.
177
- // All further format/trim options will thus be skipped as well.
178
- if (preventResize(imageResizeConfig, dimensions)) {
179
- return createResult({
180
- name: imageResizeConfig.name
181
- });
182
- }
161
+ const resizeAction = getImageResizeAction({
162
+ dimensions,
163
+ hasFocalPoint: Boolean(incomingFocalPoint),
164
+ imageResizeConfig
165
+ });
166
+ if (resizeAction === 'omit') return createResult({
167
+ name: imageResizeConfig.name
168
+ });
183
169
  const imageToResize = sharpBase.clone();
184
170
  let resized = imageToResize;
185
- const metadata = await sharpBase.metadata();
186
- if (incomingFocalPoint && applyPayloadAdjustments(imageResizeConfig, dimensions)) {
171
+ if (resizeAction === 'resizeWithFocalPoint') {
187
172
  let { height: resizeHeight, width: resizeWidth } = imageResizeConfig;
188
173
  const originalAspectRatio = dimensions.width / dimensions.height;
189
174
  // Calculate resizeWidth based on original aspect ratio if it's undefined
@@ -194,33 +179,56 @@ import fileExists from './fileExists.js';
194
179
  if (resizeWidth && !resizeHeight) {
195
180
  resizeHeight = Math.round(resizeWidth / originalAspectRatio);
196
181
  }
197
- // Scale the image up or down to fit the resize dimensions
198
- const scaledImage = imageToResize.resize({
182
+ if (!resizeHeight) resizeHeight = resizeImageMeta.height;
183
+ if (!resizeWidth) resizeWidth = resizeImageMeta.width;
184
+ // if requested image is larger than the incoming size, then resize using sharp and then extract with focal point
185
+ if (resizeHeight > resizeImageMeta.height || resizeWidth > resizeImageMeta.width) {
186
+ const resizeAspectRatio = resizeWidth / resizeHeight;
187
+ const prioritizeHeight = resizeAspectRatio < originalAspectRatio;
188
+ resized = imageToResize.resize({
189
+ height: prioritizeHeight ? resizeHeight : undefined,
190
+ width: prioritizeHeight ? undefined : resizeWidth
191
+ });
192
+ // must read from buffer, resize.metadata will return the original image metadata
193
+ const { info } = await resized.toBuffer({
194
+ resolveWithObject: true
195
+ });
196
+ resizeImageMeta.height = extractHeightFromImage({
197
+ ...originalImageMeta,
198
+ height: info.height
199
+ });
200
+ resizeImageMeta.width = info.width;
201
+ }
202
+ const halfResizeX = resizeWidth / 2;
203
+ const xFocalCenter = resizeImageMeta.width * (incomingFocalPoint.x / 100);
204
+ const calculatedRightPixelBound = xFocalCenter + halfResizeX;
205
+ let leftBound = xFocalCenter - halfResizeX;
206
+ // if the right bound is greater than the image width, adjust the left bound
207
+ // keeping focus on the right
208
+ if (calculatedRightPixelBound > resizeImageMeta.width) {
209
+ leftBound = resizeImageMeta.width - resizeWidth;
210
+ }
211
+ // if the left bound is less than 0, adjust the left bound to 0
212
+ // keeping the focus on the left
213
+ if (leftBound < 0) leftBound = 0;
214
+ const halfResizeY = resizeHeight / 2;
215
+ const yFocalCenter = resizeImageMeta.height * (incomingFocalPoint.y / 100);
216
+ const calculatedBottomPixelBound = yFocalCenter + halfResizeY;
217
+ let topBound = yFocalCenter - halfResizeY;
218
+ // if the bottom bound is greater than the image height, adjust the top bound
219
+ // keeping the image as far right as possible
220
+ if (calculatedBottomPixelBound > resizeImageMeta.height) {
221
+ topBound = resizeImageMeta.height - resizeHeight;
222
+ }
223
+ // if the top bound is less than 0, adjust the top bound to 0
224
+ // keeping the image focus near the top
225
+ if (topBound < 0) topBound = 0;
226
+ resized = resized.extract({
199
227
  height: resizeHeight,
228
+ left: Math.floor(leftBound),
229
+ top: Math.floor(topBound),
200
230
  width: resizeWidth
201
231
  });
202
- const { info: scaledImageInfo } = await scaledImage.toBuffer({
203
- resolveWithObject: true
204
- });
205
- const safeResizeWidth = resizeWidth ?? scaledImageInfo.width;
206
- const maxOffsetX = scaledImageInfo.width - safeResizeWidth;
207
- const leftFocalEdge = Math.round(scaledImageInfo.width * (incomingFocalPoint.x / 100) - safeResizeWidth / 2);
208
- const safeOffsetX = Math.min(Math.max(0, leftFocalEdge), maxOffsetX);
209
- const isAnimated = fileIsAnimatedType && metadata.pages;
210
- let safeResizeHeight = resizeHeight ?? scaledImageInfo.height;
211
- if (isAnimated && resizeHeight === undefined) {
212
- safeResizeHeight = scaledImageInfo.height / metadata.pages;
213
- }
214
- const maxOffsetY = isAnimated ? safeResizeHeight - (resizeHeight ?? safeResizeHeight) : scaledImageInfo.height - safeResizeHeight;
215
- const topFocalEdge = Math.round(scaledImageInfo.height * (incomingFocalPoint.y / 100) - safeResizeHeight / 2);
216
- const safeOffsetY = Math.min(Math.max(0, topFocalEdge), maxOffsetY);
217
- // extract the focal area from the scaled image
218
- resized = (fileIsAnimatedType ? imageToResize : scaledImage).extract({
219
- height: safeResizeHeight,
220
- left: safeOffsetX,
221
- top: safeOffsetY,
222
- width: safeResizeWidth
223
- });
224
232
  } else {
225
233
  resized = imageToResize.resize(imageResizeConfig);
226
234
  }
@@ -238,7 +246,15 @@ import fileExists from './fileExists.js';
238
246
  req.payloadUploadSizes[imageResizeConfig.name] = bufferData;
239
247
  }
240
248
  const mimeInfo = await fileTypeFromBuffer(bufferData);
241
- const imageNameWithDimensions = createImageName(sanitizedImage.name, bufferInfo, mimeInfo?.ext || sanitizedImage.ext);
249
+ const imageNameWithDimensions = createImageName({
250
+ extension: mimeInfo?.ext || sanitizedImage.ext,
251
+ height: extractHeightFromImage({
252
+ ...originalImageMeta,
253
+ height: bufferInfo.height
254
+ }),
255
+ outputImageName: sanitizedImage.name,
256
+ width: bufferInfo.width
257
+ });
242
258
  const imagePath = `${staticPath}/${imageNameWithDimensions}`;
243
259
  if (await fileExists(imagePath)) {
244
260
  try {
@@ -252,7 +268,7 @@ import fileExists from './fileExists.js';
252
268
  name: imageResizeConfig.name,
253
269
  filename: imageNameWithDimensions,
254
270
  filesize: size,
255
- height: fileIsAnimatedType && metadata.pages ? height / metadata.pages : height,
271
+ height: fileIsAnimatedType && originalImageMeta.pages ? height / originalImageMeta.pages : height,
256
272
  mimeType: mimeInfo?.mime || mimeType,
257
273
  sizesToSave: [
258
274
  {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/uploads/imageResizer.ts"],"sourcesContent":["import type { OutputInfo, Sharp, SharpOptions } from 'sharp'\n\nimport { fileTypeFromBuffer } from 'file-type'\nimport fs from 'fs'\nimport sanitize from 'sanitize-filename'\n\nimport type { SanitizedCollectionConfig } from '../collections/config/types.js'\nimport type { SharpDependency } from '../config/types.js'\nimport type { PayloadRequest } from '../types/index.js'\nimport type {\n FileSize,\n FileSizes,\n FileToSave,\n ImageSize,\n ProbedImageSize,\n UploadEdits,\n} from './types.js'\n\nimport { isNumber } from '../utilities/isNumber.js'\nimport fileExists from './fileExists.js'\n\ntype ResizeArgs = {\n config: SanitizedCollectionConfig\n dimensions: ProbedImageSize\n file: PayloadRequest['file']\n mimeType: string\n req: PayloadRequest\n savedFilename: string\n sharp?: SharpDependency\n staticPath: string\n uploadEdits?: UploadEdits\n}\n\n/** Result from resizing and transforming the requested image sizes */\ntype ImageSizesResult = {\n focalPoint?: UploadEdits['focalPoint']\n sizeData: FileSizes\n sizesToSave: FileToSave[]\n}\n\ntype SanitizedImageData = {\n ext: string\n name: string\n}\n\n/**\n * Sanitize the image name and extract the extension from the source image\n *\n * @param sourceImage - the source image\n * @returns the sanitized name and extension\n */\nconst getSanitizedImageData = (sourceImage: string): SanitizedImageData => {\n const extension = sourceImage.split('.').pop()\n const name = sanitize(sourceImage.substring(0, sourceImage.lastIndexOf('.')) || sourceImage)\n return { name, ext: extension }\n}\n\n/**\n * Create a new image name based on the output image name, the dimensions and\n * the extension.\n *\n * Ignore the fact that duplicate names could happen if the there is one\n * size with `width AND height` and one with only `height OR width`. Because\n * space is expensive, we will reuse the same image for both sizes.\n *\n * @param outputImageName - the sanitized image name\n * @param bufferInfo - the buffer info\n * @param extension - the extension to use\n * @returns the new image name that is not taken\n */\nconst createImageName = (\n outputImageName: string,\n { height, width }: OutputInfo,\n extension: string,\n) => `${outputImageName}-${width}x${height}.${extension}`\n\ntype CreateResultArgs = {\n filename?: FileSize['filename']\n filesize?: FileSize['filesize']\n height?: FileSize['height']\n mimeType?: FileSize['mimeType']\n name: string\n sizesToSave?: FileToSave[]\n width?: FileSize['width']\n}\n\n/**\n * Create the result object for the image resize operation based on the\n * provided parameters. If the name is not provided, an empty result object\n * is returned.\n *\n * @param name - the name of the image\n * @param filename - the filename of the image\n * @param width - the width of the image\n * @param height - the height of the image\n * @param filesize - the filesize of the image\n * @param mimeType - the mime type of the image\n * @param sizesToSave - the sizes to save\n * @returns the result object\n */\nconst createResult = ({\n name,\n filename = null,\n filesize = null,\n height = null,\n mimeType = null,\n sizesToSave = [],\n width = null,\n}: CreateResultArgs): ImageSizesResult => {\n return {\n sizeData: {\n [name]: {\n filename,\n filesize,\n height,\n mimeType,\n width,\n },\n },\n sizesToSave,\n }\n}\n\n/**\n * Check if the image needs to be resized according to the requested dimensions\n * and the original image size. If the resize options withoutEnlargement or withoutReduction are provided,\n * the image will be resized regardless of the requested dimensions, given that the\n * width or height to be resized is provided.\n *\n * @param resizeConfig - object containing the requested dimensions and resize options\n * @param original - the original image size\n * @returns true if resizing is not needed, false otherwise\n */\nconst preventResize = (\n { height: desiredHeight, width: desiredWidth, withoutEnlargement, withoutReduction }: ImageSize,\n original: ProbedImageSize,\n): boolean => {\n // default is to allow reduction\n if (withoutReduction !== undefined) {\n return false // needs resize\n }\n\n // default is to prevent enlargement\n if (withoutEnlargement !== undefined) {\n return false // needs resize\n }\n\n const isWidthOrHeightNotDefined = !desiredHeight || !desiredWidth\n if (isWidthOrHeightNotDefined) {\n // If width and height are not defined, it means there is a format conversion\n // and the image needs to be \"resized\" (transformed).\n return false // needs resize\n }\n\n const hasInsufficientWidth = desiredWidth > original.width\n const hasInsufficientHeight = desiredHeight > original.height\n if (hasInsufficientWidth && hasInsufficientHeight) {\n // doesn't need resize - prevent enlargement. This should only happen if both width and height are insufficient.\n // if only one dimension is insufficient and the other is sufficient, resizing needs to happen, as the image\n // should be resized to the sufficient dimension.\n return true // do not create a new size\n }\n\n return false // needs resize\n}\n\n/**\n * Check if the image should be passed directly to sharp without payload adjusting properties.\n *\n * @param resizeConfig - object containing the requested dimensions and resize options\n * @param original - the original image size\n * @returns true if the image should passed directly to sharp\n */\nconst applyPayloadAdjustments = (\n { fit, height, width, withoutEnlargement, withoutReduction }: ImageSize,\n original: ProbedImageSize,\n) => {\n if (fit === 'contain' || fit === 'inside') return false\n if (!isNumber(height) && !isNumber(width)) return false\n\n const targetAspectRatio = width / height\n const originalAspectRatio = original.width / original.height\n if (originalAspectRatio === targetAspectRatio) return false\n\n const skipEnlargement = withoutEnlargement && (original.height < height || original.width < width)\n const skipReduction = withoutReduction && (original.height > height || original.width > width)\n if (skipEnlargement || skipReduction) return false\n\n return true\n}\n\n/**\n * Sanitize the resize config. If the resize config has the `withoutReduction`\n * property set to true, the `fit` and `position` properties will be set to `contain`\n * and `top left` respectively.\n *\n * @param resizeConfig - the resize config\n * @returns a sanitized resize config\n */\nconst sanitizeResizeConfig = (resizeConfig: ImageSize): ImageSize => {\n if (resizeConfig.withoutReduction) {\n return {\n ...resizeConfig,\n // Why fit `contain` should also be set to https://github.com/lovell/sharp/issues/3595\n fit: resizeConfig?.fit || 'contain',\n position: resizeConfig?.position || 'left top',\n }\n }\n return resizeConfig\n}\n\n/**\n * For the provided image sizes, handle the resizing and the transforms\n * (format, trim, etc.) of each requested image size and return the result object.\n * This only handles the image sizes. The transforms of the original image\n * are handled in {@link ./generateFileData.ts}.\n *\n * The image will be resized according to the provided\n * resize config. If no image sizes are requested, the resolved data will be empty.\n * For every image that does not need to be resized, a result object with `null`\n * parameters will be returned.\n *\n * @param resizeConfig - the resize config\n * @returns the result of the resize operation(s)\n */\nexport async function resizeAndTransformImageSizes({\n config,\n dimensions,\n file,\n mimeType,\n req,\n savedFilename,\n sharp,\n staticPath,\n uploadEdits,\n}: ResizeArgs): Promise<ImageSizesResult> {\n const { focalPoint: focalPointEnabled = true, imageSizes } = config.upload\n\n // Focal point adjustments\n const incomingFocalPoint = uploadEdits.focalPoint\n ? {\n x: isNumber(uploadEdits.focalPoint.x) ? Math.round(uploadEdits.focalPoint.x) : 50,\n y: isNumber(uploadEdits.focalPoint.y) ? Math.round(uploadEdits.focalPoint.y) : 50,\n }\n : undefined\n\n const defaultResult: ImageSizesResult = {\n ...(focalPointEnabled && incomingFocalPoint && { focalPoint: incomingFocalPoint }),\n sizeData: {},\n sizesToSave: [],\n }\n\n if (!imageSizes || !sharp) {\n return defaultResult\n }\n\n // Determine if the file is animated\n const fileIsAnimatedType = ['image/avif', 'image/gif', 'image/webp'].includes(file.mimetype)\n const sharpOptions: SharpOptions = {}\n\n if (fileIsAnimatedType) sharpOptions.animated = true\n\n const sharpBase: Sharp | undefined = sharp(file.tempFilePath || file.data, sharpOptions).rotate() // pass rotate() to auto-rotate based on EXIF data. https://github.com/payloadcms/payload/pull/3081\n\n const results: ImageSizesResult[] = await Promise.all(\n imageSizes.map(async (imageResizeConfig): Promise<ImageSizesResult> => {\n imageResizeConfig = sanitizeResizeConfig(imageResizeConfig)\n\n // This checks if a resize should happen. If not, the resized image will be\n // skipped COMPLETELY and thus will not be included in the resulting images.\n // All further format/trim options will thus be skipped as well.\n if (preventResize(imageResizeConfig, dimensions)) {\n return createResult({ name: imageResizeConfig.name })\n }\n\n const imageToResize = sharpBase.clone()\n let resized = imageToResize\n\n const metadata = await sharpBase.metadata()\n\n if (incomingFocalPoint && applyPayloadAdjustments(imageResizeConfig, dimensions)) {\n let { height: resizeHeight, width: resizeWidth } = imageResizeConfig\n\n const originalAspectRatio = dimensions.width / dimensions.height\n\n // Calculate resizeWidth based on original aspect ratio if it's undefined\n if (resizeHeight && !resizeWidth) {\n resizeWidth = Math.round(resizeHeight * originalAspectRatio)\n }\n\n // Calculate resizeHeight based on original aspect ratio if it's undefined\n if (resizeWidth && !resizeHeight) {\n resizeHeight = Math.round(resizeWidth / originalAspectRatio)\n }\n\n // Scale the image up or down to fit the resize dimensions\n const scaledImage = imageToResize.resize({\n height: resizeHeight,\n width: resizeWidth,\n })\n\n const { info: scaledImageInfo } = await scaledImage.toBuffer({ resolveWithObject: true })\n\n const safeResizeWidth = resizeWidth ?? scaledImageInfo.width\n const maxOffsetX = scaledImageInfo.width - safeResizeWidth\n const leftFocalEdge = Math.round(\n scaledImageInfo.width * (incomingFocalPoint.x / 100) - safeResizeWidth / 2,\n )\n const safeOffsetX = Math.min(Math.max(0, leftFocalEdge), maxOffsetX)\n\n const isAnimated = fileIsAnimatedType && metadata.pages\n\n let safeResizeHeight = resizeHeight ?? scaledImageInfo.height\n\n if (isAnimated && resizeHeight === undefined) {\n safeResizeHeight = scaledImageInfo.height / metadata.pages\n }\n\n const maxOffsetY = isAnimated\n ? safeResizeHeight - (resizeHeight ?? safeResizeHeight)\n : scaledImageInfo.height - safeResizeHeight\n\n const topFocalEdge = Math.round(\n scaledImageInfo.height * (incomingFocalPoint.y / 100) - safeResizeHeight / 2,\n )\n const safeOffsetY = Math.min(Math.max(0, topFocalEdge), maxOffsetY)\n\n // extract the focal area from the scaled image\n resized = (fileIsAnimatedType ? imageToResize : scaledImage).extract({\n height: safeResizeHeight,\n left: safeOffsetX,\n top: safeOffsetY,\n width: safeResizeWidth,\n })\n } else {\n resized = imageToResize.resize(imageResizeConfig)\n }\n\n if (imageResizeConfig.formatOptions) {\n resized = resized.toFormat(\n imageResizeConfig.formatOptions.format,\n imageResizeConfig.formatOptions.options,\n )\n }\n\n if (imageResizeConfig.trimOptions) {\n resized = resized.trim(imageResizeConfig.trimOptions)\n }\n\n const { data: bufferData, info: bufferInfo } = await resized.toBuffer({\n resolveWithObject: true,\n })\n\n const sanitizedImage = getSanitizedImageData(savedFilename)\n\n if (req.payloadUploadSizes) {\n req.payloadUploadSizes[imageResizeConfig.name] = bufferData\n }\n\n const mimeInfo = await fileTypeFromBuffer(bufferData)\n\n const imageNameWithDimensions = createImageName(\n sanitizedImage.name,\n bufferInfo,\n mimeInfo?.ext || sanitizedImage.ext,\n )\n\n const imagePath = `${staticPath}/${imageNameWithDimensions}`\n\n if (await fileExists(imagePath)) {\n try {\n fs.unlinkSync(imagePath)\n } catch {\n // Ignore unlink errors\n }\n }\n\n const { height, size, width } = bufferInfo\n return createResult({\n name: imageResizeConfig.name,\n filename: imageNameWithDimensions,\n filesize: size,\n height: fileIsAnimatedType && metadata.pages ? height / metadata.pages : height,\n mimeType: mimeInfo?.mime || mimeType,\n sizesToSave: [{ buffer: bufferData, path: imagePath }],\n width,\n })\n }),\n )\n\n return results.reduce(\n (acc, result) => {\n Object.assign(acc.sizeData, result.sizeData)\n acc.sizesToSave.push(...result.sizesToSave)\n return acc\n },\n { ...defaultResult },\n )\n}\n"],"names":["fileTypeFromBuffer","fs","sanitize","isNumber","fileExists","getSanitizedImageData","sourceImage","extension","split","pop","name","substring","lastIndexOf","ext","createImageName","outputImageName","height","width","createResult","filename","filesize","mimeType","sizesToSave","sizeData","preventResize","desiredHeight","desiredWidth","withoutEnlargement","withoutReduction","original","undefined","isWidthOrHeightNotDefined","hasInsufficientWidth","hasInsufficientHeight","applyPayloadAdjustments","fit","targetAspectRatio","originalAspectRatio","skipEnlargement","skipReduction","sanitizeResizeConfig","resizeConfig","position","resizeAndTransformImageSizes","config","dimensions","file","req","savedFilename","sharp","staticPath","uploadEdits","focalPoint","focalPointEnabled","imageSizes","upload","incomingFocalPoint","x","Math","round","y","defaultResult","fileIsAnimatedType","includes","mimetype","sharpOptions","animated","sharpBase","tempFilePath","data","rotate","results","Promise","all","map","imageResizeConfig","imageToResize","clone","resized","metadata","resizeHeight","resizeWidth","scaledImage","resize","info","scaledImageInfo","toBuffer","resolveWithObject","safeResizeWidth","maxOffsetX","leftFocalEdge","safeOffsetX","min","max","isAnimated","pages","safeResizeHeight","maxOffsetY","topFocalEdge","safeOffsetY","extract","left","top","formatOptions","toFormat","format","options","trimOptions","trim","bufferData","bufferInfo","sanitizedImage","payloadUploadSizes","mimeInfo","imageNameWithDimensions","imagePath","unlinkSync","size","mime","buffer","path","reduce","acc","result","Object","assign","push"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/uploads/imageResizer.ts"],"sourcesContent":["import type { Sharp, Metadata as SharpMetadata, SharpOptions } from 'sharp'\n\nimport { fileTypeFromBuffer } from 'file-type'\nimport fs from 'fs'\nimport sanitize from 'sanitize-filename'\n\nimport type { SanitizedCollectionConfig } from '../collections/config/types.js'\nimport type { SharpDependency } from '../config/types.js'\nimport type { PayloadRequest } from '../types/index.js'\nimport type {\n FileSize,\n FileSizes,\n FileToSave,\n ImageSize,\n ProbedImageSize,\n UploadEdits,\n} from './types.js'\n\nimport { isNumber } from '../utilities/isNumber.js'\nimport fileExists from './fileExists.js'\n\ntype ResizeArgs = {\n config: SanitizedCollectionConfig\n dimensions: ProbedImageSize\n file: PayloadRequest['file']\n mimeType: string\n req: PayloadRequest\n savedFilename: string\n sharp?: SharpDependency\n staticPath: string\n uploadEdits?: UploadEdits\n}\n\n/** Result from resizing and transforming the requested image sizes */\ntype ImageSizesResult = {\n focalPoint?: UploadEdits['focalPoint']\n sizeData: FileSizes\n sizesToSave: FileToSave[]\n}\n\ntype SanitizedImageData = {\n ext: string\n name: string\n}\n\n/**\n * Sanitize the image name and extract the extension from the source image\n *\n * @param sourceImage - the source image\n * @returns the sanitized name and extension\n */\nconst getSanitizedImageData = (sourceImage: string): SanitizedImageData => {\n const extension = sourceImage.split('.').pop()\n const name = sanitize(sourceImage.substring(0, sourceImage.lastIndexOf('.')) || sourceImage)\n return { name, ext: extension }\n}\n\n/**\n * Create a new image name based on the output image name, the dimensions and\n * the extension.\n *\n * Ignore the fact that duplicate names could happen if the there is one\n * size with `width AND height` and one with only `height OR width`. Because\n * space is expensive, we will reuse the same image for both sizes.\n *\n * @param outputImageName - the sanitized image name\n * @param bufferInfo - the buffer info\n * @param extension - the extension to use\n * @returns the new image name that is not taken\n */\ntype CreateImageNameArgs = {\n extension: string\n height: number\n outputImageName: string\n width: number\n}\nconst createImageName = ({\n extension,\n height,\n outputImageName,\n width,\n}: CreateImageNameArgs): string => {\n return `${outputImageName}-${width}x${height}.${extension}`\n}\n\ntype CreateResultArgs = {\n filename?: FileSize['filename']\n filesize?: FileSize['filesize']\n height?: FileSize['height']\n mimeType?: FileSize['mimeType']\n name: string\n sizesToSave?: FileToSave[]\n width?: FileSize['width']\n}\n\n/**\n * Create the result object for the image resize operation based on the\n * provided parameters. If the name is not provided, an empty result object\n * is returned.\n *\n * @param name - the name of the image\n * @param filename - the filename of the image\n * @param width - the width of the image\n * @param height - the height of the image\n * @param filesize - the filesize of the image\n * @param mimeType - the mime type of the image\n * @param sizesToSave - the sizes to save\n * @returns the result object\n */\nconst createResult = ({\n name,\n filename = null,\n filesize = null,\n height = null,\n mimeType = null,\n sizesToSave = [],\n width = null,\n}: CreateResultArgs): ImageSizesResult => {\n return {\n sizeData: {\n [name]: {\n filename,\n filesize,\n height,\n mimeType,\n width,\n },\n },\n sizesToSave,\n }\n}\n\n/**\n * Determine whether or not to resize the image.\n * - resize using image config\n * - resize using image config with focal adjustments\n * - do not resize at all\n *\n * `imageResizeConfig.withoutEnlargement`:\n * - undefined [default]: uploading images with smaller width AND height than the image size will return null\n * - false: always enlarge images to the image size\n * - true: if the image is smaller than the image size, return the original image\n *\n * `imageResizeConfig.withoutReduction`:\n * - false [default]: always enlarge images to the image size\n * - true: if the image is smaller than the image size, return the original image\n *\n * @return 'omit' | 'resize' | 'resizeWithFocalPoint'\n */\nconst getImageResizeAction = ({\n dimensions: originalImage,\n hasFocalPoint,\n imageResizeConfig,\n}: {\n dimensions: ProbedImageSize\n hasFocalPoint?: boolean\n imageResizeConfig: ImageSize\n}): 'omit' | 'resize' | 'resizeWithFocalPoint' => {\n const {\n fit,\n height: targetHeight,\n width: targetWidth,\n withoutEnlargement,\n withoutReduction,\n } = imageResizeConfig\n\n // prevent upscaling by default when x and y are both smaller than target image size\n if (targetHeight && targetWidth) {\n const originalImageIsSmallerXAndY =\n originalImage.width < targetWidth && originalImage.height < targetHeight\n if (withoutEnlargement === undefined && originalImageIsSmallerXAndY) {\n return 'omit' // prevent image size from being enlarged\n }\n }\n\n const originalImageIsSmallerXOrY =\n originalImage.width < targetWidth || originalImage.height < targetHeight\n if (fit === 'contain' || fit === 'inside') return 'resize'\n if (!isNumber(targetHeight) && !isNumber(targetWidth)) return 'resize'\n\n const targetAspectRatio = targetWidth / targetHeight\n const originalAspectRatio = originalImage.width / originalImage.height\n if (originalAspectRatio === targetAspectRatio) return 'resize'\n\n if (withoutEnlargement && originalImageIsSmallerXOrY) return 'resize'\n if (withoutReduction && !originalImageIsSmallerXOrY) return 'resize'\n\n return hasFocalPoint ? 'resizeWithFocalPoint' : 'resize'\n}\n\n/**\n * Sanitize the resize config. If the resize config has the `withoutReduction`\n * property set to true, the `fit` and `position` properties will be set to `contain`\n * and `top left` respectively.\n *\n * @param resizeConfig - the resize config\n * @returns a sanitized resize config\n */\nconst sanitizeResizeConfig = (resizeConfig: ImageSize): ImageSize => {\n if (resizeConfig.withoutReduction) {\n return {\n ...resizeConfig,\n // Why fit `contain` should also be set to https://github.com/lovell/sharp/issues/3595\n fit: resizeConfig?.fit || 'contain',\n position: resizeConfig?.position || 'left top',\n }\n }\n return resizeConfig\n}\n\n/**\n * Used to extract height from images, animated or not.\n *\n * @param sharpMetadata - the sharp metadata\n * @returns the height of the image\n */\nfunction extractHeightFromImage(sharpMetadata: SharpMetadata): number {\n if (sharpMetadata?.pages) {\n return sharpMetadata.height / sharpMetadata.pages\n }\n return sharpMetadata.height\n}\n\n/**\n * For the provided image sizes, handle the resizing and the transforms\n * (format, trim, etc.) of each requested image size and return the result object.\n * This only handles the image sizes. The transforms of the original image\n * are handled in {@link ./generateFileData.ts}.\n *\n * The image will be resized according to the provided\n * resize config. If no image sizes are requested, the resolved data will be empty.\n * For every image that does not need to be resized, a result object with `null`\n * parameters will be returned.\n *\n * @param resizeConfig - the resize config\n * @returns the result of the resize operation(s)\n */\nexport async function resizeAndTransformImageSizes({\n config,\n dimensions,\n file,\n mimeType,\n req,\n savedFilename,\n sharp,\n staticPath,\n uploadEdits,\n}: ResizeArgs): Promise<ImageSizesResult> {\n const { focalPoint: focalPointEnabled = true, imageSizes } = config.upload\n\n // Focal point adjustments\n const incomingFocalPoint = uploadEdits.focalPoint\n ? {\n x: isNumber(uploadEdits.focalPoint.x) ? Math.round(uploadEdits.focalPoint.x) : 50,\n y: isNumber(uploadEdits.focalPoint.y) ? Math.round(uploadEdits.focalPoint.y) : 50,\n }\n : undefined\n\n const defaultResult: ImageSizesResult = {\n ...(focalPointEnabled && incomingFocalPoint && { focalPoint: incomingFocalPoint }),\n sizeData: {},\n sizesToSave: [],\n }\n\n if (!imageSizes || !sharp) {\n return defaultResult\n }\n\n // Determine if the file is animated\n const fileIsAnimatedType = ['image/avif', 'image/gif', 'image/webp'].includes(file.mimetype)\n const sharpOptions: SharpOptions = {}\n\n if (fileIsAnimatedType) sharpOptions.animated = true\n\n const sharpBase: Sharp | undefined = sharp(file.tempFilePath || file.data, sharpOptions).rotate() // pass rotate() to auto-rotate based on EXIF data. https://github.com/payloadcms/payload/pull/3081\n const originalImageMeta = await sharpBase.metadata()\n\n const resizeImageMeta = {\n height: extractHeightFromImage(originalImageMeta),\n width: originalImageMeta.width,\n }\n\n const results: ImageSizesResult[] = await Promise.all(\n imageSizes.map(async (imageResizeConfig): Promise<ImageSizesResult> => {\n imageResizeConfig = sanitizeResizeConfig(imageResizeConfig)\n\n const resizeAction = getImageResizeAction({\n dimensions,\n hasFocalPoint: Boolean(incomingFocalPoint),\n imageResizeConfig,\n })\n if (resizeAction === 'omit') return createResult({ name: imageResizeConfig.name })\n\n const imageToResize = sharpBase.clone()\n let resized = imageToResize\n\n if (resizeAction === 'resizeWithFocalPoint') {\n let { height: resizeHeight, width: resizeWidth } = imageResizeConfig\n\n const originalAspectRatio = dimensions.width / dimensions.height\n\n // Calculate resizeWidth based on original aspect ratio if it's undefined\n if (resizeHeight && !resizeWidth) {\n resizeWidth = Math.round(resizeHeight * originalAspectRatio)\n }\n\n // Calculate resizeHeight based on original aspect ratio if it's undefined\n if (resizeWidth && !resizeHeight) {\n resizeHeight = Math.round(resizeWidth / originalAspectRatio)\n }\n\n if (!resizeHeight) resizeHeight = resizeImageMeta.height\n if (!resizeWidth) resizeWidth = resizeImageMeta.width\n\n // if requested image is larger than the incoming size, then resize using sharp and then extract with focal point\n if (resizeHeight > resizeImageMeta.height || resizeWidth > resizeImageMeta.width) {\n const resizeAspectRatio = resizeWidth / resizeHeight\n const prioritizeHeight = resizeAspectRatio < originalAspectRatio\n resized = imageToResize.resize({\n height: prioritizeHeight ? resizeHeight : undefined,\n width: prioritizeHeight ? undefined : resizeWidth,\n })\n\n // must read from buffer, resize.metadata will return the original image metadata\n const { info } = await resized.toBuffer({ resolveWithObject: true })\n resizeImageMeta.height = extractHeightFromImage({\n ...originalImageMeta,\n height: info.height,\n })\n resizeImageMeta.width = info.width\n }\n\n const halfResizeX = resizeWidth / 2\n const xFocalCenter = resizeImageMeta.width * (incomingFocalPoint.x / 100)\n const calculatedRightPixelBound = xFocalCenter + halfResizeX\n let leftBound = xFocalCenter - halfResizeX\n\n // if the right bound is greater than the image width, adjust the left bound\n // keeping focus on the right\n if (calculatedRightPixelBound > resizeImageMeta.width) {\n leftBound = resizeImageMeta.width - resizeWidth\n }\n\n // if the left bound is less than 0, adjust the left bound to 0\n // keeping the focus on the left\n if (leftBound < 0) leftBound = 0\n\n const halfResizeY = resizeHeight / 2\n const yFocalCenter = resizeImageMeta.height * (incomingFocalPoint.y / 100)\n const calculatedBottomPixelBound = yFocalCenter + halfResizeY\n let topBound = yFocalCenter - halfResizeY\n\n // if the bottom bound is greater than the image height, adjust the top bound\n // keeping the image as far right as possible\n if (calculatedBottomPixelBound > resizeImageMeta.height) {\n topBound = resizeImageMeta.height - resizeHeight\n }\n\n // if the top bound is less than 0, adjust the top bound to 0\n // keeping the image focus near the top\n if (topBound < 0) topBound = 0\n\n resized = resized.extract({\n height: resizeHeight,\n left: Math.floor(leftBound),\n top: Math.floor(topBound),\n width: resizeWidth,\n })\n } else {\n resized = imageToResize.resize(imageResizeConfig)\n }\n\n if (imageResizeConfig.formatOptions) {\n resized = resized.toFormat(\n imageResizeConfig.formatOptions.format,\n imageResizeConfig.formatOptions.options,\n )\n }\n\n if (imageResizeConfig.trimOptions) {\n resized = resized.trim(imageResizeConfig.trimOptions)\n }\n\n const { data: bufferData, info: bufferInfo } = await resized.toBuffer({\n resolveWithObject: true,\n })\n\n const sanitizedImage = getSanitizedImageData(savedFilename)\n\n if (req.payloadUploadSizes) {\n req.payloadUploadSizes[imageResizeConfig.name] = bufferData\n }\n\n const mimeInfo = await fileTypeFromBuffer(bufferData)\n\n const imageNameWithDimensions = createImageName({\n extension: mimeInfo?.ext || sanitizedImage.ext,\n height: extractHeightFromImage({\n ...originalImageMeta,\n height: bufferInfo.height,\n }),\n outputImageName: sanitizedImage.name,\n width: bufferInfo.width,\n })\n\n const imagePath = `${staticPath}/${imageNameWithDimensions}`\n\n if (await fileExists(imagePath)) {\n try {\n fs.unlinkSync(imagePath)\n } catch {\n // Ignore unlink errors\n }\n }\n\n const { height, size, width } = bufferInfo\n return createResult({\n name: imageResizeConfig.name,\n filename: imageNameWithDimensions,\n filesize: size,\n height:\n fileIsAnimatedType && originalImageMeta.pages ? height / originalImageMeta.pages : height,\n mimeType: mimeInfo?.mime || mimeType,\n sizesToSave: [{ buffer: bufferData, path: imagePath }],\n width,\n })\n }),\n )\n\n return results.reduce(\n (acc, result) => {\n Object.assign(acc.sizeData, result.sizeData)\n acc.sizesToSave.push(...result.sizesToSave)\n return acc\n },\n { ...defaultResult },\n )\n}\n"],"names":["fileTypeFromBuffer","fs","sanitize","isNumber","fileExists","getSanitizedImageData","sourceImage","extension","split","pop","name","substring","lastIndexOf","ext","createImageName","height","outputImageName","width","createResult","filename","filesize","mimeType","sizesToSave","sizeData","getImageResizeAction","dimensions","originalImage","hasFocalPoint","imageResizeConfig","fit","targetHeight","targetWidth","withoutEnlargement","withoutReduction","originalImageIsSmallerXAndY","undefined","originalImageIsSmallerXOrY","targetAspectRatio","originalAspectRatio","sanitizeResizeConfig","resizeConfig","position","extractHeightFromImage","sharpMetadata","pages","resizeAndTransformImageSizes","config","file","req","savedFilename","sharp","staticPath","uploadEdits","focalPoint","focalPointEnabled","imageSizes","upload","incomingFocalPoint","x","Math","round","y","defaultResult","fileIsAnimatedType","includes","mimetype","sharpOptions","animated","sharpBase","tempFilePath","data","rotate","originalImageMeta","metadata","resizeImageMeta","results","Promise","all","map","resizeAction","Boolean","imageToResize","clone","resized","resizeHeight","resizeWidth","resizeAspectRatio","prioritizeHeight","resize","info","toBuffer","resolveWithObject","halfResizeX","xFocalCenter","calculatedRightPixelBound","leftBound","halfResizeY","yFocalCenter","calculatedBottomPixelBound","topBound","extract","left","floor","top","formatOptions","toFormat","format","options","trimOptions","trim","bufferData","bufferInfo","sanitizedImage","payloadUploadSizes","mimeInfo","imageNameWithDimensions","imagePath","unlinkSync","size","mime","buffer","path","reduce","acc","result","Object","assign","push"],"mappings":"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"}
@@ -179,16 +179,22 @@ export type FileToSave = {
179
179
  */
180
180
  path: string;
181
181
  };
182
+ type Crop = {
183
+ height: number;
184
+ unit: '%' | 'px';
185
+ width: number;
186
+ x: number;
187
+ y: number;
188
+ };
189
+ type FocalPoint = {
190
+ x: number;
191
+ y: number;
192
+ };
182
193
  export type UploadEdits = {
183
- crop?: {
184
- height?: number;
185
- width?: number;
186
- x?: number;
187
- y?: number;
188
- };
189
- focalPoint?: {
190
- x?: number;
191
- y?: number;
192
- };
194
+ crop?: Crop;
195
+ focalPoint?: FocalPoint;
196
+ heightInPixels?: number;
197
+ widthInPixels?: number;
193
198
  };
199
+ export {};
194
200
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/uploads/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/uploads/types.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/uploads/types.ts"],"sourcesContent":["import type { ResizeOptions, Sharp } from 'sharp'\n\nimport type { TypeWithID } from '../collections/config/types.js'\nimport type { PayloadRequest } from '../types/index.js'\n\nexport type FileSize = {\n filename: null | string\n filesize: null | number\n height: null | number\n mimeType: null | string\n width: null | number\n}\n\nexport type FileSizes = {\n [size: string]: FileSize\n}\n\nexport type FileData = {\n filename: string\n filesize: number\n focalX?: number\n focalY?: number\n height: number\n mimeType: string\n sizes: FileSizes\n tempFilePath?: string\n url?: string\n width: number\n}\n\nexport type ProbedImageSize = {\n height: number\n width: number\n}\n\n/**\n * Params sent to the sharp `toFormat()` function\n * @link https://sharp.pixelplumbing.com/api-output#toformat\n */\nexport type ImageUploadFormatOptions = {\n format: Parameters<Sharp['toFormat']>[0]\n options?: Parameters<Sharp['toFormat']>[1]\n}\n\n/**\n * Params sent to the sharp trim() function\n * @link https://sharp.pixelplumbing.com/api-resize#trim\n */\nexport type ImageUploadTrimOptions = Parameters<Sharp['trim']>[0]\n\nexport type ImageSize = {\n /**\n * @deprecated prefer position\n */\n crop?: string // comes from sharp package\n formatOptions?: ImageUploadFormatOptions\n name: string\n trimOptions?: ImageUploadTrimOptions\n /**\n * When an uploaded image is smaller than the defined image size, we have 3 options:\n *\n * `undefined | false | true`\n *\n * 1. `undefined` [default]: uploading images with smaller width AND height than the image size will return null\n * 2. `false`: always enlarge images to the image size\n * 3. `true`: if the image is smaller than the image size, return the original image\n */\n withoutEnlargement?: ResizeOptions['withoutEnlargement']\n} & Omit<ResizeOptions, 'withoutEnlargement'>\n\nexport type GetAdminThumbnail = (args: { doc: Record<string, unknown> }) => false | null | string\n\nexport type UploadConfig = {\n /**\n * The adapter name to use for uploads. Used for storage adapter telemetry.\n * @default undefined\n */\n adapter?: string\n /**\n * Represents an admin thumbnail, which can be either a React component or a string.\n * - If a string, it should be one of the image size names.\n * - A function that generates a fully qualified URL for the thumbnail, receives the doc as the only argument.\n **/\n adminThumbnail?: GetAdminThumbnail | string\n /**\n * Enables cropping of images.\n * @default true\n */\n crop?: boolean\n /**\n * Disable the ability to save files to disk.\n * @default false\n */\n disableLocalStorage?: boolean\n /**\n * Ability to filter/modify Request Headers when fetching a file.\n *\n * Useful for adding custom headers to fetch from external providers.\n * @default undefined\n */\n externalFileHeaderFilter?: (headers: Record<string, string>) => Record<string, string>\n /**\n * Require files to be uploaded when creating a document.\n * @default true\n */\n filesRequiredOnCreate?: boolean\n /**\n * Enables focal point positioning for image manipulation.\n * @default false\n */\n focalPoint?: boolean\n /**\n * Format options for the uploaded file. Formatting image sizes needs to be done within each formatOptions individually.\n */\n formatOptions?: ImageUploadFormatOptions\n /**\n * Custom handlers to run when a file is fetched.\n *\n * - If a handler returns a Response, the response will be sent to the client and no further handlers will be run.\n * - If a handler returns null, the next handler will be run.\n * - If no handlers return a response the file will be returned by default.\n *\n * @default undefined\n */\n handlers?: ((\n req: PayloadRequest,\n args: {\n doc: TypeWithID\n params: { collection: string; filename: string }\n },\n ) => Promise<Response> | Promise<void> | Response | void)[]\n imageSizes?: ImageSize[]\n /**\n * Restrict mimeTypes in the file picker. Array of valid mime types or mimetype wildcards\n * @example ['image/*', 'application/pdf']\n * @default undefined\n */\n mimeTypes?: string[]\n /**\n * Ability to modify the response headers fetching a file.\n * @default undefined\n */\n modifyResponseHeaders?: ({ headers }: { headers: Headers }) => Headers\n /**\n * Sharp resize options for the original image.\n * @link https://sharp.pixelplumbing.com/api-resize#resize\n * @default undefined\n */\n resizeOptions?: ResizeOptions\n /**\n * The directory to serve static files from. Defaults to collection slug.\n * @default undefined\n */\n staticDir?: string\n trimOptions?: ImageUploadTrimOptions\n}\n\nexport type SanitizedUploadConfig = {\n staticDir: UploadConfig['staticDir']\n} & UploadConfig\n\nexport type File = {\n /**\n * The buffer of the file.\n */\n data: Buffer\n /**\n * The mimetype of the file.\n */\n mimetype: string\n /**\n * The name of the file.\n */\n name: string\n /**\n * The size of the file in bytes.\n */\n size: number\n}\n\nexport type FileToSave = {\n /**\n * The buffer of the file.\n */\n buffer: Buffer\n /**\n * The path to save the file.\n */\n path: string\n}\n\nexport type UploadEdits = {\n crop?: {\n height?: number\n width?: number\n x?: number\n y?: number\n }\n focalPoint?: {\n x?: number\n y?: number\n }\n}\n"],"names":[],"mappings":"AA+LA,WAWC"}
1
+ {"version":3,"sources":["../../src/uploads/types.ts"],"sourcesContent":["import type { ResizeOptions, Sharp } from 'sharp'\n\nimport type { TypeWithID } from '../collections/config/types.js'\nimport type { PayloadRequest } from '../types/index.js'\n\nexport type FileSize = {\n filename: null | string\n filesize: null | number\n height: null | number\n mimeType: null | string\n width: null | number\n}\n\nexport type FileSizes = {\n [size: string]: FileSize\n}\n\nexport type FileData = {\n filename: string\n filesize: number\n focalX?: number\n focalY?: number\n height: number\n mimeType: string\n sizes: FileSizes\n tempFilePath?: string\n url?: string\n width: number\n}\n\nexport type ProbedImageSize = {\n height: number\n width: number\n}\n\n/**\n * Params sent to the sharp `toFormat()` function\n * @link https://sharp.pixelplumbing.com/api-output#toformat\n */\nexport type ImageUploadFormatOptions = {\n format: Parameters<Sharp['toFormat']>[0]\n options?: Parameters<Sharp['toFormat']>[1]\n}\n\n/**\n * Params sent to the sharp trim() function\n * @link https://sharp.pixelplumbing.com/api-resize#trim\n */\nexport type ImageUploadTrimOptions = Parameters<Sharp['trim']>[0]\n\nexport type ImageSize = {\n /**\n * @deprecated prefer position\n */\n crop?: string // comes from sharp package\n formatOptions?: ImageUploadFormatOptions\n name: string\n trimOptions?: ImageUploadTrimOptions\n /**\n * When an uploaded image is smaller than the defined image size, we have 3 options:\n *\n * `undefined | false | true`\n *\n * 1. `undefined` [default]: uploading images with smaller width AND height than the image size will return null\n * 2. `false`: always enlarge images to the image size\n * 3. `true`: if the image is smaller than the image size, return the original image\n */\n withoutEnlargement?: ResizeOptions['withoutEnlargement']\n} & Omit<ResizeOptions, 'withoutEnlargement'>\n\nexport type GetAdminThumbnail = (args: { doc: Record<string, unknown> }) => false | null | string\n\nexport type UploadConfig = {\n /**\n * The adapter name to use for uploads. Used for storage adapter telemetry.\n * @default undefined\n */\n adapter?: string\n /**\n * Represents an admin thumbnail, which can be either a React component or a string.\n * - If a string, it should be one of the image size names.\n * - A function that generates a fully qualified URL for the thumbnail, receives the doc as the only argument.\n **/\n adminThumbnail?: GetAdminThumbnail | string\n /**\n * Enables cropping of images.\n * @default true\n */\n crop?: boolean\n /**\n * Disable the ability to save files to disk.\n * @default false\n */\n disableLocalStorage?: boolean\n /**\n * Ability to filter/modify Request Headers when fetching a file.\n *\n * Useful for adding custom headers to fetch from external providers.\n * @default undefined\n */\n externalFileHeaderFilter?: (headers: Record<string, string>) => Record<string, string>\n /**\n * Require files to be uploaded when creating a document.\n * @default true\n */\n filesRequiredOnCreate?: boolean\n /**\n * Enables focal point positioning for image manipulation.\n * @default false\n */\n focalPoint?: boolean\n /**\n * Format options for the uploaded file. Formatting image sizes needs to be done within each formatOptions individually.\n */\n formatOptions?: ImageUploadFormatOptions\n /**\n * Custom handlers to run when a file is fetched.\n *\n * - If a handler returns a Response, the response will be sent to the client and no further handlers will be run.\n * - If a handler returns null, the next handler will be run.\n * - If no handlers return a response the file will be returned by default.\n *\n * @default undefined\n */\n handlers?: ((\n req: PayloadRequest,\n args: {\n doc: TypeWithID\n params: { collection: string; filename: string }\n },\n ) => Promise<Response> | Promise<void> | Response | void)[]\n imageSizes?: ImageSize[]\n /**\n * Restrict mimeTypes in the file picker. Array of valid mime types or mimetype wildcards\n * @example ['image/*', 'application/pdf']\n * @default undefined\n */\n mimeTypes?: string[]\n /**\n * Ability to modify the response headers fetching a file.\n * @default undefined\n */\n modifyResponseHeaders?: ({ headers }: { headers: Headers }) => Headers\n /**\n * Sharp resize options for the original image.\n * @link https://sharp.pixelplumbing.com/api-resize#resize\n * @default undefined\n */\n resizeOptions?: ResizeOptions\n /**\n * The directory to serve static files from. Defaults to collection slug.\n * @default undefined\n */\n staticDir?: string\n trimOptions?: ImageUploadTrimOptions\n}\n\nexport type SanitizedUploadConfig = {\n staticDir: UploadConfig['staticDir']\n} & UploadConfig\n\nexport type File = {\n /**\n * The buffer of the file.\n */\n data: Buffer\n /**\n * The mimetype of the file.\n */\n mimetype: string\n /**\n * The name of the file.\n */\n name: string\n /**\n * The size of the file in bytes.\n */\n size: number\n}\n\nexport type FileToSave = {\n /**\n * The buffer of the file.\n */\n buffer: Buffer\n /**\n * The path to save the file.\n */\n path: string\n}\n\ntype Crop = {\n height: number\n unit: '%' | 'px'\n width: number\n x: number\n y: number\n}\n\ntype FocalPoint = {\n x: number\n y: number\n}\n\nexport type UploadEdits = {\n crop?: Crop\n focalPoint?: FocalPoint\n heightInPixels?: number\n widthInPixels?: number\n}\n"],"names":[],"mappings":"AA4MA,WAKC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "payload",
3
- "version": "3.0.0-beta.66",
3
+ "version": "3.0.0-beta.67",
4
4
  "description": "Node, React, Headless CMS and Application Framework built on Next.js",
5
5
  "keywords": [
6
6
  "admin panel",
@@ -97,7 +97,7 @@
97
97
  "scmp": "2.1.0",
98
98
  "ts-essentials": "7.0.3",
99
99
  "uuid": "10.0.0",
100
- "@payloadcms/translations": "3.0.0-beta.66"
100
+ "@payloadcms/translations": "3.0.0-beta.67"
101
101
  },
102
102
  "devDependencies": {
103
103
  "@hyrious/esbuild-plugin-commonjs": "^0.2.4",