| | |
| | 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 |
| | }; |
| |
|
| | |
| | function init() { |
| | |
| | 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(); |
| | }); |
| | }); |
| |
|
| | |
| | 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); |
| | } |
| | }); |
| | |
| | |
| | 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(); |
| | }); |
| | } |
| | |
| | function loadImage(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 { |
| | |
| | const reader = new FileReader(); |
| | reader.onload = (e) => { |
| | appState.currentImage = e.target.result; |
| | document.getElementById('image-preview').src = appState.currentImage; |
| | resetAdjustments(); |
| | }; |
| | reader.readAsDataURL(file); |
| | } |
| | } |
| | |
| | function processRawImage(file) { |
| | const loader = document.getElementById('raw-loader'); |
| | const progressBar = document.getElementById('raw-progress'); |
| | const imagePreview = document.getElementById('image-preview'); |
| | |
| | |
| | const tempImg = new Image(); |
| | tempImg.src = 'data:image/svg+xml;base64,' + btoa( |
| | `<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="800" viewBox="0 0 1200 800"> |
| | <rect width="100%" height="100%" fill="#374151"/> |
| | <text x="50%" y="50%" fill="white" font-family="Arial" font-size="24" text-anchor="middle" dominant-baseline="middle"> |
| | Processing RAW File... |
| | </text> |
| | </svg>` |
| | ); |
| | imagePreview.src = tempImg.src; |
| | |
| | loader.classList.remove('hidden'); |
| | progressBar.style.width = '0%'; |
| | |
| | |
| | let progress = 0; |
| | const interval = setInterval(() => { |
| | progress += 5; |
| | progressBar.style.width = `${progress}%`; |
| | |
| | if (progress >= 100) { |
| | clearInterval(interval); |
| | |
| | |
| | const objectUrl = URL.createObjectURL(file); |
| | |
| | const canvas = document.createElement('canvas'); |
| | const ctx = canvas.getContext('2d'); |
| | canvas.width = 1200; |
| | canvas.height = 800; |
| | |
| | |
| | ctx.fillStyle = '#374151'; |
| | ctx.fillRect(0, 0, canvas.width, canvas.height); |
| | |
| | |
| | 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); |
| | |
| | |
| | const processedUrl = canvas.toDataURL('image/jpeg'); |
| | imagePreview.src = processedUrl; |
| | appState.currentImage = processedUrl; |
| | resetAdjustments(); |
| | |
| | |
| | loader.classList.add('hidden'); |
| | } |
| | }, 100); |
| | |
| | |
| | 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); |
| | } |
| | |
| | function resetAdjustments() { |
| | Object.keys(appState.adjustments).forEach(key => { |
| | appState.adjustments[key] = key === 'sharpening' ? 25 : 0; |
| | }); |
| | |
| | document.querySelectorAll('input[type="range"]').forEach(slider => { |
| | const adjustmentName = slider.previousElementSibling.textContent.trim().toLowerCase(); |
| | slider.value = appState.adjustments[adjustmentName]; |
| | }); |
| | } |
| | |
| | function applyAdjustments() { |
| | |
| | |
| | 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}) `; |
| | |
| | |
| | |
| | if (adj.temperature > 0) { |
| | filter += `sepia(${adj.temperature * 0.3}%) `; |
| | } |
| | |
| | image.style.filter = filter.trim(); |
| | } |
| |
|
| | |
| | document.addEventListener('DOMContentLoaded', init); |