// Global state for the application const appState = { currentImage: null, adjustments: { exposure: 0, contrast: 0, highlights: 0, shadows: 0, temperature: 0, tint: 0, vibrance: 0, saturation: 0, sharpening: 25, noiseReduction: 0 }, history: [], historyIndex: -1 }; // Initialize the application function init() { // Set up event listeners for all sliders document.querySelectorAll('input[type="range"]').forEach(slider => { slider.addEventListener('input', function() { const adjustmentName = this.previousElementSibling.textContent.trim().toLowerCase(); appState.adjustments[adjustmentName] = parseFloat(this.value); applyAdjustments(); }); }); // Set up drag and drop for image upload const imagePreview = document.getElementById('image-preview'); imagePreview.addEventListener('dragover', (e) => { e.preventDefault(); imagePreview.classList.add('border-2', 'border-blue-500'); }); imagePreview.addEventListener('dragleave', () => { imagePreview.classList.remove('border-2', 'border-blue-500'); }); imagePreview.addEventListener('drop', (e) => { e.preventDefault(); imagePreview.classList.remove('border-2', 'border-blue-500'); const file = e.dataTransfer.files[0]; if (file && file.type.match('image.*')) { loadImage(file); } }); // Click to upload imagePreview.addEventListener('click', () => { const input = document.createElement('input'); input.type = 'file'; input.accept = 'image/*'; input.onchange = (e) => { const file = e.target.files[0]; if (file) loadImage(file); }; input.click(); }); } // Load image from file function loadImage(file) { // Check if it's a RAW file const rawExtensions = [ '.cr2', '.nef', '.arw', '.dng', '.raf', '.rw2', '.cr3', '.orf', '.pef', '.srf', '.sr2', '.3fr', '.ari', '.bay', '.cap', '.dcs', '.dcr', '.drf', '.eip', '.erf', '.fff', '.iiq', '.k25', '.kdc', '.mdc', '.mef', '.mos', '.mrw', '.nrw', '.obm', '.ptx', '.pxn', '.r3d', '.raw', '.rwl', '.rwz', '.srw', '.x3f' ]; const isRaw = rawExtensions.some(ext => file.name.toLowerCase().endsWith(ext)); if (isRaw) { processRawImage(file); } else { // Regular image processing const reader = new FileReader(); reader.onload = (e) => { appState.currentImage = e.target.result; document.getElementById('image-preview').src = appState.currentImage; resetAdjustments(); }; reader.readAsDataURL(file); } } // Process RAW image (simulated since browsers can't process RAW files directly) function processRawImage(file) { const loader = document.getElementById('raw-loader'); const progressBar = document.getElementById('raw-progress'); const imagePreview = document.getElementById('image-preview'); // Create a temporary image to show the file is being processed const tempImg = new Image(); tempImg.src = 'data:image/svg+xml;base64,' + btoa( ` Processing RAW File... ` ); imagePreview.src = tempImg.src; // Show loading UI loader.classList.remove('hidden'); progressBar.style.width = '0%'; // Simulate RAW processing with progress let progress = 0; const interval = setInterval(() => { progress += 5; progressBar.style.width = `${progress}%`; if (progress >= 100) { clearInterval(interval); // Create object URL for the RAW file (in reality, you'd process it properly) const objectUrl = URL.createObjectURL(file); // Create a canvas to render a preview since browsers can't display RAW files directly const canvas = document.createElement('canvas'); const ctx = canvas.getContext('2d'); canvas.width = 1200; canvas.height = 800; // Fill with a placeholder color (simulating RAW processing) ctx.fillStyle = '#374151'; ctx.fillRect(0, 0, canvas.width, canvas.height); // Add text indicating this is a RAW file ctx.fillStyle = '#ffffff'; ctx.font = '24px Arial'; ctx.textAlign = 'center'; ctx.fillText('RAW File Processed', canvas.width/2, canvas.height/2 - 20); ctx.font = '16px Arial'; ctx.fillText(file.name, canvas.width/2, canvas.height/2 + 20); // Convert canvas to data URL and set as image source const processedUrl = canvas.toDataURL('image/jpeg'); imagePreview.src = processedUrl; appState.currentImage = processedUrl; resetAdjustments(); // Hide loader loader.classList.add('hidden'); } }, 100); // Fallback in case something goes wrong setTimeout(() => { if (!loader.classList.contains('hidden')) { clearInterval(interval); loader.classList.add('hidden'); alert('Unable to process RAW file. Please try a different file format.'); } }, 5000); } // Reset all adjustments to default function resetAdjustments() { Object.keys(appState.adjustments).forEach(key => { appState.adjustments[key] = key === 'sharpening' ? 25 : 0; }); // Reset sliders document.querySelectorAll('input[type="range"]').forEach(slider => { const adjustmentName = slider.previousElementSibling.textContent.trim().toLowerCase(); slider.value = appState.adjustments[adjustmentName]; }); } // Apply all adjustments to the image function applyAdjustments() { // In a real app, this would use WebGL or Canvas to apply the adjustments // For this demo, we'll just update the image with CSS filters const image = document.getElementById('image-preview'); const adj = appState.adjustments; let filter = ''; filter += `brightness(${1 + adj.exposure * 0.2}) `; filter += `contrast(${1 + adj.contrast * 0.01}) `; filter += `saturate(${1 + adj.saturation * 0.01}) `; // Temperature and tint would be more complex in a real app // This is a simplified approximation if (adj.temperature > 0) { filter += `sepia(${adj.temperature * 0.3}%) `; } image.style.filter = filter.trim(); } // Initialize the app when the DOM is loaded document.addEventListener('DOMContentLoaded', init);