const canvas = document.getElementById('canvas'); const ctx = canvas.getContext('2d'); const video = document.createElement('video'); const toggleCameraButton = document.getElementById('toggle-camera'); const captureButton = document.getElementById('capture'); let cameraOn = false; let stream = null; // Initialize managers ColorManager.init(); DitherManager.init(); ContrastManager.init(); BlurManager.init(); // Set the canvas dimensions to match the window size function updateCanvasSize() { const containerWidth = window.innerWidth * 0.7; // 70% of viewport width // If video is playing, use its aspect ratio if (video.videoWidth && video.videoHeight) { const videoAspect = video.videoWidth / video.videoHeight; canvas.width = containerWidth; canvas.height = containerWidth / videoAspect; } else { // Default to container width and 4:3 aspect ratio until video starts canvas.width = containerWidth; canvas.height = containerWidth * (3/4); } } // Update canvas size when window is resized window.addEventListener('resize', updateCanvasSize); // Initialize canvas size updateCanvasSize(); const focusSlider = document.getElementById('focus-slider'); let track = null; function startCamera() { navigator.mediaDevices.getUserMedia({ video: { facingMode: { ideal: 'environment' } } }) .then(s => { stream = s; video.srcObject = stream; video.play(); canvas.style.display = 'block'; // Show the canvas captureButton.disabled = false; captureButton.active = true; focusSlider.disabled = false; track = stream.getVideoTracks()[0]; const settings = track.getSettings(); // Check if focus control is supported with this browser and device combo if ('focusDistance' in settings) { focusSlider.style.display = 'block'; focusSlider.value = settings.focusDistance || focusSlider.min; focusSlider.addEventListener('input', () => { track.applyConstraints({ advanced: [{ focusDistance: focusSlider.value }] }); }); } else { console.warn('Focus control is not supported on this device.'); focusSlider.style.display = 'none'; } // Draw the video feed to the canvas video.addEventListener('play', function() { function step() { if (!cameraOn) return; drawVideoProportional(); applyContrast(); applyColorTint(); applyBlur(); applyDither(); requestAnimationFrame(step); } requestAnimationFrame(step); }); }) .catch(err => { console.error('Error accessing camera: ', err); }); } function stopCamera() { if (stream) { stream.getTracks().forEach(track => track.stop()); video.pause(); canvas.style.display = 'none'; // hide the canvas captureButton.disabled = true; captureButton.active = false; focusSlider.disabled = true; stream = null; } } function drawVideoProportional() { // Clear the entire canvas ctx.fillStyle = '#000'; ctx.fillRect(0, 0, canvas.width, canvas.height); // Draw the video content ctx.drawImage(video, 0, 0, canvas.width, canvas.height); } function applyColorTint() { const currentColor = ColorManager.getCurrentColor(); if (!currentColor) return; const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height); const tintedImageData = ColorManager.applyTint(imageData, currentColor); ctx.putImageData(tintedImageData, 0, 0); } function applyContrast() { const currentContrast = ContrastManager.getCurrentContrast(); if (!currentContrast || currentContrast === 1.0) return; const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height); const contrastedImageData = ContrastManager.applyContrast(imageData, currentContrast); ctx.putImageData(contrastedImageData, 0, 0); } function applyDither() { const currentMode = DitherManager.getCurrentMode(); if (!currentMode || currentMode === 'none') return; const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height); const ditheredImageData = DitherManager.applyDither(imageData, currentMode); ctx.putImageData(ditheredImageData, 0, 0); } function applyBlur() { const currentBlur = BlurManager.getCurrentBlur(); if (!currentBlur) return; const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height); const blurredImageData = BlurManager.applyBlur(imageData, currentBlur); ctx.putImageData(blurredImageData, 0, 0); } captureButton.addEventListener('click', () => { const currentColor = ColorManager.getCurrentColor(); const borderWidth = 4; // Create a canvas with extra space for the border const captureCanvas = document.createElement('canvas'); const captureCtx = captureCanvas.getContext('2d'); // Set dimensions including border captureCanvas.width = canvas.width + (borderWidth * 2); captureCanvas.height = canvas.height + (borderWidth * 2); // Fill with border color if a tint is selected if (currentColor) { captureCtx.fillStyle = currentColor; captureCtx.fillRect(0, 0, captureCanvas.width, captureCanvas.height); } // Draw the main canvas content captureCtx.drawImage(canvas, borderWidth, borderWidth); const link = document.createElement('a'); link.download = 'captured-image.png'; link.href = captureCanvas.toDataURL('image/png'); link.click(); }); toggleCameraButton.addEventListener('click', () => { cameraOn = !cameraOn; if (cameraOn) { startCamera(); toggleCameraButton.textContent = 'Turn Camera Off'; } else { stopCamera(); toggleCameraButton.textContent = 'Turn Camera On'; } }); if ('serviceWorker' in navigator) { window.addEventListener('load', () => { navigator.serviceWorker.register('/service-worker.js') .then(registration => { console.log('ServiceWorker registration successful with scope: ', registration.scope); }, err => { console.log('ServiceWorker registration failed: ', err); }); }); } ColorManager._setupEventListeners();