Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Photo Visual Enhancer Pro</title> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> | |
| <style> | |
| :root { | |
| --primary-color: #4361ee; | |
| --secondary-color: #3a0ca3; | |
| --accent-color: #f72585; | |
| --light-color: #f8f9fa; | |
| --dark-color: #212529; | |
| --success-color: #2ecc71; | |
| } | |
| * { | |
| margin: 0; | |
| padding: 0; | |
| box-sizing: border-box; | |
| font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; | |
| } | |
| body { | |
| background-color: #f0f2f5; | |
| color: var(--dark-color); | |
| line-height: 1.6; | |
| } | |
| .container { | |
| max-width: 1200px; | |
| margin: 0 auto; | |
| padding: 20px; | |
| } | |
| header { | |
| text-align: center; | |
| margin-bottom: 30px; | |
| padding: 20px 0; | |
| background: linear-gradient(135deg, var(--primary-color), var(--secondary-color)); | |
| color: white; | |
| border-radius: 10px; | |
| box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1); | |
| } | |
| h1 { | |
| font-size: 2.5rem; | |
| margin-bottom: 10px; | |
| } | |
| .description { | |
| font-size: 1.1rem; | |
| opacity: 0.9; | |
| } | |
| .app-container { | |
| display: flex; | |
| flex-wrap: wrap; | |
| gap: 20px; | |
| } | |
| .image-section { | |
| flex: 3; | |
| min-width: 300px; | |
| background-color: white; | |
| border-radius: 10px; | |
| padding: 20px; | |
| box-shadow: 0 4px 10px rgba(0, 0, 0, 0.08); | |
| } | |
| .controls-section { | |
| flex: 2; | |
| min-width: 300px; | |
| background-color: white; | |
| border-radius: 10px; | |
| padding: 20px; | |
| box-shadow: 0 4px 10px rgba(0, 0, 0, 0.08); | |
| } | |
| .image-container { | |
| width: 100%; | |
| aspect-ratio: 1; | |
| margin-bottom: 20px; | |
| position: relative; | |
| border: 2px dashed #ddd; | |
| border-radius: 8px; | |
| overflow: hidden; | |
| display: flex; | |
| justify-content: center; | |
| align-items: center; | |
| } | |
| #uploaded-image { | |
| max-width: 100%; | |
| max-height: 100%; | |
| display: none; | |
| object-fit: contain; | |
| } | |
| .upload-area { | |
| text-align: center; | |
| padding: 40px 20px; | |
| cursor: pointer; | |
| } | |
| .upload-icon { | |
| font-size: 3rem; | |
| color: var(--primary-color); | |
| margin-bottom: 15px; | |
| } | |
| .upload-text { | |
| font-size: 1.2rem; | |
| color: #666; | |
| } | |
| .btn { | |
| display: inline-block; | |
| padding: 10px 20px; | |
| background-color: var(--primary-color); | |
| color: white; | |
| border: none; | |
| border-radius: 5px; | |
| cursor: pointer; | |
| font-size: 1rem; | |
| transition: all 0.3s ease; | |
| margin-right: 10px; | |
| margin-bottom: 10px; | |
| } | |
| .btn:hover { | |
| background-color: var(--secondary-color); | |
| transform: translateY(-2px); | |
| } | |
| .btn-secondary { | |
| background-color: #6c757d; | |
| } | |
| .btn-secondary:hover { | |
| background-color: #5a6268; | |
| } | |
| .btn-accent { | |
| background-color: var(--accent-color); | |
| } | |
| .btn-accent:hover { | |
| background-color: #c91867; | |
| } | |
| .btn-group { | |
| margin-bottom: 20px; | |
| } | |
| .control-group { | |
| margin-bottom: 25px; | |
| } | |
| .control-title { | |
| font-weight: 600; | |
| margin-bottom: 10px; | |
| display: flex; | |
| align-items: center; | |
| } | |
| .control-title i { | |
| margin-right: 10px; | |
| color: var(--primary-color); | |
| } | |
| .filter-grid { | |
| display: grid; | |
| grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); | |
| gap: 10px; | |
| } | |
| .filter-btn { | |
| background-color: white; | |
| border: 1px solid #ddd; | |
| border-radius: 5px; | |
| padding: 10px; | |
| text-align: center; | |
| cursor: pointer; | |
| transition: all 0.3s ease; | |
| } | |
| .filter-btn:hover { | |
| background-color: #f0f8ff; | |
| transform: translateY(-2px); | |
| border-color: var(--primary-color); | |
| } | |
| .filter-preview { | |
| width: 80px; | |
| height: 80px; | |
| margin: 0 auto 5px; | |
| border-radius: 5px; | |
| overflow: hidden; | |
| } | |
| .filter-name { | |
| font-size: 0.9rem; | |
| } | |
| .slider-group { | |
| margin-top: 15px; | |
| } | |
| .slider-label { | |
| display: flex; | |
| justify-content: space-between; | |
| margin-bottom: 5px; | |
| } | |
| .slider-container { | |
| width: 100%; | |
| } | |
| input[type="range"] { | |
| width: 100%; | |
| height: 8px; | |
| border-radius: 5px; | |
| -webkit-appearance: none; | |
| background: #ddd; | |
| outline: none; | |
| } | |
| input[type="range"]::-webkit-slider-thumb { | |
| -webkit-appearance: none; | |
| appearance: none; | |
| width: 20px; | |
| height: 20px; | |
| border-radius: 50%; | |
| background: var(--primary-color); | |
| cursor: pointer; | |
| } | |
| .result-value { | |
| font-weight: bold; | |
| color: var(--primary-color); | |
| } | |
| .download-section { | |
| margin-top: 30px; | |
| text-align: center; | |
| } | |
| .canvas-container { | |
| display: none; | |
| } | |
| .status-message { | |
| padding: 10px; | |
| border-radius: 5px; | |
| margin-bottom: 20px; | |
| text-align: center; | |
| display: none; | |
| } | |
| .success { | |
| background-color: rgba(46, 204, 113, 0.2); | |
| color: var(--success-color); | |
| border: 1px solid var(--success-color); | |
| } | |
| .error { | |
| background-color: rgba(231, 76, 60, 0.2); | |
| color: #e74c3c; | |
| border: 1px solid #e74c3c; | |
| } | |
| @media (max-width: 768px) { | |
| .app-container { | |
| flex-direction: column; | |
| } | |
| .filter-grid { | |
| grid-template-columns: repeat(auto-fill, minmax(100px, 1fr)); | |
| } | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="container"> | |
| <header> | |
| <h1><i class="fas fa-magic"></i> Photo Visual Enhancer Pro</h1> | |
| <p class="description">Transform your images with powerful enhancement tools and filters</p> | |
| </header> | |
| <div class="app-container"> | |
| <div class="image-section"> | |
| <div class="image-container" id="image-container"> | |
| <div class="upload-area" id="upload-area"> | |
| <div class="upload-icon"> | |
| <i class="fas fa-cloud-upload-alt"></i> | |
| </div> | |
| <p class="upload-text">Drag & Drop your image here or click to browse</p> | |
| <input type="file" id="file-input" accept="image/*" style="display: none;"> | |
| </div> | |
| <img id="uploaded-image" alt="Uploaded Photo"> | |
| </div> | |
| <div class="status-message" id="status-message"></div> | |
| <div class="btn-group"> | |
| <button class="btn" id="enhance-btn"><i class="fas fa-star"></i> Auto Enhance</button> | |
| <button class="btn btn-secondary" id="reset-btn"><i class="fas fa-redo"></i> Reset</button> | |
| <button class="btn btn-accent" id="save-preset-btn"><i class="fas fa-save"></i> Save Preset</button> | |
| </div> | |
| <div class="canvas-container"> | |
| <canvas id="canvas"></canvas> | |
| </div> | |
| </div> | |
| <div class="controls-section"> | |
| <div class="control-group"> | |
| <h3 class="control-title"><i class="fas fa-sliders-h"></i> Basic Adjustments</h3> | |
| <div class="slider-group"> | |
| <div class="slider-label"> | |
| <span>Brightness</span> | |
| <span class="result-value" id="brightness-value">0%</span> | |
| </div> | |
| <div class="slider-container"> | |
| <input type="range" id="brightness" min="-100" max="100" value="0" step="1"> | |
| </div> | |
| </div> | |
| <div class="slider-group"> | |
| <div class="slider-label"> | |
| <span>Contrast</span> | |
| <span class="result-value" id="contrast-value">100%</span> | |
| </div> | |
| <div class="slider-container"> | |
| <input type="range" id="contrast" min="0" max="200" value="100" step="1"> | |
| </div> | |
| </div> | |
| <div class="slider-group"> | |
| <div class="slider-label"> | |
| <span>Saturation</span> | |
| <span class="result-value" id="saturation-value">100%</span> | |
| </div> | |
| <div class="slider-container"> | |
| <input type="range" id="saturation" min="0" max="200" value="100" step="1"> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="control-group"> | |
| <h3 class="control-title"><i class="fas fa-filter"></i> Creative Filters</h3> | |
| <div class="filter-grid"> | |
| <div class="filter-btn" data-filter="none"> | |
| <div class="filter-preview" style="background: #f8f9fa;"></div> | |
| <div class="filter-name">None</div> | |
| </div> | |
| <div class="filter-btn" data-filter="vintage"> | |
| <div class="filter-preview" style="background: #e6dbc9;"></div> | |
| <div class="filter-name">Vintage</div> | |
| </div> | |
| <div class="filter-btn" data-filter="blackWhite"> | |
| <div class="filter-preview" style="background: linear-gradient(to right, #000, #fff);"></div> | |
| <div class="filter-name">B&W</div> | |
| </div> | |
| <div class="filter-btn" data-filter="sepia"> | |
| <div class="filter-preview" style="background: #704214;"></div> | |
| <div class="filter-name">Sepia</div> | |
| </div> | |
| <div class="filter-btn" data-filter="clarendon"> | |
| <div class="filter-preview" style="background: linear-gradient(135deg, #4361ee, #f72585);"></div> | |
| <div class="filter-name">Clarendon</div> | |
| </div> | |
| <div class="filter-btn" data-filter="lark"> | |
| <div class="filter-preview" style="background: linear-gradient(135deg, #3a0ca3, #2ec4b6);"></div> | |
| <div class="filter-name">Lark</div> | |
| </div> | |
| <div class="filter-btn" data-filter="moon"> | |
| <div class="filter-preview" style="background: linear-gradient(135deg, #0c1a3a, #4cc9f0);"></div> | |
| <div class="filter-name">Moon</div> | |
| </div> | |
| <div class="filter-btn" data-filter="willow"> | |
| <div class="filter-preview" style="background: linear-gradient(135deg, #3a5a40, #a3b18a);"></div> | |
| <div class="filter-name">Willow</div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="control-group"> | |
| <h3 class="control-title"><i class="fas fa-tint"></i> Color Balance</h3> | |
| <div class="slider-group"> | |
| <div class="slider-label"> | |
| <span>Red</span> | |
| <span class="result-value" id="red-value">0</span> | |
| </div> | |
| <div class="slider-container"> | |
| <input type="range" id="red" min="-100" max="100" value="0" step="1"> | |
| </div> | |
| </div> | |
| <div class="slider-group"> | |
| <div class="slider-label"> | |
| <span>Green</span> | |
| <span class="result-value" id="green-value">0</span> | |
| </div> | |
| <div class="slider-container"> | |
| <input type="range" id="green" min="-100" max="100" value="0" step="1"> | |
| </div> | |
| </div> | |
| <div class="slider-group"> | |
| <div class="slider-label"> | |
| <span>Blue</span> | |
| <span class="result-value" id="blue-value">0</span> | |
| </div> | |
| <div class="slider-container"> | |
| <input type="range" id="blue" min="-100" max="100" value="0" step="1"> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="control-group"> | |
| <h3 class="control-title"><i class="fas fa-crop"></i> Transform</h3> | |
| <div class="slider-group"> | |
| <div class="slider-label"> | |
| <span>Rotate</span> | |
| <span class="result-value" id="rotate-value">0°</span> | |
| </div> | |
| <div class="slider-container"> | |
| <input type="range" id="rotate" min="0" max="360" value="0" step="1"> | |
| </div> | |
| </div> | |
| <div class="btn-group"> | |
| <button class="btn" id="flip-h"><i class="fas fa-arrows-alt-h"></i> Flip H</button> | |
| <button class="btn" id="flip-v"><i class="fas fa-arrows-alt-v"></i> Flip V</button> | |
| </div> | |
| </div> | |
| <div class="download-section"> | |
| <button class="btn btn-accent" id="download-btn"><i class="fas fa-download"></i> Download Enhanced Image</button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <script> | |
| document.addEventListener('DOMContentLoaded', function() { | |
| // DOM Elements | |
| const fileInput = document.getElementById('file-input'); | |
| const uploadArea = document.getElementById('upload-area'); | |
| const uploadedImage = document.getElementById('uploaded-image'); | |
| const imageContainer = document.getElementById('image-container'); | |
| const canvas = document.getElementById('canvas'); | |
| const ctx = canvas.getContext('2d'); | |
| // Controls | |
| const brightnessSlider = document.getElementById('brightness'); | |
| const contrastSlider = document.getElementById('contrast'); | |
| const saturationSlider = document.getElementById('saturation'); | |
| const redSlider = document.getElementById('red'); | |
| const greenSlider = document.getElementById('green'); | |
| const blueSlider = document.getElementById('blue'); | |
| const rotateSlider = document.getElementById('rotate'); | |
| // Buttons | |
| const enhanceBtn = document.getElementById('enhance-btn'); | |
| const resetBtn = document.getElementById('reset-btn'); | |
| const savePresetBtn = document.getElementById('save-preset-btn'); | |
| const downloadBtn = document.getElementById('download-btn'); | |
| const flipHBtn = document.getElementById('flip-h'); | |
| const flipVBtn = document.getElementById('flip-v'); | |
| // Value displays | |
| const brightnessValue = document.getElementById('brightness-value'); | |
| const contrastValue = document.getElementById('contrast-value'); | |
| const saturationValue = document.getElementById('saturation-value'); | |
| const redValue = document.getElementById('red-value'); | |
| const greenValue = document.getElementById('green-value'); | |
| const blueValue = document.getElementById('blue-value'); | |
| const rotateValue = document.getElementById('rotate-value'); | |
| // Status message | |
| const statusMessage = document.getElementById('status-message'); | |
| // Global variables | |
| let originalImageData = null; | |
| let flipHorizontal = false; | |
| let flipVertical = false; | |
| // Event listeners for drag and drop | |
| uploadArea.addEventListener('click', () => fileInput.click()); | |
| uploadArea.addEventListener('dragover', (e) => { | |
| e.preventDefault(); | |
| imageContainer.style.borderColor = var(--primary-color); | |
| }); | |
| uploadArea.addEventListener('dragleave', () => { | |
| imageContainer.style.borderColor = '#ddd'; | |
| }); | |
| uploadArea.addEventListener('drop', (e) => { | |
| e.preventDefault(); | |
| imageContainer.style.borderColor = '#ddd'; | |
| if (e.dataTransfer.files.length) { | |
| fileInput.files = e.dataTransfer.files; | |
| handleImageUpload(); | |
| } | |
| }); | |
| fileInput.addEventListener('change', handleImageUpload); | |
| // Slider event listeners | |
| brightnessSlider.addEventListener('input', updateSliderValues); | |
| contrastSlider.addEventListener('input', updateSliderValues); | |
| saturationSlider.addEventListener('input', updateSliderValues); | |
| redSlider.addEventListener('input', updateSliderValues); | |
| greenSlider.addEventListener('input', updateSliderValues); | |
| blueSlider.addEventListener('input', updateSliderValues); | |
| rotateSlider.addEventListener('input', updateSliderValues); | |
| // Button event listeners | |
| document.querySelectorAll('.filter-btn').forEach(btn => { | |
| btn.addEventListener('click', applyFilter); | |
| }); | |
| enhanceBtn.addEventListener('click', autoEnhance); | |
| resetBtn.addEventListener('click', resetImage); | |
| downloadBtn.addEventListener('click', downloadImage); | |
| flipHBtn.addEventListener('click', () => { | |
| flipHorizontal = !flipHorizontal; | |
| applyChanges(); | |
| }); | |
| flipVBtn.addEventListener('click', () => { | |
| flipVertical = !flipVertical; | |
| applyChanges(); | |
| }); | |
| // Handle image upload | |
| function handleImageUpload() { | |
| const file = fileInput.files[0]; | |
| if (!file) return; | |
| if (!file.type.match('image.*')) { | |
| showStatus('Please select an image file', 'error'); | |
| return; | |
| } | |
| const reader = new FileReader(); | |
| reader.onload = function(e) { | |
| uploadedImage.src = e.target.result; | |
| uploadedImage.onload = function() { | |
| uploadArea.style.display = 'none'; | |
| uploadedImage.style.display = 'block'; | |
| // Set canvas size to match image | |
| canvas.width = uploadedImage.naturalWidth; | |
| canvas.height = uploadedImage.naturalHeight; | |
| // Draw original image to canvas and save original data | |
| ctx.drawImage(uploadedImage, 0, 0); | |
| originalImageData = ctx.getImageData(0, 0, canvas.width, canvas.height); | |
| showStatus('Image uploaded successfully!', 'success'); | |
| }; | |
| }; | |
| reader.readAsDataURL(file); | |
| } | |
| // Update slider value displays | |
| function updateSliderValues() { | |
| brightnessValue.textContent = brightnessSlider.value + '%'; | |
| contrastValue.textContent = contrastSlider.value + '%'; | |
| saturationValue.textContent = saturationSlider.value + '%'; | |
| redValue.textContent = redSlider.value; | |
| greenValue.textContent = greenSlider.value; | |
| blueValue.textContent = blueSlider.value; | |
| rotateValue.textContent = rotateSlider.value + '°'; | |
| applyChanges(); | |
| } | |
| // Apply all adjustments to the image | |
| function applyChanges() { | |
| if (!originalImageData) return; | |
| // Restore original image data | |
| ctx.putImageData(originalImageData, 0, 0); | |
| // Apply filters | |
| applyBrightnessContrast(); | |
| applyColorBalance(); | |
| applySaturation(); | |
| // Simple rotation (for demo purposes - would need more complex transformation for better quality) | |
| if (rotateSlider.value != 0 || flipHorizontal || flipVertical) { | |
| rotateImage(); | |
| } | |
| } | |
| // Apply brightness and contrast | |
| function applyBrightnessContrast() { | |
| const brightness = parseInt(brightnessSlider.value); | |
| const contrast = parseInt(contrastSlider.value) / 100; | |
| const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height); | |
| const data = imageData.data; | |
| // Apply brightness and contrast | |
| const factor = (259 * (contrast * 255 + 255)) / (255 * (259 - contrast * 255)); | |
| for (let i = 0; i < data.length; i += 4) { | |
| // Contrast | |
| data[i] = factor * (data[i] - 128) + 128; | |
| data[i+1] = factor * (data[i+1] - 128) + 128; | |
| data[i+2] = factor * (data[i+2] - 128) + 128; | |
| // Brightness | |
| data[i] += brightness * 2.55; | |
| data[i+1] += brightness * 2.55; | |
| data[i+2] += brightness * 2.55; | |
| } | |
| ctx.putImageData(imageData, 0, 0); | |
| } | |
| // Apply color balance (red, green, blue) | |
| function applyColorBalance() { | |
| const red = parseInt(redSlider.value) / 100; | |
| const green = parseInt(greenSlider.value) / 100; | |
| const blue = parseInt(blueSlider.value) / 100; | |
| const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height); | |
| const data = imageData.data; | |
| for (let i = 0; i < data.length; i += 4) { | |
| // Red channel | |
| data[i] = data[i] + (255 - data[i]) * red; | |
| // Green channel | |
| data[i+1] = data[i+1] + (255 - data[i+1]) * green; | |
| // Blue channel | |
| data[i+2] = data[i+2] + (255 - data[i+2]) * blue; | |
| } | |
| ctx.putImageData(imageData, 0, 0); | |
| } | |
| // Apply saturation | |
| function applySaturation() { | |
| const saturation = parseInt(saturationSlider.value) / 100; | |
| const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height); | |
| const data = imageData.data; | |
| for (let i = 0; i < data.length; i += 4) { | |
| const r = data[i]; | |
| const g = data[i+1]; | |
| const b = data[i+2]; | |
| // Calculate grayscale value | |
| const gray = 0.299 * r + 0.587 * g + 0.114 * b; | |
| // Apply saturation | |
| data[i] = gray + (r - gray) * saturation; | |
| data[i+1] = gray + (g - gray) * saturation; | |
| data[i+2] = gray + (b - gray) * saturation; | |
| } | |
| ctx.putImageData(imageData, 0, 0); | |
| } | |
| // Rotate and flip image | |
| function rotateImage() { | |
| const angle = parseInt(rotateSlider.value); | |
| // Save current canvas content | |
| const tempCanvas = document.createElement('canvas'); | |
| tempCanvas.width = canvas.width; | |
| tempCanvas.height = canvas.height; | |
| const tempCtx = tempCanvas.getContext('2d'); | |
| tempCtx.drawImage(canvas, 0, 0); | |
| // Clear canvas | |
| ctx.clearRect(0, 0, canvas.width, canvas.height); | |
| // Save context | |
| ctx.save(); | |
| // Move to center of canvas | |
| ctx.translate(canvas.width / 2, canvas.height / 2); | |
| // Apply rotation | |
| if (angle !== 0) { | |
| ctx.rotate(angle * Math.PI / 180); | |
| } | |
| // Apply flips | |
| let scaleX = 1; | |
| let scaleY = 1; | |
| if (flipHorizontal) scaleX = -1; | |
| if (flipVertical) scaleY = -1; | |
| ctx.scale(scaleX, scaleY); | |
| // Draw image | |
| ctx.drawImage(tempCanvas, -tempCanvas.width / 2, -tempCanvas.height / 2); | |
| // Restore context | |
| ctx.restore(); | |
| } | |
| // Apply filter preset | |
| function applyFilter(e) { | |
| const filter = e.currentTarget.getAttribute('data-filter'); | |
| switch(filter) { | |
| case 'vintage': | |
| brightnessSlider.value = 10; | |
| contrastSlider.value = 90; | |
| saturationSlider.value = 60; | |
| redSlider.value = 30; | |
| greenSlider.value = -10; | |
| blueSlider.value = -20; | |
| break; | |
| case 'blackWhite': | |
| brightnessSlider.value = 5; | |
| contrastSlider.value = 120; | |
| saturationSlider.value = 0; | |
| break; | |
| case 'sepia': | |
| brightnessSlider.value = 10; | |
| contrastSlider.value = 90; | |
| saturationSlider.value = 60; | |
| redSlider.value = 40; | |
| greenSlider.value = 20; | |
| blueSlider.value = -40; | |
| break; | |
| case 'clarendon': | |
| brightnessSlider.value = 5; | |
| contrastSlider.value = 120; | |
| saturationSlider.value = 110; | |
| redSlider.value = 10; | |
| greenSlider.value = 0; | |
| blueSlider.value = 10; | |
| break; | |
| case 'lark': | |
| brightnessSlider.value = 15; | |
| contrastSlider.value = 110; | |
| saturationSlider.value = 120; | |
| redSlider.value = -10; | |
| greenSlider.value = 5; | |
| blueSlider.value = 25; | |
| break; | |
| case 'moon': | |
| brightnessSlider.value = 0; | |
| contrastSlider.value = 130; | |
| saturationSlider.value = 0; | |
| redSlider.value = 0; | |
| greenSlider.value = 0; | |
| blueSlider.value = 30; | |
| break; | |
| case 'willow': | |
| brightnessSlider.value = 10; | |
| contrastSlider.value = 90; | |
| saturationSlider.value = 80; | |
| redSlider.value = -15; | |
| greenSlider.value = 20; | |
| blueSlider.value = -20; | |
| break; | |
| case 'none': | |
| default: | |
| brightnessSlider.value = 0; | |
| contrastSlider.value = 100; | |
| saturationSlider.value = 100; | |
| redSlider.value = 0; | |
| greenSlider.value = 0; | |
| blueSlider.value = 0; | |
| } | |
| updateSliderValues(); | |
| applyChanges(); | |
| // Highlight selected filter | |
| document.querySelectorAll('.filter-btn').forEach(btn => { | |
| btn.style.borderColor = btn === e.currentTarget ? var(--primary-color) : '#ddd'; | |
| }); | |
| } | |
| // Auto enhance image | |
| function autoEnhance() { | |
| brightnessSlider.value = 15; | |
| contrastSlider.value = 115; | |
| saturationSlider.value = 110; | |
| redSlider.value = 5; | |
| greenSlider.value = 0; | |
| blueSlider.value = 0; | |
| updateSliderValues(); | |
| applyChanges(); | |
| showStatus('Image auto-enhanced!', 'success'); | |
| } | |
| // Reset image to original | |
| function resetImage() { | |
| brightnessSlider.value = 0; | |
| contrastSlider.value = 100; | |
| saturationSlider.value = 100; | |
| redSlider.value = 0; | |
| greenSlider.value = 0; | |
| blueSlider.value = 0; | |
| rotateSlider.value = 0; | |
| flipHorizontal = false; | |
| flipVertical = false; | |
| updateSliderValues(); | |
| if (originalImageData) { | |
| ctx.putImageData(originalImageData, 0, 0); | |
| } | |
| // Reset filter selection | |
| document.querySelectorAll('.filter-btn').forEach(btn => { | |
| btn.style.borderColor = '#ddd'; | |
| }); | |
| showStatus('Image reset to original', 'success'); | |
| } | |
| // Download enhanced image | |
| function downloadImage() { | |
| if (!originalImageData) { | |
| showStatus('No image to download', 'error'); | |
| return; | |
| } | |
| // Create a temporary canvas for final processing | |
| const tempCanvas = document.createElement('canvas'); | |
| tempCanvas.width = canvas.width; | |
| tempCanvas.height = canvas.height; | |
| const tempCtx = tempCanvas.getContext('2d'); | |
| tempCtx.drawImage(canvas, 0, 0); | |
| // Convert to data URL and create download link | |
| const dataURL = tempCanvas.toDataURL('image/jpeg', 0.9); | |
| const link = document.createElement('a'); | |
| link.download = 'enhanced-photo.jpg'; | |
| link.href = dataURL; | |
| link.click(); | |
| showStatus('Image downloaded successfully!', 'success'); | |
| } | |
| // Show status message | |
| function showStatus(message, type) { | |
| statusMessage.textContent = message; | |
| statusMessage.className = 'status-message ' + type; | |
| statusMessage.style.display = 'block'; | |
| // Hide after 3 seconds | |
| setTimeout(() => { | |
| statusMessage.style.display = 'none'; | |
| }, 3000); | |
| } | |
| }); | |
| </script> | |
| <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <a href="https://enzostvs-deepsite.hf.space" style="color: #fff;" target="_blank" >DeepSite</a> <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;"></p></body> | |
| </html> |