2022.11.08

blurhashで画像読み込み前のぼかし画像を表示する

複数の大きなサイズの画像を読み込む場合、読み込みから表示されるまでに多少時間がかかることがあります。

そんなとき、「ここに画像が入るよ」というのを予め示しておきたい場合に使えるライブラリを紹介。

仕組みとしては、画像ファイルからハッシュ値を生成し、生成したハッシュ値を利用して画像をぼかした状態のものをcanvasで生成します。

前提条件

以下をインストール済みであること

  • Node.js(16系)
  • npm または yarn

この記事ではReact(Next.js)のサイトで利用することを前提とします。

使うもの

やること

  1. blurhashを利用して画像ファイルからハッシュ値を生成
  2. 1の値を利用して、react-blurhashで表示側でcanvasを生成

1. blurhashを利用して画像ファイルからハッシュ値を生成

ハッシュ生成スクリプト

import { encode } from 'blurhash'

const loadImage = async (src: string) =>
  new Promise((resolve, reject) => {
    const img = new Image()
    img.onload = () => resolve(img)
    img.onerror = (...args) => reject(args)
    img.src = src
  })

const getImageData = async (image: any): Promise<ImageData | undefined> => {
  const canvas = document.createElement('canvas')
  canvas.width = image.width
  canvas.height = image.height
  const context = canvas.getContext('2d')
  context?.drawImage(image, 0, 0)
  return context?.getImageData(0, 0, image.width, image.height)
}

export const encodeImageToBlurHash = async (imageUrl: string): Promise<string> => {
  const image = await loadImage(imageUrl)
  const imageData = await getImageData(image)
  return imageData ? encode(imageData.data, imageData.width, imageData.height, 4, 4) : ''
}

画像からハッシュを生成

const imgElement: HTMLElement | null = document.getElementById('{imgタグのID}')
if (!imgElement) return
const img = imgElement as HTMLImageElement
const imageSrc: string = img.src
const hash: string = await encodeImageToBlurHash(imageSrc)

2. 1の値を利用して、react-blurhashで表示側でcanvasを生成

import React from 'react'
import { BlurhashCanvas } from 'react-blurhash'

interface Props {
  blurHash: string // 1で生成したハッシュ値
}

const Component: React.FC<Props> = (props: Props) => {
  const { blurHash } = props

  return (
    <div>
      <BlurhashCanvas {...{ hash: blurHash }} />
    </div>
  )
}

以下の画像で実行した場合

元の画像

表示側のキャプチャ