동영상의 썸네일이 가끔 흰색으로 잘못 생성되던 버그 수정

This commit is contained in:
static
2025-07-12 05:39:39 +09:00
parent 0d35f0b607
commit 4679b1d6bd
2 changed files with 38 additions and 43 deletions

View File

@@ -54,9 +54,7 @@ export const deleteFileCache = async (fileId: number) => {
export const getFileThumbnailCache = async (fileId: number) => { export const getFileThumbnailCache = async (fileId: number) => {
const thumbnail = loadedThumbnails.get(fileId); const thumbnail = loadedThumbnails.get(fileId);
if (thumbnail) { if (thumbnail) return thumbnail;
return thumbnail;
}
const thumbnailBuffer = await readFile(`/thumbnail/file/${fileId}`); const thumbnailBuffer = await readFile(`/thumbnail/file/${fileId}`);
if (!thumbnailBuffer) return null; if (!thumbnailBuffer) return null;

View File

@@ -12,22 +12,25 @@ const scaleSize = (width: number, height: number, targetSize: number) => {
}; };
}; };
const generateImageThumbnail = (imageUrl: string) => { const capture = (
width: number,
height: number,
drawer: (context: CanvasRenderingContext2D, width: number, height: number) => void,
targetSize = 250,
) => {
return new Promise<Blob>((resolve, reject) => { return new Promise<Blob>((resolve, reject) => {
const image = new Image();
image.onload = () => {
const canvas = document.createElement("canvas"); const canvas = document.createElement("canvas");
const { width, height } = scaleSize(image.width, image.height, 250); const { width: scaledWidth, height: scaledHeight } = scaleSize(width, height, targetSize);
canvas.width = width; canvas.width = scaledWidth;
canvas.height = height; canvas.height = scaledHeight;
const context = canvas.getContext("2d"); const context = canvas.getContext("2d");
if (!context) { if (!context) {
return reject(new Error("Failed to generate thumbnail")); return reject(new Error("Failed to generate thumbnail"));
} }
context.drawImage(image, 0, 0, width, height); drawer(context, scaledWidth, scaledHeight);
canvas.toBlob((blob) => { canvas.toBlob((blob) => {
if (blob) { if (blob) {
resolve(blob); resolve(blob);
@@ -35,6 +38,18 @@ const generateImageThumbnail = (imageUrl: string) => {
reject(new Error("Failed to generate thumbnail")); reject(new Error("Failed to generate thumbnail"));
} }
}, "image/webp"); }, "image/webp");
});
};
const generateImageThumbnail = (imageUrl: string) => {
return new Promise<Blob>((resolve, reject) => {
const image = new Image();
image.onload = () => {
capture(image.width, image.height, (context, width, height) => {
context.drawImage(image, 0, 0, width, height);
})
.then(resolve)
.catch(reject);
}; };
image.onerror = reject; image.onerror = reject;
@@ -43,37 +58,19 @@ const generateImageThumbnail = (imageUrl: string) => {
}; };
export const captureVideoThumbnail = (video: HTMLVideoElement) => { export const captureVideoThumbnail = (video: HTMLVideoElement) => {
return new Promise<Blob>((resolve, reject) => { return capture(video.videoWidth, video.videoHeight, (context, width, height) => {
const canvas = document.createElement("canvas");
const { width, height } = scaleSize(video.videoWidth, video.videoHeight, 250);
canvas.width = width;
canvas.height = height;
const context = canvas.getContext("2d");
if (!context) {
return reject(new Error("Failed to generate thumbnail"));
}
context.drawImage(video, 0, 0, width, height); context.drawImage(video, 0, 0, width, height);
canvas.toBlob((blob) => {
if (blob) {
resolve(blob);
} else {
reject(new Error("Failed to generate thumbnail"));
}
}, "image/webp");
}); });
}; };
const generateVideoThumbnail = (videoUrl: string, time = 0) => { const generateVideoThumbnail = (videoUrl: string, time = 0) => {
return new Promise<Blob>((resolve, reject) => { return new Promise<Blob>((resolve, reject) => {
const video = document.createElement("video"); const video = document.createElement("video");
video.onloadeddata = () => { video.onloadedmetadata = () => {
video.currentTime = time; video.currentTime = Math.min(time, video.duration);
}; video.requestVideoFrameCallback(() => {
video.onseeked = () => {
captureVideoThumbnail(video).then(resolve).catch(reject); captureVideoThumbnail(video).then(resolve).catch(reject);
});
}; };
video.onerror = reject; video.onerror = reject;