import { useEffect, useRef } from 'react'
import PropTypes from 'prop-types'
import { decode, naturalSize } from '../utils/thumbhash'
const DECODE_SIZE = 32
const bitmapSize = (hash, ratio) => {
if (!(ratio > 0) || !Number.isFinite(ratio)) {
try {
return naturalSize(hash)
} catch {
return { width: DECODE_SIZE, height: DECODE_SIZE }
}
}
return ratio >= 1
? {
width: DECODE_SIZE,
height: Math.max(1, Math.round(DECODE_SIZE / ratio)),
}
: {
width: Math.max(1, Math.round(DECODE_SIZE * ratio)),
height: DECODE_SIZE,
}
}
export const ThumbHashCanvas = ({ hash, ratio, fit, className, style }) => {
const canvasRef = useRef(null)
const { width, height } = bitmapSize(hash, ratio)
useEffect(() => {
if (!hash || !canvasRef.current) {
return
}
const ctx = canvasRef.current.getContext('2d')
if (!ctx) {
return
}
ctx.clearRect(0, 0, width, height)
try {
const pixels = decode(hash, width, height)
const imageData = ctx.createImageData(width, height)
imageData.data.set(pixels)
ctx.putImageData(imageData, 0, 0)
} catch {
}
}, [hash, width, height])
if (!hash) {
return null
}
return (
<canvas
ref={canvasRef}
width={width}
height={height}
className={className}
style={{ ...style, objectFit: fit }}
aria-hidden="true"
/>
)
}
ThumbHashCanvas.propTypes = {
hash: PropTypes.string,
ratio: PropTypes.number,
fit: PropTypes.oneOf(['cover', 'contain']),
className: PropTypes.string,
style: PropTypes.object,
}