Skip to content

Instantly share code, notes, and snippets.

@kmelve
Last active July 22, 2023 14:29
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kmelve/8f1738397a3d29fc8639bda890eeb116 to your computer and use it in GitHub Desktop.
Save kmelve/8f1738397a3d29fc8639bda890eeb116 to your computer and use it in GitHub Desktop.
Retroactively add Blurhash strings to image assets in your Sanity Content Lake.
/**
* Retroactively add Blurhash strings to image assets in your Sanity Content Lake.
* 1. yarn add got sharp blurhash
* 2. run sanity exec blurhash --with-user-token
* 3. repeat (patches 100 assets in 1 transaction pr run)
*
* Some images might take a while to process.
*/
import client from 'part:@sanity/base/client'
import got from 'got'
import sharp from 'sharp'
import { encode } from "blurhash";
const versionedClient = client.withConfig({ apiVersion: '2021-10-22' })
const BASE_COMPONENT = 5
const loadImage = async src => {
try {
const response = await got(src, { responseType: 'buffer' })
const arr = new Uint8Array(response.body)
return arr
}
catch (error) {
console.log(error)
return undefined
}
}
const encodeImageToBlurhash = async ({ url, metadata }) => {
const { dimensions } = metadata
const dimensionedUrl = url
const imageBuffer = await loadImage(dimensionedUrl);
const { data, info } = await sharp(imageBuffer).raw().ensureAlpha().toBuffer({ resolveWithObject: true })
const { height, width } = info
let componentX = BASE_COMPONENT
let componentY = BASE_COMPONENT
if (width > height) {
componentY = Math.ceil(BASE_COMPONENT * (height / width))
} else {
componentX = Math.ceil(BASE_COMPONENT * (width / height))
}
try {
return encode(data, width, height, componentX, componentY);
} catch (err) {
console.error(err)
return undefined
}
};
async function run() {
// Fetch assets without blurhash, 100 at a time
const assets = await versionedClient
.fetch(`*[_type == "sanity.imageAsset" && metadata.blurHash == null][0...100]`)
if (!assets.length) {
return 'No assets to blurhash'
}
const createTransaction = patches =>
patches.reduce((tx, patch) => tx.patch(patch.id, patch.patch), versionedClient.transaction())
// build transaction, one by one
let patches = []
for (const asset of assets) {
const hash = await encodeImageToBlurhash(asset)
console.log(`Created hash for ${asset._id}: ${hash}`)
if (hash) {
patches = [...patches, {
id: asset._id,
patch: {
set: {
'metadata.blurHash': hash
}
}
}]
}
}
console.log(`Creating ${patches.length} transactions…`)
const transaction = createTransaction(patches)
const result = await transaction.commit()
return JSON.stringify(result, null, 2)
}
run().then(result => console.log(result))
@emilsomm
Copy link

emilsomm commented Nov 16, 2021

thanks for this @kmelve, i got a linting error when running this because of a missing const in your
for (asset of assets) {...}
should be
for (const asset of assets) {...}

also i was running a script with sanity exec for the first time so i found this article useful.

After changing this it works like a charm! Thanks again for your great work!

@janhoogeveen
Copy link

janhoogeveen commented Feb 1, 2022

Worth mentioning that got is now a pure ES6 package and will throw errors if you use got@latest. You probably want to do:

yarn add got@11.8.3 sharp blurhash

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment