-
-
Save notflip/e33c0b45299674ce56d80f1c6d08bd09 to your computer and use it in GitHub Desktop.
| import {APIError, CollectionBeforeValidateHook} from 'payload'; | |
| import {getPlaiceholder} from 'plaiceholder'; | |
| export const generateBlurHash: CollectionBeforeValidateHook = async ({data, operation, req}) => { | |
| if (operation === 'create' || operation === 'update') { | |
| try { | |
| const buffer = req?.file?.data; | |
| if (buffer) { | |
| const {base64} = await getPlaiceholder(buffer, {size: 32}); | |
| return { | |
| ...data, | |
| blurhash: base64, | |
| }; | |
| } | |
| } catch (error) { | |
| throw new APIError('Failed to generate blur data url'); | |
| } | |
| } | |
| }; |
| {image && | |
| <ImageBox | |
| fill | |
| media={image as Media} | |
| sizes="(max-width: 1024px) 100vw, 50vw" | |
| /> | |
| } |
| import type {Media} from "@payload-types"; | |
| import Image from 'next/image' | |
| interface ImageBoxProps { | |
| media: Media | |
| fill?: boolean | |
| sizes?: string | |
| imageClassName?: string | |
| } | |
| export const ImageBox: React.FC<ImageBoxProps> = (props) => { | |
| const {media, fill, imageClassName, sizes} = props | |
| const {width: imageWidth, height: imageHeight} = media; | |
| const width = imageWidth ?? undefined; | |
| const height = imageHeight ?? undefined; | |
| const objectPosition = | |
| media.focalX != null && media.focalY != null | |
| ? `${media.focalX}% ${media.focalY}%` | |
| : 'center'; | |
| return ( | |
| <Image | |
| src={`${media.url!}?${media.updatedAt}`} alt={`Image box alt`} | |
| quality={95} | |
| fill={fill} | |
| width={!fill ? width : undefined} | |
| height={!fill ? height : undefined} | |
| className={imageClassName} | |
| sizes={sizes} | |
| style={{ | |
| objectFit: "cover", | |
| objectPosition | |
| }} | |
| placeholder={media.blurhash ? "blur" : "empty"} | |
| blurDataURL={media.blurhash || undefined} | |
| /> | |
| ) | |
| } |
| import path from 'path' | |
| import {fileURLToPath} from 'url' | |
| import {CollectionConfig} from "payload"; | |
| import {generateBlurHash} from "@/hooks/generateBlurhash"; | |
| const filename = fileURLToPath(import.meta.url) | |
| const dirname = path.dirname(filename) | |
| export const Media: CollectionConfig = { | |
| slug: "media", | |
| upload: { | |
| staticDir: path.resolve(dirname, '../../public/media'), | |
| adminThumbnail: 'thumbnail', | |
| mimeTypes: ['image/*'], | |
| imageSizes: [ | |
| { | |
| name: "medium", | |
| width: 1400, | |
| height: 800, | |
| }, | |
| ], | |
| }, | |
| fields: [ | |
| { | |
| name: "alt", | |
| type: "text", | |
| label: "Alt Text", | |
| }, | |
| { | |
| name: "blurhash", | |
| type: "text", | |
| admin: { | |
| hidden: true, | |
| disableListColumn: true, | |
| disableListFilter: true | |
| } | |
| } | |
| ], | |
| hooks: { | |
| beforeValidate: [generateBlurHash] | |
| } | |
| }; | |
| export default Media; |
@joelcorey I would just write (vibe-code) a node js script that gets the images from S3 runs the blurhash method and then reuploads, payloadCMS has nothing to do with it then, just a node script
@joelcorey I would just write (vibe-code) a node js script that gets the images from S3 runs the blurhash method and then reuploads, payloadCMS has nothing to do with it then, just a node script
That makes sense. Thanks!
As suggested I made this gist: https://gist.github.com/joelcorey/dd1e66cb4b10e42ba80a5d53a72bd915 that worked for all but 2 (very large) image files out of 40 plus images.
Nice! Good to hear you have it sorted.
Nice! Good to hear you have it sorted.
Given that I did use some of your code, I am realizing that I should have forked your code first. Having a bit of a face palm moment over here. I did give you a mention and link here in my gist at the very least. :\ Thank you!
Don't worry about it man! I couldn't care less, it's public code.
How do I regenerate images if I have a bunch of them in an s3 bucket?