feat: enhance photo capturing and uploading features with auto-capture and image cropping

This commit is contained in:
mrkad@rpi
2026-01-17 13:20:17 +07:00
parent e90c06230b
commit 39afc25aba
5 changed files with 322 additions and 53 deletions

View File

@@ -37,14 +37,16 @@ const getGridStyle = computed(() => {
display: 'grid',
gridTemplateColumns: '1fr',
gridTemplateRows: 'repeat(4, 1fr)',
gap: '8px'
gap: '8px',
aspectRatio: '1/2' // ทำให้แต่ละภาพยาวขึ้น (1:2 aspect ratio รวม)
}
} else {
return {
display: 'grid',
gridTemplateColumns: 'repeat(2, 1fr)',
gridTemplateRows: 'repeat(2, 1fr)',
gap: '8px'
gap: '8px',
aspectRatio: '1/1' // 2x2 เป็น square
}
}
})
@@ -67,24 +69,113 @@ const generateShareUrl = () => {
qrCodeUrl.value = `https://api.qrserver.com/v1/create-qr-code/?size=200x200&data=${encodeURIComponent(shareUrl.value)}`
}
const downloadImage = () => {
// ในโปรเจกต์จริงควรสร้าง canvas และ download เป็นไฟล์ภาพ
// ตัวอย่างนี้ download เป็น JSON ชั่วคราว
const data = {
photos: photos.value,
layout: layout.value,
frame: frame.value
const downloadImage = async () => {
if (photos.value.length === 0) return
// สร้าง canvas สำหรับรวมรูป
const canvas = document.createElement('canvas')
const context = canvas.getContext('2d')
if (!context) return
// ขนาดรูปแต่ละภาพ (720x960 = 3:4)
const photoWidth = 720
const photoHeight = 960
const gap = 20 // ระยะห่างระหว่างรูป
let canvasWidth, canvasHeight
if (layout.value === '1x4') {
// 1x4: 1 คอลัมน์ 4 แถว
canvasWidth = photoWidth
canvasHeight = (photoHeight * 4) + (gap * 3)
} else {
// 2x2: 2 คอลัมน์ 2 แถว
canvasWidth = (photoWidth * 2) + gap
canvasHeight = (photoHeight * 2) + gap
}
const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' })
const url = URL.createObjectURL(blob)
const a = document.createElement('a')
a.href = url
a.download = `photobooth-${Date.now()}.json`
document.body.appendChild(a)
a.click()
document.body.removeChild(a)
URL.revokeObjectURL(url)
canvas.width = canvasWidth
canvas.height = canvasHeight
// วาด background ตาม frame
drawFrameBackground(context, canvasWidth, canvasHeight, frame.value)
// วาดรูปภาพ
for (let i = 0; i < photos.value.length; i++) {
const img = new Image()
img.src = photos.value[i]
await new Promise((resolve) => {
img.onload = () => {
let x, y
if (layout.value === '1x4') {
// 1x4 layout
x = 0
y = i * (photoHeight + gap)
} else {
// 2x2 layout
const col = i % 2
const row = Math.floor(i / 2)
x = col * (photoWidth + gap)
y = row * (photoHeight + gap)
}
// วาดรูปภาพ
context.drawImage(img, x, y, photoWidth, photoHeight)
resolve(void 0)
}
})
}
// สร้าง PNG และ download
canvas.toBlob((blob) => {
if (blob) {
const url = URL.createObjectURL(blob)
const a = document.createElement('a')
a.href = url
a.download = `photobooth-${Date.now()}.png`
document.body.appendChild(a)
a.click()
document.body.removeChild(a)
URL.revokeObjectURL(url)
}
}, 'image/png')
}
const drawFrameBackground = (context: CanvasRenderingContext2D, width: number, height: number, frameType: number) => {
// วาด background ตาม frame type
switch (frameType) {
case 0: // Classic - white
context.fillStyle = '#ffffff'
break
case 1: // Modern - gradient
const gradient1 = context.createLinearGradient(0, 0, width, height)
gradient1.addColorStop(0, '#667eea')
gradient1.addColorStop(1, '#764ba2')
context.fillStyle = gradient1
break
case 2: // Vintage - gradient
const gradient2 = context.createLinearGradient(0, 0, width, height)
gradient2.addColorStop(0, '#f093fb')
gradient2.addColorStop(1, '#f5576c')
context.fillStyle = gradient2
break
case 3: // Colorful - gradient
const gradient3 = context.createLinearGradient(0, 0, width, height)
gradient3.addColorStop(0, '#4facfe')
gradient3.addColorStop(1, '#00f2fe')
context.fillStyle = gradient3
break
case 4: // Minimal - light gray
context.fillStyle = '#f8f9fa'
break
default:
context.fillStyle = '#ffffff'
}
context.fillRect(0, 0, width, height)
}
const shareImage = async () => {
@@ -223,7 +314,6 @@ const startOver = () => {
background: #f8f9fa;
border-radius: 8px;
padding: 12px;
aspect-ratio: 3/4;
}
.photo-cell {