diff options
Diffstat (limited to 'js/leibovitz/balance.js')
-rw-r--r-- | js/leibovitz/balance.js | 103 |
1 files changed, 103 insertions, 0 deletions
diff --git a/js/leibovitz/balance.js b/js/leibovitz/balance.js new file mode 100644 index 0000000..aeff62e --- /dev/null +++ b/js/leibovitz/balance.js @@ -0,0 +1,103 @@ +/** + * White balance management module implementing temperature-based color adjustment. + * + * Implements white balance adjustment using temperature-based RGB channel scaling. + * Provides non-linear temperature adjustment for natural color correction. + * + * Implements the following design patterns: + * - Observer Pattern: state management and effect application + * - Factory Pattern: UI initialization + * - Strategy Pattern: temperature adjustment algorithm + * - Command Pattern: state reset operations + * + * White balance adjustment process: + * 1. Convert temperature to ratio relative to neutral (6500K) + * 2. Apply non-linear scaling (0.2 factor) to red and blue channels + * 3. Warmer temps (<6500K) increase red, decrease blue + * 4. Cooler temps (>6500K) increase blue, decrease red + * + * Features: + * - Temperature-based color adjustment + * - Non-linear response curve + * - Preserves green channel + * - Real-time updates + */ + +const BalanceManager = { + // Private state + _observers: new Set(), + _slider: null, + _value: null, + + /** + * Initializes the balance manager and sets up UI controls + */ + init() { + this._slider = document.getElementById('balance-slider'); + this._value = document.getElementById('balance-value'); + this._setupEventListeners(); + }, + + _setupEventListeners() { + this._slider.addEventListener('input', () => { + const value = this._slider.value; + this._value.textContent = `${value}K`; + this._notifyObservers(); + }); + }, + + _notifyObservers() { + this._observers.forEach(observer => observer(this.getCurrentBalance())); + }, + + /** + * Subscribes to balance state changes + * @param {Function} observer - Callback function for state changes + * @returns {Function} Unsubscribe function + */ + subscribe(observer) { + this._observers.add(observer); + return () => this._observers.delete(observer); + }, + + /** + * Gets the current white balance temperature + * @returns {number} Current temperature in Kelvin (2000K-10000K) + */ + getCurrentBalance() { + return parseInt(this._slider.value); + }, + + /** + * Applies white balance adjustment to an image + * And implements temperature-based RGB channel scaling with non-linear response + * @param {ImageData} imageData - Source image data + * @returns {ImageData} White balanced image data + */ + 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; + }, + + /** + * Resets balance effect to default state + */ + reset() { + this._slider.value = 6500; + this._value.textContent = '6500K'; + this._notifyObservers(); + } +}; \ No newline at end of file |