From cbec55432d406942c7c505fd99a20dc40aeaac27 Mon Sep 17 00:00:00 2001 From: "mrkad@rpi" Date: Sun, 18 Jan 2026 00:52:50 +0700 Subject: [PATCH] feat: add film effect and date stamp to photos, update header and footer images --- public/assets/footer-1x4.png | Bin 15078 -> 8759 bytes public/assets/header-1x4.png | Bin 20035 -> 18374 bytes src/views/PrintStepView.vue | 2 +- src/views/ShootingView.vue | 114 ++++++++++++++++++++++ src/views/UploadView.vue | 178 +++++++++++++++++++++++++++++------ 5 files changed, 264 insertions(+), 30 deletions(-) diff --git a/public/assets/footer-1x4.png b/public/assets/footer-1x4.png index 910348981412dd9f47888dff34087603f8ad80bc..a116f7975dbc5f12c076e642b390a5e1d3cc3ed7 100644 GIT binary patch delta 5900 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 delta 12267 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 IkunSY4`t$K82|tP delta 17263 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 S?WCVF0D-5gpUXO@geCw?CeFwJ diff --git a/src/views/PrintStepView.vue b/src/views/PrintStepView.vue index ed1365b..3972614 100644 --- a/src/views/PrintStepView.vue +++ b/src/views/PrintStepView.vue @@ -40,7 +40,7 @@ const startCountdown = () => { // หลังจากแสดงผล 3 วินาที ให้ไปหน้า pickup setTimeout(() => { - router.push('/pickup') + // router.push('/pickup') }, 3000) } }, 1000) diff --git a/src/views/ShootingView.vue b/src/views/ShootingView.vue index f234215..757ed01 100644 --- a/src/views/ShootingView.vue +++ b/src/views/ShootingView.vue @@ -49,6 +49,116 @@ const stopCamera = () => { } } +const applyFilmEffect = (context: CanvasRenderingContext2D, width: number, height: number, volume: number = 5) => { + const imageData = context.getImageData(0, 0, width, height); + const data = imageData.data; + + // 1. แปลง Volume (1-10) เป็นค่าที่ใช้งานได้จริง + // contrast: ยิ่งเยอะ ภาพยิ่งคมเข้ม (แนะนำช่วง 0 ถึง 50) + const contrast = (volume / 10) * 50; + const contrastFactor = (259 * (contrast + 255)) / (255 * (259 - contrast)); + + // tint: ปรับโทนสี (Film มักจะอมแดง/เขียว ลดฟ้า) + const redBoost = volume * 2; // เพิ่มแดงนิดหน่อย + const greenBoost = volume * 1; // เพิ่มเขียวจางๆ + const blueCut = volume * 3; // ลดฟ้าลงเพื่อให้ภาพดูอุ่น (Warm tone) + + // grain: ความแรงของเม็ดเกรน + const grainStrength = volume * 1.5; + + for (let i = 0; i < data.length; i += 4) { + let r = data[i]; + let g = data[i + 1]; + let b = data[i + 2]; + + // --- STEP 1: Apply Contrast (ทำให้ภาพไม่แบน) --- + // สูตร Contrast มาตรฐาน + r = contrastFactor * (r - 128) + 128; + g = contrastFactor * (g - 128) + 128; + b = contrastFactor * (b - 128) + 128; + + // --- STEP 2: Color Grading (ปรับโทนฟิล์ม) --- + // ฟิล์ม Kodak/Fuji มักจะไม่ใช่ Sepia ล้วน แต่คือการจูน Channel + r += redBoost; + g += greenBoost; + b -= blueCut; + + // --- STEP 3: Add Grain (เม็ดเกรน) --- + // ใช้เทคนิคสุ่มทั้งบวกและลบ เพื่อไม่ให้ความสว่างรวมเพี้ยน + const grain = (Math.random() - 0.5) * grainStrength; + + // ผสมเกรนลงไป + r += grain; + g += grain; + b += grain; + + // --- STEP 4: Clamp values (กันค่าเกิน 0-255) --- + // ถ้าไม่กันค่า จะเกิดจุดสีประหลาดๆ เมื่อค่าทะลุ 255 หรือต่ำกว่า 0 + data[i] = Math.max(0, Math.min(255, r)); + data[i + 1] = Math.max(0, Math.min(255, g)); + data[i + 2] = Math.max(0, Math.min(255, b)); + } + + context.putImageData(imageData, 0, 0); + + // --- STEP 5: (Optional) Add Vignette (ขอบมืด) --- + // การวาด Gradient ทับ เร็วกว่าและเนียนกว่าการคำนวณทีละ pixel + if (volume > 2) { + addVignette(context, width, height, volume); + } +}; + +// ฟังก์ชันเสริมสำหรับทำขอบมืด (Vignette) +const addVignette = (ctx: CanvasRenderingContext2D, w: number, h: number, strength: number) => { + const opacity = (strength / 10) * 0.6; // สูงสุดที่ 0.6 opacity + const radius = Math.max(w, h) * 0.8; + + // สร้าง Gradient วงกลมจากตรงกลาง + const gradient = ctx.createRadialGradient(w/2, h/2, 0, w/2, h/2, radius); + gradient.addColorStop(0.5, "rgba(0,0,0,0)"); // ตรงกลางใส + gradient.addColorStop(1, `rgba(0,0,0,${opacity})`); // ขอบดำ + + ctx.globalCompositeOperation = 'source-over'; + ctx.fillStyle = gradient; + ctx.fillRect(0, 0, w, h); +}; + +const drawDateStamp = (context: CanvasRenderingContext2D, width: number, height: number) => { + const now = new Date(); + + // จัดรูปแบบวันที่แบบกล้องฟิล์ม (เช่น '98 1 25 หรือ 25 1 '98) + // ปีเอาแค่ 2 หลักท้าย + const year = now.getFullYear().toString().slice(-2); + const month = (now.getMonth() + 1).toString().padStart(2, '0'); // หรือจะใช้เลขเดียวแบบกล้องเก่าๆ ก็ได้ + const day = now.getDate().toString().padStart(2, '0'); + + const dateString = `'${year} ${month} ${day}`; // รูปแบบ: '24 01 18 + + // ตั้งค่า Font (Digital-like) + // แนะนำให้หา Font ชื่อ 'Digital-7' หรือ 'DS-Digital' มาลงจะเหมือนมาก + // แต่ถ้าไม่มี ใช้ Arial หรือ Courier New ก็พอไหวครับ + const fontSize = height * 0.05; // ขนาด 5% ของความสูงภาพ + context.font = `bold ${fontSize}px "Courier New", monospace`; + + // สีส้มอมแดง (Classic Date Stamp Color) + context.fillStyle = "#ff5e3a"; + + // เพิ่มเงาเรืองแสงนิดๆ ให้ดูเหมือนไฟ LED ที่ยิงลงฟิล์ม + context.shadowColor = "#ff0000"; + context.shadowBlur = 10; + + // ตำแหน่ง: มุมขวาล่าง + const paddingX = width * 0.05; + const paddingY = height * 0.03; + const x = width - context.measureText(dateString).width - paddingX; + const y = height - paddingY; + + context.fillText(dateString, x, y); + + // Reset shadow เพื่อไม่ให้กวนการวาดส่วนอื่น + context.shadowBlur = 0; +}; + const captureSinglePhoto = () => { if (!videoRef.value || !canvasRef.value || isCapturing.value) return @@ -95,6 +205,10 @@ const captureSinglePhoto = () => { 0, 0, finalWidth, finalHeight // ตำแหน่งและขนาดใน canvas ) + // Apply film effect with default volume + applyFilmEffect(context, finalWidth, finalHeight, 5); + drawDateStamp(context, finalWidth, finalHeight); + // แปลงเป็น base64 ด้วย quality 0.7 เพื่อลดขนาด const photoDataUrl = canvas.toDataURL('image/jpeg', 0.7) photos.value.push(photoDataUrl) diff --git a/src/views/UploadView.vue b/src/views/UploadView.vue index 2cb3969..8cbb601 100644 --- a/src/views/UploadView.vue +++ b/src/views/UploadView.vue @@ -8,59 +8,179 @@ const fileInputRef = ref() const totalPhotos = 4 +const applyFilmEffect = (context: CanvasRenderingContext2D, width: number, height: number, volume: number = 5) => { + const imageData = context.getImageData(0, 0, width, height); + const data = imageData.data; + + // 1. แปลง Volume (1-10) เป็นค่าที่ใช้งานได้จริง + // contrast: ยิ่งเยอะ ภาพยิ่งคมเข้ม (แนะนำช่วง 0 ถึง 50) + const contrast = (volume / 10) * 50; + const contrastFactor = (259 * (contrast + 255)) / (255 * (259 - contrast)); + + // tint: ปรับโทนสี (Film มักจะอมแดง/เขียว ลดฟ้า) + const redBoost = volume * 2; // เพิ่มแดงนิดหน่อย + const greenBoost = volume * 1; // เพิ่มเขียวจางๆ + const blueCut = volume * 3; // ลดฟ้าลงเพื่อให้ภาพดูอุ่น (Warm tone) + + // grain: ความแรงของเม็ดเกรน + const grainStrength = volume * 1.5; + + for (let i = 0; i < data.length; i += 4) { + let r = data[i]; + let g = data[i + 1]; + let b = data[i + 2]; + + // --- STEP 1: Apply Contrast (ทำให้ภาพไม่แบน) --- + // สูตร Contrast มาตรฐาน + r = contrastFactor * (r - 128) + 128; + g = contrastFactor * (g - 128) + 128; + b = contrastFactor * (b - 128) + 128; + + // --- STEP 2: Color Grading (ปรับโทนฟิล์ม) --- + // ฟิล์ม Kodak/Fuji มักจะไม่ใช่ Sepia ล้วน แต่คือการจูน Channel + r += redBoost; + g += greenBoost; + b -= blueCut; + + // --- STEP 3: Add Grain (เม็ดเกรน) --- + // ใช้เทคนิคสุ่มทั้งบวกและลบ เพื่อไม่ให้ความสว่างรวมเพี้ยน + const grain = (Math.random() - 0.5) * grainStrength; + + // ผสมเกรนลงไป + r += grain; + g += grain; + b += grain; + + // --- STEP 4: Clamp values (กันค่าเกิน 0-255) --- + // ถ้าไม่กันค่า จะเกิดจุดสีประหลาดๆ เมื่อค่าทะลุ 255 หรือต่ำกว่า 0 + data[i] = Math.max(0, Math.min(255, r)); + data[i + 1] = Math.max(0, Math.min(255, g)); + data[i + 2] = Math.max(0, Math.min(255, b)); + } + + context.putImageData(imageData, 0, 0); + + // --- STEP 5: (Optional) Add Vignette (ขอบมืด) --- + // การวาด Gradient ทับ เร็วกว่าและเนียนกว่าการคำนวณทีละ pixel + if (volume > 2) { + addVignette(context, width, height, volume); + } +}; + +// ฟังก์ชันเสริมสำหรับทำขอบมืด (Vignette) +const addVignette = (ctx: CanvasRenderingContext2D, w: number, h: number, strength: number) => { + const opacity = (strength / 10) * 0.6; // สูงสุดที่ 0.6 opacity + const radius = Math.max(w, h) * 0.8; + + // สร้าง Gradient วงกลมจากตรงกลาง + const gradient = ctx.createRadialGradient(w/2, h/2, 0, w/2, h/2, radius); + gradient.addColorStop(0.5, "rgba(0,0,0,0)"); // ตรงกลางใส + gradient.addColorStop(1, `rgba(0,0,0,${opacity})`); // ขอบดำ + + ctx.globalCompositeOperation = 'source-over'; + ctx.fillStyle = gradient; + ctx.fillRect(0, 0, w, h); +}; + +const drawDateStamp = (context: CanvasRenderingContext2D, width: number, height: number) => { + const now = new Date(); + + // จัดรูปแบบวันที่แบบกล้องฟิล์ม (เช่น '98 1 25 หรือ 25 1 '98) + // ปีเอาแค่ 2 หลักท้าย + const year = now.getFullYear().toString().slice(-2); + const month = (now.getMonth() + 1).toString().padStart(2, '0'); // หรือจะใช้เลขเดียวแบบกล้องเก่าๆ ก็ได้ + const day = now.getDate().toString().padStart(2, '0'); + + const dateString = `'${year} ${month} ${day}`; // รูปแบบ: '24 01 18 + + // ตั้งค่า Font (Digital-like) + // แนะนำให้หา Font ชื่อ 'Digital-7' หรือ 'DS-Digital' มาลงจะเหมือนมาก + // แต่ถ้าไม่มี ใช้ Arial หรือ Courier New ก็พอไหวครับ + const fontSize = height * 0.05; // ขนาด 5% ของความสูงภาพ + context.font = `bold ${fontSize}px "Courier New", monospace`; + + // สีส้มอมแดง (Classic Date Stamp Color) + context.fillStyle = "#ff5e3a"; + + // เพิ่มเงาเรืองแสงนิดๆ ให้ดูเหมือนไฟ LED ที่ยิงลงฟิล์ม + context.shadowColor = "#ff0000"; + context.shadowBlur = 10; + + // ตำแหน่ง: มุมขวาล่าง + const paddingX = width * 0.05; + const paddingY = height * 0.03; + const x = width - context.measureText(dateString).width - paddingX; + const y = height - paddingY; + + context.fillText(dateString, x, y); + + // Reset shadow เพื่อไม่ให้กวนการวาดส่วนอื่น + context.shadowBlur = 0; +}; + const cropImageTo34 = (imageSrc: string): Promise => { return new Promise((resolve) => { - const img = new Image() + const img = new Image(); img.onload = () => { - const canvas = document.createElement('canvas') - const context = canvas.getContext('2d') + const canvas = document.createElement('canvas'); + const context = canvas.getContext('2d'); if (!context) { - resolve(imageSrc) - return + resolve(imageSrc); + return; } - const imgWidth = img.width - const imgHeight = img.height + const imgWidth = img.width; + const imgHeight = img.height; // คำนวณขนาดสำหรับ 3:4 aspect ratio - const targetAspectRatio = 3/4 // width:height = 3:4 - let cropWidth, cropHeight, cropX, cropY + const targetAspectRatio = 3 / 4; // width:height = 3:4 + let cropWidth, cropHeight, cropX, cropY; if (imgWidth / imgHeight > targetAspectRatio) { // ภาพกว้างกว่าที่ต้องการ - ครอบด้านข้าง - cropHeight = imgHeight - cropWidth = imgHeight * targetAspectRatio - cropX = (imgWidth - cropWidth) / 2 - cropY = 0 + cropHeight = imgHeight; + cropWidth = imgHeight * targetAspectRatio; + cropX = (imgWidth - cropWidth) / 2; + cropY = 0; } else { // ภาพสูงกว่าที่ต้องการ - ครอบด้านบน/ล่าง - cropWidth = imgWidth - cropHeight = imgWidth / targetAspectRatio - cropX = 0 - cropY = (imgHeight - cropHeight) / 2 + cropWidth = imgWidth; + cropHeight = imgWidth / targetAspectRatio; + cropX = 0; + cropY = (imgHeight - cropHeight) / 2; } // ตั้งค่าขนาด canvas เป็น 3:4 (360x480) - ลดขนาดเพื่อป้องกัน localStorage quota exceeded - const finalWidth = 360 - const finalHeight = 480 + const finalWidth = 360; + const finalHeight = 480; - canvas.width = finalWidth - canvas.height = finalHeight + canvas.width = finalWidth; + canvas.height = finalHeight; // วาดภาพที่ครอบแล้วไปยัง canvas context.drawImage( img, - cropX, cropY, cropWidth, cropHeight, // ตำแหน่งและขนาดที่ครอบจากภาพต้นฉบับ - 0, 0, finalWidth, finalHeight // ตำแหน่งและขนาดใน canvas - ) + cropX, + cropY, + cropWidth, + cropHeight, // ตำแหน่งและขนาดที่ครอบจากภาพต้นฉบับ + 0, + 0, + finalWidth, + finalHeight // ตำแหน่งและขนาดใน canvas + ); + + // Apply film effect with adjustable volume + applyFilmEffect(context, finalWidth, finalHeight, 7); // Default volume = 5 + drawDateStamp(context, finalWidth, finalHeight); // แปลงเป็น base64 ด้วย quality 0.7 เพื่อลดขนาด - const croppedDataUrl = canvas.toDataURL('image/jpeg', 0.7) - resolve(croppedDataUrl) - } - img.src = imageSrc - }) + const croppedDataUrl = canvas.toDataURL('image/jpeg', 0.7); + resolve(croppedDataUrl); + }; + img.src = imageSrc; + }); } const triggerFileInput = () => {