Spaces:
Paused
Paused
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8" /> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0" /> | |
| <title>Watermark Remover</title> | |
| <link rel="stylesheet" href="/static/style.css" /> | |
| </head> | |
| <body> | |
| <div class="app"> | |
| <!-- Header --> | |
| <header> | |
| <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="#6366f1" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> | |
| <rect x="3" y="3" width="18" height="18" rx="2"/> | |
| <path d="M3 9h18M9 21V9"/> | |
| </svg> | |
| <h1>Watermark Remover</h1> | |
| <div id="caps-bar"></div> | |
| </header> | |
| <!-- Workspace --> | |
| <div class="workspace"> | |
| <!-- Main area (left) --> | |
| <div class="canvas-area"> | |
| <!-- 1. Drop zone --> | |
| <div class="drop-zone" id="drop-zone"> | |
| <svg width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"> | |
| <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/> | |
| <polyline points="17 8 12 3 7 8"/> | |
| <line x1="12" y1="3" x2="12" y2="15"/> | |
| </svg> | |
| <p>Drop an image or video here</p> | |
| <button class="btn btn-secondary btn-sm" id="choose-btn">Choose file</button> | |
| <input type="file" id="file-input" accept="image/*,video/mp4,video/quicktime,video/x-msvideo,video/x-matroska,video/webm" hidden /> | |
| </div> | |
| <!-- 2. Mask panel — canvas + optional video player --> | |
| <div class="mask-panel hidden" id="mask-panel"> | |
| <!-- Video source player (videos only) --> | |
| <div class="source-video-bar hidden" id="source-video-bar"> | |
| <video id="source-video" controls preload="metadata"></video> | |
| <p class="hint" style="text-align:center;margin-top:4px">Watch original · draw mask on the frame below</p> | |
| </div> | |
| <!-- Canvas for mask drawing --> | |
| <div class="canvas-scroll" id="canvas-scroll"> | |
| <div class="canvas-wrap" id="canvas-wrap"> | |
| <canvas id="img-canvas"></canvas> | |
| <canvas id="overlay-canvas"></canvas> | |
| </div> | |
| </div> | |
| <!-- Toolbar --> | |
| <div class="toolbar" id="toolbar"> | |
| <label> | |
| Brush | |
| <input type="range" id="brush-size" min="4" max="120" value="24" /> | |
| <span id="brush-label">24px</span> | |
| </label> | |
| <div class="toolbar-sep"></div> | |
| <button class="tool-btn active" id="brush-btn">Brush</button> | |
| <button class="tool-btn" id="box-btn">Box</button> | |
| <button class="tool-btn" id="eraser-btn">Eraser</button> | |
| <button class="tool-btn" id="sam-btn" title="Click on the watermark — AI segments it automatically">SAM ✦</button> | |
| <button class="tool-btn" id="clear-btn">Clear mask</button> | |
| <div class="toolbar-sep"></div> | |
| <span class="file-name-label" id="file-name-label"></span> | |
| <button class="tool-btn btn-sm" id="change-file-btn" style="margin-left:auto">Change file</button> | |
| </div> | |
| </div><!-- /mask-panel --> | |
| <!-- 3. Compare panel — before/after slider --> | |
| <div class="compare-panel hidden" id="compare-panel"> | |
| <div class="compare-wrap" id="compare-wrap"> | |
| <!-- After layer (result) — always fully visible --> | |
| <div class="compare-layer compare-after" id="compare-after"> | |
| <img id="cmp-after-img" alt="After" /> | |
| <video id="cmp-after-video" preload="metadata" loop playsinline></video> | |
| </div> | |
| <!-- Before layer (original) — clipped by handle --> | |
| <div class="compare-layer compare-before" id="compare-before"> | |
| <img id="cmp-before-img" alt="Before" /> | |
| <video id="cmp-before-video" preload="metadata" loop playsinline muted></video> | |
| </div> | |
| <!-- Divider handle --> | |
| <div class="compare-handle" id="compare-handle"> | |
| <div class="compare-line"></div> | |
| <div class="compare-knob"> | |
| <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"> | |
| <polyline points="15 18 9 12 15 6"/> | |
| </svg> | |
| <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"> | |
| <polyline points="9 18 15 12 9 6"/> | |
| </svg> | |
| </div> | |
| </div> | |
| <!-- Labels --> | |
| <span class="cmp-label cmp-label-before">Before</span> | |
| <span class="cmp-label cmp-label-after">After</span> | |
| </div> | |
| <!-- Video controls bar (videos only) --> | |
| <div class="compare-video-bar hidden" id="compare-video-bar"> | |
| <button class="tool-btn" id="cmp-play-btn"> | |
| <svg id="cmp-play-icon" width="13" height="13" viewBox="0 0 24 24" fill="currentColor"><polygon points="5 3 19 12 5 21 5 3"/></svg> | |
| Play | |
| </button> | |
| <input type="range" id="cmp-seek" min="0" max="100" value="0" step="0.1" style="flex:1" /> | |
| <span id="cmp-time" style="font-size:11px;color:var(--muted);white-space:nowrap">0:00 / 0:00</span> | |
| </div> | |
| <!-- Back to mask / new file --> | |
| <div class="compare-toolbar"> | |
| <button class="tool-btn" id="back-to-mask-btn">← Edit mask</button> | |
| <span class="file-name-label" id="cmp-file-label"></span> | |
| <button class="tool-btn btn-sm" id="new-file-btn" style="margin-left:auto">Load new file</button> | |
| </div> | |
| </div><!-- /compare-panel --> | |
| </div><!-- /canvas-area --> | |
| <!-- Sidebar (right) --> | |
| <div class="sidebar"> | |
| <!-- Method --> | |
| <div> | |
| <h2>Method</h2> | |
| <div class="control-group" style="margin-top:10px"> | |
| <label>Inpainting engine</label> | |
| <div class="segmented" id="method-seg"> | |
| <button class="active" data-val="opencv">OpenCV <span style="opacity:.5;font-size:10px">Fast</span></button> | |
| <button data-val="lama" id="lama-btn">LaMa <span style="opacity:.5;font-size:10px">Quality</span></button> | |
| <button data-val="sd" id="sd-btn">SD <span style="opacity:.5;font-size:10px">Best</span></button> | |
| </div> | |
| <p class="hint">OpenCV: instant. LaMa: ML quality. SD: Stable Diffusion — near-invisible results, ~20s on M4.</p> | |
| </div> | |
| </div> | |
| <hr class="divider" /> | |
| <!-- Video options --> | |
| <div id="video-opts" class="hidden"> | |
| <h2>Video</h2> | |
| <div class="control-group" style="margin-top:10px"> | |
| <label>Processing mode</label> | |
| <div class="segmented" id="mode-seg"> | |
| <button class="active" data-val="fast">Fast</button> | |
| <button data-val="thorough">Thorough</button> | |
| </div> | |
| <p class="hint"><b>Fast:</b> one inpaint, applied to all frames. <b>Thorough:</b> inpaints every frame — handles moving watermarks, much slower.</p> | |
| </div> | |
| <hr class="divider" style="margin-top:16px"/> | |
| </div> | |
| <!-- Actions --> | |
| <div> | |
| <h2>Actions</h2> | |
| <div class="sidebar-actions" style="margin-top:10px"> | |
| <button class="btn btn-secondary" id="detect-btn" disabled> | |
| <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg> | |
| Auto Detect | |
| </button> | |
| <button class="btn btn-primary" id="process-btn" disabled> | |
| <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 11 12 14 22 4"/><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"/></svg> | |
| Remove Watermark | |
| </button> | |
| </div> | |
| </div> | |
| <!-- Status --> | |
| <div class="status-block hidden" id="status-block"> | |
| <div class="spinner hidden" id="status-spinner"></div> | |
| <div class="status-body"> | |
| <span id="status-text">Processing…</span> | |
| <div class="progress-wrap hidden" id="progress-wrap"> | |
| <div class="progress-track"> | |
| <div class="progress-fill" id="progress-fill"></div> | |
| </div> | |
| <span class="progress-label" id="progress-label">0%</span> | |
| </div> | |
| </div> | |
| </div> | |
| <hr class="divider" /> | |
| <!-- Result --> | |
| <div id="result-section" class="hidden"> | |
| <h2>Result</h2> | |
| <div class="sidebar-actions" style="margin-top:10px"> | |
| <a class="btn btn-primary hidden" id="download-btn" download> | |
| <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg> | |
| Download | |
| </a> | |
| </div> | |
| </div> | |
| </div><!-- /sidebar --> | |
| </div><!-- /workspace --> | |
| </div> | |
| <script src="/static/app.js"></script> | |
| </body> | |
| </html> | |