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