Spaces:
Running
Running
| <html lang="ar" dir="rtl"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>اداة تحسين الصور</title> | |
| <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.rtl.min.css" rel="stylesheet"> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css"> | |
| <link href="https://fonts.googleapis.com/css2?family=Cairo:wght@400;600;700&display=swap" rel="stylesheet"> | |
| <style> | |
| :root { | |
| --primary-color: #6366f1; | |
| --primary-hover: #4f46e5; | |
| --accent-color: #14b8a6; | |
| --bg-gradient: linear-gradient(135deg, #0f172a 0%, #1e293b 50%, #0f172a 100%); | |
| --card-bg: rgba(255, 255, 255, 0.08); | |
| --glass-border: rgba(255, 255, 255, 0.15); | |
| --text-primary: #f1f5f9; | |
| --text-secondary: #94a3b8; | |
| } | |
| * { | |
| font-family: 'Cairo', sans-serif; | |
| } | |
| body { | |
| background: var(--bg-gradient); | |
| min-height: 100vh; | |
| display: flex; | |
| align-items: center; | |
| padding: 2rem 0; | |
| position: relative; | |
| overflow-x: hidden; | |
| } | |
| /* Animated background orbs */ | |
| body::before, body::after { | |
| content: ''; | |
| position: fixed; | |
| border-radius: 50%; | |
| filter: blur(100px); | |
| opacity: 0.4; | |
| animation: float 8s ease-in-out infinite; | |
| z-index: -1; | |
| } | |
| body::before { | |
| width: 400px; | |
| height: 400px; | |
| background: var(--primary-color); | |
| top: -100px; | |
| right: -100px; | |
| } | |
| body::after { | |
| width: 300px; | |
| height: 300px; | |
| background: var(--accent-color); | |
| bottom: -50px; | |
| left: -50px; | |
| animation-delay: -4s; | |
| } | |
| @keyframes float { | |
| 0%, 100% { transform: translateY(0) scale(1); } | |
| 50% { transform: translateY(-30px) scale(1.05); } | |
| } | |
| .main-card { | |
| background: var(--card-bg); | |
| backdrop-filter: blur(20px); | |
| -webkit-backdrop-filter: blur(20px); | |
| border: 1px solid var(--glass-border); | |
| border-radius: 24px; | |
| box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5); | |
| overflow: hidden; | |
| max-width: 550px; | |
| width: 100%; | |
| margin: auto; | |
| transition: transform 0.3s ease, box-shadow 0.3s ease; | |
| } | |
| .main-card:hover { | |
| transform: translateY(-5px); | |
| box-shadow: 0 30px 60px -12px rgba(0, 0, 0, 0.6); | |
| } | |
| .card-header { | |
| background: linear-gradient(135deg, var(--primary-color) 0%, var(--accent-color) 100%); | |
| color: white; | |
| padding: 2.5rem 2rem; | |
| text-align: center; | |
| border: none; | |
| position: relative; | |
| overflow: hidden; | |
| } | |
| .card-header::before { | |
| content: ''; | |
| position: absolute; | |
| top: 0; | |
| left: 0; | |
| right: 0; | |
| bottom: 0; | |
| background: url("data:image/svg+xml,%3Csvg width='60' height='60' viewBox='0 0 60 60' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cg fill='%23ffffff' fill-opacity='0.05'%3E%3Ccircle cx='30' cy='30' r='2'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E"); | |
| animation: patternMove 20s linear infinite; | |
| } | |
| @keyframes patternMove { | |
| 0% { transform: translateX(0) translateY(0); } | |
| 100% { transform: translateX(60px) translateY(60px); } | |
| } | |
| .card-header h2, .card-header p { | |
| position: relative; | |
| z-index: 1; | |
| } | |
| .card-header h2 { | |
| font-weight: 700; | |
| font-size: 1.75rem; | |
| margin-bottom: 0.5rem; | |
| } | |
| .card-body { | |
| padding: 2rem; | |
| } | |
| .upload-area { | |
| border: 2px dashed var(--glass-border); | |
| border-radius: 16px; | |
| padding: 2.5rem 2rem; | |
| text-align: center; | |
| cursor: pointer; | |
| transition: all 0.3s ease; | |
| position: relative; | |
| background: rgba(255, 255, 255, 0.02); | |
| } | |
| .upload-area:hover, .upload-area.dragover { | |
| border-color: var(--accent-color); | |
| background: rgba(20, 184, 166, 0.1); | |
| transform: scale(1.02); | |
| } | |
| .upload-icon { | |
| font-size: 3.5rem; | |
| background: linear-gradient(135deg, var(--primary-color), var(--accent-color)); | |
| -webkit-background-clip: text; | |
| -webkit-text-fill-color: transparent; | |
| background-clip: text; | |
| margin-bottom: 1rem; | |
| animation: pulse 2s ease-in-out infinite; | |
| } | |
| @keyframes pulse { | |
| 0%, 100% { transform: scale(1); } | |
| 50% { transform: scale(1.1); } | |
| } | |
| .upload-area h5 { | |
| color: var(--text-primary); | |
| font-weight: 600; | |
| } | |
| .upload-area p { | |
| color: var(--text-secondary); | |
| } | |
| .file-preview { | |
| max-width: 100%; | |
| max-height: 200px; | |
| border-radius: 12px; | |
| display: none; | |
| margin-top: 1rem; | |
| box-shadow: 0 8px 20px rgba(0, 0, 0, 0.3); | |
| } | |
| .form-label { | |
| color: var(--text-primary); | |
| font-weight: 600; | |
| } | |
| .form-range { | |
| accent-color: var(--accent-color); | |
| } | |
| .form-select { | |
| background-color: rgba(255, 255, 255, 0.05); | |
| border: 1px solid var(--glass-border); | |
| color: var(--text-primary); | |
| border-radius: 12px; | |
| padding: 0.75rem 1rem; | |
| transition: all 0.3s ease; | |
| } | |
| .form-select:focus { | |
| background-color: rgba(255, 255, 255, 0.1); | |
| border-color: var(--accent-color); | |
| box-shadow: 0 0 0 3px rgba(20, 184, 166, 0.2); | |
| } | |
| .form-select option { | |
| background-color: #1e293b; | |
| color: var(--text-primary); | |
| } | |
| .badge { | |
| background: linear-gradient(135deg, var(--primary-color), var(--accent-color)) ; | |
| font-size: 0.85rem; | |
| padding: 0.4rem 0.8rem; | |
| } | |
| .text-muted { | |
| color: var(--text-secondary) ; | |
| } | |
| .form-check-input { | |
| background-color: rgba(255, 255, 255, 0.1); | |
| border-color: var(--glass-border); | |
| width: 3rem; | |
| height: 1.5rem; | |
| } | |
| .form-check-input:checked { | |
| background-color: var(--accent-color); | |
| border-color: var(--accent-color); | |
| } | |
| .form-check-label { | |
| color: var(--text-primary); | |
| margin-right: 0.5rem; | |
| } | |
| .btn-primary { | |
| background: linear-gradient(135deg, var(--primary-color) 0%, var(--accent-color) 100%); | |
| border: none; | |
| padding: 1rem 2rem; | |
| font-weight: 700; | |
| font-size: 1.1rem; | |
| border-radius: 14px; | |
| transition: all 0.3s ease; | |
| position: relative; | |
| overflow: hidden; | |
| } | |
| .btn-primary::before { | |
| content: ''; | |
| position: absolute; | |
| top: 0; | |
| left: -100%; | |
| width: 100%; | |
| height: 100%; | |
| background: linear-gradient(90deg, transparent, rgba(255,255,255,0.2), transparent); | |
| transition: left 0.5s ease; | |
| } | |
| .btn-primary:hover::before { | |
| left: 100%; | |
| } | |
| .btn-primary:hover { | |
| transform: translateY(-3px); | |
| box-shadow: 0 10px 30px rgba(99, 102, 241, 0.4); | |
| } | |
| /* Loading Overlay */ | |
| #loadingOverlay { | |
| position: fixed; | |
| top: 0; | |
| left: 0; | |
| width: 100%; | |
| height: 100%; | |
| background: rgba(15, 23, 42, 0.95); | |
| backdrop-filter: blur(10px); | |
| display: none; | |
| justify-content: center; | |
| align-items: center; | |
| z-index: 9999; | |
| flex-direction: column; | |
| } | |
| .spinner { | |
| width: 60px; | |
| height: 60px; | |
| border: 4px solid rgba(255, 255, 255, 0.1); | |
| border-top: 4px solid var(--accent-color); | |
| border-radius: 50%; | |
| animation: spin 1s linear infinite; | |
| margin-bottom: 1.5rem; | |
| } | |
| @keyframes spin { | |
| 0% { transform: rotate(0deg); } | |
| 100% { transform: rotate(360deg); } | |
| } | |
| .loading-text { | |
| color: var(--text-primary); | |
| font-size: 1.3rem; | |
| font-weight: 600; | |
| } | |
| .loading-subtext { | |
| color: var(--text-secondary); | |
| font-size: 1rem; | |
| margin-top: 0.5rem; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="container"> | |
| <div class="main-card"> | |
| <div class="card-header"> | |
| <h2 class="mb-2"><i class="fas fa-wand-magic-sparkles me-2"></i>اداة تحسين الصور</h2> | |
| <p class="mb-0 opacity-90">تحسين وترميم صور الوجه تلقائياً</p> | |
| </div> | |
| <div class="card-body"> | |
| <form action="/process" method="post" enctype="multipart/form-data" id="uploadForm"> | |
| <!-- File Upload --> | |
| <div class="mb-4"> | |
| <label class="form-label fw-bold">Input Images</label> | |
| <div class="upload-area" id="dropZone"> | |
| <i class="fas fa-cloud-upload-alt upload-icon"></i> | |
| <h5 class="mb-1">Drag & Drop or Click to Upload</h5> | |
| <p class="text-muted small mb-0">Supports JPG, PNG, WEBP (Multiple files allowed)</p> | |
| <input type="file" name="image" id="imageInput" accept="image/*" class="d-none" multiple required> | |
| <div id="previewContainer" class="d-flex flex-wrap gap-2 justify-content-center mt-3" style="display:none;"></div> | |
| </div> | |
| </div> | |
| <!-- Settings --> | |
| <div class="row g-3 mb-4"> | |
| <div class="col-12"> | |
| <label for="fidelity" class="form-label d-flex justify-content-between"> | |
| وزن الدقة | |
| <span class="badge rounded-pill" id="fidelityVal">0.5</span> | |
| </label> | |
| <input type="range" class="form-range" name="fidelity" id="fidelity" min="0" max="1" step="0.01" value="0.5"> | |
| <div class="d-flex justify-content-between text-muted small"> | |
| <span>جودة أفضل (0.0)</span> | |
| <span>هوية أدق (1.0)</span> | |
| </div> | |
| </div> | |
| <div class="col-12"> | |
| <label class="form-label fw-bold">Upscale Factor</label> | |
| <div class="p-2 border rounded bg-light text-center fw-bold text-primary"> | |
| <i class="fas fa-bolt me-2"></i>4x Super-Resolution Active | |
| </div> | |
| <input type="hidden" name="upscale" value="4"> | |
| </div> | |
| </div> | |
| <!-- Toggles --> | |
| <div class="d-flex gap-4 mb-4 justify-content-center flex-wrap"> | |
| <div class="form-check form-switch"> | |
| <input class="form-check-input" type="checkbox" name="background_enhance" id="bgEnhance" checked> | |
| <label class="form-check-label" for="bgEnhance">تحسين الخلفية</label> | |
| </div> | |
| <div class="form-check form-switch"> | |
| <input class="form-check-input" type="checkbox" name="face_upsample" id="faceUpsample" checked> | |
| <label class="form-check-label" for="faceUpsample">تحسين الوجه</label> | |
| </div> | |
| </div> | |
| <!-- Submit --> | |
| <button type="submit" class="btn btn-primary w-100 py-3"> | |
| <i class="fas fa-wand-magic-sparkles me-2"></i>استعادة الصورة | |
| </button> | |
| </form> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Loading Overlay --> | |
| <div id="loadingOverlay"> | |
| <div class="spinner"></div> | |
| <div class="loading-text">جاري معالجة الصورة...</div> | |
| <div class="loading-subtext"> يرجى الانتظار.</div> | |
| </div> | |
| <script> | |
| const dropZone = document.getElementById('dropZone'); | |
| const fileInput = document.getElementById('imageInput'); | |
| const preview = document.getElementById('imagePreview'); | |
| const form = document.getElementById('uploadForm'); | |
| const loadingOverlay = document.getElementById('loadingOverlay'); | |
| const fidelityRange = document.getElementById('fidelity'); | |
| const fidelityVal = document.getElementById('fidelityVal'); | |
| // Range slider update | |
| fidelityRange.addEventListener('input', (e) => { | |
| fidelityVal.textContent = e.target.value; | |
| }); | |
| // Drag and Drop | |
| dropZone.addEventListener('click', () => fileInput.click()); | |
| dropZone.addEventListener('dragover', (e) => { | |
| e.preventDefault(); | |
| dropZone.classList.add('dragover'); | |
| }); | |
| dropZone.addEventListener('dragleave', () => { | |
| dropZone.classList.remove('dragover'); | |
| }); | |
| dropZone.addEventListener('drop', (e) => { | |
| e.preventDefault(); | |
| dropZone.classList.remove('dragover'); | |
| if (e.dataTransfer.files.length) { | |
| fileInput.files = e.dataTransfer.files; | |
| showPreview(fileInput.files[0]); | |
| } | |
| }); | |
| fileInput.addEventListener('change', () => { | |
| if (fileInput.files.length) { | |
| showPreview(fileInput.files[0]); | |
| } | |
| }); | |
| function showPreview(file) { | |
| // This function is now deprecated for single preview only logic | |
| // We handle multiple files in the change event listener | |
| } | |
| // Handle File Selection (Drag & Drop or Click) | |
| function handleFiles(files) { | |
| if (files.length > 0) { | |
| fileInput.files = files; // Update input files | |
| // Hide initial upload prompts | |
| dropZone.querySelector('.upload-icon').style.display = 'none'; | |
| dropZone.querySelector('h5').style.display = 'none'; | |
| dropZone.querySelector('p').style.display = 'none'; | |
| // Clear previous previews | |
| const previewContainer = document.getElementById('previewContainer'); | |
| previewContainer.innerHTML = ''; | |
| previewContainer.style.display = 'flex'; | |
| preview.style.display = 'none'; // Hide single large preview | |
| if (files.length === 1) { | |
| // Single file: Show large preview | |
| const reader = new FileReader(); | |
| reader.onload = function(e) { | |
| preview.src = e.target.result; | |
| preview.style.display = 'block'; | |
| } | |
| reader.readAsDataURL(files[0]); | |
| } else { | |
| // Multiple files: Show thumbnails or count | |
| const countMsg = document.createElement('div'); | |
| countMsg.className = 'text-center w-100 mb-2 fw-bold text-white'; | |
| countMsg.textContent = `${files.length} images selected`; | |
| previewContainer.appendChild(countMsg); | |
| // Show up to 4 thumbnails | |
| Array.from(files).slice(0, 4).forEach(file => { | |
| const reader = new FileReader(); | |
| reader.onload = function(e) { | |
| const img = document.createElement('img'); | |
| img.src = e.target.result; | |
| img.className = 'file-preview'; | |
| img.style.width = '80px'; | |
| img.style.height = '80px'; | |
| img.style.objectFit = 'cover'; | |
| img.style.margin = '5px'; | |
| img.style.display = 'block'; | |
| previewContainer.appendChild(img); | |
| } | |
| reader.readAsDataURL(file); | |
| }); | |
| if (files.length > 4) { | |
| const more = document.createElement('div'); | |
| more.textContent = `+${files.length - 4} more`; | |
| more.className = 'd-flex align-items-center justify-content-center text-white bg-dark rounded'; | |
| more.style.width = '80px'; | |
| more.style.height = '80px'; | |
| more.style.opacity = '0.7'; | |
| previewContainer.appendChild(more); | |
| } | |
| } | |
| } | |
| } | |
| dropZone.addEventListener('drop', (e) => { | |
| e.preventDefault(); | |
| dropZone.classList.remove('dragover'); | |
| handleFiles(e.dataTransfer.files); | |
| }); | |
| fileInput.addEventListener('change', () => { | |
| handleFiles(fileInput.files); | |
| }); | |
| form.addEventListener('submit', (e) => { | |
| loadingOverlay.style.display = 'flex'; | |
| // Allow the form to submit naturally | |
| }); | |
| </script> | |
| </body> | |
| </html> |