blurhash.tsx 1.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748
  1. import { memo, useRef, useEffect } from 'react';
  2. import { decode } from 'blurhash';
  3. interface Props extends React.HTMLAttributes<HTMLCanvasElement> {
  4. hash: string;
  5. width?: number;
  6. height?: number;
  7. dummy?: boolean; // Whether dummy mode is enabled. If enabled, nothing is rendered and canvas left untouched
  8. children?: never;
  9. }
  10. const Blurhash: React.FC<Props> = ({
  11. hash,
  12. width = 32,
  13. height = width,
  14. dummy = false,
  15. ...canvasProps
  16. }) => {
  17. const canvasRef = useRef<HTMLCanvasElement>(null);
  18. useEffect(() => {
  19. // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
  20. const canvas = canvasRef.current!;
  21. // eslint-disable-next-line no-self-assign
  22. canvas.width = canvas.width; // resets canvas
  23. if (dummy || !hash) return;
  24. try {
  25. const pixels = decode(hash, width, height);
  26. const ctx = canvas.getContext('2d');
  27. const imageData = new ImageData(pixels, width, height);
  28. ctx?.putImageData(imageData, 0, 0);
  29. } catch (err) {
  30. console.error('Blurhash decoding failure', { err, hash });
  31. }
  32. }, [dummy, hash, width, height]);
  33. return (
  34. <canvas {...canvasProps} ref={canvasRef} width={width} height={height} />
  35. );
  36. };
  37. const MemoizedBlurhash = memo(Blurhash);
  38. export { MemoizedBlurhash as Blurhash };