Skip to content

Commit

Permalink
feat: use web workers for placeholder hash calculation
Browse files Browse the repository at this point in the history
(cherry picked from commit 1ef1ef1)
  • Loading branch information
felixranesberger committed Aug 23, 2023
1 parent 96e854a commit 94e3ef9
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 18 deletions.
18 changes: 12 additions & 6 deletions packages/core/src/blurhash.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
import { decodeBlurHash } from 'fast-blurhash'
import { DEFAULT_PLACEHOLDER_SIZE } from './constants'
import { getScaledDimensions } from './utils'
import { rgbaToDataUri } from './utils/dataUri'

export interface BlurHashOptions {
/**
Expand All @@ -27,7 +24,16 @@ export function createPngDataUri(
size = DEFAULT_PLACEHOLDER_SIZE,
}: BlurHashOptions = {},
) {
const { width, height } = getScaledDimensions(ratio, size)
const rgba = decodeBlurHash(hash, width, height)
return rgbaToDataUri(width, height, rgba)
const worker = new Worker('./workers/blurhash-worker.ts')
worker.postMessage({
hash,
ratio,
size,
})

return new Promise<string>((resolve) => {
worker.onmessage = (event) => {
resolve(event.data)
}
})
}
15 changes: 9 additions & 6 deletions packages/core/src/lazyLoad.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,17 @@ export function lazyLoad<T extends HTMLImageElement>(

// Generate the blurry placeholder from a Blurhash or ThumbHash string if applicable
if (__ENABLE_HASH_DECODING__ && hash) {
const placeholder = createPlaceholderFromHash({
createPlaceholderFromHash({
image,
hash: typeof hash === 'string' ? hash : undefined,
hashType,
size: placeholderSize,
})
if (placeholder)
image.src = placeholder
.then((placeholder) => {
if (!placeholder)
return
image.src = placeholder
})
}

// Bail if the image doesn't provide a `data-src` or `data-srcset` attribute
Expand Down Expand Up @@ -117,7 +120,7 @@ export function loadImage(
})
}

export function createPlaceholderFromHash(
export async function createPlaceholderFromHash(
{
/** If given, the hash will be extracted from the image's `data-blurhash` or `data-thumbhash` attribute and ratio will be calculated from the image's actual dimensions */
image,
Expand Down Expand Up @@ -146,7 +149,7 @@ export function createPlaceholderFromHash(

try {
if (hashType === 'thumbhash') {
return createPngDataUriFromThumbHash(hash)
return await createPngDataUriFromThumbHash(hash)
}
else {
// Preserve the original image's aspect ratio
Expand All @@ -155,7 +158,7 @@ export function createPlaceholderFromHash(
const actualHeight = image.height || image.offsetHeight || size
ratio = actualWidth / actualHeight
}
return createPngDataUriFromBlurHash(hash, { ratio, size })
return await createPngDataUriFromBlurHash(hash, { ratio, size })
}
}
catch (error) {
Expand Down
14 changes: 8 additions & 6 deletions packages/core/src/thumbhash.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { thumbHashToRGBA } from 'thumbhash'
import { base64ToBytes } from './utils'
import { rgbaToDataUri } from './utils/dataUri'

export function createPngDataUri(hash: string) {
const { w, h, rgba } = thumbHashToRGBA(base64ToBytes(hash))
return rgbaToDataUri(w, h, rgba)
const worker = new Worker('./workers/thumbhash-worker.ts')
worker.postMessage({ hash })

return new Promise<string>((resolve) => {
worker.onmessage = (event) => {
resolve(event.data)
}
})
}
19 changes: 19 additions & 0 deletions packages/core/src/workers/blurhash-worker.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { decodeBlurHash } from 'fast-blurhash'
import { getScaledDimensions } from '../utils'
import { rgbaToDataUri } from '../utils/dataUri'

interface MessageEventData {
hash: string
ratio: number
size: number
}

onmessage = (event: MessageEvent<MessageEventData>) => {
const { hash, ratio, size } = event.data

const { width, height } = getScaledDimensions(ratio, size)
const rgba = decodeBlurHash(hash, width, height)
const dataURL = rgbaToDataUri(width, height, rgba)

postMessage(dataURL)
}
16 changes: 16 additions & 0 deletions packages/core/src/workers/thumbhash-worker.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { thumbHashToRGBA } from 'thumbhash'
import { base64ToBytes } from '../utils'
import { rgbaToDataUri } from '../utils/dataUri'

interface MessageEventData {
hash: string
}

onmessage = (event: MessageEvent<MessageEventData>) => {
const { hash } = event.data

const { w, h, rgba } = thumbHashToRGBA(base64ToBytes(hash))
const dataURL = rgbaToDataUri(w, h, rgba)

postMessage(dataURL)
}

0 comments on commit 94e3ef9

Please sign in to comment.