diff options
author | elioat <elioat@tilde.institute> | 2024-08-14 22:24:17 -0400 |
---|---|---|
committer | elioat <elioat@tilde.institute> | 2024-08-14 22:24:17 -0400 |
commit | 91851865712e188650ea11a046c8de2c22674548 (patch) | |
tree | edbc32992d5561a1851848e3fe829125ddf32a1a /js/lut-cam | |
parent | 391793456f87ccba1a8e1775e1695ced9594ae33 (diff) | |
download | tour-91851865712e188650ea11a046c8de2c22674548.tar.gz |
*
Diffstat (limited to 'js/lut-cam')
-rw-r--r-- | js/lut-cam/index.html | 74 | ||||
-rw-r--r-- | js/lut-cam/lut.js | 128 |
2 files changed, 202 insertions, 0 deletions
diff --git a/js/lut-cam/index.html b/js/lut-cam/index.html new file mode 100644 index 0000000..f31c465 --- /dev/null +++ b/js/lut-cam/index.html @@ -0,0 +1,74 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <title>LUT Cam</title> + <style> + body, html { + margin: 0; + padding: 0; + width: 100%; + height: 100%; + display: flex; + justify-content: center; + align-items: center; + background-color: #000; + } + #canvas { + width: 100%; + height: 100%; + object-fit: cover; + display: none; + } + #controls { + position: absolute; + bottom: 10px; + width: 100%; + display: flex; + justify-content: center; + align-items: center; + gap: 10px; + } + #lut-container { + position: absolute; + top: 10px; + right: 10px; + } + button, select { + padding: 10px; + font-size: 18px; + cursor: pointer; + } + </style> +</head> +<body> + +<canvas id="canvas"></canvas> + +<div id="lut-container"> + <select id="lut-select" disabled> + <option value="none">None</option> + <option value="lut1">Inverted</option> + <option value="lut2">Enhanced</option> + <option value="lut3">Subtle Cool Tone</option> + <option value="lut4">Subtle Warm Tone</option> + <option value="lut5">Subtle Green Tone</option> + <option value="lut6">Subtle Yellow Tone</option> + <option value="lut7">Desaturated</option> + <option value="lut8">Saturated</option> + <option value="lut9">Warm Tint</option> + <option value="lut10">Cool Tint</option> + <option value="lut11">Greyscale</option> + <option value="lut12">Sepia</option> + </select> +</div> + +<div id="controls"> + <button id="toggle-camera">Turn Camera On</button> + <button id="capture" disabled>Capture Frame</button> +</div> + +<script src="lut.js"></script> +</body> +</html> diff --git a/js/lut-cam/lut.js b/js/lut-cam/lut.js new file mode 100644 index 0000000..6466f32 --- /dev/null +++ b/js/lut-cam/lut.js @@ -0,0 +1,128 @@ +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], // Inverted Colors + 'lut2': (r, g, b) => [r * 1.2, g * 0.8, b * 1.5], // Enhanced Colors + 'lut3': (r, g, b) => [r * 0.9, g * 0.9, b * 1.1], // Subtle Cool Tone + 'lut4': (r, g, b) => [r * 1.1, g * 0.9, b * 0.9], // Subtle Warm Tone + 'lut5': (r, g, b) => [r * 0.9, g * 1.1, b * 0.9], // Subtle Green Tone + 'lut6': (r, g, b) => [r * 1.1, g * 1.1, b * 0.9], // Subtle Yellow Tone + 'lut7': (r, g, b) => [r * 0.9, g * 0.9, b * 0.9], // Desaturated + 'lut8': (r, g, b) => [r * 1.1, g * 1.1, b * 1.1], // Saturated + 'lut9': (r, g, b) => [r * 0.9, g * 1.1, b * 1.1], // Warm Tint + 'lut10': (r, g, b) => [r * 1.1, g * 0.9, b * 0.9], // Cool Tint + 'lut11': (r, g, b) => { const avg = (r + g + b) / 3; return [avg, avg, avg]; }, // Greyscale + 'lut12': (r, g, b) => { const avg = (r + g + b) / 3; return [avg * 1.1, avg * 0.9, avg * 0.9]; } // Sepia +}; + +let currentLUT = 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; + + // Display the video feed on the canvas + video.addEventListener('play', function() { + function step() { + if (!cameraOn) return; // Don't show the video feed if there isn't a video feed to show + 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'; + lutSelect.disabled = true; + captureButton.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(); +}); |