Download script.js from herbertrt/rawtastic-image-wizardry: direct link, hf CLI and curl.
- Browser
- Download file 7.03 kB
-
https://huggingface.co/spaces/herbertrt/rawtastic-image-wizardry/resolve/main/script.js
- Command line
-
hf download hf://spaces/herbertrt/rawtastic-image-wizardry/script.js
-
curl -L -o script.js https://huggingface.co/spaces/herbertrt/rawtastic-image-wizardry/resolve/main/script.js
7.03 kB
| // 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); |