From 301216915e5ace0822b313eea343a92b0a3dc136 Mon Sep 17 00:00:00 2001 From: static Date: Sat, 12 Jul 2025 19:44:16 +0900 Subject: [PATCH] =?UTF-8?q?=EB=B8=8C=EB=9D=BC=EC=9A=B0=EC=A0=80=EA=B0=80?= =?UTF-8?q?=20heic=20=EB=94=94=EC=BD=94=EB=94=A9=EC=9D=84=20=EC=A7=80?= =?UTF-8?q?=EC=9B=90=ED=95=98=EB=8A=94=20=EA=B2=BD=EC=9A=B0=20heic2any?= =?UTF-8?q?=EB=A5=BC=20=EC=82=AC=EC=9A=A9=ED=95=98=EC=A7=80=20=EC=95=8A?= =?UTF-8?q?=EB=8F=84=EB=A1=9D=20=EA=B0=9C=EC=84=A0=20=EB=B0=8F=20=EB=B8=8C?= =?UTF-8?q?=EB=9D=BC=EC=9A=B0=EC=A0=80=EA=B0=80=20webp=20=EC=9D=B8?= =?UTF-8?q?=EC=BD=94=EB=94=A9=EC=9D=84=20=EC=A7=80=EC=9B=90=ED=95=98?= =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EB=8A=94=20=EA=B2=BD=EC=9A=B0=20=EC=8D=B8?= =?UTF-8?q?=EB=84=A4=EC=9D=BC=EC=9D=84=20=EC=83=9D=EC=84=B1=ED=95=98?= =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lib/modules/thumbnail.ts | 34 ++++++++++++------- .../(fullscreen)/file/[id]/+page.svelte | 25 +++++++++----- 2 files changed, 38 insertions(+), 21 deletions(-) diff --git a/src/lib/modules/thumbnail.ts b/src/lib/modules/thumbnail.ts index 9c009bd..2d5cd55 100644 --- a/src/lib/modules/thumbnail.ts +++ b/src/lib/modules/thumbnail.ts @@ -32,7 +32,7 @@ const capture = ( drawer(context, scaledWidth, scaledHeight); canvas.toBlob((blob) => { - if (blob) { + if (blob && blob.type === "image/webp") { resolve(blob); } else { reject(new Error("Failed to generate thumbnail")); @@ -83,18 +83,26 @@ const generateVideoThumbnail = (videoUrl: string, time = 0) => { export const generateThumbnail = async (fileBuffer: ArrayBuffer, fileType: string) => { let url; try { - if (fileType === "image/heic") { - const { default: heic2any } = await import("heic2any"); - url = URL.createObjectURL( - (await heic2any({ - blob: new Blob([fileBuffer], { type: fileType }), - toType: "image/png", - })) as Blob, - ); - return await generateImageThumbnail(url); - } else if (fileType.startsWith("image/")) { - url = URL.createObjectURL(new Blob([fileBuffer], { type: fileType })); - return await generateImageThumbnail(url); + if (fileType.startsWith("image/")) { + const fileBlob = new Blob([fileBuffer], { type: fileType }); + url = URL.createObjectURL(fileBlob); + + try { + return await generateImageThumbnail(url); + } catch { + URL.revokeObjectURL(url); + url = undefined; + + if (fileType === "image/heic") { + const { default: heic2any } = await import("heic2any"); + url = URL.createObjectURL( + (await heic2any({ blob: fileBlob, toType: "image/png" })) as Blob, + ); + return await generateImageThumbnail(url); + } else { + return null; + } + } } else if (fileType.startsWith("video/")) { url = URL.createObjectURL(new Blob([fileBuffer], { type: fileType })); return await generateVideoThumbnail(url); diff --git a/src/routes/(fullscreen)/file/[id]/+page.svelte b/src/routes/(fullscreen)/file/[id]/+page.svelte index 61465bd..4047e7c 100644 --- a/src/routes/(fullscreen)/file/[id]/+page.svelte +++ b/src/routes/(fullscreen)/file/[id]/+page.svelte @@ -43,22 +43,31 @@ let isDownloadRequested = $state(false); let viewerType: "image" | "video" | undefined = $state(); let fileBlobUrl: string | undefined = $state(); + let heicBlob: Blob | undefined = $state(); let videoElement: HTMLVideoElement | undefined = $state(); const updateViewer = async (buffer: ArrayBuffer, contentType: string) => { const fileBlob = new Blob([buffer], { type: contentType }); - if (contentType === "image/heic") { - const { default: heic2any } = await import("heic2any"); - fileBlobUrl = URL.createObjectURL( - (await heic2any({ blob: fileBlob, toType: "image/jpeg" })) as Blob, - ); - } else if (viewerType) { + if (viewerType) { fileBlobUrl = URL.createObjectURL(fileBlob); + heicBlob = contentType === "image/heic" ? fileBlob : undefined; } - return fileBlob; }; + const convertHeicToJpeg = async () => { + if (!heicBlob) return; + + URL.revokeObjectURL(fileBlobUrl!); + fileBlobUrl = undefined; + + const { default: heic2any } = await import("heic2any"); + fileBlobUrl = URL.createObjectURL( + (await heic2any({ blob: heicBlob, toType: "image/jpeg" })) as Blob, + ); + heicBlob = undefined; + }; + const updateThumbnail = async (dataKey: CryptoKey, dataKeyVersion: Date) => { const thumbnail = await captureVideoThumbnail(videoElement!); await requestThumbnailUpload(data.id, thumbnail, dataKey, dataKeyVersion); @@ -136,7 +145,7 @@ {#if viewerType === "image"} {#if fileBlobUrl} - {$info.name} + {$info.name} {:else} {@render viewerLoading("이미지를 불러오고 있어요.")} {/if}