Zum Hauptinhalt springen
tsecurity.de LIVE
Echtzeit-Radar & Feeds
Alle RSS Feeds
👥 Community & Social
Windows Tipps & SecurityWindows-Update beschädigt wichtige Datenrettungsfunktion(22.09.2026 um 09:04 Uhr)
Sichere ProgrammierungBuilding an Accessible Ecommerce Product Page with WCAG 2.2(22.09.2026 um 03:39 Uhr)
Sichere ProgrammierungGet Your Website Protected in 10 Minutes with SafeLine WAF(22.09.2026 um 08:42 Uhr)
Sichere ProgrammierungIntroduction to SPRINGBOOT(22.09.2026 um 08:42 Uhr)
Windows Tipps & SecurityWindows-Update beschädigt wichtige Datenrettungsfunktion(22.09.2026 um 09:04 Uhr)
Sichere ProgrammierungBuilding an Accessible Ecommerce Product Page with WCAG 2.2(22.09.2026 um 03:39 Uhr)
Sichere ProgrammierungGet Your Website Protected in 10 Minutes with SafeLine WAF(22.09.2026 um 08:42 Uhr)
Sichere ProgrammierungIntroduction to SPRINGBOOT(22.09.2026 um 08:42 Uhr)
Intelligence View
⚡ tsecurity.de Intelligence

Removing a Photo's Background in the Browser, With No Upload: AI Licenses, ONNX Models, and a Frozen Tab

I wanted to add a background-removal tool to my site's image cluster that stayed true to the 100% client-side processing principle I already use for PDFs and image conversions. The path there was anything but linear: a library dropped over…

0
↗ Quelle (dev.to)
Reagiere als Erste:r — dein Feedback zählt!

I wanted to add a background-removal tool to my site's image cluster that stayed true to the 100% client-side processing principle I already use for PDFs and image conversions. The path there was anything but linear: a library dropped over a licensing problem, a carefully chosen model that turned out more limited than expected, and a bug that froze the entire page — not just the tool — during computation.



Here's the full build, including the parts that didn't work the first time.






The starting problem: what's actually feasible for free?



The initial idea was broad: remove backgrounds, and maybe unwanted objects too. The two tasks have very different difficulty levels.



Removing objects requires inpainting — plausibly reconstructing the erased area — which in practice still means heavy generative models, impractical to run client-side with good quality on an average device.



Removing a background, on the other hand, is a segmentation problem: separating a subject from its surroundings. That has much lighter models available, runnable entirely via WebAssembly with no server involved at all.



So: background removal only, object removal shelved for later.






The AGPL trap



The first library that looked like a perfect fit turned out to be distributed under AGPL, a strong copyleft license. Free to use — but with a real catch for anyone embedding it in a public, closed-source web service: AGPL can require releasing the full source of the project that embeds it, under the same license.



"Free for the end user" and "safe to drop into a closed-source commercial product" are two different questions, and it's worth answering the second one before writing integration code, not after deploying it.




Before wiring any "free" AI library into a commercial project, check the exact license, not just the price tag. AGPL, GPL, and other strong copyleft licenses are fine for personal or internal tools, risky for a public closed-source product.




The fix: switch to Transformers.js — Hugging Face's library for running ML models in the browser on top of ONNX Runtime Web — with a permissively licensed model (Apache-2.0) instead of the AGPL wrapper. Same principle (an ONNX model pulled once from a CDN, then cached by the browser), clean license.






A light CNN, not a heavy transformer



Picking the model taught me a lesson that generalizes to any browser-ML project: architecture matters more than file size.



A transformer-based model, even a qualitatively great one with a permissive license, can crash from memory exhaustion during WASM inference on a lot of machines. Transformer attention scales memory with the number of image "patches," and at normal photo resolution the intermediate tensors get huge. A smaller CNN with an architecture built for segmentation runs far more reliably in WASM.
































Layer Choice
Runtime Transformers.js on top of ONNX Runtime Web (WASM)
Default model Light CNN, Apache-2.0, optimized for people
Optional model Heavier transformer, MIT, more general-purpose
Processing 100% local, no image upload
Cache Browser + service worker, one-time download





The "raw matte" problem



The model often left a residual color halo around the cutout, because the output is a soft alpha matte rather than a clean binary mask — background pixels could carry residual alpha values of 5–15% instead of a clean 0.



No second model needed. Just post-process the alpha curve: force low values to full transparency, force high values to full opacity, use a smoothstep transition in between so soft edges (hair, fine detail) survive. On a test image this pushed over 60% of pixels to fully transparent and over 35% to fully opaque, leaving only a small sliver in the mid-range — a clean result.




// Simplified alpha cleanup
function cleanAlpha(a, lowT = 0.08, highT = 0.85) {
if (a <= lowT) return 0;
if (a >= highT) return 1;
const t = (a - lowT) / (highT - lowT);
return t * t * (3 - 2 * t); // smoothstep
}









The real limit: a specialized model isn't a general one



First real-world tests were disappointing on two fronts: a flat illustration (the model only trimmed the margin around the shape, leaving the whole drawing opaque) and a dim, cluttered indoor photo (the model nearly erased the main subject too).



To isolate the cause, I temporarily added a debug panel showing the model's raw mask, before any alpha cleanup, next to the final result. They were nearly identical — so the bug wasn't in my post-processing, it was upstream, in the model itself.



Checking the model card confirmed it: the default model was trained specifically on a human segmentation dataset, not a general-purpose one. On a well-lit, close-up portrait, the cutout is genuinely clean, hair included. On anything far from that training domain — illustrations, dark scenes, cluttered framing — quality drops in a predictable, not-a-bug way.




A model that's "light and WASM-reliable" is often exactly that because it's trained on a narrow domain. Before calling a model "bad," check what it was actually trained on — the mismatch is usually domain, not quality.







An optional "better model" button, not a default swap



Instead of replacing the light model with a heavier, more general one for everyone — making every user pay the load-time cost for a case they may never hit — I added a second model (an MIT-licensed transformer, better suited to generic scenes) available only on request. A "Try the better model" button appears after the first result and reprocesses the same image, without overwriting the existing output until the heavier model succeeds. If it fails from insufficient memory, the first result stays intact and the user gets a clear error instead of a broken tool.



Light by default, heavy on explicit request — nobody pays for a download they'll never use.






The real bug: the main thread freezes during inference



Testing the heavier model surfaced something much worse than mediocre output: during processing, the entire page stopped responding — not just the tool, the top nav links too.



The cause: by default, ONNX Runtime Web runs WASM computation on the browser's main thread, the same one handling clicks, scroll, and rendering. During heavy inference that thread stays busy and the whole UI freezes.



First attempt at a fix — flipping an internal library option meant to delegate computation to a separate thread — didn't work, likely due to delicate initialization timing. The reliable fix was writing and controlling a real dedicated Web Worker myself: a separate thread that loads the library, downloads the model, and runs the whole inference, talking to the main page only through postMessage (input image in, progress and result out).




// worker.js (simplified)
self.onmessage = async (e) => {
const { imageBuffer } = e.data;
const { pipeline } = await import('https://cdn.jsdelivr.net/npm/@huggingface/transformers');
const remover = await pipeline('background-removal', MODEL_ID, { device: 'wasm' });
const result = await remover(imageBuffer);
self.postMessage({ type: 'done', result }, [result.buffer]);
};






This way the main thread never does heavy computation by construction, not by a configuration flag I was hoping would hold.




If client-side AI processing freezes the whole interface, not just the component using it, the top suspect is main-thread computation. A config flag might not be enough — a dedicated, explicitly written Web Worker is the more reliable fix.







Handling a real two-minute wait



Even with the freeze fixed, there was a perception problem left: the heavier model takes roughly two minutes on common hardware, and the library doesn't expose real percentage progress during inference — only during the model download.



A progress bar sitting "full and still" for two minutes reads as broken, not slow.



Final approach: a bar that advances on an estimated curve over ~2.5 minutes, with elapsed seconds shown below, and — if processing runs past that estimate — an automatic switch to an indeterminate animation (a continuously scrolling stripe), the universal "still working" signal without faking a percentage the model can't provide. A wider safety timeout unlocks the UI if something really goes wrong, so the user can retry.






What I took away from this



The most useful lesson isn't about one bug — it's about ordering priorities:




  • Check the license before you check the quality.

  • Check a model's training domain before you judge its output.

  • Don't trust a library flag for something as critical as "doesn't block the main thread" — verify it with a real test, don't assume it holds.

  • A clearly communicated limitation ("works best on well-lit close-up photos") is far less frustrating for users than an unexplained bad result.



If you've hit the AGPL-vs-permissive-license question before, or fought with onnxruntime-web blocking a UI thread, I'd be curious to hear how you solved it.






I write about building and maintaining roversia.it — a personal site with 35+ browser tools, PWA games, and small web apps, all vanilla JS, zero monthly cost, and (as much as possible) zero server-side processing.

Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten Removing a Photo's Background in the Browser, With No Upload: AI Licenses, ONNX Models, and a Frozen Tab

Thematisch verwandte Begriffe: Removing, Photos, Background, Browser · 6 Treffer

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Zum Aktualisieren ziehen
ZERO-DAY CVE-2026-55210 | Joplin is an open source note-taking and to-do application that organise…
Advisory →
TTS Reader • tsecurity.de Voice
tsecurity.de Icon
tsecurity.de App
Offline-Lesen, Eilmeldungen & 0ms Ladezeit

Installiere tsecurity.de direkt auf deinen Home-Bildschirm für das ultimative Vollbild-Magazinerlebnis ohne Browser-Leisten.

Nächster Beitrag
Themen-Radar & Intelligence Matrix
Echtzeit-Taxonomie nach Angriffsvektoren & Plattformen

tsecurity.de Live Threat Radar

🔴 LIVE RADAR
MONITORING
AKTIV
CVE-DATENBANK
LIVE
🔍
Community Radar & Live Chat
Sentinel Bot online • Live-Stream
Dein Cluster: Security Explorer
Match:
lädt…
Verbindung zum Community-Stream wird aufgebaut...
Bearbeitungsmodus — Senden überschreibt deine Nachricht
Community-Puls — was gerade passiert
lädt…
Aktivitäten deiner Analysten
lädt…
Neues Thema oder Eilmeldung einreichen

Reiche interessante Links, Zero-Days oder Debatten ein. Die Community entscheidet per Upvote über die Veröffentlichung.

Heiß diskutierte Einreichungen
🔖 Gespeicherte Artikel
📂 Keine gespeicherten Artikel vorhanden.
Zurück Ziehen Vor
Links: vorheriger Artikel Rechts: nächster Artikel unten: schließen
News NIS-2 Frühwarnung Tier-1 Intel ⏱️ 3 Min vor 10 Min
Artikeldaten werden geladen...

Zurück: vorheriger Vor: nächster
↗ Original-Quelle
Social Reaktionen Deine Reaktion zählt
Einstufung & Relevanz-Poll 0 Stimmen
In sozialen Netzwerken teilen 1-Klick