From 58f344db8517c98cb28b789d41bde4bb5ff64b68 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Tue, 5 May 2026 10:57:38 +0100 Subject: [PATCH] =?UTF-8?q?piano-sheet(upload):=20mobile/pad=20first?= =?UTF-8?q?=EF=BC=8C=E4=B8=BB=E5=85=A5=E5=8F=A3=E7=9B=B4=E8=B0=83=E5=90=8E?= =?UTF-8?q?=E7=BD=AE=E6=91=84=E5=83=8F=E5=A4=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 主 CTA「拍下一页」+ capture=environment,副 CTA「从相册」multiple - 底部 sticky 上传按钮,iOS safe area 兜住刘海/Home indicator - 客户端压缩 1800px JPEG 0.85(createImageBitmap + EXIF 自动旋转) - 页码 ↑↓ 移动 + ✕ 删除替代旧拖拽 --- apps/piano-sheet/frontend/src/lib/compress.js | 32 ++ .../frontend/src/views/UploadView.vue | 382 ++++++++++++------ 2 files changed, 282 insertions(+), 132 deletions(-) create mode 100644 apps/piano-sheet/frontend/src/lib/compress.js diff --git a/apps/piano-sheet/frontend/src/lib/compress.js b/apps/piano-sheet/frontend/src/lib/compress.js new file mode 100644 index 0000000..a9389a7 --- /dev/null +++ b/apps/piano-sheet/frontend/src/lib/compress.js @@ -0,0 +1,32 @@ +// 移动端拍照原图常 5–12MB,1500–1800px 长边 + JPEG 0.85 已经够看清楚音符。 +// 用 createImageBitmap 的 imageOrientation: 'from-image' 自动按 EXIF 旋转, +// 否则横拍照在 canvas 里会变成竖图。 + +export async function compressImage(file, { maxEdge = 1800, quality = 0.85 } = {}) { + if (!file || !file.type || !file.type.startsWith('image/')) return file + + let bitmap + try { + bitmap = await createImageBitmap(file, { imageOrientation: 'from-image' }) + } catch { + return file + } + + const { width, height } = bitmap + const scale = Math.min(1, maxEdge / Math.max(width, height)) + const w = Math.max(1, Math.round(width * scale)) + const h = Math.max(1, Math.round(height * scale)) + + const canvas = document.createElement('canvas') + canvas.width = w + canvas.height = h + const ctx = canvas.getContext('2d') + ctx.drawImage(bitmap, 0, 0, w, h) + bitmap.close?.() + + const blob = await new Promise((res) => canvas.toBlob(res, 'image/jpeg', quality)) + if (!blob || blob.size >= file.size) return file + + const baseName = file.name?.replace(/\.[^.]+$/, '') || 'photo' + return new File([blob], `${baseName}.jpg`, { type: 'image/jpeg', lastModified: Date.now() }) +} diff --git a/apps/piano-sheet/frontend/src/views/UploadView.vue b/apps/piano-sheet/frontend/src/views/UploadView.vue index 01f86c9..4b23609 100644 --- a/apps/piano-sheet/frontend/src/views/UploadView.vue +++ b/apps/piano-sheet/frontend/src/views/UploadView.vue @@ -1,115 +1,149 @@