Browse Source

fix: image preview/download

Timothy Jaeryang Baek 4 months ago
parent
commit
32135a29bb
1 changed files with 44 additions and 27 deletions
  1. 44 27
      src/lib/components/common/ImagePreview.svelte

+ 44 - 27
src/lib/components/common/ImagePreview.svelte

@@ -2,6 +2,9 @@
 	import { onDestroy, onMount } from 'svelte';
 	import panzoom, { type PanZoom } from 'panzoom';
 
+	import fileSaver from 'file-saver';
+	const { saveAs } = fileSaver;
+
 	export let show = false;
 	export let src = '';
 	export let alt = '';
@@ -29,22 +32,6 @@
 		console.log(instance.getTransform());
 	};
 
-	const downloadImage = (url, filename, prefixName = '') => {
-		fetch(url)
-			.then((response) => response.blob())
-			.then((blob) => {
-				const objectUrl = window.URL.createObjectURL(blob);
-				const link = document.createElement('a');
-				link.href = objectUrl;
-				link.download = `${prefixName}${filename}`;
-				document.body.appendChild(link);
-				link.click();
-				document.body.removeChild(link);
-				window.URL.revokeObjectURL(objectUrl);
-			})
-			.catch((error) => console.error('Error downloading image:', error));
-	};
-
 	const handleKeyDown = (event: KeyboardEvent) => {
 		if (event.key === 'Escape') {
 			console.log('Escape');
@@ -82,7 +69,7 @@
 		bind:this={previewElement}
 		class="modal fixed top-0 right-0 left-0 bottom-0 bg-black text-white w-full min-h-screen h-screen flex justify-center z-9999 overflow-hidden overscroll-contain"
 	>
-		<div class=" absolute left-0 w-full flex justify-between select-none z-10">
+		<div class=" absolute left-0 w-full flex justify-between select-none z-20">
 			<div>
 				<button
 					class=" p-5"
@@ -110,14 +97,38 @@
 
 			<div>
 				<button
-					class=" p-5"
-					on:pointerdown={(e) => {
-						e.stopImmediatePropagation();
-						e.preventDefault();
-						downloadImage(src, src.substring(src.lastIndexOf('/') + 1), alt);
-					}}
-					on:click={(e) => {
-						downloadImage(src, src.substring(src.lastIndexOf('/') + 1), alt);
+					class=" p-5 z-999"
+					on:click={() => {
+						if (src.startsWith('data:image/')) {
+							const base64Data = src.split(',')[1];
+							const blob = new Blob([Uint8Array.from(atob(base64Data), (c) => c.charCodeAt(0))], {
+								type: 'image/png'
+							});
+							saveAs(blob, alt || 'download.png');
+							return;
+						} else if (src.startsWith('blob:')) {
+							// Handle blob URLs
+							fetch(src)
+								.then((response) => response.blob())
+								.then((blob) => {
+									saveAs(blob, alt || 'download.png');
+								})
+								.catch((error) => {
+									console.error('Error downloading blob:', error);
+								});
+							return;
+						} else if (src.startsWith('http://') || src.startsWith('https://')) {
+							// Handle remote URLs
+							fetch(src)
+								.then((response) => response.blob())
+								.then((blob) => {
+									saveAs(blob, alt || 'download.png');
+								})
+								.catch((error) => {
+									console.error('Error downloading remote image:', error);
+								});
+							return;
+						}
 					}}
 				>
 					<svg
@@ -136,8 +147,14 @@
 				</button>
 			</div>
 		</div>
-		<div bind:this={sceneElement} class="flex h-full max-h-full justify-center items-center">
-			<img {src} {alt} class=" mx-auto h-full object-scale-down select-none" draggable="false" />
+		<div class="flex h-full max-h-full justify-center items-center z-0">
+			<img
+				bind:this={sceneElement}
+				{src}
+				{alt}
+				class=" mx-auto h-full object-scale-down select-none"
+				draggable="false"
+			/>
 		</div>
 	</div>
 {/if}