const canvas = document.getElementById('canvas'); const ctx = canvas.getContext('2d'); const video = document.createElement('video'); const toggleCameraButton = document.getElementById('toggle-camera'); const lutSelect = document.getElementById('lut-select'); const captureButton = document.getElementById('capture'); let cameraOn = false; let stream = null; // Set the canvas dimensions to match the window size canvas.width = window.innerWidth; canvas.height = window.innerHeight; const LUTs = { 'none': null, 'lut1': (r, g, b) => [255 - r, 255 - g, 255 - b], 'lut2': (r, g, b) => [r * 1.2, g * 0.8, b * 1.5], 'lut3': (r, g, b) => [r * 0.9, g * 0.9, b * 1.1], 'lut4': (r, g, b) => [r * 1.1, g * 0.9, b * 0.9], 'lut5': (r, g, b) => [r * 0.9, g * 1.1, b * 0.9], 'lut6': (r, g, b) => [r * 1.1, g * 1.1, b * 0.9], 'lut7': (r, g, b) => [r * 0.9, g * 0.9, b * 0.9], 'lut8': (r, g, b) => [r * 1.1, g * 1.1, b * 1.1], 'lut9': (r, g, b) => [r * 0.9, g * 1.1, b * 1.1], 'lut10': (r, g, b) => [r * 1.1, g * 0.9, b * 0.9], 'lut11': (r, g, b) => { const avg = (r + g + b) / 3; return [avg, avg, avg]; }, 'lut12': (r, g, b) => { const avg = (r + g + b) / 3; return [avg * 1.1, avg * 0.9, avg * 0.9]; }, 'lut13': (r, g, b) => [r * 1.5, g * 1.5, b * 1.5] }; let currentLUT = null; 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 lutSelect.disabled = false; captureButton.disabled = false; captureButton.active = true; focusSlider.disabled = false; track = stream.getVideoTracks()[0]; const settings = track.getSettings(); // So, I don't seem to have a device where this is supported // Check if focus control is supported with this browser and device combo if ('focusDistance' in settings) { // If it is available, enable the slider for focus control focusSlider.style.display = 'block'; // Set initial focus value, and a fallback 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(); applyLUT(); 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 lutSelect.disabled = true; captureButton.disabled = true; captureButton.active = false; focusSlider.disabled = true; stream = null; } } function drawVideoProportional() { const videoAspectRatio = video.videoWidth / video.videoHeight; const canvasAspectRatio = canvas.width / canvas.height; let drawWidth, drawHeight; if (canvasAspectRatio > videoAspectRatio) { drawHeight = canvas.height; drawWidth = videoAspectRatio * drawHeight; } else { drawWidth = canvas.width; drawHeight = drawWidth / videoAspectRatio; } const offsetX = (canvas.width - drawWidth) / 2; const offsetY = (canvas.height - drawHeight) / 2; ctx.clearRect(0, 0, canvas.width, canvas.height); // Clear the canvas ctx.drawImage(video, offsetX, offsetY, drawWidth, drawHeight); // Draw the video normally } function applyLUT() { if (!currentLUT) return; const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height); const data = imageData.data; for (let i = 0; i < data.length; i += 4) { const [r, g, b] = currentLUT(data[i], data[i + 1], data[i + 2]); data[i] = r; data[i + 1] = g; data[i + 2] = b; } ctx.putImageData(imageData, 0, 0); } toggleCameraButton.addEventListener('click', () => { cameraOn = !cameraOn; if (cameraOn) { startCamera(); toggleCameraButton.textContent = 'Turn Camera Off'; } else { stopCamera(); toggleCameraButton.textContent = 'Turn Camera On'; } }); lutSelect.addEventListener('change', () => { const selectedLUT = lutSelect.value; currentLUT = LUTs[selectedLUT]; }); captureButton.addEventListener('click', () => { const link = document.createElement('a'); link.download = 'captured-image.png'; link.href = canvas.toDataURL('image/png'); link.click(); }); 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); }); }); }