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);
});
});
}