You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

65 lines
1.7 KiB

  1. // @ts-check
  2. import { decode } from 'blurhash';
  3. import React, { useRef, useEffect } from 'react';
  4. import PropTypes from 'prop-types';
  5. /**
  6. * @typedef BlurhashPropsBase
  7. * @property {string?} hash Hash to render
  8. * @property {number} width
  9. * Width of the blurred region in pixels. Defaults to 32
  10. * @property {number} [height]
  11. * Height of the blurred region in pixels. Defaults to width
  12. * @property {boolean} [dummy]
  13. * Whether dummy mode is enabled. If enabled, nothing is rendered
  14. * and canvas left untouched
  15. */
  16. /** @typedef {JSX.IntrinsicElements['canvas'] & BlurhashPropsBase} BlurhashProps */
  17. /**
  18. * Component that is used to render blurred of blurhash string
  19. *
  20. * @param {BlurhashProps} param1 Props of the component
  21. * @returns Canvas which will render blurred region element to embed
  22. */
  23. function Blurhash({
  24. hash,
  25. width = 32,
  26. height = width,
  27. dummy = false,
  28. ...canvasProps
  29. }) {
  30. const canvasRef = /** @type {import('react').MutableRefObject<HTMLCanvasElement>} */ (useRef());
  31. useEffect(() => {
  32. const { current: canvas } = canvasRef;
  33. canvas.width = canvas.width; // resets canvas
  34. if (dummy || !hash) return;
  35. try {
  36. const pixels = decode(hash, width, height);
  37. const ctx = canvas.getContext('2d');
  38. const imageData = new ImageData(pixels, width, height);
  39. ctx.putImageData(imageData, 0, 0);
  40. } catch (err) {
  41. console.error('Blurhash decoding failure', { err, hash });
  42. }
  43. }, [dummy, hash, width, height]);
  44. return (
  45. <canvas {...canvasProps} ref={canvasRef} width={width} height={height} />
  46. );
  47. }
  48. Blurhash.propTypes = {
  49. hash: PropTypes.string.isRequired,
  50. width: PropTypes.number,
  51. height: PropTypes.number,
  52. dummy: PropTypes.bool,
  53. };
  54. export default React.memo(Blurhash);