fa0170daa9
C++ WebView2 host app driving a Python/rembg engine as a JSON-stdio sidecar, with live before/after preview for images and video frames. Also includes the original CLI (removebg.py) built on the same core/ engine. The WebView2 SDK is fetched on demand via native/third_party/fetch-webview2.ps1 (wired into the Makefile) rather than vendored, since it's ~15MB of prebuilt/generated Microsoft SDK content. A Makefile provides make sync/build/run/clean as the standard entry points.
236 lines
11 KiB
HTML
236 lines
11 KiB
HTML
<!doctype html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
<title>RemoveBG Studio</title>
|
|
<link rel="stylesheet" href="styles.css" />
|
|
</head>
|
|
<body>
|
|
<div class="app">
|
|
<nav class="rail">
|
|
<div class="rail-mark">
|
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none"><path d="M12 2 L21 7 L21 17 L12 22 L3 17 L3 7 Z" stroke="currentColor" stroke-width="1.3"/><path d="M3 7 L12 12 L21 7 M12 12 L12 22" stroke="currentColor" stroke-width="1.3"/></svg>
|
|
</div>
|
|
|
|
<button class="rail-btn is-active" data-view="image" title="Image Processor">
|
|
<svg viewBox="0 0 24 24" fill="none"><rect x="3.5" y="4.5" width="17" height="15" rx="2.5" stroke="currentColor" stroke-width="1.3"/><circle cx="9" cy="10" r="1.5" stroke="currentColor" stroke-width="1.3"/><path d="M5 17 L10 12.5 L13 15 L16.5 11 L19.5 15" stroke="currentColor" stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
|
</button>
|
|
|
|
<button class="rail-btn" data-view="video" title="Video Processor">
|
|
<svg viewBox="0 0 24 24" fill="none"><rect x="3.5" y="6" width="12.5" height="12" rx="2.5" stroke="currentColor" stroke-width="1.3"/><path d="M16 10.5 L20.5 7.8 V16.2 L16 13.5" stroke="currentColor" stroke-width="1.3" stroke-linejoin="round"/></svg>
|
|
</button>
|
|
|
|
<div class="rail-spacer"></div>
|
|
<div class="rail-status" id="engineStatus" title="Sidecar status"><span class="dot"></span></div>
|
|
</nav>
|
|
|
|
<div class="main">
|
|
<header class="toolbar">
|
|
<h1 id="viewTitle">Image Processor</h1>
|
|
<div class="toolbar-actions">
|
|
<div class="seg" id="imgModeSeg">
|
|
<button class="seg-btn is-active" data-mode="single">Single</button>
|
|
<button class="seg-btn" data-mode="batch">Batch</button>
|
|
</div>
|
|
</div>
|
|
</header>
|
|
|
|
<div class="workspace">
|
|
|
|
<!-- ============================= IMAGE STAGE ============================= -->
|
|
<section class="stage" id="stage-image">
|
|
<div class="stage-empty" id="imgEmpty">
|
|
<div class="empty-icon">
|
|
<svg viewBox="0 0 24 24" fill="none"><rect x="3.5" y="4.5" width="17" height="15" rx="2.5" stroke="currentColor" stroke-width="1.2"/><circle cx="9" cy="10" r="1.5" stroke="currentColor" stroke-width="1.2"/><path d="M5 17 L10 12.5 L13 15 L16.5 11 L19.5 15" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
|
</div>
|
|
<button class="ghost-btn" id="imgOpenBtn">Open Image…</button>
|
|
<span class="empty-hint">or drop a file here</span>
|
|
</div>
|
|
|
|
<div class="compare" id="imgCompare" hidden>
|
|
<div class="compare-stage" id="imgCompareStage">
|
|
<div class="checker"></div>
|
|
<img class="layer layer-original" id="imgOriginalImg" alt="" />
|
|
<img class="layer layer-processed" id="imgProcessedImg" alt="" />
|
|
<div class="handle" id="imgHandle"><span class="handle-grip"></span></div>
|
|
<span class="tag tag-before">Original</span>
|
|
<span class="tag tag-after">Result</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="stage-loading" id="imgLoading" hidden><span class="spinner"></span>Generating preview…</div>
|
|
|
|
<div class="batch-list" id="imgBatchList" hidden>
|
|
<div class="batch-list-head">Selected files</div>
|
|
<div class="batch-list-body" id="imgBatchListBody"></div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- ============================= IMAGE PANEL ============================= -->
|
|
<aside class="panel" id="panel-image">
|
|
<div class="panel-section">
|
|
<div class="panel-label">Input</div>
|
|
<button class="row-btn" id="imgBrowseInput">Choose file(s)…</button>
|
|
<div class="path-line" id="imgInputPath">No input selected</div>
|
|
</div>
|
|
|
|
<div class="divider"></div>
|
|
|
|
<div class="panel-section">
|
|
<div class="panel-label">Model</div>
|
|
<select class="full-select" id="imgModel"></select>
|
|
<p class="panel-hint" id="imgModelDesc"></p>
|
|
</div>
|
|
|
|
<div class="divider"></div>
|
|
|
|
<div class="panel-section">
|
|
<div class="panel-label">Background</div>
|
|
<div class="swatch-row" id="imgBgSeg">
|
|
<button class="swatch-btn is-active" data-bg="transparent" title="Transparent"><span class="swatch checker-swatch"></span></button>
|
|
<button class="swatch-btn" data-bg="green" title="Green screen"><span class="swatch" style="background:#00ff00"></span></button>
|
|
<button class="swatch-btn" data-bg="white" title="White"><span class="swatch" style="background:#ffffff"></span></button>
|
|
<button class="swatch-btn" data-bg="black" title="Black"><span class="swatch" style="background:#000000"></span></button>
|
|
<button class="swatch-btn" data-bg="custom" title="Custom colour"><span class="swatch" id="imgSwatch" style="background:#00ff00"></span></button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="divider"></div>
|
|
|
|
<div class="panel-section">
|
|
<label class="switch-row">
|
|
<span>Alpha matting</span>
|
|
<span class="switch" id="imgAlphaToggle"><span class="knob"></span></span>
|
|
</label>
|
|
<p class="panel-hint">Refines hair & fine edges. Slower.</p>
|
|
</div>
|
|
|
|
<div class="panel-spacer"></div>
|
|
|
|
<div class="panel-section">
|
|
<div class="panel-label">Output</div>
|
|
<button class="row-btn" id="imgBrowseOutput">Choose destination…</button>
|
|
<div class="path-line" id="imgOutputPath">Not set</div>
|
|
<div class="panel-field" id="imgFormatField">
|
|
<span>Format</span>
|
|
<select id="imgFormat">
|
|
<option value="png">PNG</option>
|
|
<option value="webp">WEBP</option>
|
|
<option value="jpg">JPG</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
<button class="primary-btn" id="imgStartBtn">Save Result</button>
|
|
</aside>
|
|
|
|
<!-- ============================= VIDEO STAGE ============================= -->
|
|
<section class="stage" id="stage-video" hidden>
|
|
<div class="stage-empty" id="vidEmpty">
|
|
<div class="empty-icon">
|
|
<svg viewBox="0 0 24 24" fill="none"><rect x="3.5" y="6" width="12.5" height="12" rx="2.5" stroke="currentColor" stroke-width="1.2"/><path d="M16 10.5 L20.5 7.8 V16.2 L16 13.5" stroke="currentColor" stroke-width="1.2" stroke-linejoin="round"/></svg>
|
|
</div>
|
|
<button class="ghost-btn" id="vidOpenBtn">Open Video…</button>
|
|
<span class="empty-hint">or drop a file here</span>
|
|
</div>
|
|
|
|
<div class="compare" id="vidCompare" hidden>
|
|
<div class="compare-stage" id="vidCompareStage">
|
|
<div class="checker"></div>
|
|
<img class="layer layer-original" id="vidOriginalImg" alt="" />
|
|
<img class="layer layer-processed" id="vidProcessedImg" alt="" />
|
|
<div class="handle" id="vidHandle"><span class="handle-grip"></span></div>
|
|
<span class="tag tag-before">Original frame</span>
|
|
<span class="tag tag-after">Result</span>
|
|
</div>
|
|
<div class="stage-toolbar">
|
|
<span id="vidMeta"></span>
|
|
<button class="mini-btn" id="vidRefreshPreview">Refresh preview</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="stage-loading" id="vidLoading" hidden><span class="spinner"></span>Extracting & processing frame…</div>
|
|
</section>
|
|
|
|
<!-- ============================= VIDEO PANEL ============================= -->
|
|
<aside class="panel" id="panel-video" hidden>
|
|
<div class="panel-section">
|
|
<div class="panel-label">Input</div>
|
|
<button class="row-btn" id="vidBrowseInput">Choose video…</button>
|
|
<div class="path-line" id="vidInputPath">No video selected</div>
|
|
</div>
|
|
|
|
<div class="divider"></div>
|
|
|
|
<div class="panel-section">
|
|
<div class="panel-label">Model</div>
|
|
<select class="full-select" id="vidModel"></select>
|
|
</div>
|
|
|
|
<div class="divider"></div>
|
|
|
|
<div class="panel-section">
|
|
<div class="panel-label">Background</div>
|
|
<div class="swatch-row" id="vidBgSeg">
|
|
<button class="swatch-btn is-active" data-bg="transparent" title="Transparent"><span class="swatch checker-swatch"></span></button>
|
|
<button class="swatch-btn" data-bg="green" title="Green screen"><span class="swatch" style="background:#00ff00"></span></button>
|
|
<button class="swatch-btn" data-bg="white" title="White"><span class="swatch" style="background:#ffffff"></span></button>
|
|
<button class="swatch-btn" data-bg="black" title="Black"><span class="swatch" style="background:#000000"></span></button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="divider"></div>
|
|
|
|
<div class="panel-section">
|
|
<div class="panel-field">
|
|
<span>Target FPS</span>
|
|
<input class="glass-input" id="vidFps" type="number" min="0" step="0.1" value="0" placeholder="0 = original" />
|
|
</div>
|
|
</div>
|
|
|
|
<div class="divider"></div>
|
|
|
|
<div class="panel-section">
|
|
<label class="switch-row">
|
|
<span>Alpha matting</span>
|
|
<span class="switch" id="vidAlphaToggle"><span class="knob"></span></span>
|
|
</label>
|
|
</div>
|
|
|
|
<div class="panel-spacer"></div>
|
|
|
|
<div class="panel-section">
|
|
<div class="panel-label">Output</div>
|
|
<button class="row-btn" id="vidBrowseOutput">Choose destination…</button>
|
|
<div class="path-line" id="vidOutputPath">Not set</div>
|
|
<div class="panel-field">
|
|
<span>Export</span>
|
|
<select id="vidExportFormat">
|
|
<option value="mov_transparent">MOV · ProRes 4444</option>
|
|
<option value="webm_transparent">WebM · VP9 Alpha</option>
|
|
<option value="mp4_solid">MP4 · H.264 Solid</option>
|
|
<option value="png_sequence">PNG Sequence</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
<button class="primary-btn" id="vidStartBtn">Process Video</button>
|
|
</aside>
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<footer class="statusbar">
|
|
<div class="statusbar-track"><div class="statusbar-fill" id="progressFill"></div></div>
|
|
<span class="statusbar-text" id="statusText">Ready</span>
|
|
<button class="statusbar-log" id="logToggle">Log <svg viewBox="0 0 24 24" fill="none"><path d="M6 9l6 6 6-6" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"/></svg></button>
|
|
</footer>
|
|
|
|
<div class="log-drawer" id="logPanel"></div>
|
|
|
|
<script src="app.js"></script>
|
|
</body>
|
|
</html>
|