diff --git a/package.json b/package.json index e551c55..15ee12b 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,9 @@ "serve": "npx serve dist" }, "dependencies": { - "jszip": "^3.10.1" + "exifr": "^7.1.3", + "jszip": "^3.10.1", + "medium-zoom": "^1.1.0" }, "devDependencies": { "esbuild": "^0.24.0" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 33952ec..b908065 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,9 +8,15 @@ importers: .: dependencies: + exifr: + specifier: ^7.1.3 + version: 7.1.3 jszip: specifier: ^3.10.1 version: 3.10.1 + medium-zoom: + specifier: ^1.1.0 + version: 1.1.0 devDependencies: esbuild: specifier: ^0.24.0 @@ -176,6 +182,9 @@ packages: engines: {node: '>=18'} hasBin: true + exifr@7.1.3: + resolution: {integrity: sha512-g/aje2noHivrRSLbAUtBPWFbxKdKhgj/xr1vATDdUXPOFYJlQ62Ft0oy+72V6XLIpDJfHs6gXLbBLAolqOXYRw==} + immediate@3.0.6: resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==} @@ -191,6 +200,9 @@ packages: lie@3.3.0: resolution: {integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==} + medium-zoom@1.1.0: + resolution: {integrity: sha512-ewyDsp7k4InCUp3jRmwHBRFGyjBimKps/AJLjRSox+2q/2H4p/PNpQf+pwONWlJiOudkBXtbdmVbFjqyybfTmQ==} + pako@1.0.11: resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==} @@ -319,6 +331,8 @@ snapshots: '@esbuild/win32-ia32': 0.24.2 '@esbuild/win32-x64': 0.24.2 + exifr@7.1.3: {} + immediate@3.0.6: {} inherits@2.0.4: {} @@ -336,6 +350,8 @@ snapshots: dependencies: immediate: 3.0.6 + medium-zoom@1.1.0: {} + pako@1.0.11: {} process-nextick-args@2.0.1: {} diff --git a/public/index.html b/public/index.html index f46edd6..455c18b 100644 --- a/public/index.html +++ b/public/index.html @@ -19,6 +19,10 @@ primary: '#10B981', 'primary-hover': '#059669', dark: '#1F2937', + success: '#10B981', + warn: '#F59E0B', + err: '#EF4444', + info: '#3B82F6', }, boxShadow: { 'soft': '0 4px 20px -2px rgba(16, 185, 129, 0.1)', @@ -65,6 +69,14 @@ } body.loading { opacity: 0; } body { transition: opacity 0s; } + + .medium-zoom-overlay, + .medium-zoom-image--opened { + z-index: 999; + } + .medium-zoom-overlay { + backdrop-filter: blur(4px); + }
@@ -103,7 +115,7 @@点击选择 或 拖拽图片至此
支持 JPG, PNG, WebP
@@ -140,8 +152,8 @@${i18n.t('info.size')}: ${img.width}×${img.height}
+${i18n.t('info.watermark')}: ${watermarkInfo.size}×${watermarkInfo.size}
+${i18n.t('info.position')}: (${watermarkInfo.position.x},${watermarkInfo.position.y})
`; const result = await engine.removeWatermarkFromImage(img); @@ -158,10 +166,13 @@ async function processSingle(item) { downloadBtn.onclick = () => downloadImage(item); processedInfo.innerHTML = ` - ${i18n.t('info.size')}:${img.width} × ${img.height} px${i18n.t('info.size')}: ${img.width}×${img.height}
+${i18n.t('info.status')}: ${i18n.t('info.removed')}
`; + zoom.detach(); + zoom.attach('[data-zoomable]'); + processedSection.scrollIntoView({ behavior: 'smooth', block: 'start' }); } catch (error) { console.error(error); @@ -171,20 +182,20 @@ async function processSingle(item) { function createImageCard(item) { const card = document.createElement('div'); card.id = `card-${item.id}`; - card.className = 'bg-white md:h-[130px] rounded-xl shadow-card border border-gray-100 overflow-hidden'; + card.className = 'bg-white md:h-[140px] rounded-xl shadow-card border border-gray-100 overflow-hidden'; card.innerHTML = ` -${i18n.t('info.size')}: ${item.originalImg.width}×${item.originalImg.height}
+${i18n.t('info.watermark')}: ${watermarkInfo.size}×${watermarkInfo.size}
+${i18n.t('info.position')}: (${watermarkInfo.position.x},${watermarkInfo.position.y})
+${originalStatus}
`, true); const downloadBtn = document.getElementById(`download-${item.id}`); downloadBtn.classList.remove('hidden'); @@ -235,20 +251,6 @@ async function processQueue() { } } -function loadImage(file) { - return new Promise((resolve, reject) => { - const reader = new FileReader(); - reader.onload = (e) => { - const img = new Image(); - img.onload = () => resolve(img); - img.onerror = reject; - img.src = e.target.result; - }; - reader.onerror = reject; - reader.readAsDataURL(file); - }); -} - function updateStatus(id, text, isHtml = false) { const el = document.getElementById(`status-${id}`); if (el) el.innerHTML = isHtml ? text : text.replace(/\n/g, '