File size: 7,026 Bytes
e8c53c6 572627b e8c53c6 68df552 e8c53c6 32073c4 e8c53c6 68df552 e8c53c6 32073c4 572627b 32073c4 68df552 32073c4 68df552 32073c4 68df552 32073c4 572627b 32073c4 e8c53c6 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 |
// 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(
`<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;
// 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); |