mirror of
https://github.com/bitsocialnet/5chan.git
synced 2026-08-03 07:41:04 +02:00
86 lines
2.3 KiB
TypeScript
86 lines
2.3 KiB
TypeScript
import { useEffect, useState } from 'react';
|
|
|
|
export const fetchImage = (url: string): Promise<ArrayBuffer> => {
|
|
return new Promise((resolve, reject) => {
|
|
const request = new XMLHttpRequest();
|
|
request.open('GET', url, true);
|
|
request.responseType = 'arraybuffer';
|
|
request.onloadend = () => {
|
|
if (request.response !== undefined && (request.status === 200 || request.status === 304)) {
|
|
resolve(request.response);
|
|
} else {
|
|
reject(new Error(`XMLHttpRequest, ${request.statusText}`));
|
|
}
|
|
};
|
|
request.send();
|
|
});
|
|
};
|
|
|
|
export const readImage = (file: File): Promise<ArrayBuffer> => {
|
|
return new Promise((resolve) => {
|
|
const reader = new FileReader();
|
|
reader.onload = () => {
|
|
resolve(reader.result as ArrayBuffer);
|
|
};
|
|
reader.readAsArrayBuffer(file);
|
|
});
|
|
};
|
|
|
|
const parseGif = async (buf: ArrayBuffer): Promise<Blob> => {
|
|
const image = new Image();
|
|
await new Promise((resolve) => {
|
|
image.src = URL.createObjectURL(new Blob([buf]));
|
|
image.onload = resolve;
|
|
});
|
|
const canvas = document.createElement('canvas');
|
|
canvas.width = image.width;
|
|
canvas.height = image.height;
|
|
const ctx = canvas.getContext('2d');
|
|
if (ctx === null) throw new Error('Canvas Context null');
|
|
ctx.drawImage(image, 0, 0, image.width, image.height);
|
|
return await new Promise((resolve, reject) =>
|
|
canvas.toBlob((blob) => {
|
|
if (blob === null) {
|
|
reject('Canvas Blob null');
|
|
} else {
|
|
resolve(blob);
|
|
}
|
|
}),
|
|
);
|
|
};
|
|
|
|
const useFetchGifFirstFrame = (url: string | undefined) => {
|
|
const [frameUrl, setFrameUrl] = useState<string | null>(null);
|
|
|
|
useEffect(() => {
|
|
if (!url) {
|
|
setFrameUrl(null);
|
|
return;
|
|
}
|
|
|
|
let isActive = true;
|
|
|
|
const fetchFrame = async () => {
|
|
try {
|
|
const blob = typeof url === 'string' ? await parseGif(await fetchImage(url)) : await parseGif(await readImage(url as File));
|
|
const objectUrl = URL.createObjectURL(blob);
|
|
if (isActive) setFrameUrl(objectUrl);
|
|
} catch (error) {
|
|
console.error('Failed to load GIF frame:', error);
|
|
if (isActive) setFrameUrl(null);
|
|
}
|
|
};
|
|
|
|
fetchFrame();
|
|
|
|
// Cleanup function to avoid setting state on unmounted component
|
|
return () => {
|
|
isActive = false;
|
|
};
|
|
}, [url]);
|
|
|
|
return frameUrl;
|
|
};
|
|
|
|
export default useFetchGifFirstFrame;
|