about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorelioat <elioat@tilde.institute>2025-03-30 09:31:14 -0400
committerelioat <elioat@tilde.institute>2025-03-30 09:31:14 -0400
commitc169f89e17f4a241ac128c236876d244ba392d4e (patch)
treeaa666f654ea75552761bba01a6760e0e5bd894fd
parent172a0d1b2a817ce75c1d9d1572b3cc8eee5d9f26 (diff)
downloadtour-c169f89e17f4a241ac128c236876d244ba392d4e.tar.gz
*
-rw-r--r--js/leibovitz/balance.js37
-rw-r--r--js/leibovitz/color.js10
-rw-r--r--js/leibovitz/index.html14
-rw-r--r--js/leibovitz/leibovitz.js27
4 files changed, 77 insertions, 11 deletions
diff --git a/js/leibovitz/balance.js b/js/leibovitz/balance.js
new file mode 100644
index 0000000..6566176
--- /dev/null
+++ b/js/leibovitz/balance.js
@@ -0,0 +1,37 @@
+// BalanceManager handles white balance adjustments
+class BalanceManager {
+    static init() {
+        this.balanceSlider = document.getElementById('balance-slider');
+        this.balanceValue = document.getElementById('balance-value');
+        this._setupEventListeners();
+    }
+
+    static _setupEventListeners() {
+        this.balanceSlider.addEventListener('input', () => {
+            const value = this.balanceSlider.value;
+            this.balanceValue.textContent = `${value}K`;
+        });
+    }
+
+    static getCurrentBalance() {
+        return parseInt(this.balanceSlider.value);
+    }
+
+    static applyBalance(imageData) {
+        const balance = this.getCurrentBalance();
+        if (!balance || balance === 6500) return imageData; // 6500K is neutral
+
+        const data = imageData.data;
+        const temperature = balance / 6500; // Convert to temperature ratio
+
+        for (let i = 0; i < data.length; i += 4) {
+            // Adjust red and blue channels based on temperature
+            // Warmer (lower K) increases red, decreases blue
+            // Cooler (higher K) increases blue, decreases red
+            data[i] = Math.min(255, data[i] * (1 + (temperature - 1) * 0.2));     // Red
+            data[i + 2] = Math.min(255, data[i + 2] * (1 + (1 - temperature) * 0.2)); // Blue
+        }
+
+        return imageData;
+    }
+} 
\ No newline at end of file
diff --git a/js/leibovitz/color.js b/js/leibovitz/color.js
index 136638f..4319a21 100644
--- a/js/leibovitz/color.js
+++ b/js/leibovitz/color.js
@@ -24,7 +24,7 @@ const ColorManager = {
         resetButton.addEventListener('click', () => {
             // Reset color tint
             this._currentColor = null;
-            this._colorInput.value = '#000000';
+            this._colorInput.value = '#ffffff';
             this._notifyObservers();
 
             // Reset contrast
@@ -32,6 +32,14 @@ const ColorManager = {
 
             // Reset blur
             BlurManager.reset();
+
+            // Reset white balance to default (6500K)
+            const balanceSlider = document.getElementById('balance-slider');
+            const balanceValue = document.getElementById('balance-value');
+            if (balanceSlider && balanceValue) {
+                balanceSlider.value = 6500;
+                balanceValue.textContent = '6500K';
+            }
         });
     },
 
diff --git a/js/leibovitz/index.html b/js/leibovitz/index.html
index 451ef9f..c8eb9af 100644
--- a/js/leibovitz/index.html
+++ b/js/leibovitz/index.html
@@ -376,6 +376,16 @@
             <input type="range" id="contrast-slider" min="-255" max="255" value="0" step="1">
             <span class="value" id="contrast-value">0</span>
         </div>
+        <div class="slider-group">
+            <label for="balance-slider">White Balance</label>
+            <input type="range" id="balance-slider" min="2000" max="10000" value="6500" step="100">
+            <span class="value" id="balance-value">6500K</span>
+        </div>
+        <div class="slider-group" id="focus-control" style="display: none;">
+            <label for="focus-slider">Focus</label>
+            <input type="range" id="focus-slider" min="0" max="100" step="1" value="50" disabled>
+            <span class="value" id="focus-value">50%</span>
+        </div>
         <div class="slider-group" id="pixel-size-control" style="display: none;">
             <label for="block-size-slider">Pixel Size</label>
             <input type="range" id="block-size-slider" min="1" max="12" value="4" step="1">
@@ -401,9 +411,6 @@
 </div>
 
 <div id="controls">
-    <div id="focus-container">
-        <input style="display: none;" type="range" id="focus-slider" min="0" max="100" step="1" value="50" disabled>
-    </div>
     <button id="toggle-camera">Camera On</button>
     <button id="capture" disabled class="capture">Capture Image</button>
 </div>
@@ -412,6 +419,7 @@
 <script src="contrast.js"></script>
 <script src="color.js"></script>
 <script src="blur.js"></script>
+<script src="balance.js"></script>
 <script src="leibovitz.js"></script>
 </body>
 </html>
diff --git a/js/leibovitz/leibovitz.js b/js/leibovitz/leibovitz.js
index 2f828c2..3b43d86 100644
--- a/js/leibovitz/leibovitz.js
+++ b/js/leibovitz/leibovitz.js
@@ -3,15 +3,20 @@ const ctx = canvas.getContext('2d');
 const video = document.createElement('video');
 const toggleCameraButton = document.getElementById('toggle-camera');
 const captureButton = document.getElementById('capture');
+const focusControl = document.getElementById('focus-control');
+const focusSlider = document.getElementById('focus-slider');
+const focusValue = document.getElementById('focus-value');
 
 let cameraOn = false;
 let stream = null;
+let track = null;
 
 // Initialize managers
 ColorManager.init();
 DitherManager.init();
 ContrastManager.init();
 BlurManager.init();
+BalanceManager.init();
 
 // Set the canvas dimensions to match the window size
 function updateCanvasSize() {
@@ -48,9 +53,6 @@ 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 => {
@@ -60,24 +62,27 @@ function startCamera() {
             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';
+                focusControl.style.display = 'flex';
+                focusSlider.disabled = false;
                 focusSlider.value = settings.focusDistance || focusSlider.min;
+                focusValue.textContent = `${focusSlider.value}%`;
 
                 focusSlider.addEventListener('input', () => {
+                    const value = focusSlider.value;
+                    focusValue.textContent = `${value}%`;
                     track.applyConstraints({
-                        advanced: [{ focusDistance: focusSlider.value }]
+                        advanced: [{ focusDistance: value }]
                     });
                 });
             } else {
                 console.warn('Focus control is not supported on this device.');
-                focusSlider.style.display = 'none';
+                focusControl.style.display = 'none';
             }
 
             // Draw the video feed to the canvas
@@ -88,6 +93,7 @@ function startCamera() {
                     applyContrast();
                     applyColorTint();
                     applyBlur();
+                    applyBalance();
                     applyDither();
                     requestAnimationFrame(step);
                 }
@@ -107,6 +113,7 @@ function stopCamera() {
         captureButton.disabled = true;
         captureButton.active = false;
         focusSlider.disabled = true;
+        focusControl.style.display = 'none';
         stream = null;
     }
 }
@@ -141,6 +148,12 @@ function applyColorTint() {
     ctx.putImageData(tintedImageData, 0, 0);
 }
 
+function applyBalance() {
+    const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
+    const balancedImageData = BalanceManager.applyBalance(imageData);
+    ctx.putImageData(balancedImageData, 0, 0);
+}
+
 function applyContrast() {
     const currentContrast = ContrastManager.getCurrentContrast();
     if (!currentContrast || currentContrast === 1.0) return;