u
This commit is contained in:
69
src/components/article/ThumbHashImage.jsx
Normal file
69
src/components/article/ThumbHashImage.jsx
Normal file
@@ -0,0 +1,69 @@
|
||||
import { useEffect, useRef } from 'react';
|
||||
import Box from '@mui/material/Box';
|
||||
import { thumbHashToRGBA } from 'thumbhash';
|
||||
|
||||
function decodeThumbHash(thumbHash) {
|
||||
const bytes = Uint8Array.from(atob(thumbHash), (c) => c.charCodeAt(0));
|
||||
return thumbHashToRGBA(bytes);
|
||||
}
|
||||
|
||||
function paintThumbHash(canvas, thumbHash) {
|
||||
const parent = canvas.parentElement;
|
||||
if (!parent) return;
|
||||
|
||||
const { width, height } = parent.getBoundingClientRect();
|
||||
if (width === 0 || height === 0) return;
|
||||
|
||||
const { w, h, rgba } = decodeThumbHash(thumbHash);
|
||||
const src = document.createElement('canvas');
|
||||
src.width = w;
|
||||
src.height = h;
|
||||
src.getContext('2d').putImageData(
|
||||
new ImageData(new Uint8ClampedArray(rgba), w, h),
|
||||
0,
|
||||
0,
|
||||
);
|
||||
|
||||
canvas.width = Math.round(width);
|
||||
canvas.height = Math.round(height);
|
||||
const ctx = canvas.getContext('2d');
|
||||
if (!ctx) return;
|
||||
|
||||
ctx.imageSmoothingEnabled = true;
|
||||
ctx.imageSmoothingQuality = 'high';
|
||||
ctx.drawImage(src, 0, 0, canvas.width, canvas.height);
|
||||
}
|
||||
|
||||
export default function ThumbHashImage({ thumbHash, sx }) {
|
||||
const canvasRef = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
const canvas = canvasRef.current;
|
||||
if (!canvas || !thumbHash) return;
|
||||
|
||||
paintThumbHash(canvas, thumbHash);
|
||||
|
||||
const parent = canvas.parentElement;
|
||||
if (!parent || typeof ResizeObserver === 'undefined') return undefined;
|
||||
|
||||
const observer = new ResizeObserver(() => {
|
||||
paintThumbHash(canvas, thumbHash);
|
||||
});
|
||||
observer.observe(parent);
|
||||
return () => observer.disconnect();
|
||||
}, [thumbHash]);
|
||||
|
||||
return (
|
||||
<Box
|
||||
component="canvas"
|
||||
ref={canvasRef}
|
||||
aria-hidden
|
||||
sx={{
|
||||
display: 'block',
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
...sx,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user