Created
January 12, 2025 12:31
-
-
Save notflip/e33c0b45299674ce56d80f1c6d08bd09 to your computer and use it in GitHub Desktop.
PayloadCMS BlurHash
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 {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'); | |
| } | |
| } | |
| }; |
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
| {image && | |
| <ImageBox | |
| fill | |
| media={image as Media} | |
| sizes="(max-width: 1024px) 100vw, 50vw" | |
| /> | |
| } |
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 {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} | |
| /> | |
| ) | |
| } |
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 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; |
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.
Author
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!
Author
Don't worry about it man! I couldn't care less, it's public code.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
That makes sense. Thanks!