Last active
June 28, 2025 11:03
-
-
Save HarleySalas/ca24eea1301a94abaaf15311cbffdf14 to your computer and use it in GitHub Desktop.
Payload Image Aspect Ratio
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import type { CollectionBeforeOperationHook, FileData, Plugin, UploadCollectionSlug } from 'payload' | |
type AspectRatios = Record<string, number> | |
type Collections = Partial<Record<UploadCollectionSlug, AspectRatios>> | |
interface ImageAspectRatiosPluginArgs { | |
collections: Collections | |
enable?: boolean | |
} | |
const imageAspectRatiosPlugin = ({ | |
collections, | |
enable = true, | |
}: ImageAspectRatiosPluginArgs): Plugin => { | |
return (config) => { | |
if (!enable) { | |
return config | |
} | |
const uploadCollections = collections | |
const uploadCollectionSlugs = Object.keys(collections) | |
config.collections = (config.collections || []).map((c) => { | |
const slug = c.slug as UploadCollectionSlug | |
if (uploadCollectionSlugs.includes(c.slug) && slug in uploadCollections) { | |
return { | |
...c, | |
hooks: { | |
...(c.hooks || {}), | |
beforeOperation: [ | |
createBeforeOperationHook(uploadCollections[slug]!), | |
...(c.hooks?.beforeOperation || []), | |
], | |
}, | |
} | |
} else { | |
return c | |
} | |
}) | |
return config | |
} | |
} | |
type Dimensions = { | |
height: number | |
width: number | |
} | |
const createBeforeOperationHook = (aspectRatios: AspectRatios) => { | |
const beforeOperationHook: CollectionBeforeOperationHook = async ({ | |
req, | |
args, | |
collection, | |
operation, | |
}) => { | |
if (operation == 'update' || operation == 'create') { | |
let originalDimensions: Dimensions | undefined = undefined | |
if (req.file) { | |
const sharp = req.payload.config.sharp | |
const metadata = await sharp(req.file.data).metadata() | |
if (metadata.width && metadata.height) { | |
originalDimensions = { | |
width: metadata.width, | |
height: metadata.height, | |
} | |
} | |
} else { | |
const duplicateFromID: string | number | undefined = args.duplicateFromID | |
if (duplicateFromID) { | |
const data = await req.payload.findByID({ | |
collection: collection.slug as UploadCollectionSlug, | |
id: duplicateFromID, | |
select: { | |
width: true, | |
height: true, | |
}, | |
}) | |
originalDimensions = { | |
width: data.width!, | |
height: data.height!, | |
} | |
} else { | |
const data = args.data as FileData | |
originalDimensions = { | |
width: data.width, | |
height: data.height, | |
} | |
} | |
} | |
if (originalDimensions) { | |
const originalWidth = originalDimensions.width | |
const originalHeight = originalDimensions.height | |
const originalAspectRatio = originalWidth / originalHeight | |
collection.upload.imageSizes = (collection.upload.imageSizes || []).map((size) => { | |
if (size.name in aspectRatios) { | |
const desiredAspectRatio = aspectRatios[size.name]! | |
const dimensions = | |
desiredAspectRatio > originalAspectRatio | |
? { | |
width: originalWidth, | |
height: Math.round(originalWidth / desiredAspectRatio), | |
} | |
: { | |
width: Math.round(originalHeight * desiredAspectRatio), | |
height: originalHeight, | |
} | |
return { | |
...size, | |
...dimensions, | |
} | |
} | |
return size | |
}) | |
} | |
} | |
return args | |
} | |
return beforeOperationHook | |
} | |
export const imageAspectRatio = imageAspectRatiosPlugin({ | |
enable: true, | |
collections: { | |
media: { | |
square: 1.0, | |
portrait: 0.75, | |
landscape: 1.5, | |
}, | |
}, | |
}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment