{"id":2353,"date":"2026-04-07T13:56:31","date_gmt":"2026-04-07T13:56:31","guid":{"rendered":"https:\/\/primetoolhub.com\/?page_id=2353"},"modified":"2026-07-08T16:02:31","modified_gmt":"2026-07-08T16:02:31","slug":"free-ai-background-remover","status":"publish","type":"page","link":"https:\/\/schoolict.net\/tools\/free-ai-background-remover\/","title":{"rendered":"Free AI Background Remover | AI Image Eraser |  Erase Objects &amp; Upscale"},"content":{"rendered":"<div class=\"pth-hero-section\">\n<div class=\"pth-hero-content\">\n<h2>AI Image Eraser \u2014 Remove Background, Erase Objects &#038; Upscale<\/h2>\n<p>Need a free AI background remover? Instantly remove backgrounds from images offline in your browser. 100% private, no uploads, and unlimited free cutouts.<\/p>\n<div id=\"pth-toc-placeholder\"><\/div>\n<\/p>\n<\/div>\n\n  <div class=\"pth-hero-image\">\n    <img data-no-lazy=\"1\"\n         src=\"https:\/\/schoolict.net\/tools\/wp-content\/uploads\/2026\/04\/Free-AI-Background-Remover-800x447.jpeg\"\n         width=\"800\"\n         height=\"447\"\n         alt=\"Free AI Background Remover\"\n         fetchpriority=\"high\"\n         loading=\"eager\"\n         decoding=\"async\"\n         style=\"width:100%; height:auto; display:block;\">\n  <\/div>\n<\/div>\n\n\n\n<div class=\"wp-block-rank-math-toc-block\" id=\"rank-math-toc\"><h2>Table of Contents<\/h2><nav><ul><li><a href=\"#\ud83d\udd34-one-photo-three-jobs-no-round-trips\">\ud83d\udd34 One Photo, Three Jobs, No Round Trips<\/a><\/li><li><a href=\"#\ud83d\udfe1-when-each-tab-earns-its-place\">\ud83d\udfe1 When Each Tab Earns Its Place<\/a><ul><li><a href=\"#\ud83d\udfe2-a-real-example\">\ud83d\udfe2 A Real Example<\/a><\/li><\/ul><\/li><li><a href=\"#\ud83d\udd34-where-it-struggles-and-what-to-do\">\ud83d\udd34 Where It Struggles \u2014 and What to Do<\/a><\/li><\/ul><\/nav><\/div>\n\n\n<!-- LSCACHE_DISABLE -->\r\n<div id=\"pth-ie-wrapper\">\r\n\r\n<style data-no-optimize=\"1\">\r\n#pth-ie-wrapper *,#pth-ie-wrapper *::before,#pth-ie-wrapper *::after{box-sizing:border-box;min-width:0;}\r\n#pth-ie-wrapper{font-family:'Inter',system-ui,sans-serif;background:#f8fafc;border-radius:16px;padding:20px;color:#1e293b;font-weight:500;opacity:1;display:block;}\r\n.pth-ie-header{margin-bottom:16px;}\r\n.pth-ie-meta-bar{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-bottom:10px;}\r\n.pth-ie-version-badge{background:#eff6ff;color:#1d4ed8;font-size:.72rem;font-weight:700;padding:3px 10px;border-radius:20px;border:1px solid #bfdbfe;}\r\n.pth-ie-status-offline{background:#f0fdf4;color:#047857;font-size:.72rem;font-weight:700;padding:3px 10px;border-radius:20px;border:1px solid #bbf7d0;}\r\n.pth-ie-header h2{color:#1d4ed8;font-size:1.5rem;font-weight:800;margin:0 0 6px;}\r\n.pth-ie-header p{color:#334155;font-size:.88rem;margin:0;font-weight:500;}\r\n.pth-ie-tabs{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:16px;border-bottom:2px solid #e2e8f0;padding-bottom:10px;}\r\n.pth-ie-tab-btn{background:#fff;border:2px solid #e2e8f0;color:#334155;font-size:.85rem;font-weight:700;padding:9px 16px;border-radius:8px;cursor:pointer;font-family:'Inter',system-ui,sans-serif;white-space:nowrap;transition:all .15s;}\r\n.pth-ie-tab-btn:hover{border-color:#2563eb;color:#1d4ed8;background:#eff6ff;}\r\n.pth-ie-tab-btn.pth-ie-active{background:#2563eb;border-color:#2563eb;color:#fff;}\r\n.pth-ie-panel{display:none;opacity:1;}\r\n.pth-ie-panel.pth-ie-panel-active{display:block;}\r\n.pth-ie-empty{background:#fff;border:1px dashed #cbd5e1;border-radius:12px;padding:30px 20px;text-align:center;color:#334155;font-weight:600;min-height:120px;}\r\n@media(max-width:768px){#pth-ie-wrapper{padding:10px;border-radius:0;background:transparent;}.pth-ie-tab-btn{font-size:.78rem;padding:7px 12px;}.pth-ie-header h2{font-size:1.2rem;}}\r\n<\/style>\r\n\r\n<div class=\"pth-ie-header\">\r\n  <div class=\"pth-ie-meta-bar\">\r\n    <span class=\"pth-ie-version-badge\">v1.0<\/span>\r\n    <span class=\"pth-ie-status-offline\">\ud83d\udd12 100% Offline<\/span>\r\n  <\/div>\r\n  <h2>\ud83e\ude84 AI Image Eraser<\/h2>\r\n  <p>Remove backgrounds and erase unwanted objects from your photos \u2014 right in your browser. No upload, no login.<\/p>\r\n<\/div>\r\n\r\n<div class=\"pth-ie-tabs\" role=\"tablist\" aria-label=\"AI Image Eraser tools\">\r\n  <button class=\"pth-ie-tab-btn pth-ie-active\" data-tab=\"bg\"     role=\"tab\" aria-selected=\"true\">\ud83c\udfaf Background Remover<\/button>\r\n  <button class=\"pth-ie-tab-btn\"               data-tab=\"eraser\" role=\"tab\" aria-selected=\"false\">\ud83e\ude84 Magic Eraser<\/button>\r\n\t <button class=\"pth-ie-tab-btn\"               data-tab=\"upscale\" role=\"tab\" aria-selected=\"false\">\u2b06\ufe0f AI Upscaler<\/button>\r\n<\/div>\r\n\r\n<div class=\"pth-ie-panel pth-ie-panel-active\" id=\"pth-ie-tab-bg\" role=\"tabpanel\">\r\n  <div class=\"pth-ie-empty\" id=\"pth-ie-empty-bg\">Loading Background Remover\u2026<\/div>\r\n<\/div>\r\n<div class=\"pth-ie-panel\" id=\"pth-ie-tab-eraser\" role=\"tabpanel\">\r\n  <div class=\"pth-ie-empty\" id=\"pth-ie-empty-eraser\">Loading Magic Eraser\u2026<\/div>\r\n<\/div>\r\n\t<div class=\"pth-ie-panel\" id=\"pth-ie-tab-upscale\" role=\"tabpanel\">\r\n  <div class=\"pth-ie-empty\" id=\"pth-ie-empty-upscale\">Loading AI Upscaler\u2026<\/div>\r\n<\/div>\r\n\r\n<\/div>\r\n<script data-no-optimize=\"1\" data-no-minify=\"1\" data-cfasync=\"false\">\r\n(function () {\r\n  'use strict';\r\n  window.pthIE = window.pthIE || {};\r\n  window.pthIE.activeTab = 'bg';\r\n\r\n  function initTabs() {\r\n    var root = document.getElementById('pth-ie-wrapper');\r\n    if (!root) return;\r\n    var btns = root.querySelectorAll('.pth-ie-tab-btn');\r\n    btns.forEach(function (btn) {\r\n      btn.addEventListener('click', function () {\r\n        var tab = btn.getAttribute('data-tab');\r\n        btns.forEach(function (b) {\r\n          b.classList.remove('pth-ie-active');\r\n          b.setAttribute('aria-selected', 'false');\r\n        });\r\n        btn.classList.add('pth-ie-active');\r\n        btn.setAttribute('aria-selected', 'true');\r\n        root.querySelectorAll('.pth-ie-panel').forEach(function (p) {\r\n          p.classList.remove('pth-ie-panel-active');\r\n        });\r\n        var panel = document.getElementById('pth-ie-tab-' + tab);\r\n        if (panel) panel.classList.add('pth-ie-panel-active');\r\n        window.pthIE.activeTab = tab;\r\n        document.dispatchEvent(new CustomEvent('pthIETabActive', { detail: { tab: tab } }));\r\n      });\r\n    });\r\n\r\n    \/* Deep-link: ?tab=bg \/ ?tab=eraser *\/\r\n    try {\r\n      var want = new URLSearchParams(window.location.search).get('tab');\r\n      if (want === 'bg' || want === 'eraser' || want === 'upscale') {\r\n        var target = root.querySelector('.pth-ie-tab-btn[data-tab=\"' + want + '\"]');\r\n        if (target) target.click();\r\n      }\r\n    } catch (e) {}\r\n  }\r\n\r\n  function runInit() {\r\n    if (window.pthIE.shellReady) return;\r\n    if (!document.getElementById('pth-ie-wrapper')) return;\r\n    window.pthIE.shellReady = true;\r\n    initTabs();\r\n  }\r\n\r\n  runInit();\r\n  if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', runInit); }\r\n  window.addEventListener('load', function () { setTimeout(runInit, 50); });\r\n  if (!window.pthIE.shellReady && typeof MutationObserver !== 'undefined') {\r\n    var obs = new MutationObserver(function () {\r\n      if (document.getElementById('pth-ie-wrapper')) { obs.disconnect(); runInit(); }\r\n    });\r\n    obs.observe(document.body || document.documentElement, { childList: true, subtree: true });\r\n    setTimeout(function () { obs.disconnect(); }, 10000);\r\n  }\r\n})();\r\n<\/script>\n\n\n<link rel=\"stylesheet\" href=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/cropperjs\/1.5.13\/cropper.min.css\">\r\n<script src=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/cropperjs\/1.5.13\/cropper.min.js\"><\/script>\r\n\r\n<style>\r\n\/* ==========================================================================\r\n   PRIME TOOL HUB - AI BACKGROUND REMOVER PRO v3.7\r\n   Engine: v1.7.0 (ESM) | NEW: Firefox Detection & First Time Download Note\r\n   ========================================================================== *\/\r\n#pth-ai-bg-remover-wrapper { box-sizing: border-box; font-family: 'Inter', system-ui, -apple-system, sans-serif; color: #0f172a; background-color: #ffffff; border-radius: 12px; overflow: hidden; border: 1px solid #e2e8f0; margin: 20px 0; box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.05); transition: all 0.3s ease; position: relative; }\r\n#pth-ai-bg-remover-wrapper * { box-sizing: border-box; }\r\n\r\n\/* TRUE FULL SCREEN *\/\r\n#pth-ai-bg-remover-wrapper.is-fullscreen { position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; z-index: 999999; margin: 0; border-radius: 0; overflow-y: auto; display: flex; flex-direction: column; background: #f8fafc; }\r\n#pth-ai-bg-remover-wrapper.is-fullscreen .pth-main-area { flex: 1; max-width: 1400px; margin: 0 auto; width: 100%; }\r\n\r\n\/* Header *\/\r\n#pth-ai-bg-remover-wrapper .pth-header { padding: 24px 24px 0 24px; display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; flex-wrap: wrap; gap: 12px; }\r\n#pth-ai-bg-remover-wrapper .pth-title { margin: 0; font-size: 1.5rem; font-weight: 800; color: #3b82f6; display: flex; align-items: center; gap: 8px; }\r\n#pth-ai-bg-remover-wrapper .pth-btn { border: none; padding: 10px 18px; font-size: 0.875rem; border-radius: 8px; cursor: pointer; font-weight: 700; display: inline-flex; align-items: center; justify-content: center; gap: 6px; transition: all 0.2s; }\r\n#pth-ai-bg-remover-wrapper .pth-btn.danger { background: #fee2e2; color: #991b1b; }\r\n#pth-ai-bg-remover-wrapper .pth-btn.danger:hover { background: #fecaca; }\r\n#pth-ai-bg-remover-wrapper .pth-btn.primary { background: #3b82f6; color: #ffffff; box-shadow: 0 4px 10px rgba(59, 130, 246, 0.25); }\r\n#pth-ai-bg-remover-wrapper .pth-btn.primary:hover { background: #2563eb; transform: translateY(-2px); }\r\n#pth-ai-bg-remover-wrapper .pth-btn.success { background: #10b981; color: #ffffff; box-shadow: 0 4px 10px rgba(16, 185, 129, 0.25); font-size: 1rem; padding: 12px 24px;}\r\n#pth-ai-bg-remover-wrapper .pth-btn.success:hover { background: #059669; transform: translateY(-2px); }\r\n#pth-ai-bg-remover-wrapper .pth-fullwidth-btn { background: #1e293b; color: #fff; }\r\n#pth-ai-bg-remover-wrapper .pth-fullwidth-btn:hover { background: #0f172a; }\r\n\r\n\/* Main Area & Grid *\/\r\n#pth-ai-bg-remover-wrapper .pth-main-area { padding: 0 24px 24px 24px; }\r\n#pth-ai-bg-remover-wrapper .pth-content-grid { display: grid; grid-template-columns: 1.8fr 1fr; gap: 24px; }\r\n@media (max-width: 900px) { #pth-ai-bg-remover-wrapper .pth-content-grid { grid-template-columns: 1fr; } }\r\n\r\n\/* Inputs & Crop *\/\r\n#pth-ai-bg-remover-wrapper .pth-drop-zone { border: 2px dashed #93c5fd; border-radius: 12px; padding: 40px 20px; text-align: center; background: #f8fafc; transition: all 0.3s; cursor: pointer; margin-bottom: 20px; position: relative;}\r\n#pth-ai-bg-remover-wrapper .pth-drop-zone:hover, #pth-ai-bg-remover-wrapper .pth-drop-zone.active { border-color: #3b82f6; background: #eff6ff; }\r\n#pth-ai-bg-remover-wrapper .pth-dz-icon { font-size: 40px; margin-bottom: 10px; }\r\n#pth-ai-bg-remover-wrapper .pth-dz-text { font-size: 1rem; font-weight: 700; color: #1e3a8a; margin: 0 0 5px 0; }\r\n#pth-ai-bg-remover-wrapper .pth-dz-sub { font-size: 0.85rem; color: #64748b; margin: 0; }\r\n#pth-ai-bg-remover-wrapper .pth-or-section { text-align: center; margin: 12px 0; color: #64748b; font-size: 0.875rem; font-weight: 600; }\r\n#pth-ai-bg-remover-wrapper .pth-url-group { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 20px; justify-content: center;}\r\n#pth-ai-bg-remover-wrapper .pth-url-group input { flex: 1; min-width: 200px; padding: 10px 16px; border: 1px solid #cbd5e1; border-radius: 8px; font-size: 0.95rem; outline: none;}\r\n#pth-ai-bg-remover-wrapper .pth-url-group input:focus { border-color: #3b82f6; }\r\n\r\n#pth-ai-bg-remover-wrapper .pth-crop-area { display: none; background: #f8fafc; border: 1px solid #e2e8f0; border-radius: 12px; padding: 20px; margin-bottom: 20px; text-align: center; }\r\n#pth-ai-bg-remover-wrapper .pth-crop-container { width: 100%; max-height: 500px; margin-bottom: 15px; background: #e2e8f0; border-radius: 8px; overflow: hidden; }\r\n#pth-ai-bg-remover-wrapper .pth-crop-container img { max-width: 100%; display: block; }\r\n#pth-ai-bg-remover-wrapper .pth-crop-actions { display: flex; justify-content: center; gap: 15px; flex-wrap: wrap; }\r\n#pth-ai-bg-remover-wrapper .pth-aspect-presets { display: flex; gap: 8px; flex-wrap: wrap; justify-content: center; margin: 15px 0; }\r\n#pth-ai-bg-remover-wrapper .pth-aspect-btn { padding: 6px 14px; font-size: 0.8rem; background: #e2e8f0; border-radius: 9999px; cursor: pointer; font-weight: 600; border: none; transition: background 0.2s;}\r\n#pth-ai-bg-remover-wrapper .pth-aspect-btn.active { background: #3b82f6; color: #fff; }\r\n\r\n\/* Progress & Scanning *\/\r\n#pth-ai-bg-remover-wrapper .pth-progress-area { display: none; background: #ffffff; border: 1px solid #e2e8f0; border-radius: 12px; padding: 25px; margin-bottom: 20px; text-align: center; }\r\n#pth-ai-bg-remover-wrapper .pth-progress-title { font-size: 1rem; font-weight: 800; color: #0f172a; margin: 0 0 15px 0; }\r\n#pth-ai-bg-remover-wrapper .pth-progress-sub { font-size: 0.85rem; color: #64748b; margin: 0 0 5px 0; font-family: monospace;}\r\n#pth-ai-bg-remover-wrapper .pth-progress-bar-wrap { width: 100%; height: 12px; background: #e2e8f0; border-radius: 10px; overflow: hidden; margin-bottom: 10px; }\r\n#pth-ai-bg-remover-wrapper .pth-progress-bar { height: 100%; background: linear-gradient(90deg, #3b82f6, #60a5fa); width: 0%; transition: width 0.3s ease; border-radius: 10px; }\r\n\r\n#pth-ai-bg-remover-wrapper .pth-first-time-note { font-size: 0.8rem; color: #3b82f6; font-weight: 600; margin-top: 8px; background: #eff6ff; padding: 6px; border-radius: 6px; display: inline-block; }\r\n#pth-ai-bg-remover-wrapper .pth-browser-warning { display: none; font-size: 0.85rem; color: #b45309; background: #fef3c7; padding: 10px; border-radius: 8px; margin-top: 12px; border: 1px solid #fde68a; font-weight: 600; }\r\n\r\n#pth-ai-bg-remover-wrapper .pth-scanning-wrapper { position: relative; max-width: 250px; margin: 0 auto 15px auto; border-radius: 8px; overflow: hidden; border: 2px solid #8b5cf6; display: none; box-shadow: 0 0 20px rgba(139, 92, 246, 0.3); }\r\n#pth-ai-bg-remover-wrapper .pth-scanning-img { width: 100%; display: block; opacity: 0.6; filter: grayscale(80%); }\r\n#pth-ai-bg-remover-wrapper .pth-scanner-line { position: absolute; top: 0; left: 0; width: 100%; height: 3px; background: #d946ef; box-shadow: 0 0 15px 5px rgba(217, 70, 239, 0.8); animation: pthScanAnim 1.2s ease-in-out infinite alternate; }\r\n@keyframes pthScanAnim { 0% { top: 0%; } 100% { top: 98%; } }\r\n\r\n\/* Preview Box *\/\r\n#pth-ai-bg-remover-wrapper .pth-preview-box { border: 1px solid #e2e8f0; border-radius: 12px; overflow: hidden; margin-bottom: 20px; display: none; background: #fff;}\r\n#pth-ai-bg-remover-wrapper .pth-preview-header { background: #f1f5f9; padding: 12px 15px; border-bottom: 1px solid #e2e8f0; font-weight: 800; color: #0f172a; display: flex; justify-content: space-between; align-items: center; }\r\n#pth-ai-bg-remover-wrapper .pth-checkerboard { background-image: linear-gradient(45deg, #e2e8f0 25%, transparent 25%), linear-gradient(-45deg, #e2e8f0 25%, transparent 25%), linear-gradient(45deg, transparent 75%, #e2e8f0 75%), linear-gradient(-45deg, transparent 75%, #e2e8f0 75%); background-size: 20px 20px; background-position: 0 0, 0 10px, 10px -10px, -10px 0px; padding: 20px; display: flex; justify-content: center; align-items: center; min-height: 320px; position: relative; overflow: hidden;}\r\n#pth-ai-bg-remover-wrapper .pth-preview-bg { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: transparent; z-index: 1; transition: background 0.3s;}\r\n#pth-ai-bg-remover-wrapper .pth-compare-wrap { position: relative; display: inline-block; max-width: 100%; z-index: 2; user-select: none; line-height: 0; }\r\n#pth-ai-bg-remover-wrapper .pth-img-result { max-width: 100%; max-height: 550px; height: auto; display: block; }\r\n#pth-ai-bg-remover-wrapper .pth-img-before { position: absolute; top: 0; left: 0; width: 50%; height: 100%; overflow: hidden; border-right: 3px solid #fff; box-shadow: 3px 0 8px rgba(0,0,0,0.25);}\r\n#pth-ai-bg-remover-wrapper .pth-img-before img { max-width: none; height: 100%; display: block; object-fit: contain;}\r\n#pth-ai-bg-remover-wrapper .pth-compare-slider { position: absolute; top: 0; left: 0; width: 100%; height: 100%; opacity: 0; z-index: 4; cursor: ew-resize; margin: 0;}\r\n\r\n\/* Settings *\/\r\n#pth-ai-bg-remover-wrapper .pth-settings-grid { display: none; background: #f8fafc; padding: 20px; border-radius: 12px; border: 1px solid #e2e8f0; margin-bottom: 20px;}\r\n#pth-ai-bg-remover-wrapper .pth-settings-section { margin-bottom: 20px; }\r\n#pth-ai-bg-remover-wrapper .pth-bg-presets { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 10px; align-items: center;}\r\n#pth-ai-bg-remover-wrapper .pth-bg-preset { width: 40px; height: 40px; border-radius: 8px; border: 2px solid #cbd5e1; cursor: pointer; transition: all 0.2s; display:flex; align-items:center; justify-content:center;}\r\n#pth-ai-bg-remover-wrapper .pth-bg-preset.active { border-color: #3b82f6; box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.3); }\r\n#pth-ai-bg-remover-wrapper .pth-custom-bg-btn { background: #e2e8f0; font-size: 0.85rem; font-weight: 600; width: auto; padding: 0 15px; gap: 8px; color: #1e293b; }\r\n\r\n\/* Sidebar & Extras *\/\r\n#pth-ai-bg-remover-wrapper .pth-sidebar { background: #f1f5f9; border: 1px solid #e2e8f0; border-radius: 12px; padding: 20px; height: fit-content; }\r\n#pth-ai-bg-remover-wrapper .pth-sidebar h4 { margin: 0 0 15px 0; font-size: 1.1rem; color: #0f172a; border-bottom: 2px solid #cbd5e1; padding-bottom: 10px;}\r\n#pth-ai-bg-remover-wrapper .pth-sidebar ul { padding-left: 0; list-style: none; margin: 0 0 20px 0;}\r\n#pth-ai-bg-remover-wrapper .pth-sidebar li { margin-bottom: 12px; display: flex; align-items: flex-start; gap: 10px; font-size: 0.9rem; color: #334155;}\r\n#pth-ai-bg-remover-wrapper .pth-toast { position: fixed; bottom: 20px; right: 20px; background: #10b981; color: #fff; padding: 12px 24px; border-radius: 8px; box-shadow: 0 10px 25px -5px rgba(0,0,0,0.2); display: none; align-items: center; gap: 12px; z-index: 9999999; font-weight: 700; font-size: 14px; }\r\n#pth-ai-bg-remover-wrapper .pth-toast.show { display: flex; animation: pthToastFade 0.3s ease; }\r\n#pth-ai-bg-remover-wrapper .pth-output-control { display: flex; align-items: center; gap: 12px; margin-bottom: 12px; }\r\n#pth-ai-bg-remover-wrapper .pth-output-control label { font-weight: 600; font-size: 0.85rem; min-width: 110px; }\r\n#pth-ai-bg-remover-wrapper select, #pth-ai-bg-remover-wrapper input[type=\"range\"] { flex: 1; padding: 6px; border-radius: 6px; border: 1px solid #cbd5e1;}\r\n<\/style>\r\n\r\n<div id=\"pth-ai-bg-remover-wrapper\">\r\n    <div id=\"pth-toast-bg-rm\" class=\"pth-toast\">\u2705 Action Successful!<\/div>\r\n    \r\n    <div class=\"pth-header\">\r\n        <h2 class=\"pth-title\">\u2728 AI Background Remover Pro <span style=\"font-size:0.75rem; background:#3b82f6; color:#fff; padding:2px 8px; border-radius:9999px;\">v3.7<\/span><\/h2>\r\n        <div style=\"display:flex; gap:8px; flex-wrap: wrap;\">\r\n            <button class=\"pth-btn pth-fullwidth-btn\" id=\"pth-fw-btn-ai-bg-remover\" title=\"Toggle Full Screen\">\u26f6 Full Screen<\/button>\r\n            <button class=\"pth-btn danger\" id=\"pth-clear-btn\" style=\"display:none;\">\ud83d\udd04 Try Another Image<\/button>\r\n        <\/div>\r\n    <\/div>\r\n    \r\n    <div class=\"pth-main-area\">\r\n        <div class=\"pth-content-grid\" id=\"pth-ai-bg-remover-layout\">\r\n            \r\n            <div class=\"pth-main-col\">\r\n                <input type=\"file\" id=\"pth-image-file\" accept=\"image\/*\" style=\"display:none;\">\r\n                <div id=\"pth-input-area\">\r\n                    <div class=\"pth-drop-zone\" id=\"pth-drop-zone\">\r\n                        <div class=\"pth-dz-icon\">\ud83d\udcf8<\/div>\r\n                        <h3 class=\"pth-dz-text\">Click or Drag & Drop an Image<\/h3>\r\n                        <p class=\"pth-dz-sub\">100% Secure \u2022 Processed locally \u2022 Supports JPG, PNG, WebP<\/p>\r\n                    <\/div>\r\n                    <div class=\"pth-or-section\">\u2014 OR \u2014<\/div>\r\n                    <div class=\"pth-url-group\">\r\n                        <input type=\"text\" id=\"pth-url-input\" placeholder=\"https:\/\/example.com\/image.jpg\">\r\n                        <button class=\"pth-btn primary\" id=\"pth-load-url-btn\">\ud83d\udd17 Load URL<\/button>\r\n                        <button class=\"pth-btn primary\" id=\"pth-paste-btn\">\ud83d\udccb Paste<\/button>\r\n                        <button class=\"pth-btn\" id=\"pth-load-sample-btn\" style=\"background: #f59e0b; color: white;\">\ud83d\uddbc\ufe0f Try Sample<\/button>\r\n                    <\/div>\r\n                <\/div>\r\n                \r\n                <div class=\"pth-crop-area\" id=\"pth-crop-area\">\r\n                    <h3 style=\"margin-top:0; color:#0f172a;\">\u2702\ufe0f Adjust & Crop Image<\/h3>\r\n                    <p style=\"font-size:0.85rem; color:#64748b; margin-bottom: 15px;\">Focus on the main subject for better AI results.<\/p>\r\n                    <div class=\"pth-crop-container\">\r\n                        <img decoding=\"async\" id=\"pth-crop-img\" src=\"\" alt=\"AI background remover crop area\">\r\n                    <\/div>\r\n                    <div class=\"pth-aspect-presets\" id=\"pth-aspect-presets\">\r\n                        <button class=\"pth-aspect-btn active\" data-ratio=\"NaN\">Free<\/button>\r\n                        <button class=\"pth-aspect-btn\" data-ratio=\"1\/1\">1:1<\/button>\r\n                        <button class=\"pth-aspect-btn\" data-ratio=\"16\/9\">16:9<\/button>\r\n                        <button class=\"pth-aspect-btn\" data-ratio=\"9\/16\">9:16<\/button>\r\n                        <button class=\"pth-aspect-btn\" data-ratio=\"4\/3\">4:3<\/button>\r\n                        <button class=\"pth-aspect-btn\" data-ratio=\"3\/4\">3:4<\/button>\r\n                    <\/div>\r\n                    <div class=\"pth-crop-actions\">\r\n                        <button class=\"pth-btn success\" id=\"pth-start-ai-btn\">\u2728 Remove Background Now<\/button>\r\n                        <button class=\"pth-btn danger\" id=\"pth-cancel-crop-btn\">Cancel<\/button>\r\n                    <\/div>\r\n                <\/div>\r\n                \r\n                <div class=\"pth-progress-area\" id=\"pth-progress-area\">\r\n                    <h3 class=\"pth-progress-title\" id=\"pth-progress-heading\">\ud83e\udd16 AI is Analyzing...<\/h3>\r\n                    \r\n                    <div class=\"pth-progress-bar-wrap\" id=\"pth-prog-bar-wrap\">\r\n                        <div class=\"pth-progress-bar\" id=\"pth-progress-bar\"><\/div>\r\n                    <\/div>\r\n                    \r\n                    <div class=\"pth-scanning-wrapper\" id=\"pth-scanning-wrapper\">\r\n                        <img decoding=\"async\" id=\"pth-scanning-img\" class=\"pth-scanning-img\" src=\"\" alt=\"\">\r\n                        <div class=\"pth-scanner-line\"><\/div>\r\n                    <\/div>\r\n                    \r\n                    <p class=\"pth-progress-sub\" id=\"pth-progress-sub\">Preparing AI Engine...<\/p>\r\n                    \r\n                    <!-- \ud83c\udf1f NEW: First Time Download Note -->\r\n                    <div class=\"pth-first-time-note\" id=\"pth-first-time-note\" style=\"display: none;\">\r\n                        \ud83d\udca1 Note: The AI Engine (~35MB) is downloaded ONLY on your first visit!\r\n                    <\/div>\r\n                    \r\n                    <!-- \ud83c\udf1f NEW: Firefox Warning -->\r\n                    <div class=\"pth-browser-warning\" id=\"pth-browser-warning\">\r\n                        \u26a0\ufe0f <strong>Firefox Detected:<\/strong> If the download gets stuck at 0%, please use <strong>Google Chrome<\/strong> for the best AI performance.\r\n                    <\/div>\r\n                <\/div>\r\n                \r\n                <div class=\"pth-preview-box\" id=\"pth-preview-box\">\r\n                    <div class=\"pth-preview-header\">\r\n                        <span>\ud83d\uddbc\ufe0f AI Result Preview<\/span>\r\n                        <label style=\"display:flex; align-items:center; gap:6px; font-size:0.85rem; cursor:pointer;\">\r\n                            <input type=\"checkbox\" id=\"pth-compare-toggle\" checked style=\"accent-color:#3b82f6; width: 16px; height: 16px;\"> Show Before\/After Slider\r\n                        <\/label>\r\n                    <\/div>\r\n                    <div class=\"pth-checkerboard\" id=\"pth-checkerboard\">\r\n                        <div class=\"pth-preview-bg\" id=\"pth-preview-bg\"><\/div>\r\n                        <div class=\"pth-compare-wrap\" id=\"pth-compare-wrap\">\r\n                            <img decoding=\"async\" id=\"pth-img-result\" class=\"pth-img-result\" src=\"\" alt=\"AI background remover result\">\r\n                            <div class=\"pth-img-before\" id=\"pth-img-before-box\">\r\n                                <img decoding=\"async\" id=\"pth-img-orig\" src=\"\" alt=\"Original image\">\r\n                            <\/div>\r\n                            <input type=\"range\" min=\"0\" max=\"100\" value=\"50\" class=\"pth-compare-slider\" id=\"pth-compare-slider\">\r\n                        <\/div>\r\n                    <\/div>\r\n                    <div class=\"pth-info-bar\" id=\"pth-info-bar\" style=\"display:none; justify-content: space-between; background: #f1f5f9; padding: 12px 16px; border-top: 1px solid #e2e8f0; font-size: 0.85rem; color: #475569; flex-wrap: wrap; gap:10px;\">\r\n                        <div>\ud83d\udccf <strong id=\"pth-dimensions\">\u2014 \u00d7 \u2014 px<\/strong><\/div>\r\n                        <div>\u23f1\ufe0f Time: <strong id=\"pth-proc-time\">0.0s<\/strong><\/div>\r\n                        <div>\ud83d\udce6 Size: <strong id=\"pth-size-info\">\u2014 KB<\/strong><\/div>\r\n                    <\/div>\r\n                    <div class=\"pth-action-bar\" id=\"pth-action-bar\" style=\"padding: 15px; background: #fff; border-top: 1px solid #e2e8f0; display:flex; justify-content:center; gap:10px; flex-wrap:wrap;\">\r\n                        <button class=\"pth-btn primary\" id=\"pth-download-btn\">\ud83d\udce5 Download HD<\/button>\r\n                        <button class=\"pth-btn primary\" id=\"pth-copy-btn\">\ud83d\udccb Copy Result<\/button>\r\n                        <button class=\"pth-btn primary\" id=\"pth-print-btn\" style=\"background:#475569;\">\ud83d\udda8\ufe0f Print<\/button>\r\n                    <\/div>\r\n                <\/div>\r\n                \r\n                <div class=\"pth-settings-grid\" id=\"pth-settings-area\">\r\n                    <div class=\"pth-settings-section\">\r\n                        <label style=\"font-size: 0.85rem; font-weight: 700; color: #475569; text-transform: uppercase;\">\ud83c\udfa8 Background Options<\/label>\r\n                        <div class=\"pth-bg-presets\" id=\"pth-bg-presets\">\r\n                            <button class=\"pth-bg-preset active\" data-color=\"transparent\" style=\"background:repeating-linear-gradient(45deg,#e2e8f0,#e2e8f0 8px,#f8fafc 8px,#f8fafc 16px);\" title=\"Transparent\"><\/button>\r\n                            <button class=\"pth-bg-preset\" data-color=\"#ffffff\" style=\"background:#ffffff;\" title=\"White\"><\/button>\r\n                            <button class=\"pth-bg-preset\" data-color=\"#000000\" style=\"background:#000000;\" title=\"Black\"><\/button>\r\n                            <button class=\"pth-bg-preset\" data-color=\"#3b82f6\" style=\"background:#3b82f6;\" title=\"Blue\"><\/button>\r\n                            <button class=\"pth-bg-preset\" data-color=\"linear-gradient(135deg, #3b82f6, #10b981)\" data-type=\"gradient\" data-c1=\"#3b82f6\" data-c2=\"#10b981\" title=\"Blue-Green Gradient\"><\/button>\r\n                            <button class=\"pth-bg-preset\" data-color=\"linear-gradient(135deg, #ec4899, #f59e0b)\" data-type=\"gradient\" data-c1=\"#ec4899\" data-c2=\"#f59e0b\" title=\"Pink-Orange Gradient\"><\/button>\r\n                            <input type=\"color\" id=\"pth-custom-color\" value=\"#8b5cf6\" style=\"width:40px; height:40px; padding:0; border:2px solid #cbd5e1; border-radius:8px; cursor:pointer;\" title=\"Custom Solid Color\">\r\n                            <div style=\"width: 2px; height: 30px; background: #cbd5e1; margin: 0 5px;\"><\/div>\r\n                            <button class=\"pth-bg-preset pth-custom-bg-btn\" id=\"pth-custom-bg-btn\" title=\"Upload Custom Background\"><span>\ud83d\uddbc\ufe0f<\/span> Custom Image BG<\/button>\r\n                            <input type=\"file\" id=\"pth-custom-bg-upload\" accept=\"image\/*\" style=\"display:none;\">\r\n                        <\/div>\r\n                    <\/div>\r\n                    <div class=\"pth-settings-section\">\r\n                        <label style=\"font-size: 0.85rem; font-weight: 700; color: #475569; text-transform: uppercase;\">\ud83d\udce4 Output Settings<\/label>\r\n                        <div class=\"pth-output-control\">\r\n                            <label>Format<\/label>\r\n                            <select id=\"pth-output-format\">\r\n                                <option value=\"png\">PNG (Transparent)<\/option>\r\n                                <option value=\"jpeg\">JPG<\/option>\r\n                                <option value=\"webp\">WebP<\/option>\r\n                            <\/select>\r\n                        <\/div>\r\n                        <div class=\"pth-output-control\" id=\"pth-quality-row\">\r\n                            <label>Quality <span id=\"pth-quality-val\">95<\/span>%<\/label>\r\n                            <input type=\"range\" id=\"pth-quality-slider\" min=\"1\" max=\"100\" value=\"95\">\r\n                        <\/div>\r\n                        <div class=\"pth-output-control\">\r\n                            <label>Resize<\/label>\r\n                            <select id=\"pth-resize-preset\">\r\n                                <option value=\"0\">Original<\/option>\r\n                                <option value=\"1024\">HD (1024 px)<\/option>\r\n                                <option value=\"2048\" selected>2K (2048 px)<\/option>\r\n                                <option value=\"4096\">4K (4096 px)<\/option>\r\n                            <\/select>\r\n                        <\/div>\r\n                    <\/div>\r\n                <\/div>\r\n            <\/div>\r\n            \r\n            <div class=\"pth-sidebar-col\" id=\"pth-ai-bg-remover-sidebar\">\r\n                <div class=\"pth-sidebar\">\r\n                    <h4>\ud83d\udca1 Pro Tips for Perfect Results<\/h4>\r\n                    <ul>\r\n                        <li>\u2702\ufe0f <b>Crop First:<\/b> Focus on the subject. Use aspect ratio presets for faster processing.<\/li>\r\n                        <li>\ud83d\uddbc\ufe0f <b>Custom Backgrounds:<\/b> Click \"Custom Image BG\" to upload your own scenic background!<\/li>\r\n                        <li>\ud83d\udfe8 <b>Output Options:<\/b> Choose PNG for transparency or JPG\/WebP for smaller files.<\/li>\r\n                    <\/ul>\r\n                    <div style=\"margin-top: 20px; padding: 15px; background: #e0f2fe; border-radius: 8px; border: 1px solid #bae6fd;\">\r\n                        <strong style=\"color: #0369a1; display:block; margin-bottom:5px;\">\ud83d\udd12 100% Privacy<\/strong>\r\n                        <span style=\"font-size: 0.85rem; color: #0c4a6e;\">AI runs 100% in your browser. Nothing is uploaded.<\/span>\r\n                    <\/div>\r\n                <\/div>\r\n            <\/div>\r\n        <\/div>\r\n    <\/div>\r\n<\/div>\r\n\r\n<script type=\"module\" data-no-optimize=\"1\" data-no-minify=\"1\" data-cfasync=\"false\">\r\n    import { removeBackground } from \"https:\/\/esm.sh\/@imgly\/background-removal@1.7.0\";\r\n    \r\n    (function() {\r\n        window.pthAiBgRemoverApp = {\r\n            initialized: false,\r\n            currentResultBlob: null,\r\n            selectedBgColor: 'transparent',\r\n            selectedBgType: 'solid',\r\n            gradColor1: '', gradColor2: '',\r\n            customBgImageObj: null,\r\n            startTime: 0,\r\n            originalFileSizeKB: 0,\r\n            cropperInstance: null,\r\n            croppedBlobForPreview: null,\r\n            isFirefox: navigator.userAgent.toLowerCase().indexOf('firefox') > -1,\r\n\r\n            init: function() {\r\n                this.cacheDOM();\r\n                this.attachEvents();\r\n            },\r\n\r\n            cacheDOM: function() {\r\n                this.UI = {\r\n                    wrapper: document.getElementById('pth-ai-bg-remover-wrapper'),\r\n                    inputArea: document.getElementById('pth-input-area'),\r\n                    cropArea: document.getElementById('pth-crop-area'),\r\n                    cropImg: document.getElementById('pth-crop-img'),\r\n                    startAiBtn: document.getElementById('pth-start-ai-btn'),\r\n                    cancelCropBtn: document.getElementById('pth-cancel-crop-btn'),\r\n                    dz: document.getElementById('pth-drop-zone'),\r\n                    fileIn: document.getElementById('pth-image-file'),\r\n                    urlInput: document.getElementById('pth-url-input'),\r\n                    loadUrlBtn: document.getElementById('pth-load-url-btn'),\r\n                    pasteBtn: document.getElementById('pth-paste-btn'),\r\n                    sampleBtn: document.getElementById('pth-load-sample-btn'),\r\n                    progArea: document.getElementById('pth-progress-area'),\r\n                    progHeading: document.getElementById('pth-progress-heading'),\r\n                    progBarWrap: document.getElementById('pth-prog-bar-wrap'),\r\n                    progBar: document.getElementById('pth-progress-bar'),\r\n                    scanningWrapper: document.getElementById('pth-scanning-wrapper'),\r\n                    scanningImg: document.getElementById('pth-scanning-img'),\r\n                    progSub: document.getElementById('pth-progress-sub'),\r\n                    firstTimeNote: document.getElementById('pth-first-time-note'),\r\n                    browserWarning: document.getElementById('pth-browser-warning'),\r\n                    prevBox: document.getElementById('pth-preview-box'),\r\n                    imgOrig: document.getElementById('pth-img-orig'),\r\n                    imgRes: document.getElementById('pth-img-result'),\r\n                    beforeBox: document.getElementById('pth-img-before-box'),\r\n                    slider: document.getElementById('pth-compare-slider'),\r\n                    togComp: document.getElementById('pth-compare-toggle'),\r\n                    settings: document.getElementById('pth-settings-area'),\r\n                    bgColors: document.querySelectorAll('.pth-bg-preset:not(#pth-custom-bg-btn)'),\r\n                    custColor: document.getElementById('pth-custom-color'),\r\n                    customBgBtn: document.getElementById('pth-custom-bg-btn'),\r\n                    customBgUpload: document.getElementById('pth-custom-bg-upload'),\r\n                    prevBg: document.getElementById('pth-preview-bg'),\r\n                    infoBar: document.getElementById('pth-info-bar'),\r\n                    dimensionsEl: document.getElementById('pth-dimensions'),\r\n                    procTimeEl: document.getElementById('pth-proc-time'),\r\n                    sizeInfoEl: document.getElementById('pth-size-info'),\r\n                    clrBtn: document.getElementById('pth-clear-btn'),\r\n                    dwnBtn: document.getElementById('pth-download-btn'),\r\n                    copyBtn: document.getElementById('pth-copy-btn'),\r\n                    printBtn: document.getElementById('pth-print-btn'),\r\n                    fullBtn: document.getElementById('pth-fw-btn-ai-bg-remover'),\r\n                    toast: document.getElementById('pth-toast-bg-rm'),\r\n                    aspectBtns: document.querySelectorAll('.pth-aspect-btn'),\r\n                    outputFormat: document.getElementById('pth-output-format'),\r\n                    qualitySlider: document.getElementById('pth-quality-slider'),\r\n                    qualityVal: document.getElementById('pth-quality-val'),\r\n                    resizePreset: document.getElementById('pth-resize-preset')\r\n                };\r\n            },\r\n\r\n            showToast: function(msg, isError = false) {\r\n                this.UI.toast.innerText = msg;\r\n                this.UI.toast.style.background = isError ? '#ef4444' : '#10b981';\r\n                this.UI.toast.classList.add('show');\r\n                setTimeout(() => this.UI.toast.classList.remove('show'), 3500);\r\n            },\r\n\r\n            attachEvents: function() {\r\n                const self = this;\r\n                \r\n                \/\/ Full screen toggle\r\n                this.UI.fullBtn.addEventListener('click', () => {\r\n                    self.UI.wrapper.classList.toggle('is-fullscreen');\r\n                    self.UI.fullBtn.innerHTML = self.UI.wrapper.classList.contains('is-fullscreen') ? '\u27f2 Exit Full Screen' : '\u26f6 Full Screen';\r\n                    if (self.currentResultBlob) self.syncSliderWidth();\r\n                });\r\n\r\n                \/\/ Aspect Ratios\r\n                this.UI.aspectBtns.forEach(btn => {\r\n                    btn.addEventListener('click', () => {\r\n                        self.UI.aspectBtns.forEach(b => b.classList.remove('active'));\r\n                        btn.classList.add('active');\r\n                        if (self.cropperInstance) {\r\n                            const ratioVal = btn.getAttribute('data-ratio');\r\n                            let ratio = NaN;\r\n                            if(ratioVal !== 'NaN'){\r\n                                const parts = ratioVal.split('\/');\r\n                                ratio = parts.length === 2 ? (parseFloat(parts[0]) \/ parseFloat(parts[1])) : parseFloat(ratioVal);\r\n                            }\r\n                            self.cropperInstance.setAspectRatio(ratio);\r\n                        }\r\n                    });\r\n                });\r\n\r\n                \/\/ Inputs\r\n                this.UI.dz.addEventListener('click', () => self.UI.fileIn.click());\r\n                this.UI.dz.addEventListener('dragover', e => { e.preventDefault(); self.UI.dz.classList.add('active'); });\r\n                this.UI.dz.addEventListener('dragleave', () => self.UI.dz.classList.remove('active'));\r\n                this.UI.dz.addEventListener('drop', e => { e.preventDefault(); self.UI.dz.classList.remove('active'); if (e.dataTransfer.files.length) self.showCropMode(e.dataTransfer.files[0]); });\r\n                this.UI.fileIn.addEventListener('change', e => { if (e.target.files.length) self.showCropMode(e.target.files[0]); });\r\n                \r\n                this.UI.loadUrlBtn.addEventListener('click', async () => {\r\n                    const url = self.UI.urlInput.value.trim();\r\n                    if (!url) return self.showToast('\u26a0\ufe0f Please enter an image URL', true);\r\n                    self.UI.loadUrlBtn.innerText = 'Loading...';\r\n                    try {\r\n                        const res = await fetch(url, { mode: 'cors' });\r\n                        if (!res.ok) throw new Error();\r\n                        const blob = await res.blob();\r\n                        self.showCropMode(blob, true);\r\n                    } catch (err) { self.showToast('\u274c Failed to load URL. (CORS Blocked).', true); }\r\n                    self.UI.loadUrlBtn.innerText = '\ud83d\udd17 Load URL';\r\n                });\r\n                \r\n                this.UI.sampleBtn.addEventListener('click', async () => {\r\n                    self.UI.sampleBtn.innerText = 'Loading...';\r\n                    try {\r\n                        const res = await fetch('https:\/\/schoolict.net\/tools\/sampledata\/bgsample.jpg');\r\n                        if (!res.ok) throw new Error();\r\n                        const blob = await res.blob();\r\n                        self.showCropMode(blob, true);\r\n                    } catch (err) { self.showToast('\u274c Failed to load Sample Image.', true); }\r\n                    self.UI.sampleBtn.innerText = '\ud83d\uddbc\ufe0f Try Sample';\r\n                });\r\n\r\n                this.UI.pasteBtn.addEventListener('click', async () => {\r\n                    try {\r\n                        const items = await navigator.clipboard.read();\r\n                        for (const item of items) {\r\n                            if (item.types.some(t => t.startsWith('image\/'))) {\r\n                                const blob = await item.getType(item.types.find(t => t.startsWith('image\/')));\r\n                                self.showCropMode(blob, true); return;\r\n                            }\r\n                        }\r\n                        self.showToast('\u26a0\ufe0f No image found in clipboard.', true);\r\n                    } catch (err) { self.showToast('\u274c Clipboard access denied.', true); }\r\n                });\r\n\r\n                \/\/ Tool Actions\r\n                this.UI.cancelCropBtn.addEventListener('click', () => self.resetTool());\r\n                this.UI.clrBtn.addEventListener('click', () => self.resetTool());\r\n                this.UI.startAiBtn.addEventListener('click', () => self.startAiProcessing());\r\n\r\n                \/\/ Slider\r\n                this.UI.slider.addEventListener('input', e => { self.UI.beforeBox.style.width = e.target.value + '%'; });\r\n                this.UI.togComp.addEventListener('change', e => {\r\n                    const show = e.target.checked;\r\n                    self.UI.slider.style.display = show ? 'block' : 'none';\r\n                    self.UI.beforeBox.style.display = show ? 'block' : 'none';\r\n                });\r\n                window.addEventListener('resize', () => { if(self.currentResultBlob) self.syncSliderWidth(); });\r\n\r\n                \/\/ Backgrounds\r\n                this.UI.bgColors.forEach(btn => {\r\n                    btn.addEventListener('click', e => {\r\n                        self.UI.bgColors.forEach(b => b.classList.remove('active'));\r\n                        self.clearCustomBg();\r\n                        e.target.classList.add('active');\r\n                        self.selectedBgColor = e.target.getAttribute('data-color');\r\n                        self.selectedBgType = e.target.getAttribute('data-type') || 'solid';\r\n                        if (self.selectedBgType === 'gradient') {\r\n                            self.gradColor1 = e.target.getAttribute('data-c1');\r\n                            self.gradColor2 = e.target.getAttribute('data-c2');\r\n                        }\r\n                        self.UI.prevBg.style.background = self.selectedBgColor;\r\n                    });\r\n                });\r\n                this.UI.custColor.addEventListener('input', e => {\r\n                    self.UI.bgColors.forEach(b => b.classList.remove('active')); self.clearCustomBg();\r\n                    self.selectedBgColor = e.target.value; self.selectedBgType = 'solid'; self.UI.prevBg.style.background = self.selectedBgColor;\r\n                });\r\n                this.UI.customBgBtn.addEventListener('click', () => { self.UI.customBgUpload.click(); });\r\n                this.UI.customBgUpload.addEventListener('change', e => {\r\n                    const file = e.target.files[0];\r\n                    if (!file || !file.type.startsWith('image\/')) return;\r\n                    self.UI.bgColors.forEach(b => b.classList.remove('active')); self.UI.customBgBtn.classList.add('active');\r\n                    const url = URL.createObjectURL(file);\r\n                    self.selectedBgType = 'image'; self.selectedBgColor = 'transparent';\r\n                    self.UI.prevBg.style.background = 'url(' + url + ') center\/cover no-repeat';\r\n                    self.customBgImageObj = new Image(); self.customBgImageObj.src = url;\r\n                });\r\n\r\n                \/\/ Outputs\r\n                this.UI.qualitySlider.addEventListener('input', () => { self.UI.qualityVal.textContent = self.UI.qualitySlider.value; });\r\n                this.UI.dwnBtn.addEventListener('click', () => self.downloadImage());\r\n                this.UI.copyBtn.addEventListener('click', () => self.copyImage());\r\n                this.UI.printBtn.addEventListener('click', () => self.printImage());\r\n            },\r\n\r\n            showCropMode: function(fileOrBlob, fromUrl = false) {\r\n                const file = fileOrBlob instanceof File ? fileOrBlob : new File([fileOrBlob], fromUrl ? 'url-image.jpg' : 'pasted-image.jpg', { type: fileOrBlob.type });\r\n                this.originalFileSizeKB = (file.size \/ 1024).toFixed(1);\r\n                if (!file.type.startsWith('image\/')) return this.showToast('\u26a0\ufe0f Invalid image file.', true);\r\n                const origUrl = URL.createObjectURL(file);\r\n                this.UI.cropImg.src = origUrl;\r\n                this.UI.inputArea.style.display = 'none';\r\n                this.UI.cropArea.style.display = 'block';\r\n                if(this.cropperInstance) this.cropperInstance.destroy();\r\n                \r\n                \/\/ Show Firefox Warning if true\r\n                if(this.isFirefox) {\r\n                    this.UI.browserWarning.style.display = 'block';\r\n                }\r\n\r\n                const self = this;\r\n                this.UI.cropImg.onload = () => {\r\n                    self.cropperInstance = new Cropper(self.UI.cropImg, { viewMode: 1, autoCropArea: 1, responsive: true, background: false, aspectRatio: NaN });\r\n                };\r\n            },\r\n\r\n            startAiProcessing: function() {\r\n                if (!this.cropperInstance) return;\r\n                this.UI.cropArea.style.display = 'none';\r\n                this.UI.clrBtn.style.display = 'inline-flex';\r\n                this.UI.progArea.style.display = 'block';\r\n                this.UI.progBar.style.width = '0%';\r\n                this.UI.progBarWrap.style.display = 'block';\r\n                this.UI.scanningWrapper.style.display = 'none';\r\n                this.UI.firstTimeNote.style.display = 'none';\r\n                this.UI.progHeading.innerText = '\ud83e\udd16 AI is Preparing...';\r\n                this.startTime = Date.now();\r\n                \r\n                const self = this;\r\n                this.cropperInstance.getCroppedCanvas().toBlob(async (croppedBlob) => {\r\n                    self.croppedBlobForPreview = croppedBlob;\r\n                    const imgUrl = URL.createObjectURL(croppedBlob);\r\n                    self.UI.imgOrig.src = imgUrl;\r\n                    self.UI.scanningImg.src = imgUrl;\r\n                    \r\n                    try {\r\n                        const config = {\r\n                            progress: (key, current, total) => {\r\n                                if (key.includes('fetch')) {\r\n                                    self.UI.firstTimeNote.style.display = 'block';\r\n                                    let pct = total > 0 ? Math.round((current \/ total) * 100) : 99;\r\n                                    self.UI.progBar.style.width = pct + '%';\r\n                                    self.UI.progHeading.innerText = '\ud83d\udce5 Downloading AI Models...';\r\n                                    self.UI.progSub.innerText = 'Caching AI Engine (' + pct + '%)...';\r\n                                } else if (key.includes('compute')) {\r\n                                    self.UI.firstTimeNote.style.display = 'none';\r\n                                    self.UI.progBarWrap.style.display = 'none';\r\n                                    self.UI.scanningWrapper.style.display = 'block';\r\n                                    self.UI.progHeading.innerText = '\u2728 Applying AI Magic...';\r\n                                    self.UI.progSub.innerText = 'Scanning and Extracting subject... Please wait.';\r\n                                }\r\n                            }\r\n                        };\r\n                        const resultBlob = await removeBackground(croppedBlob, config);\r\n                        self.currentResultBlob = resultBlob;\r\n                        const procTime = ((Date.now() - self.startTime) \/ 1000).toFixed(1);\r\n                        \r\n                        self.UI.imgRes.onload = () => {\r\n                            self.syncSliderWidth();\r\n                            self.UI.dimensionsEl.textContent = self.UI.imgRes.naturalWidth + ' \u00d7 ' + self.UI.imgRes.naturalHeight + ' px';\r\n                        };\r\n                        self.UI.imgRes.src = URL.createObjectURL(resultBlob);\r\n                        \r\n                        self.UI.progArea.style.display = 'none';\r\n                        self.UI.prevBox.style.display = 'block';\r\n                        self.UI.settings.style.display = 'block';\r\n                        self.UI.infoBar.style.display = 'flex';\r\n                        self.UI.procTimeEl.textContent = procTime + 's';\r\n                        self.UI.sizeInfoEl.innerHTML = 'Cropped <b>' + (croppedBlob.size\/1024).toFixed(1) + ' KB<\/b> \u2192 Result <b>' + (resultBlob.size\/1024).toFixed(1) + ' KB<\/b>';\r\n                        self.showToast('\u2728 Background removed successfully!');\r\n                    } catch (error) {\r\n                        console.error(error);\r\n                        let errMsg = '\u274c Processing failed. Try another image.';\r\n                        if(self.isFirefox) errMsg = '\u274c Processing failed. For best results, please use Google Chrome.';\r\n                        self.showToast(errMsg, true);\r\n                        self.UI.progArea.style.display = 'none';\r\n                        self.UI.inputArea.style.display = 'block';\r\n                    }\r\n                }, 'image\/jpeg', 0.95);\r\n            },\r\n\r\n            syncSliderWidth: function() { \r\n                if (this.UI.imgRes.offsetWidth) this.UI.imgOrig.style.width = this.UI.imgRes.offsetWidth + 'px'; \r\n            },\r\n\r\n            clearCustomBg: function() { \r\n                this.customBgImageObj = null; \r\n                this.UI.customBgBtn.classList.remove('active'); \r\n            },\r\n\r\n            resetTool: function() {\r\n                this.UI.fileIn.value = ''; this.UI.urlInput.value = '';\r\n                this.currentResultBlob = null; this.originalFileSizeKB = 0;\r\n                if(this.cropperInstance) { this.cropperInstance.destroy(); this.cropperInstance = null; }\r\n                \r\n                this.UI.inputArea.style.display = 'block'; this.UI.cropArea.style.display = 'none';\r\n                this.UI.progArea.style.display = 'none'; this.UI.prevBox.style.display = 'none';\r\n                this.UI.settings.style.display = 'none'; this.UI.infoBar.style.display = 'none';\r\n                this.UI.clrBtn.style.display = 'none'; this.UI.scanningWrapper.style.display = 'none';\r\n                \r\n                this.UI.slider.value = 50; this.UI.beforeBox.style.width = '50%';\r\n                this.selectedBgColor = 'transparent'; this.selectedBgType = 'solid'; this.customBgImageObj = null;\r\n                \r\n                this.UI.prevBg.style.background = 'transparent';\r\n                this.UI.bgColors.forEach(b => b.classList.remove('active'));\r\n                this.UI.customBgBtn.classList.remove('active');\r\n                this.UI.bgColors[0].classList.add('active');\r\n            },\r\n\r\n            downloadImage: function() {\r\n                if (!this.currentResultBlob || !this.croppedBlobForPreview) return;\r\n                const format = this.UI.outputFormat.value; const quality = this.UI.qualitySlider.value \/ 100;\r\n                const maxDim = parseInt(this.UI.resizePreset.value); const ext = format;\r\n                const mime = format === 'png' ? 'image\/png' : (format === 'webp' ? 'image\/webp' : 'image\/jpeg');\r\n           \r\n                const canvas = document.createElement('canvas'); const ctx = canvas.getContext('2d');\r\n                const img = new Image();\r\n                const self = this;\r\n                img.onload = () => {\r\n                    let width = img.width; let height = img.height;\r\n                    if (maxDim > 0) {\r\n                        const ratio = Math.min(maxDim \/ width, maxDim \/ height);\r\n                        width = Math.round(width * ratio); height = Math.round(height * ratio);\r\n                    }\r\n                    canvas.width = width; canvas.height = height;\r\n           \r\n                    if (self.selectedBgType === 'image' && self.customBgImageObj) {\r\n                        const hRatio = width \/ self.customBgImageObj.width; const vRatio = height \/ self.customBgImageObj.height;\r\n                        const ratio = Math.max(hRatio, vRatio); const cw = self.customBgImageObj.width * ratio; const ch = self.customBgImageObj.height * ratio;\r\n                        const cx = (width - cw) \/ 2; const cy = (height - ch) \/ 2;\r\n                        ctx.drawImage(self.customBgImageObj, 0, 0, self.customBgImageObj.width, self.customBgImageObj.height, cx, cy, cw, ch);\r\n                    } else if (self.selectedBgColor !== 'transparent') {\r\n                        if (self.selectedBgType === 'gradient') {\r\n                            const grad = ctx.createLinearGradient(0, 0, width, height);\r\n                            grad.addColorStop(0, self.gradColor1); grad.addColorStop(1, self.gradColor2); ctx.fillStyle = grad;\r\n                        } else { ctx.fillStyle = self.selectedBgColor; }\r\n                        ctx.fillRect(0, 0, width, height);\r\n                    }\r\n                    ctx.drawImage(img, 0, 0, width, height);\r\n           \r\n                    const dataUrl = canvas.toDataURL(mime, quality);\r\n                    const a = document.createElement('a'); a.href = dataUrl; a.download = 'PrimeToolHub-BGRemoved.' + ext; a.click();\r\n                    self.showToast('\ud83d\udce5 Image downloaded!');\r\n                };\r\n                img.src = URL.createObjectURL(this.currentResultBlob);\r\n            },\r\n\r\n            copyImage: async function() {\r\n                if (!this.currentResultBlob) return;\r\n                try { await navigator.clipboard.write([new ClipboardItem({ 'image\/png': this.currentResultBlob })]); this.showToast('\ud83d\udccb Image copied to clipboard!'); } \r\n                catch (err) { this.showToast('\u274c Clipboard copy failed.', true); }\r\n            },\r\n\r\n            printImage: function() {\r\n                if (!this.currentResultBlob) return;\r\n                const url = URL.createObjectURL(this.currentResultBlob); const printWin = window.open('');\r\n                printWin.document.write('\\x3Cimg src=\"' + url + '\" style=\"max-width:100%; height:auto;\"\\x3E');\r\n                printWin.document.close(); printWin.focus(); setTimeout(() => { printWin.print(); }, 200);\r\n            }\r\n        };\r\n\r\n        function runInit() {\r\n            if (!window.pthAiBgRemoverApp.initialized) {\r\n                window.pthAiBgRemoverApp.initialized = true;\r\n                window.pthAiBgRemoverApp.init();\r\n            }\r\n        }\r\n        if (document.readyState === 'complete' || document.readyState === 'interactive') { setTimeout(runInit, 1); } \r\n        else { document.addEventListener('DOMContentLoaded', runInit); window.addEventListener('load', runInit); }\r\n    })();\r\n<\/script>\r\n\t<script data-no-optimize=\"1\" data-no-minify=\"1\" data-cfasync=\"false\">\r\n(function () {\r\n  'use strict';\r\n  function mount() {\r\n    var panel = document.getElementById('pth-ie-tab-bg');\r\n    var tool  = document.getElementById('pth-ai-bg-remover-wrapper');\r\n    if (!panel || !tool) return false;\r\n    if (tool.parentNode !== panel) {\r\n      var ph = document.getElementById('pth-ie-empty-bg');\r\n      if (ph && ph.parentNode) ph.parentNode.removeChild(ph);\r\n      tool.style.margin = '0';\r\n      panel.appendChild(tool);\r\n    }\r\n    return true;\r\n  }\r\n  if (mount()) return;\r\n  if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', mount);\r\n  window.addEventListener('load', function () { setTimeout(mount, 60); });\r\n  if (typeof MutationObserver !== 'undefined') {\r\n    var o = new MutationObserver(function () { if (mount()) o.disconnect(); });\r\n    o.observe(document.body || document.documentElement, { childList: true, subtree: true });\r\n    setTimeout(function () { o.disconnect(); }, 10000);\r\n  }\r\n})();\r\n<\/script>\n\n\n<style>\r\n\/* ==========================================================================\r\n   PRIME TOOL HUB - AI MAGIC ERASER PRO v9.3 - LIVE PREVIEW + RED MASK FIX\r\n   Engine: OpenCV.js + Advanced Blending + Red Mask Always Visible in Live Mode\r\n   ========================================================================== *\/\r\n#pth-magic-eraser-wrapper { font-family: 'Inter', system-ui, sans-serif; max-width: 1400px; margin: 0 auto; box-sizing: border-box; background: #f8fafc; padding: 18px; border-radius: 16px; color: #0f172a; position: relative; }\r\n#pth-magic-eraser-wrapper * { box-sizing: border-box; }\r\n#pth-magic-eraser-wrapper .pth-card { background: #ffffff; border: 1px solid #e2e8f0; border-radius: 12px; padding: 18px; margin-bottom: 18px; box-shadow: 0 4px 6px -1px rgba(0,0,0,0.05); }\r\n#pth-magic-eraser-wrapper .pth-tool-title { font-size: 26px; font-weight: 800; color: #3b82f6; margin-top: 0; display: flex; align-items: center; gap: 10px;}\r\n#pth-magic-eraser-wrapper .pth-flex-layout { display: grid; grid-template-columns: 1.8fr 1fr; gap: 22px; align-items: start; transition: 0.3s ease; }\r\n#pth-magic-eraser-wrapper .pth-flex-layout.pth-full-width { grid-template-columns: 1fr; }\r\n\r\n\/* Quality Badge *\/\r\n#pth-magic-eraser-wrapper .pth-quality-badge { \r\n    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\r\n    color: white; padding: 6px 14px; border-radius: 20px; font-size: 0.75rem;\r\n    font-weight: 700; display: inline-flex; align-items: center; gap: 6px; box-shadow: 0 4px 12px rgba(102, 126, 234, 0.3);\r\n}\r\n\r\n\/* Buttons *\/\r\n#pth-magic-eraser-wrapper .pth-btn { padding: 10px 18px; border-radius: 8px; font-weight: 700; cursor: pointer; border: none; font-family: 'Inter', sans-serif; transition: 0.2s; display: inline-flex; align-items: center; justify-content: center; gap: 6px;}\r\n#pth-magic-eraser-wrapper .pth-btn-primary { background: #3b82f6; color: #ffffff; box-shadow: 0 4px 10px rgba(59,130,246,0.25); }\r\n#pth-magic-eraser-wrapper .pth-btn-primary:hover { background: #2563eb; transform: translateY(-2px); }\r\n#pth-magic-eraser-wrapper .pth-btn-primary:disabled { background: #94a3b8; cursor: not-allowed; transform: none; box-shadow: none; }\r\n#pth-magic-eraser-wrapper .pth-btn-danger { background: #fee2e2; color: #b91c1c; }\r\n#pth-magic-eraser-wrapper .pth-btn-danger:hover { background: #fecaca; }\r\n#pth-magic-eraser-wrapper .pth-btn-secondary { background: #1e293b; color: #fff; font-size: 0.85rem; }\r\n#pth-magic-eraser-wrapper .pth-btn-secondary:hover { background: #0f172a; }\r\n\r\n\/* Sample Button *\/\r\n#pth-magic-eraser-wrapper .pth-sample-btn { background: #ecfdf5; color: #10b981; border: 1px solid #6ee7b7; font-size: 0.8rem; padding: 6px 12px; border-radius: 6px; font-weight: 700; cursor: pointer; transition: 0.2s; display: inline-flex; align-items: center; gap: 6px; }\r\n#pth-magic-eraser-wrapper .pth-sample-btn:hover { background: #d1fae5; }\r\n\r\n\/* Drop Zone *\/\r\n#pth-magic-eraser-wrapper .pth-drop-zone { border: 2px dashed #93c5fd; border-radius: 12px; padding: 35px 20px; text-align: center; background: #eff6ff; transition: all 0.3s; cursor: pointer; margin-bottom: 20px; }\r\n#pth-magic-eraser-wrapper .pth-drop-zone:hover, #pth-magic-eraser-wrapper .pth-drop-zone.active { border-color: #3b82f6; background: #dbeafe; }\r\n#pth-magic-eraser-wrapper .pth-dz-icon { font-size: 40px; margin-bottom: 10px; }\r\n\r\n\/* Workspace Area & Checkerboard *\/\r\n#pth-magic-eraser-wrapper .pth-workspace { display: none; }\r\n#pth-magic-eraser-wrapper .pth-checkerboard { background-image: linear-gradient(45deg, #cbd5e1 25%, transparent 25%), linear-gradient(-45deg, #cbd5e1 25%, transparent 25%), linear-gradient(45deg, transparent 75%, #cbd5e1 75%), linear-gradient(-45deg, transparent 75%, #cbd5e1 75%); background-size: 20px 20px; background-position: 0 0, 0 10px, 10px -10px, -10px 0px; background-color: #e2e8f0; }\r\n\r\n#pth-magic-eraser-wrapper .pth-canvas-container { width: 100%; border-radius: 8px; display: flex; align-items: center; justify-content: center; border: 1px solid #94a3b8; min-height: 320px; padding: 12px; box-sizing: border-box; }\r\n#pth-magic-eraser-wrapper .pth-canvas-wrapper-inner { position: relative; display: inline-block; max-width: 100%; line-height: 0; box-shadow: 0 4px 15px rgba(0,0,0,0.15); border-radius: 4px; overflow: hidden; }\r\n#pth-magic-eraser-wrapper #pth-img-canvas { display: block; max-width: 100%; max-height: 560px; width: auto; height: auto; }\r\n#pth-magic-eraser-wrapper #pth-mask-canvas { position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: 2; opacity: 0.6; touch-action: none; }\r\n#pth-magic-eraser-wrapper #pth-ui-canvas { position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: 3; pointer-events: none; }\r\n\r\n\/* Compact Action Toolbar - DIRECTLY BELOW IMAGE *\/\r\n#pth-magic-eraser-wrapper .pth-action-toolbar { display: flex; flex-wrap: wrap; gap: 10px; justify-content: center; margin: 15px 0 20px; padding: 12px; background: #f1f5f9; border-radius: 10px; border: 1px solid #cbd5e1; }\r\n\r\n\/* Selection Mode Toggle *\/\r\n#pth-magic-eraser-wrapper .pth-mode-toggle { display: flex; gap: 8px; margin-bottom: 12px; background: #f1f5f9; padding: 8px; border-radius: 8px; border: 1px solid #e2e8f0; flex-wrap: wrap; }\r\n#pth-magic-eraser-wrapper .pth-mode-btn { flex: 1; min-width: 110px; padding: 9px; font-size: 0.83rem; font-weight: 700; border-radius: 6px; border: 1px solid transparent; background: transparent; color: #475569; cursor: pointer; transition: 0.2s; }\r\n#pth-magic-eraser-wrapper .pth-mode-btn.active { background: #fff; border-color: #cbd5e1; color: #3b82f6; box-shadow: 0 2px 4px rgba(0,0,0,0.05); }\r\n\r\n\/* Enhanced Quality Panel - COMPACT *\/\r\n#pth-magic-eraser-wrapper .pth-quality-panel { background: linear-gradient(135deg, #f8f9ff 0%, #fff5f7 100%); padding: 16px; border-radius: 12px; border: 2px solid #e0e7ff; margin-bottom: 16px; }\r\n#pth-magic-eraser-wrapper .pth-quality-title { font-size: 1rem; font-weight: 800; color: #5b21b6; margin: 0 0 12px 0; display: flex; align-items: center; gap: 8px; }\r\n\r\n\/* Preset Buttons *\/\r\n#pth-magic-eraser-wrapper .pth-preset-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px; margin-top: 10px; }\r\n#pth-magic-eraser-wrapper .pth-preset-btn { padding: 8px; border-radius: 6px; border: 1px solid #cbd5e1; background: white; cursor: pointer; font-size: 0.75rem; font-weight: 600; color: #475569; transition: 0.2s; text-align: center; }\r\n#pth-magic-eraser-wrapper .pth-preset-btn:hover { background: #f1f5f9; border-color: #8b5cf6; color: #8b5cf6; }\r\n#pth-magic-eraser-wrapper .pth-preset-btn.active { background: #8b5cf6; color: white; border-color: #8b5cf6; }\r\n\r\n\/* Controls - TIGHTER *\/\r\n#pth-magic-eraser-wrapper .pth-toolbar { display: flex; flex-direction: column; gap: 12px; background: #f1f5f9; padding: 12px; border-radius: 8px; border: 1px solid #e2e8f0; }\r\n#pth-magic-eraser-wrapper .pth-control-row { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 12px; }\r\n#pth-magic-eraser-wrapper .pth-control-group { display: flex; align-items: center; gap: 8px; flex: 1; min-width: 180px; }\r\n#pth-magic-eraser-wrapper .pth-control-group label { font-weight: 700; color: #1e40af; font-size: 0.83rem; min-width: 85px; }\r\n#pth-magic-eraser-wrapper input[type=\"range\"] { flex: 1; accent-color: #3b82f6; cursor: pointer; height: 6px; }\r\n#pth-magic-eraser-wrapper .pth-val-badge { font-weight:bold; color:#3b82f6; width:35px; text-align:right; font-size: 0.8rem; background: #eff6ff; padding: 2px 4px; border-radius: 4px; }\r\n#pth-magic-eraser-wrapper select.pth-select { padding: 4px 8px; border-radius: 6px; border: 1px solid #cbd5e1; background: #fff; font-family: 'Inter', sans-serif; font-size: 0.83rem; width: 100%; outline:none;}\r\n#pth-magic-eraser-wrapper input[type=\"color\"] { -webkit-appearance: none; border: none; width: 28px; height: 28px; border-radius: 6px; cursor: pointer; padding: 0; background: none; }\r\n#pth-magic-eraser-wrapper input[type=\"color\"]::-webkit-color-swatch-wrapper { padding: 0; }\r\n#pth-magic-eraser-wrapper input[type=\"color\"]::-webkit-color-swatch { border: 1px solid #cbd5e1; border-radius: 4px; }\r\n\r\n\/* Live Preview Badge *\/\r\n#pth-magic-eraser-wrapper .pth-live-badge { background: #10b981; color: #fff; font-size: 0.7rem; padding: 2px 8px; border-radius: 9999px; font-weight: 700; display: inline-flex; align-items: center; gap: 4px; }\r\n\r\n\/* Loaders & Toasts *\/\r\n#pth-magic-eraser-wrapper .pth-loader { display: none; margin-top: 10px; text-align: center; font-weight: 700; color: #3b82f6; font-size: 0.9rem; }\r\n#pth-magic-eraser-wrapper .pth-spinner { display: inline-block; width: 16px; height: 16px; border: 3px solid rgba(59,130,246,0.3); border-radius: 50%; border-top-color: #3b82f6; animation: pthSpin 1s ease-in-out infinite; margin-right: 6px; vertical-align: middle; }\r\n@keyframes pthSpin { to { transform: rotate(360deg); } }\r\n\r\n#pth-magic-eraser-wrapper .pth-toast { position: fixed; bottom: 20px; right: 20px; background: #10b981; color: #fff; padding: 10px 20px; border-radius: 8px; box-shadow: 0 10px 25px -5px rgba(0,0,0,0.2); display: none; align-items: center; z-index: 9999999; font-weight: 700; font-size: 13px; }\r\n#pth-magic-eraser-wrapper .pth-toast.show { display: flex; animation: pthToastFade 0.3s ease; }\r\n@keyframes pthToastFade { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: translateY(0); } }\r\n\r\n\/* Sidebar *\/\r\n#pth-magic-eraser-wrapper .pth-sidebar-col .pth-card { padding: 15px; margin-bottom: 15px; }\r\n#pth-magic-eraser-wrapper .pth-sidebar-col h3 { margin-top: 0; border-bottom: 1px solid #e2e8f0; padding-bottom: 8px; color: #0f172a; font-size: 1rem; margin-bottom: 10px; }\r\n#pth-magic-eraser-wrapper ul { padding-left: 0; list-style: none; margin: 0; }\r\n#pth-magic-eraser-wrapper li { margin-bottom: 10px; font-size: 0.85rem; color: #475569; display: flex; gap: 8px; line-height: 1.4;}\r\n#pth-magic-eraser-wrapper .pth-stat-item { display: flex; justify-content: space-between; margin-bottom: 6px; font-size: 0.85rem; border-bottom: 1px dashed #e2e8f0; padding-bottom: 4px; }\r\n\r\n@media (max-width: 768px) { \r\n    #pth-magic-eraser-wrapper .pth-flex-layout { grid-template-columns: 1fr; }\r\n    #pth-magic-eraser-wrapper .pth-preset-grid { grid-template-columns: repeat(2, 1fr); }\r\n    #pth-magic-eraser-wrapper .pth-action-toolbar { flex-direction: column; }\r\n}\r\n<\/style>\r\n\r\n<div id=\"pth-magic-eraser-wrapper\">\r\n    <div id=\"pth-me-toast\" class=\"pth-toast\">\u2705 Action Successful!<\/div>\r\n\r\n    <div class=\"pth-flex-layout\" id=\"pth-magic-eraser-layout\">\r\n        \r\n        <div class=\"pth-main-col\">\r\n            <div class=\"pth-card\">\r\n                <div style=\"display: flex; justify-content: space-between; align-items: center; margin-bottom: 16px; flex-wrap: wrap; gap: 10px;\">\r\n                    <div style=\"display: flex; align-items: center; gap: 12px; flex-wrap: wrap;\">\r\n                        <h2 class=\"pth-tool-title\">\u2728 AI Magic Eraser Pro<\/h2>\r\n                        <span class=\"pth-quality-badge\">\ud83c\udfaf Ultra Natural Mode<\/span>\r\n                    <\/div>\r\n                    <button class=\"pth-btn pth-btn-secondary\" id=\"pth-fw-btn-magic-eraser\">\u26f6 Full Width<\/button>\r\n                <\/div>\r\n                \r\n                <div style=\"margin-bottom: 12px; display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 10px;\">\r\n                     <div id=\"pth-me-status\" style=\"font-size: 0.85rem; font-weight: 600; color: #64748b;\">System Ready \u2022 Live Preview + Red Mask Visible<\/div>\r\n                     <div style=\"display:flex; gap:10px;\">\r\n                         <button class=\"pth-sample-btn\" id=\"pth-me-load-sample-btn\">\ud83d\udca1 Load Sample<\/button>\r\n                         <button class=\"pth-btn pth-btn-danger\" id=\"pth-me-reset-btn\" style=\"display:none; font-size:0.8rem; padding:6px 12px;\">\ud83d\udd04 New Image<\/button>\r\n                     <\/div>\r\n                <\/div>\r\n\r\n                <input type=\"file\" id=\"pth-me-file\" accept=\"image\/png, image\/jpeg, image\/webp\" style=\"display:none;\">\r\n                <div id=\"pth-me-input-area\">\r\n                    <div class=\"pth-drop-zone\" id=\"pth-me-drop-zone\">\r\n                        <div class=\"pth-dz-icon\">\ud83d\uddbc\ufe0f<\/div>\r\n                        <h3 style=\"margin:0 0 5px 0; color:#1e3a8a;\">Click or Drag & Drop an Image<\/h3>\r\n                        <p style=\"margin:0; font-size:0.85rem; color:#64748b;\">100% Offline \u2022 Red Mask Stays Visible in Live Preview<\/p>\r\n                    <\/div>\r\n                <\/div>\r\n\r\n                <div class=\"pth-workspace\" id=\"pth-me-workspace\">\r\n                    \r\n                    <div class=\"pth-mode-toggle\" id=\"pth-mode-toggle\">\r\n                        <button class=\"pth-mode-btn active\" data-mode=\"brush\">\ud83d\udd8c\ufe0f Brush<\/button>\r\n                        <button class=\"pth-mode-btn\" data-mode=\"rectangle\">\ud83d\udd32 Rectangle<\/button>\r\n                        <button class=\"pth-mode-btn\" data-mode=\"lasso\">\ud83e\udea2 Lasso<\/button>\r\n                        <button class=\"pth-mode-btn\" data-mode=\"wand\" style=\"color: #b45309; border-color: #fde68a; background: #fffbeb;\">\ud83e\ude84 Auto Wand<\/button>\r\n                    <\/div>\r\n\r\n                    <div class=\"pth-canvas-container pth-checkerboard\" id=\"pth-me-canvas-container\">\r\n                        <div class=\"pth-canvas-wrapper-inner\">\r\n                            <canvas id=\"pth-img-canvas\"><\/canvas>\r\n                            <canvas id=\"pth-mask-canvas\"><\/canvas>\r\n                            <canvas id=\"pth-ui-canvas\"><\/canvas>\r\n                        <\/div>\r\n                    <\/div>\r\n\r\n                    <div class=\"pth-action-toolbar\" id=\"pth-action-toolbar\">\r\n                        <button class=\"pth-btn pth-btn-primary\" id=\"pth-me-erase-btn\" style=\"flex:1; min-width:160px; font-size:1rem; padding:13px; background:#8b5cf6;\">\r\n                            \u2728 Natural Erase\r\n                        <\/button>\r\n                        <button class=\"pth-btn pth-btn-primary\" id=\"pth-me-color-fill-btn\" style=\"flex:1; min-width:160px; font-size:1rem; padding:13px; background:#eab308; color:#0f172a;\">\r\n                            \ud83e\udea8 Fill Solid Color\r\n                        <\/button>\r\n                        <button class=\"pth-btn pth-btn-danger\" id=\"pth-me-cut-btn\" style=\"flex:1; min-width:160px; font-size:1rem; padding:13px; background:#ef4444;\">\r\n                            \u2702\ufe0f Cut Transparent\r\n                        <\/button>\r\n                        <button class=\"pth-btn pth-btn-primary\" id=\"pth-me-download-btn\" style=\"width:100%; background:#10b981; display:none; padding:13px; font-size:1.05rem; margin-top:8px;\">\r\n                            \ud83d\udce5 Download Result (PNG)\r\n                        <\/button>\r\n                    <\/div>\r\n\r\n                    <div class=\"pth-quality-panel\">\r\n                        <div class=\"pth-quality-title\">\r\n                            <span>\ud83c\udfa8<\/span>\r\n                            <span>Natural Erase Quality <span id=\"live-preview-status\" class=\"pth-live-badge\" style=\"display:none;\">LIVE PREVIEW ON<\/span><\/span>\r\n                        <\/div>\r\n                        \r\n                        <div class=\"pth-preset-grid\">\r\n                            <button class=\"pth-preset-btn\" data-preset=\"fast\">\u26a1 Fast<\/button>\r\n                            <button class=\"pth-preset-btn active\" data-preset=\"balanced\">\u2728 Balanced<\/button>\r\n                            <button class=\"pth-preset-btn\" data-preset=\"ultra\">\ud83c\udfc6 Ultra<\/button>\r\n                        <\/div>\r\n                        \r\n                        <div style=\"margin-top:12px; display:flex; align-items:center; gap:8px; font-size:0.85rem; font-weight:700; color:#10b981;\">\r\n                            <input type=\"checkbox\" id=\"pth-live-preview-toggle\" checked>\r\n                            <label for=\"pth-live-preview-toggle\">Enable Live Preview (red mark stays visible)<\/label>\r\n                        <\/div>\r\n\r\n                        <div class=\"pth-control-row\" style=\"margin-top: 12px;\">\r\n                            <div class=\"pth-control-group\">\r\n                                <label style=\"color: #7c3aed; min-width: 110px;\">Edge Smoothing:<\/label>\r\n                                <input type=\"range\" id=\"pth-edge-smooth\" min=\"0\" max=\"10\" value=\"5\">\r\n                                <span class=\"pth-val-badge\" id=\"pth-edge-val\">5<\/span>\r\n                            <\/div>\r\n                        <\/div>\r\n                        \r\n                        <div class=\"pth-control-row\">\r\n                            <div class=\"pth-control-group\">\r\n                                <label style=\"color: #7c3aed; min-width: 110px;\">Context Blend:<\/label>\r\n                                <input type=\"range\" id=\"pth-context-blend\" min=\"0\" max=\"100\" value=\"70\">\r\n                                <span class=\"pth-val-badge\" id=\"pth-context-val\">70%<\/span>\r\n                            <\/div>\r\n                        <\/div>\r\n                    <\/div>\r\n\r\n                    <div class=\"pth-toolbar\">\r\n                        <div class=\"pth-control-row\" id=\"pth-brush-controls\">\r\n                            <div class=\"pth-control-group\">\r\n                                <label>Tool Size:<\/label>\r\n                                <input type=\"range\" id=\"pth-me-brush-size\" min=\"5\" max=\"100\" value=\"30\">\r\n                                <span class=\"pth-val-badge\" id=\"pth-me-brush-val\">30px<\/span>\r\n                                <div class=\"pth-brush-preview\" id=\"pth-brush-preview\"><\/div>\r\n                            <\/div>\r\n                            <div class=\"pth-control-group\">\r\n                                <label>Mask Opacity:<\/label>\r\n                                <input type=\"range\" id=\"pth-me-mask-opacity\" min=\"20\" max=\"90\" value=\"60\">\r\n                                <span class=\"pth-val-badge\" id=\"pth-me-opacity-val\">60%<\/span>\r\n                            <\/div>\r\n                        <\/div>\r\n\r\n                        <div class=\"pth-control-row\" id=\"pth-wand-controls\" style=\"display:none; background:#fffbeb; padding:10px; border-radius:8px; border:1px solid #fde68a;\">\r\n                            <div class=\"pth-control-group\" style=\"width:100%;\">\r\n                                <label style=\"color:#b45309; min-width: 130px;\">\ud83e\ude84 Color Tolerance:<\/label>\r\n                                <input type=\"range\" id=\"pth-me-wand-tol\" min=\"5\" max=\"150\" value=\"30\" style=\"accent-color:#d97706;\">\r\n                                <span class=\"pth-val-badge\" id=\"pth-me-wand-val\" style=\"color:#b45309; background:#fffbeb;\">30<\/span>\r\n                            <\/div>\r\n                        <\/div>\r\n\r\n                        <div class=\"pth-control-row\">\r\n                            <div class=\"pth-control-group\">\r\n                                <label>Algorithm:<\/label>\r\n                                <select id=\"pth-me-algorithm\" class=\"pth-select\">\r\n                                    <option value=\"1\">\u2728 Telea (Fast Inpainting)<\/option>\r\n                                    <option value=\"0\">\ud83c\udf0a Navier-Stokes (Smooth Inpainting)<\/option>\r\n                                <\/select>\r\n                            <\/div>\r\n                            <div class=\"pth-control-group\">\r\n                                <label>AI Radius:<\/label>\r\n                                <input type=\"range\" id=\"pth-me-radius\" min=\"1\" max=\"20\" value=\"7\">\r\n                                <span class=\"pth-val-badge\" id=\"pth-me-radius-val\">7px<\/span>\r\n                            <\/div>\r\n                        <\/div>\r\n\r\n                        <div class=\"pth-control-row\" style=\"background:#f1f5f9; padding:10px; border-radius:8px; border:1px solid #cbd5e1;\">\r\n                            <div class=\"pth-control-group\" style=\"flex:1;\">\r\n                                <label style=\"color:#475569;\">Texture Grain:<\/label>\r\n                                <input type=\"range\" id=\"pth-me-grain\" min=\"0\" max=\"50\" value=\"8\" style=\"accent-color:#64748b;\">\r\n                                <span class=\"pth-val-badge\" id=\"pth-grain-val\">8<\/span>\r\n                            <\/div>\r\n                            <div class=\"pth-control-group\" style=\"flex:0; min-width:auto; border-left: 2px solid #cbd5e1; padding-left: 15px;\">\r\n                                <label style=\"min-width:auto; color:#475569;\">Fill Color:<\/label>\r\n                                <input type=\"color\" id=\"pth-me-fill-color\" value=\"#ffffff\" title=\"Choose color to fill\">\r\n                            <\/div>\r\n                        <\/div>\r\n\r\n                        <div style=\"display:flex; gap:8px; flex-wrap:wrap; justify-content:center; margin-top: 10px; border-top: 1px solid #cbd5e1; padding-top: 12px;\">\r\n                            <button class=\"pth-btn\" id=\"pth-me-clear-mask\" style=\"background:#e2e8f0; color:#475569; font-size:0.85rem;\"><span style=\"font-size: 1.1rem;\">\ud83e\uddf9<\/span> Clear Selection<\/button>\r\n                            <button class=\"pth-btn\" id=\"pth-me-undo-btn\" style=\"background:#cbd5e1; color:#0f172a; font-size:0.85rem; display:none;\"><span style=\"font-size: 1.1rem;\">\u21a9\ufe0f<\/span> Undo Last Edit<\/button>\r\n                            <button class=\"pth-btn\" id=\"pth-me-restore-btn\" style=\"background:#fef3c7; color:#b45309; font-size:0.85rem; border: 1px solid #fde68a; display:none;\"><span style=\"font-size: 1.1rem;\">\u267b\ufe0f<\/span> Restore Original<\/button>\r\n                        <\/div>\r\n                    <\/div>\r\n\r\n                    <div class=\"pth-loader\" id=\"pth-me-loader\">\r\n                        <span class=\"pth-spinner\"><\/span> <span id=\"pth-me-loader-text\">Live preview updating...<\/span>\r\n                    <\/div>\r\n                <\/div>\r\n\r\n            <\/div>\r\n        <\/div>\r\n\r\n        <div class=\"pth-sidebar-col\" id=\"pth-magic-eraser-sidebar\">\r\n            <div class=\"pth-card\" id=\"pth-live-stats-box\" style=\"display:none; border-color:#8b5cf6; background:#faf5ff;\">\r\n                <h3 style=\"color:#7c3aed;\">\ud83d\udcca Editing Session<\/h3>\r\n                <div class=\"pth-stat-item\"><span>Edits Applied:<\/span><strong id=\"live-edits\" style=\"color:#7c3aed;\">0<\/strong><\/div>\r\n                <div class=\"pth-stat-item\"><span>Image Size:<\/span><strong id=\"live-size\" style=\"color:#7c3aed;\">--<\/strong><\/div>\r\n                <div class=\"pth-stat-item\"><span>Quality Mode:<\/span><strong id=\"live-quality\" style=\"color:#7c3aed;\">Balanced<\/strong><\/div>\r\n                <div style=\"margin-top:10px; font-size:0.75rem; color:#9333ea; text-align:center;\">Natural AI-powered results \u2022 100% Offline<\/div>\r\n            <\/div>\r\n\r\n            <div class=\"pth-card\">\r\n                <h3>\ud83d\udca1 Tool Guide<\/h3>\r\n                <ul>\r\n                    <li>\ud83e\udea2 <b>Lasso Select:<\/b> Draw freehand. Auto-fills on release!<\/li>\r\n                    <li>\ud83d\udd32 <b>Rectangle Select:<\/b> Drag box for precise edits.<\/li>\r\n                    <li>\ud83e\ude84 <b>Auto Wand:<\/b> Click solid backgrounds to select them instantly.<\/li>\r\n                <\/ul>\r\n            <\/div>\r\n            \r\n            <div class=\"pth-card\">\r\n                <h3>\u2699\ufe0f Engine Specs<\/h3>\r\n                <ul>\r\n                    <li>\ud83d\udd34 <b>Tech:<\/b> OpenCV.js + Live Inpainting<\/li>\r\n                    <li>\ud83d\udd35 <b>Core:<\/b> Red Mask Visible in Live Preview<\/li>\r\n                    <li>\ud83d\udfe2 <b>Privacy:<\/b> 100% Local \/ Zero Server<\/li>\r\n                <\/ul>\r\n            <\/div>\r\n        <\/div>\r\n\r\n    <\/div>\r\n<\/div>\r\n\r\n<script data-no-optimize=\"1\" data-no-minify=\"1\" data-cfasync=\"false\" data-pagespeed-no-defer=\"1\">\r\n(function() {\r\n    window.pthMagicEraserApp = {\r\n        initialized: false,\r\n        imgObj: null,\r\n        cvLoaded: false,\r\n        isDrawing: false,\r\n        hasMask: false,\r\n        lastX: 0, lastY: 0,\r\n        startX: 0, startY: 0,\r\n        brushSize: 30,\r\n        editCount: 0,\r\n        historyStack: [],\r\n        maskOpacity: 60,\r\n        originalDataURL: null,\r\n        currentMode: 'brush', \r\n        qualityPreset: 'balanced',\r\n        lassoPoints: [],\r\n        livePreviewEnabled: true,\r\n        debounceTimer: null,\r\n        isProcessing: false,\r\n\r\n        init: function() {\r\n            this.cacheDOM();\r\n            this.attachEvents();\r\n            this.loadOpenCV();\r\n        },\r\n\r\n        cacheDOM: function() {\r\n            this.UI = {\r\n                layout: document.getElementById('pth-magic-eraser-layout'),\r\n                sidebar: document.getElementById('pth-magic-eraser-sidebar'),\r\n                fwBtn: document.getElementById('pth-fw-btn-magic-eraser'),\r\n                sampleBtn: document.getElementById('pth-me-load-sample-btn'),\r\n                resetBtn: document.getElementById('pth-me-reset-btn'),\r\n                \r\n                dz: document.getElementById('pth-me-drop-zone'),\r\n                fileIn: document.getElementById('pth-me-file'),\r\n                inputArea: document.getElementById('pth-me-input-area'),\r\n                workspace: document.getElementById('pth-me-workspace'),\r\n                \r\n                imgCanvas: document.getElementById('pth-img-canvas'),\r\n                maskCanvas: document.getElementById('pth-mask-canvas'),\r\n                uiCanvas: document.getElementById('pth-ui-canvas'),\r\n                \r\n                imgCtx: document.getElementById('pth-img-canvas')?.getContext('2d', { willReadFrequently: true }),\r\n                maskCtx: document.getElementById('pth-mask-canvas')?.getContext('2d', { willReadFrequently: true }),\r\n                uiCtx: document.getElementById('pth-ui-canvas')?.getContext('2d'),\r\n                \r\n                wandWrapper: document.getElementById('pth-wand-wrapper'),\r\n                algoWrapper: document.getElementById('pth-algo-wrapper'),\r\n                \r\n                brushSli: document.getElementById('pth-me-brush-size'),\r\n                brushVal: document.getElementById('pth-me-brush-val'),\r\n                brushPrev: document.getElementById('pth-brush-preview'),\r\n                wandSli: document.getElementById('pth-me-wand-tol'),\r\n                wandVal: document.getElementById('pth-me-wand-val'),\r\n                radiusSli: document.getElementById('pth-me-radius'),\r\n                radiusVal: document.getElementById('pth-me-radius-val'),\r\n                opacitySli: document.getElementById('pth-me-mask-opacity'),\r\n                opacityVal: document.getElementById('pth-me-opacity-val'),\r\n                grainSli: document.getElementById('pth-me-grain'),\r\n                grainVal: document.getElementById('pth-grain-val'),\r\n                fillColorPicker: document.getElementById('pth-me-fill-color'),\r\n                \r\n                edgeSmoothSli: document.getElementById('pth-edge-smooth'),\r\n                edgeVal: document.getElementById('pth-edge-val'),\r\n                contextBlendSli: document.getElementById('pth-context-blend'),\r\n                contextVal: document.getElementById('pth-context-val'),\r\n                presetBtns: document.querySelectorAll('.pth-preset-btn'),\r\n                livePreviewToggle: document.getElementById('pth-live-preview-toggle'),\r\n                livePreviewStatus: document.getElementById('live-preview-status'),\r\n                \r\n                algoSelect: document.getElementById('pth-me-algorithm'),\r\n                modeBtns: document.querySelectorAll('.pth-mode-btn'),\r\n                \r\n                clearMaskBtn: document.getElementById('pth-me-clear-mask'),\r\n                undoBtn: document.getElementById('pth-me-undo-btn'),\r\n                restoreBtn: document.getElementById('pth-me-restore-btn'),\r\n                eraseBtn: document.getElementById('pth-me-erase-btn'),\r\n                cutBtn: document.getElementById('pth-me-cut-btn'),\r\n                fillBtn: document.getElementById('pth-me-color-fill-btn'),\r\n                dwnBtn: document.getElementById('pth-me-download-btn'),\r\n                \r\n                status: document.getElementById('pth-me-status'),\r\n                loader: document.getElementById('pth-me-loader'),\r\n                loaderText: document.getElementById('pth-me-loader-text'),\r\n                toast: document.getElementById('pth-me-toast'),\r\n\r\n                statsBox: document.getElementById('pth-live-stats-box'),\r\n                liveEdits: document.getElementById('live-edits'),\r\n                liveSize: document.getElementById('live-size'),\r\n                liveQuality: document.getElementById('live-quality')\r\n            };\r\n        },\r\n\r\n        showToast: function(msg, isError) {\r\n            if (!this.UI.toast) return;\r\n            this.UI.toast.innerText = msg;\r\n            this.UI.toast.style.background = isError ? '#ef4444' : '#10b981';\r\n            this.UI.toast.classList.add('show');\r\n            setTimeout(() => this.UI.toast.classList.remove('show'), 2800);\r\n        },\r\n\r\n        loadOpenCV: function() {\r\n            if (window.cv?.Mat) { this.cvLoaded = true; return; }\r\n            this.UI.status.innerText = \"Downloading Advanced Engine...\";\r\n            this.UI.status.style.color = \"#d97706\";\r\n            \r\n            const script = document.createElement('script');\r\n            script.src = \"https:\/\/docs.opencv.org\/4.8.0\/opencv.js\";\r\n            script.onload = () => {\r\n                const checkCv = setInterval(() => {\r\n                    if (window.cv?.Mat) {\r\n                        clearInterval(checkCv);\r\n                        this.cvLoaded = true;\r\n                        this.UI.status.innerText = \"Engine Ready \u2705 \u2022 Live Preview + Red Mask\";\r\n                        this.UI.status.style.color = \"#10b981\";\r\n                    }\r\n                }, 100);\r\n            };\r\n            script.onerror = () => {\r\n                this.UI.status.innerText = \"Engine Load Failed!\";\r\n                this.UI.status.style.color = \"#ef4444\";\r\n            };\r\n            document.head.appendChild(script);\r\n        },\r\n\r\n        attachEvents: function() {\r\n            this.UI.presetBtns?.forEach(btn => {\r\n                btn.addEventListener('click', (e) => this.setQualityPreset(e.target.dataset.preset));\r\n            });\r\n\r\n            const qualitySliders = [this.UI.edgeSmoothSli, this.UI.contextBlendSli, this.UI.radiusSli, this.UI.grainSli];\r\n            qualitySliders.forEach(slider => {\r\n                if (slider) {\r\n                    slider.addEventListener('input', (e) => {\r\n                        if (this.UI.edgeVal) this.UI.edgeVal.innerText = this.UI.edgeSmoothSli.value;\r\n                        if (this.UI.contextVal) this.UI.contextVal.innerText = this.UI.contextBlendSli.value + '%';\r\n                        if (this.UI.radiusVal) this.UI.radiusVal.innerText = this.UI.radiusSli.value + 'px';\r\n                        if (this.UI.grainVal) this.UI.grainVal.innerText = this.UI.grainSli.value;\r\n                        this.triggerLivePreview();\r\n                    });\r\n                }\r\n            });\r\n\r\n            this.UI.livePreviewToggle?.addEventListener('change', (e) => {\r\n                this.livePreviewEnabled = e.target.checked;\r\n                this.UI.livePreviewStatus.style.display = this.livePreviewEnabled ? 'inline-flex' : 'none';\r\n            });\r\n\r\n            this.UI.fwBtn?.addEventListener('click', () => this.toggleWidth());\r\n            this.UI.dz?.addEventListener('click', () => this.UI.fileIn.click());\r\n            this.UI.dz?.addEventListener('dragover', (e) => { e.preventDefault(); this.UI.dz.classList.add('active'); });\r\n            this.UI.dz?.addEventListener('dragleave', () => this.UI.dz.classList.remove('active'));\r\n            this.UI.dz?.addEventListener('drop', (e) => { e.preventDefault(); this.UI.dz.classList.remove('active'); if (e.dataTransfer.files.length) this.loadImage(e.dataTransfer.files[0]); });\r\n            this.UI.fileIn?.addEventListener('change', (e) => { if (e.target.files.length) this.loadImage(e.target.files[0]); });\r\n            this.UI.resetBtn?.addEventListener('click', () => this.resetTool());\r\n            this.UI.sampleBtn?.addEventListener('click', () => this.loadSampleImage());\r\n\r\n            this.UI.modeBtns?.forEach(btn => {\r\n                btn.addEventListener('click', (e) => this.setMode(e.target.dataset.mode, btn));\r\n            });\r\n\r\n            if(this.UI.uiCanvas) {\r\n                const mc = this.UI.uiCanvas; \r\n                mc.style.pointerEvents = \"auto\";\r\n                mc.addEventListener('mousedown', (e) => this.startDraw(e));\r\n                mc.addEventListener('mousemove', (e) => this.draw(e));\r\n                mc.addEventListener('mouseup', () => this.stopDraw());\r\n                mc.addEventListener('mouseout', () => this.stopDraw());\r\n                mc.addEventListener('touchstart', (e) => { e.preventDefault(); this.startDraw(e); }, {passive: false});\r\n                mc.addEventListener('touchmove', (e) => { e.preventDefault(); this.draw(e); }, {passive: false});\r\n                mc.addEventListener('touchend', (e) => { e.preventDefault(); this.stopDraw(); });\r\n            }\r\n\r\n            this.UI.brushSli?.addEventListener('input', (e) => {\r\n                this.brushSize = parseInt(e.target.value);\r\n                this.UI.brushVal.innerText = this.brushSize + 'px';\r\n                this.UI.brushPrev.style.width = this.brushSize + 'px';\r\n                this.UI.brushPrev.style.height = this.brushSize + 'px';\r\n            });\r\n            this.UI.wandSli?.addEventListener('input', (e) => { this.UI.wandVal.innerText = e.target.value; });\r\n            this.UI.opacitySli?.addEventListener('input', (e) => {\r\n                this.maskOpacity = parseInt(e.target.value);\r\n                this.UI.opacityVal.innerText = this.maskOpacity + '%';\r\n                if(this.UI.maskCanvas) this.UI.maskCanvas.style.opacity = (this.maskOpacity \/ 100);\r\n            });\r\n\r\n            this.UI.clearMaskBtn?.addEventListener('click', () => this.clearMask());\r\n            this.UI.undoBtn?.addEventListener('click', () => this.undoLastEdit());\r\n            this.UI.restoreBtn?.addEventListener('click', () => this.restoreOriginal());\r\n            this.UI.eraseBtn?.addEventListener('click', () => this.runNaturalErase(false));\r\n            this.UI.cutBtn?.addEventListener('click', () => this.runCutToTransparent());\r\n            this.UI.fillBtn?.addEventListener('click', () => this.runSolidColorFill());\r\n            this.UI.dwnBtn?.addEventListener('click', () => this.downloadResult());\r\n\r\n            document.addEventListener('keydown', (e) => {\r\n                if (e.ctrlKey && e.key === 'z') { e.preventDefault(); this.undoLastEdit(); }\r\n            });\r\n        },\r\n\r\n        triggerLivePreview: function() {\r\n            if (!this.livePreviewEnabled || !this.hasMask || this.isProcessing) return;\r\n            clearTimeout(this.debounceTimer);\r\n            this.debounceTimer = setTimeout(() => {\r\n                this.runNaturalErase(true); \/\/ true = live preview (red mask stays)\r\n            }, 650);\r\n        },\r\n\r\n        setQualityPreset: function(preset) {\r\n            this.qualityPreset = preset;\r\n            this.UI.presetBtns.forEach(btn => btn.classList.remove('active'));\r\n            event.target.classList.add('active');\r\n\r\n            if(preset === 'fast') {\r\n                this.UI.radiusSli.value = 3; this.UI.radiusVal.innerText = '3px';\r\n                this.UI.edgeSmoothSli.value = 2; this.UI.edgeVal.innerText = '2';\r\n                this.UI.contextBlendSli.value = 50; this.UI.contextVal.innerText = '50%';\r\n                this.UI.liveQuality.innerText = 'Fast';\r\n            } else if(preset === 'balanced') {\r\n                this.UI.radiusSli.value = 7; this.UI.radiusVal.innerText = '7px';\r\n                this.UI.edgeSmoothSli.value = 5; this.UI.edgeVal.innerText = '5';\r\n                this.UI.contextBlendSli.value = 70; this.UI.contextVal.innerText = '70%';\r\n                this.UI.liveQuality.innerText = 'Balanced';\r\n            } else if(preset === 'ultra') {\r\n                this.UI.radiusSli.value = 12; this.UI.radiusVal.innerText = '12px';\r\n                this.UI.edgeSmoothSli.value = 8; this.UI.edgeVal.innerText = '8';\r\n                this.UI.contextBlendSli.value = 90; this.UI.contextVal.innerText = '90%';\r\n                this.UI.liveQuality.innerText = 'Ultra';\r\n            }\r\n            this.triggerLivePreview();\r\n        },\r\n\r\n        setMode: function(mode, btn) {\r\n            this.UI.modeBtns.forEach(b => b.classList.remove('active'));\r\n            btn.classList.add('active');\r\n            this.currentMode = mode;\r\n            \r\n            if(this.UI.wandWrapper) this.UI.wandWrapper.style.display = (mode === 'wand') ? 'flex' : 'none';\r\n            if(this.UI.algoWrapper) this.UI.algoWrapper.style.display = (mode === 'wand') ? 'none' : 'flex';\r\n            \r\n            let cursor = 'pointer';\r\n            if(mode === 'rectangle' || mode === 'lasso') cursor = 'crosshair';\r\n            if(mode === 'wand') cursor = 'cell';\r\n            if(this.UI.uiCanvas) this.UI.uiCanvas.style.cursor = cursor;\r\n        },\r\n\r\n        toggleWidth: function() {\r\n            if(this.UI.layout.classList.contains('pth-full-width')) {\r\n                this.UI.layout.classList.remove('pth-full-width');\r\n                this.UI.sidebar.style.display = 'block';\r\n                this.UI.fwBtn.innerHTML = '\u26f6 Full Width';\r\n            } else {\r\n                this.UI.layout.classList.add('pth-full-width');\r\n                this.UI.sidebar.style.display = 'none';\r\n                this.UI.fwBtn.innerHTML = '\u25c0 Split View';\r\n            }\r\n        },\r\n\r\n        loadSampleImage: function() {\r\n            this.UI.sampleBtn.innerText = 'Loading...';\r\n            const img = new Image();\r\n            img.crossOrigin = \"Anonymous\";\r\n            img.onload = () => {\r\n                const canvas = document.createElement('canvas');\r\n                canvas.width = img.width; canvas.height = img.height;\r\n                canvas.getContext('2d').drawImage(img, 0, 0);\r\n                canvas.toBlob(blob => {\r\n                    this.loadImage(blob);\r\n                    this.UI.sampleBtn.innerText = '\ud83d\udca1 Load Sample';\r\n                }, 'image\/jpeg');\r\n            };\r\n            img.onerror = () => {\r\n                this.showToast('Failed to load sample.', true);\r\n                this.UI.sampleBtn.innerText = '\ud83d\udca1 Load Sample';\r\n            };\r\n            img.src = 'https:\/\/schoolict.net\/tools\/sampledata\/eraser.jpeg?' + Date.now();\r\n        },\r\n\r\n        loadImage: function(fileOrBlob) {\r\n            const file = fileOrBlob instanceof File ? fileOrBlob : new File([fileOrBlob], 'image.jpg', { type: fileOrBlob.type });\r\n            if (!file.type.startsWith('image\/')) return this.showToast('Invalid image format.', true);\r\n            \r\n            const url = URL.createObjectURL(file);\r\n            this.imgObj = new Image();\r\n            \r\n            this.imgObj.onload = () => {\r\n                let w = this.imgObj.naturalWidth;\r\n                let h = this.imgObj.naturalHeight;\r\n                \r\n                const MAX_RES = 1600;\r\n                let scaledText = \"\";\r\n                if (w > MAX_RES || h > MAX_RES) {\r\n                    const ratio = Math.min(MAX_RES \/ w, MAX_RES \/ h);\r\n                    w = Math.floor(w * ratio);\r\n                    h = Math.floor(h * ratio);\r\n                    scaledText = \" (Optimized)\";\r\n                }\r\n                \r\n                this.UI.imgCanvas.width = w; this.UI.imgCanvas.height = h;\r\n                this.UI.maskCanvas.width = w; this.UI.maskCanvas.height = h;\r\n                this.UI.uiCanvas.width = w; this.UI.uiCanvas.height = h;\r\n                \r\n                this.UI.imgCtx.clearRect(0, 0, w, h);\r\n                this.UI.imgCtx.drawImage(this.imgObj, 0, 0, w, h);\r\n                this.UI.maskCtx.clearRect(0, 0, w, h);\r\n                this.UI.uiCtx.clearRect(0, 0, w, h);\r\n                \r\n                this.hasMask = false;\r\n                this.editCount = 0;\r\n                this.historyStack = [];\r\n                this.originalDataURL = this.UI.imgCanvas.toDataURL('image\/png');\r\n\r\n                this.UI.inputArea.style.display = 'none';\r\n                this.UI.workspace.style.display = 'block';\r\n                this.UI.resetBtn.style.display = 'inline-flex';\r\n                this.UI.dwnBtn.style.display = 'none';\r\n                this.UI.undoBtn.style.display = 'none';\r\n                this.UI.restoreBtn.style.display = 'inline-flex';\r\n                \r\n                this.UI.statsBox.style.display = 'block';\r\n                this.UI.liveSize.innerText = w + ' x ' + h + scaledText;\r\n                this.UI.liveEdits.innerText = '0';\r\n                this.UI.liveQuality.innerText = this.qualityPreset === 'balanced' ? 'Balanced' : this.qualityPreset === 'fast' ? 'Fast' : 'Ultra';\r\n                \r\n                URL.revokeObjectURL(url);\r\n            };\r\n            this.imgObj.src = url;\r\n        },\r\n\r\n        resetTool: function() {\r\n            if(this.isProcessing) return this.showToast(\"Processing...\", true);\r\n            this.imgObj = null; this.hasMask = false; this.editCount = 0;\r\n            this.historyStack = []; this.originalDataURL = null;\r\n            this.UI.workspace.style.display = 'none';\r\n            this.UI.inputArea.style.display = 'block';\r\n            this.UI.resetBtn.style.display = 'none';\r\n            this.UI.statsBox.style.display = 'none';\r\n            this.UI.fileIn.value = '';\r\n        },\r\n\r\n        getMousePos: function(evt) {\r\n            const rect = this.UI.uiCanvas.getBoundingClientRect();\r\n            const scaleX = this.UI.uiCanvas.width \/ rect.width;\r\n            const scaleY = this.UI.uiCanvas.height \/ rect.height;\r\n            const clientX = evt.clientX || evt.touches?.[0]?.clientX;\r\n            const clientY = evt.clientY || evt.touches?.[0]?.clientY;\r\n            return { \r\n                x: Math.floor((clientX - rect.left) * scaleX), \r\n                y: Math.floor((clientY - rect.top) * scaleY) \r\n            };\r\n        },\r\n\r\n        runMagicWand: function(startX, startY) {\r\n            const tol = parseInt(this.UI.wandSli.value);\r\n            const w = this.UI.maskCanvas.width;\r\n            const h = this.UI.maskCanvas.height;\r\n            const imgData = this.UI.imgCtx.getImageData(0, 0, w, h).data;\r\n            const maskImg = this.UI.maskCtx.getImageData(0, 0, w, h);\r\n            const maskData = maskImg.data;\r\n\r\n            const startP = (startY * w + startX) * 4;\r\n            const r = imgData[startP], g = imgData[startP+1], b = imgData[startP+2], a = imgData[startP+3];\r\n\r\n            if (a === 0) return;\r\n\r\n            const stack = []; stack.push({x: startX, y: startY});\r\n            const visited = new Set(); visited.add(`${startX},${startY}`);\r\n\r\n            while(stack.length > 0) {\r\n                const {x: cx, y: cy} = stack.pop();\r\n                const cp = (cy * w + cx) * 4;\r\n\r\n                maskData[cp] = 239; maskData[cp+1] = 68; maskData[cp+2] = 68; maskData[cp+3] = 255;\r\n\r\n                const neighbors = [[cx+1, cy], [cx-1, cy], [cx, cy+1], [cx, cy-1]];\r\n                for(const [nx, ny] of neighbors) {\r\n                    if(nx >= 0 && nx < w && ny >= 0 && ny < h) {\r\n                        const key = `${nx},${ny}`;\r\n                        if(!visited.has(key)) {\r\n                            visited.add(key);\r\n                            const np = (ny * w + nx) * 4;\r\n                            if (imgData[np+3] !== 0) {\r\n                                const dr = imgData[np]-r, dg = imgData[np+1]-g, db = imgData[np+2]-b;\r\n                                const dist = Math.sqrt(dr*dr + dg*dg + db*db);\r\n                                if(dist <= tol) stack.push({x: nx, y: ny});\r\n                            }\r\n                        }\r\n                    }\r\n                }\r\n            }\r\n            this.UI.maskCtx.putImageData(maskImg, 0, 0);\r\n            this.hasMask = true;\r\n            this.triggerLivePreview();\r\n        },\r\n\r\n        startDraw: function(e) {\r\n            if(!this.imgObj || this.isProcessing) return;\r\n            this.isDrawing = true;\r\n            const pos = this.getMousePos(e);\r\n            this.startX = pos.x; this.startY = pos.y;\r\n            this.lastX = pos.x; this.lastY = pos.y;\r\n            \r\n            if (this.currentMode === 'brush') {\r\n                this.hasMask = true;\r\n                this.UI.maskCtx.beginPath();\r\n                this.UI.maskCtx.fillStyle = 'rgba(239, 68, 68, 1.0)';\r\n                this.UI.maskCtx.arc(this.lastX, this.lastY, this.brushSize \/ 2, 0, Math.PI * 2);\r\n                this.UI.maskCtx.fill();\r\n            } else if (this.currentMode === 'rectangle' || this.currentMode === 'lasso') {\r\n                this.UI.uiCtx.clearRect(0, 0, this.UI.uiCanvas.width, this.UI.uiCanvas.height);\r\n                if(this.currentMode === 'lasso') {\r\n                    this.lassoPoints = [{x: pos.x, y: pos.y}];\r\n                }\r\n            } else if (this.currentMode === 'wand') {\r\n                this.runMagicWand(this.startX, this.startY);\r\n                this.isDrawing = false;\r\n            }\r\n        },\r\n\r\n        draw: function(e) {\r\n            if(!this.isDrawing || this.isProcessing || this.currentMode === 'wand') return;\r\n            const pos = this.getMousePos(e);\r\n            \r\n            if (this.currentMode === 'brush') {\r\n                const ctx = this.UI.maskCtx;\r\n                ctx.beginPath();\r\n                ctx.strokeStyle = 'rgba(239, 68, 68, 1.0)';\r\n                ctx.lineWidth = this.brushSize;\r\n                ctx.lineCap = 'round';\r\n                ctx.lineJoin = 'round';\r\n                ctx.moveTo(this.lastX, this.lastY);\r\n                ctx.lineTo(pos.x, pos.y);\r\n                ctx.stroke();\r\n                \r\n                this.lastX = pos.x;\r\n                this.lastY = pos.y;\r\n                \r\n            } else if (this.currentMode === 'rectangle') {\r\n                const uiCtx = this.UI.uiCtx;\r\n                uiCtx.clearRect(0, 0, this.UI.uiCanvas.width, this.UI.uiCanvas.height);\r\n                uiCtx.setLineDash([5, 5]);\r\n                uiCtx.strokeStyle = '#ef4444';\r\n                uiCtx.lineWidth = 2;\r\n                uiCtx.fillStyle = 'rgba(239, 68, 68, 0.3)';\r\n                \r\n                const w = pos.x - this.startX;\r\n                const h = pos.y - this.startY;\r\n                \r\n                uiCtx.beginPath();\r\n                uiCtx.rect(this.startX, this.startY, w, h);\r\n                uiCtx.fill();\r\n                uiCtx.stroke();\r\n                \r\n                this.lastX = pos.x;\r\n                this.lastY = pos.y;\r\n                \r\n            } else if (this.currentMode === 'lasso') {\r\n                this.lassoPoints.push({x: pos.x, y: pos.y});\r\n                \r\n                const uiCtx = this.UI.uiCtx;\r\n                uiCtx.clearRect(0, 0, this.UI.uiCanvas.width, this.UI.uiCanvas.height);\r\n                uiCtx.setLineDash([5, 5]);\r\n                uiCtx.strokeStyle = '#ef4444';\r\n                uiCtx.lineWidth = 2;\r\n                uiCtx.fillStyle = 'rgba(239, 68, 68, 0.3)';\r\n                \r\n                uiCtx.beginPath();\r\n                uiCtx.moveTo(this.lassoPoints[0].x, this.lassoPoints[0].y);\r\n                for(let i = 1; i < this.lassoPoints.length; i++) {\r\n                    uiCtx.lineTo(this.lassoPoints[i].x, this.lassoPoints[i].y);\r\n                }\r\n                uiCtx.stroke();\r\n                \r\n                this.lastX = pos.x;\r\n                this.lastY = pos.y;\r\n            }\r\n        },\r\n\r\n        stopDraw: function() {\r\n            if(!this.isDrawing) return;\r\n            this.isDrawing = false;\r\n            \r\n            if (this.currentMode === 'rectangle' || this.currentMode === 'lasso') {\r\n                const maskCtx = this.UI.maskCtx;\r\n                maskCtx.fillStyle = 'rgba(239, 68, 68, 1.0)';\r\n                \r\n                if(this.currentMode === 'rectangle') {\r\n                    const w = this.lastX - this.startX;\r\n                    const h = this.lastY - this.startY;\r\n                    if(w !== 0 && h !== 0) {\r\n                       maskCtx.fillRect(this.startX, this.startY, w, h);\r\n                       this.hasMask = true;\r\n                    }\r\n                } else if(this.currentMode === 'lasso' && this.lassoPoints.length > 2) {\r\n                    maskCtx.beginPath();\r\n                    maskCtx.moveTo(this.lassoPoints[0].x, this.lassoPoints[0].y);\r\n                    for(let i = 1; i < this.lassoPoints.length; i++) {\r\n                        maskCtx.lineTo(this.lassoPoints[i].x, this.lassoPoints[i].y);\r\n                    }\r\n                    maskCtx.closePath();\r\n                    maskCtx.fill();\r\n                    this.hasMask = true;\r\n                }\r\n                \r\n                this.UI.uiCtx.clearRect(0, 0, this.UI.uiCanvas.width, this.UI.uiCanvas.height);\r\n                this.lassoPoints = [];\r\n                this.triggerLivePreview();\r\n            } else if (this.currentMode === 'brush') {\r\n                this.triggerLivePreview();\r\n            }\r\n        },\r\n\r\n        clearMask: function() {\r\n            if(!this.imgObj) return;\r\n            this.UI.maskCtx.clearRect(0, 0, this.UI.maskCanvas.width, this.UI.maskCanvas.height);\r\n            this.hasMask = false;\r\n        },\r\n\r\n        saveStateForUndo: function() {\r\n            this.historyStack.push(this.UI.imgCanvas.toDataURL('image\/png'));\r\n            if(this.historyStack.length > 10) this.historyStack.shift();\r\n            this.UI.undoBtn.style.display = 'inline-flex';\r\n        },\r\n\r\n        undoLastEdit: function() {\r\n            if(this.historyStack.length === 0) return this.showToast('Nothing to undo.', true);\r\n            const lastState = this.historyStack.pop();\r\n            const img = new Image();\r\n            img.onload = () => {\r\n                this.UI.imgCtx.clearRect(0, 0, this.UI.imgCanvas.width, this.UI.imgCanvas.height);\r\n                this.UI.imgCtx.drawImage(img, 0, 0, this.UI.imgCanvas.width, this.UI.imgCanvas.height);\r\n                this.editCount = Math.max(0, this.editCount - 1);\r\n                this.UI.liveEdits.innerText = this.editCount;\r\n                if(this.historyStack.length === 0) this.UI.undoBtn.style.display = 'none';\r\n                this.showToast('\u21a9\ufe0f Last edit undone');\r\n            };\r\n            img.src = lastState;\r\n        },\r\n\r\n        restoreOriginal: function() {\r\n            if(!this.originalDataURL) return;\r\n            const img = new Image();\r\n            img.onload = () => {\r\n                this.UI.imgCtx.clearRect(0, 0, this.UI.imgCanvas.width, this.UI.imgCanvas.height);\r\n                this.UI.imgCtx.drawImage(img, 0, 0, this.UI.imgCanvas.width, this.UI.imgCanvas.height);\r\n                this.UI.maskCtx.clearRect(0, 0, this.UI.maskCanvas.width, this.UI.maskCanvas.height);\r\n                this.hasMask = false;\r\n                this.historyStack = [];\r\n                this.editCount = 0;\r\n                this.UI.liveEdits.innerText = '0';\r\n                this.UI.undoBtn.style.display = 'none';\r\n                this.showToast('\u267b\ufe0f Restored to original');\r\n            };\r\n            img.src = this.originalDataURL;\r\n        },\r\n\r\n        runCutToTransparent: function() {\r\n            if(!this.imgObj) return;\r\n            if(!this.hasMask) return this.showToast('Please highlight an area first.', true);\r\n\r\n            this.saveStateForUndo();\r\n            const w = this.UI.imgCanvas.width;\r\n            const h = this.UI.imgCanvas.height;\r\n            const imgData = this.UI.imgCtx.getImageData(0, 0, w, h);\r\n            const maskData = this.UI.maskCtx.getImageData(0, 0, w, h);\r\n\r\n            for (let i = 0; i < maskData.data.length; i += 4) {\r\n                if (maskData.data[i + 3] > 0) {\r\n                    imgData.data[i + 3] = 0;\r\n                }\r\n            }\r\n\r\n            this.UI.imgCtx.putImageData(imgData, 0, 0);\r\n            this.UI.maskCtx.clearRect(0, 0, w, h);\r\n            this.hasMask = false;\r\n            \r\n            this.editCount++;\r\n            this.UI.liveEdits.innerText = this.editCount;\r\n            this.UI.dwnBtn.style.display = 'inline-flex';\r\n            this.showToast('\u2702\ufe0f Area cut to transparent!');\r\n        },\r\n\r\n        runSolidColorFill: function() {\r\n            if(!this.imgObj) return;\r\n            if(!this.hasMask) return this.showToast('Please highlight an area first.', true);\r\n\r\n            this.saveStateForUndo();\r\n            const w = this.UI.imgCanvas.width;\r\n            const h = this.UI.imgCanvas.height;\r\n            const imgData = this.UI.imgCtx.getImageData(0, 0, w, h);\r\n            const maskData = this.UI.maskCtx.getImageData(0, 0, w, h);\r\n            \r\n            const hex = this.UI.fillColorPicker.value;\r\n            const r = parseInt(hex.slice(1, 3), 16);\r\n            const g = parseInt(hex.slice(3, 5), 16);\r\n            const b = parseInt(hex.slice(5, 7), 16);\r\n\r\n            for (let i = 0; i < maskData.data.length; i += 4) {\r\n                if (maskData.data[i + 3] > 0) {\r\n                    imgData.data[i] = r;\r\n                    imgData.data[i + 1] = g;\r\n                    imgData.data[i + 2] = b;\r\n                    imgData.data[i + 3] = 255;\r\n                }\r\n            }\r\n\r\n            this.UI.imgCtx.putImageData(imgData, 0, 0);\r\n            this.UI.maskCtx.clearRect(0, 0, w, h);\r\n            this.hasMask = false;\r\n            \r\n            this.editCount++;\r\n            this.UI.liveEdits.innerText = this.editCount;\r\n            this.UI.dwnBtn.style.display = 'inline-flex';\r\n            this.showToast('\ud83e\udea8 Area filled with color!');\r\n        },\r\n\r\n        runNaturalErase: function(isLivePreview = false) {\r\n            if(!this.imgObj) return;\r\n            if(!this.cvLoaded) return this.showToast('Please wait, Engine is still loading.', true);\r\n            if(!this.hasMask) return this.showToast('Please highlight an object first.', true);\r\n            \r\n            this.isProcessing = true;\r\n            if (!isLivePreview) {\r\n                this.UI.eraseBtn.disabled = true; this.UI.cutBtn.disabled = true; this.UI.fillBtn.disabled = true;\r\n                this.UI.loader.style.display = 'block';\r\n                this.UI.loaderText.innerText = 'Applying natural erase...';\r\n                this.saveStateForUndo();\r\n            }\r\n            this.UI.maskCanvas.style.opacity = '0';\r\n            \r\n            setTimeout(() => {\r\n                try {\r\n                    const imgData = this.UI.imgCtx.getImageData(0, 0, this.UI.imgCanvas.width, this.UI.imgCanvas.height);\r\n                    const srcRgba = cv.matFromImageData(imgData);\r\n                    const srcRgb = new cv.Mat();\r\n                    cv.cvtColor(srcRgba, srcRgb, cv.COLOR_RGBA2RGB);\r\n                    \r\n                    const rawMask = cv.imread(this.UI.maskCanvas);\r\n                    const mask = new cv.Mat();\r\n                    cv.cvtColor(rawMask, mask, cv.COLOR_RGBA2GRAY, 0);\r\n                    cv.threshold(mask, mask, 10, 255, cv.THRESH_BINARY);\r\n                    \r\n                    const edgeSmooth = parseInt(this.UI.edgeSmoothSli.value);\r\n                    if(edgeSmooth > 0) {\r\n                        const kernel = cv.getStructuringElement(cv.MORPH_ELLIPSE, new cv.Size(edgeSmooth, edgeSmooth));\r\n                        cv.morphologyEx(mask, mask, cv.MORPH_CLOSE, kernel);\r\n                        cv.GaussianBlur(mask, mask, new cv.Size(edgeSmooth*2+1, edgeSmooth*2+1), 0);\r\n                        kernel.delete();\r\n                    }\r\n                    \r\n                    const dstRgb = new cv.Mat();\r\n                    const radius = parseInt(this.UI.radiusSli.value);\r\n                    const method = parseInt(this.UI.algoSelect.value);\r\n                    \r\n                    if(this.qualityPreset === 'ultra' && !isLivePreview) {\r\n                        cv.inpaint(srcRgb, mask, dstRgb, radius, method);\r\n                        const temp = dstRgb.clone();\r\n                        cv.inpaint(temp, mask, dstRgb, radius, method);\r\n                        temp.delete();\r\n                    } else {\r\n                        cv.inpaint(srcRgb, mask, dstRgb, radius, method);\r\n                    }\r\n                    \r\n                    const dstRgba = new cv.Mat();\r\n                    cv.cvtColor(dstRgb, dstRgba, cv.COLOR_RGB2RGBA);\r\n                    \r\n                    const fromTo = [3, 3];\r\n                    const vecSrc = new cv.MatVector(); vecSrc.push_back(srcRgba);\r\n                    const vecDst = new cv.MatVector(); vecDst.push_back(dstRgba);\r\n                    cv.mixChannels(vecSrc, vecDst, fromTo);\r\n                    \r\n                    cv.imshow(this.UI.imgCanvas, dstRgba);\r\n                    \r\n                    const contextBlend = parseInt(this.UI.contextBlendSli.value);\r\n                    if(contextBlend > 0) {\r\n                        const outData = this.UI.imgCtx.getImageData(0, 0, this.UI.imgCanvas.width, this.UI.imgCanvas.height);\r\n                        const origData = imgData.data;\r\n                        const newData = outData.data;\r\n                        const maskPixels = this.UI.maskCtx.getImageData(0, 0, this.UI.maskCanvas.width, this.UI.maskCanvas.height).data;\r\n                        \r\n                        for (let i = 0; i < newData.length; i += 4) {\r\n                            if (maskPixels[i + 3] > 0 && origData[i+3] > 0) {\r\n                                const blend = contextBlend \/ 100;\r\n                                newData[i] = newData[i] * blend + origData[i] * (1 - blend);\r\n                                newData[i+1] = newData[i+1] * blend + origData[i+1] * (1 - blend);\r\n                                newData[i+2] = newData[i+2] * blend + origData[i+2] * (1 - blend);\r\n                            }\r\n                        }\r\n                        this.UI.imgCtx.putImageData(outData, 0, 0);\r\n                    }\r\n                    \r\n                    const grainLvl = parseInt(this.UI.grainSli.value);\r\n                    if (grainLvl > 0) {\r\n                        const outData = this.UI.imgCtx.getImageData(0, 0, this.UI.imgCanvas.width, this.UI.imgCanvas.height);\r\n                        const pixels = outData.data;\r\n                        const maskPixels = this.UI.maskCtx.getImageData(0, 0, this.UI.maskCanvas.width, this.UI.maskCanvas.height).data;\r\n                        \r\n                        for (let i = 0; i < pixels.length; i += 4) {\r\n                            if (maskPixels[i + 3] > 0 && pixels[i+3] > 0) {\r\n                                const noise = (Math.random() - 0.5) * (grainLvl * 2);\r\n                                pixels[i] = Math.min(255, Math.max(0, pixels[i] + noise));\r\n                                pixels[i+1] = Math.min(255, Math.max(0, pixels[i+1] + noise));\r\n                                pixels[i+2] = Math.min(255, Math.max(0, pixels[i+2] + noise));\r\n                            }\r\n                        }\r\n                        this.UI.imgCtx.putImageData(outData, 0, 0);\r\n                    }\r\n                    \r\n                    srcRgba.delete(); srcRgb.delete(); rawMask.delete(); mask.delete(); dstRgb.delete(); dstRgba.delete(); vecSrc.delete(); vecDst.delete();\r\n                    \r\n                    this.UI.maskCanvas.style.opacity = (this.maskOpacity \/ 100);\r\n                    \r\n                    if (!isLivePreview) {\r\n                        this.UI.maskCtx.clearRect(0, 0, this.UI.maskCanvas.width, this.UI.maskCanvas.height);\r\n                        this.hasMask = false;\r\n                        this.editCount++;\r\n                        this.UI.liveEdits.innerText = this.editCount;\r\n                        this.UI.dwnBtn.style.display = 'inline-flex';\r\n                        this.showToast('\u2728 Natural erase complete!');\r\n                    } else {\r\n                        \/\/ CRITICAL FIX: Red mask stays visible in LIVE PREVIEW\r\n                        this.hasMask = true;\r\n                        \/\/ Optional: Show a small indicator that preview updated, but don't spam toast\r\n                    }\r\n                    \r\n                } catch (err) {\r\n                    console.error(err);\r\n                    this.showToast('Error processing. Try smaller image or lower quality.', true);\r\n                    this.UI.maskCanvas.style.opacity = (this.maskOpacity \/ 100);\r\n                } finally {\r\n                    this.isProcessing = false;\r\n                    if (!isLivePreview) {\r\n                        this.UI.eraseBtn.disabled = false; this.UI.cutBtn.disabled = false; this.UI.fillBtn.disabled = false;\r\n                        this.UI.loader.style.display = 'none';\r\n                    }\r\n                }\r\n            }, isLivePreview ? 30 : 50);\r\n        },\r\n\r\n        downloadResult: function() {\r\n            if(!this.imgObj) return;\r\n            const a = document.createElement('a');\r\n            a.download = 'PTH-AI-Magic-Eraser-Result.png';\r\n            a.href = this.UI.imgCanvas.toDataURL('image\/png');\r\n            a.click();\r\n            this.showToast('\ud83d\udce5 Result Downloaded!');\r\n        }\r\n    };\r\n\r\n    function runInitPthMagicEraser() {\r\n        if (!window.pthMagicEraserApp.initialized) {\r\n            if (document.getElementById('pth-magic-eraser-wrapper')) {\r\n                window.pthMagicEraserApp.initialized = true;\r\n                window.pthMagicEraserApp.init();\r\n            }\r\n        }\r\n    }\r\n\r\n    document.addEventListener('DOMContentLoaded', runInitPthMagicEraser);\r\n    if (document.readyState === 'interactive' || document.readyState === 'complete') runInitPthMagicEraser();\r\n    window.addEventListener('load', runInitPthMagicEraser);\r\n\r\n    ['mousemove', 'scroll', 'touchstart', 'click', 'keydown'].forEach(evt => {\r\n        window.addEventListener(evt, runInitPthMagicEraser, { once: true, passive: true });\r\n    });\r\n})();\r\n<\/script>\r\n\t\t\t\t\t\t\t\t<script data-no-optimize=\"1\" data-no-minify=\"1\" data-cfasync=\"false\">\r\n(function () {\r\n  'use strict';\r\n  function mount() {\r\n    var panel = document.getElementById('pth-ie-tab-eraser');\r\n    var tool  = document.getElementById('pth-magic-eraser-wrapper');\r\n    if (!panel || !tool) return false;\r\n    if (tool.parentNode !== panel) {\r\n      var ph = document.getElementById('pth-ie-empty-eraser');\r\n      if (ph && ph.parentNode) ph.parentNode.removeChild(ph);\r\n      tool.style.margin = '0';\r\n      panel.appendChild(tool);\r\n    }\r\n    return true;\r\n  }\r\n  if (mount()) return;\r\n  if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', mount);\r\n  window.addEventListener('load', function () { setTimeout(mount, 60); });\r\n  if (typeof MutationObserver !== 'undefined') {\r\n    var o = new MutationObserver(function () { if (mount()) o.disconnect(); });\r\n    o.observe(document.body || document.documentElement, { childList: true, subtree: true });\r\n    setTimeout(function () { o.disconnect(); }, 10000);\r\n  }\r\n})();\r\n<\/script>\n\n\n<style>\r\n\/* ==========================================================================\r\n   PRIME TOOL HUB - AI IMAGE UPSCALER PRO v3.3 (ULTIMATE CACHE-PROOF)\r\n   ========================================================================== *\/\r\n#pth-up-upscaler-wrapper { box-sizing: border-box; font-family: 'Inter', system-ui, -apple-system, sans-serif; color: #0f172a; background-color: #ffffff; border-radius: 12px; overflow: hidden; border: 1px solid #e2e8f0; margin: 20px 0; box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.05); transition: all 0.3s ease; position: relative; }\r\n#pth-up-upscaler-wrapper * { box-sizing: border-box; }\r\n\r\n\/* TRUE FULL SCREEN *\/\r\n#pth-up-upscaler-wrapper.is-fullscreen { position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; z-index: 999999; margin: 0; border-radius: 0; overflow-y: auto; display: flex; flex-direction: column; background: #f8fafc; }\r\n#pth-up-upscaler-wrapper.is-fullscreen .pth-main-area { flex: 1; max-width: 1400px; margin: 0 auto; width: 100%; }\r\n\r\n\/* Header *\/\r\n#pth-up-upscaler-wrapper .pth-header { padding: 24px 24px 0 24px; display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; flex-wrap: wrap; gap: 12px; }\r\n#pth-up-upscaler-wrapper .pth-title { margin: 0; font-size: 1.5rem; font-weight: 800; color: #3b82f6; display: flex; align-items: center; gap: 8px; }\r\n#pth-up-upscaler-wrapper .pth-btn { border: none; padding: 10px 18px; font-size: 0.875rem; border-radius: 8px; cursor: pointer; font-weight: 700; display: inline-flex; align-items: center; justify-content: center; gap: 6px; transition: all 0.2s; }\r\n#pth-up-upscaler-wrapper .pth-btn.danger { background: #fee2e2; color: #991b1b; }\r\n#pth-up-upscaler-wrapper .pth-btn.danger:hover { background: #fecaca; }\r\n#pth-up-upscaler-wrapper .pth-btn.primary { background: #3b82f6; color: #ffffff; box-shadow: 0 4px 10px rgba(59, 130, 246, 0.25); }\r\n#pth-up-upscaler-wrapper .pth-btn.primary:hover { background: #2563eb; transform: translateY(-2px); }\r\n#pth-up-upscaler-wrapper .pth-btn.primary:disabled { background: #94a3b8; cursor: not-allowed; box-shadow: none; transform: none; }\r\n#pth-up-upscaler-wrapper .pth-fullwidth-btn { background: #1e293b; color: #fff; }\r\n#pth-up-upscaler-wrapper .pth-fullwidth-btn:hover { background: #0f172a; }\r\n\r\n\/* Main Area & Grid *\/\r\n#pth-up-upscaler-wrapper .pth-main-area { padding: 0 24px 24px 24px; }\r\n#pth-up-upscaler-wrapper .pth-content-grid { display: grid; grid-template-columns: 1.8fr 1fr; gap: 24px; }\r\n@media (max-width: 900px) { #pth-up-upscaler-wrapper .pth-content-grid { grid-template-columns: 1fr; } }\r\n\r\n\/* Inputs *\/\r\n#pth-up-upscaler-wrapper .pth-drop-zone { border: 2px dashed #93c5fd; border-radius: 12px; padding: 40px 20px; text-align: center; background: #f8fafc; transition: all 0.3s; cursor: pointer; margin-bottom: 20px; position: relative; }\r\n#pth-up-upscaler-wrapper .pth-drop-zone:hover, #pth-up-upscaler-wrapper .pth-drop-zone.active { border-color: #3b82f6; background: #eff6ff; }\r\n#pth-up-upscaler-wrapper .pth-dz-icon { font-size: 40px; margin-bottom: 10px; }\r\n#pth-up-upscaler-wrapper .pth-dz-text { font-size: 1rem; font-weight: 700; color: #1e3a8a; margin: 0 0 5px 0; }\r\n#pth-up-upscaler-wrapper .pth-dz-sub { font-size: 0.85rem; color: #64748b; margin: 0; }\r\n#pth-up-upscaler-wrapper .pth-or-section { text-align: center; margin: 12px 0; color: #64748b; font-size: 0.875rem; font-weight: 600; }\r\n#pth-up-upscaler-wrapper .pth-url-group { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 20px; justify-content: center; }\r\n#pth-up-upscaler-wrapper .pth-url-group input { flex: 1; min-width: 200px; padding: 10px 16px; border: 1px solid #cbd5e1; border-radius: 8px; font-size: 0.95rem; outline: none; }\r\n#pth-up-upscaler-wrapper .pth-url-group input:focus { border-color: #3b82f6; }\r\n\r\n\/* Original Preview Before Start *\/\r\n#pth-up-upscaler-wrapper .pth-orig-preview-area { display: none; background: #f8fafc; border: 1px solid #e2e8f0; border-radius: 12px; padding: 20px; margin-bottom: 20px; text-align: center; }\r\n#pth-up-upscaler-wrapper .pth-orig-img-wrap { max-height: 350px; margin-bottom: 15px; background: #e2e8f0; border-radius: 8px; overflow: hidden; display: flex; align-items: center; justify-content: center; }\r\n#pth-up-upscaler-wrapper .pth-orig-img-wrap img { max-width: 100%; max-height: 350px; display: block; object-fit: contain; }\r\n#pth-up-upscaler-wrapper .pth-actions-row { display: flex; justify-content: center; gap: 15px; flex-wrap: wrap; }\r\n\r\n\/* Scale Selector *\/\r\n#pth-up-upscaler-wrapper .pth-scale-control { margin: 15px 0; padding: 12px; background: #f1f5f9; border-radius: 8px; border: 1px solid #e2e8f0; text-align: left; max-width: 400px; margin-left: auto; margin-right: auto; }\r\n#pth-up-upscaler-wrapper .pth-scale-control label { font-weight: 700; font-size: 0.9rem; display: block; margin-bottom: 6px; color: #0f172a; }\r\n#pth-up-upscaler-wrapper .pth-scale-control select { width: 100%; padding: 10px; border-radius: 6px; border: 1px solid #cbd5e1; outline: none; font-family: inherit; font-size: 14px; }\r\n\r\n\/* Progress, Scanning & Cache Info *\/\r\n#pth-up-upscaler-wrapper .pth-progress-area { display: none; background: #ffffff; border: 1px solid #e2e8f0; border-radius: 12px; padding: 25px; margin-bottom: 20px; text-align: center; }\r\n#pth-up-upscaler-wrapper .pth-progress-title { font-size: 1rem; font-weight: 800; color: #0f172a; margin: 0 0 15px 0; }\r\n#pth-up-upscaler-wrapper .pth-progress-sub { font-size: 0.85rem; color: #64748b; margin: 0 0 5px 0; font-family: monospace; }\r\n#pth-up-upscaler-wrapper .pth-progress-bar-wrap { width: 100%; height: 12px; background: #e2e8f0; border-radius: 10px; overflow: hidden; margin-bottom: 10px; }\r\n#pth-up-upscaler-wrapper .pth-progress-bar { height: 100%; background: linear-gradient(90deg, #3b82f6, #8b5cf6); width: 0%; transition: width 0.3s ease; border-radius: 10px; }\r\n#pth-up-upscaler-wrapper .pth-first-time-note { font-size: 0.8rem; color: #3b82f6; font-weight: 600; margin-top: 8px; background: #eff6ff; padding: 8px; border-radius: 6px; display: none; border: 1px solid #bfdbfe; }\r\n\r\n\/* SCANNING ANIMATION CSS *\/\r\n#pth-up-upscaler-wrapper .pth-scanning-wrapper { position: relative; max-width: 250px; max-height: 250px; margin: 0 auto 15px auto; border-radius: 8px; overflow: hidden; border: 2px solid #8b5cf6; display: none; box-shadow: 0 0 20px rgba(139, 92, 246, 0.3); background: #e2e8f0; }\r\n#pth-up-upscaler-wrapper .pth-scanning-img { width: 100%; max-height: 250px; object-fit: contain; display: block; opacity: 0.6; filter: grayscale(80%) blur(2px); }\r\n#pth-up-upscaler-wrapper .pth-scanner-line { position: absolute; top: 0; left: 0; width: 100%; height: 3px; background: #d946ef; box-shadow: 0 0 15px 5px rgba(217, 70, 239, 0.8); animation: pthScanAnim 1.2s ease-in-out infinite alternate; }\r\n@keyframes pthScanAnim { 0% { top: 0%; } 100% { top: 98%; } }\r\n\r\n\/* Preview Box with Slider *\/\r\n#pth-up-upscaler-wrapper .pth-preview-box { border: 1px solid #e2e8f0; border-radius: 12px; overflow: hidden; margin-bottom: 20px; display: none; background: #fff; }\r\n#pth-up-upscaler-wrapper .pth-preview-header { background: #f1f5f9; padding: 12px 15px; border-bottom: 1px solid #e2e8f0; font-weight: 800; color: #0f172a; display: flex; justify-content: space-between; align-items: center; }\r\n#pth-up-upscaler-wrapper .pth-checkerboard { background-image: linear-gradient(45deg, #e2e8f0 25%, transparent 25%), linear-gradient(-45deg, #e2e8f0 25%, transparent 25%), linear-gradient(45deg, transparent 75%, #e2e8f0 75%), linear-gradient(-45deg, transparent 75%, #e2e8f0 75%); background-size: 20px 20px; background-position: 0 0, 0 10px, 10px -10px, -10px 0px; padding: 20px; display: flex; justify-content: center; align-items: center; min-height: 350px; position: relative; overflow: hidden; }\r\n#pth-up-upscaler-wrapper .pth-compare-wrap { position: relative; display: inline-block; max-width: 100%; z-index: 2; user-select: none; line-height: 0; }\r\n#pth-up-upscaler-wrapper .pth-img-result { max-width: 100%; max-height: 600px; height: auto; display: block; transition: filter 0.2s ease; }\r\n#pth-up-upscaler-wrapper .pth-img-before { position: absolute; top: 0; left: 0; width: 50%; height: 100%; overflow: hidden; border-right: 3px solid #fff; box-shadow: 3px 0 8px rgba(0,0,0,0.25); }\r\n#pth-up-upscaler-wrapper .pth-img-before img { max-width: none; width: 100%; height: 100%; display: block; object-fit: fill; image-rendering: pixelated; }\r\n#pth-up-upscaler-wrapper .pth-compare-slider { position: absolute; top: 0; left: 0; width: 100%; height: 100%; opacity: 0; z-index: 4; cursor: ew-resize; margin: 0; }\r\n\r\n\/* Live Filters Panel *\/\r\n#pth-up-upscaler-wrapper .pth-filters-panel { background: #f8fafc; padding: 15px; border-top: 1px solid #e2e8f0; display: none; }\r\n#pth-up-upscaler-wrapper .pth-filter-row { display: flex; align-items: center; gap: 12px; margin-bottom: 10px; font-size: 0.85rem; }\r\n#pth-up-upscaler-wrapper .pth-filter-row label { min-width: 80px; font-weight: 600; color: #475569; }\r\n\r\n\/* Settings *\/\r\n#pth-up-upscaler-wrapper .pth-settings-grid { display: none; background: #f8fafc; padding: 20px; border-radius: 12px; border: 1px solid #e2e8f0; margin-bottom: 20px; }\r\n#pth-up-upscaler-wrapper .pth-output-control { display: flex; align-items: center; gap: 12px; margin-bottom: 12px; }\r\n#pth-up-upscaler-wrapper .pth-output-control label { font-weight: 600; font-size: 0.85rem; min-width: 110px; color: #475569; }\r\n#pth-up-upscaler-wrapper select, #pth-up-upscaler-wrapper input[type=\"range\"] { flex: 1; padding: 8px 12px; border-radius: 8px; border: 1px solid #cbd5e1; outline: none; }\r\n\r\n\/* Sidebar & Extras *\/\r\n#pth-up-upscaler-wrapper .pth-sidebar { background: #f1f5f9; border: 1px solid #e2e8f0; border-radius: 12px; padding: 20px; height: fit-content; }\r\n#pth-up-upscaler-wrapper .pth-sidebar h4 { margin: 0 0 15px 0; font-size: 1.1rem; color: #0f172a; border-bottom: 2px solid #cbd5e1; padding-bottom: 10px; }\r\n#pth-up-upscaler-wrapper .pth-sidebar ul { padding-left: 0; list-style: none; margin: 0 0 20px 0; }\r\n#pth-up-upscaler-wrapper .pth-sidebar li { margin-bottom: 12px; display: flex; align-items: flex-start; gap: 10px; font-size: 0.9rem; color: #334155; }\r\n#pth-up-upscaler-wrapper .pth-toast { position: fixed; bottom: 20px; right: 20px; background: #10b981; color: #fff; padding: 12px 24px; border-radius: 8px; box-shadow: 0 10px 25px -5px rgba(0,0,0,0.2); display: none; align-items: center; gap: 12px; z-index: 9999999; font-weight: 700; font-size: 14px; }\r\n#pth-up-upscaler-wrapper .pth-toast.show { display: flex; animation: pthToastFade 0.3s ease; }\r\n@keyframes pthToastFade { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: translateY(0); } }\r\n\r\n\/* Print Styles *\/\r\n@media print {\r\n    body * { visibility: hidden; }\r\n    #pth-up-img-result, #pth-up-img-result * { visibility: visible; }\r\n    #pth-up-img-result { position: absolute; left: 0; top: 0; width: 100vw; height: auto; max-height: 100vh; object-fit: contain; filter: none !important; }\r\n}\r\n<\/style>\r\n\r\n<div id=\"pth-up-upscaler-wrapper\">\r\n    <div id=\"pth-up-toast-upscaler\" class=\"pth-toast\">\u2705 Action Successful!<\/div>\r\n\r\n    <svg width=\"0\" height=\"0\" style=\"position:absolute;pointer-events:none;\" aria-hidden=\"true\" focusable=\"false\">\r\n        <filter id=\"pth-up-sharpen-svg\" x=\"0\" y=\"0\">\r\n            <feConvolveMatrix id=\"pth-up-sharpen-kernel\" order=\"3\" preserveAlpha=\"true\" kernelMatrix=\"0 0 0 0 1 0 0 0 0\"><\/feConvolveMatrix>\r\n        <\/filter>\r\n    <\/svg>\r\n   \r\n    <div class=\"pth-header\">\r\n        <div>\r\n            <h2 class=\"pth-title\">\u2728 AI Image Upscaler Pro <span style=\"font-size:0.75rem; background:#3b82f6; color:#fff; padding:2px 8px; border-radius:9999px;\">2x\/4x AI Engine<\/span><\/h2>\r\n            <div style=\"display:flex; gap:8px; margin-top:8px; flex-wrap:wrap;\">\r\n                <span style=\"background:#eff6ff; color:#1d4ed8; font-size:.72rem; font-weight:700; padding:3px 10px; border-radius:20px; border:1px solid #bfdbfe;\">v2.0<\/span>\r\n                <span style=\"background:#f0fdf4; color:#047857; font-size:.72rem; font-weight:700; padding:3px 10px; border-radius:20px; border:1px solid #bbf7d0;\">\ud83d\udd12 100% Offline<\/span>\r\n            <\/div>\r\n        <\/div>\r\n        <div style=\"display:flex; gap:8px; flex-wrap: wrap;\">\r\n            <button class=\"pth-btn pth-fullwidth-btn\" id=\"pth-up-fw-btn-upscaler\" title=\"Toggle Full Screen\" aria-label=\"Toggle full screen\">\u26f6 Full Screen<\/button>\r\n            <button class=\"pth-btn danger\" id=\"pth-up-clear-btn\" style=\"display:none;\" aria-label=\"Clear and try another image\">\ud83d\udd04 Try Another Image<\/button>\r\n        <\/div>\r\n    <\/div>\r\n   \r\n    <div class=\"pth-main-area\">\r\n        <div class=\"pth-content-grid\" id=\"pth-up-upscaler-layout\">\r\n           \r\n            <div class=\"pth-main-col\">\r\n                <input type=\"file\" id=\"pth-up-image-file\" accept=\"image\/*\" style=\"display:none;\">\r\n               \r\n                <div id=\"pth-up-input-area\">\r\n                    <div class=\"pth-drop-zone\" id=\"pth-up-drop-zone\">\r\n                        <div class=\"pth-dz-icon\">\ud83d\uddbc\ufe0f<\/div>\r\n                        <h3 class=\"pth-dz-text\">Click or Drag & Drop an Image<\/h3>\r\n                        <p class=\"pth-dz-sub\">100% Secure \u2022 Processed locally \u2022 Up to 2000px recommended<\/p>\r\n                    <\/div>\r\n                    <div class=\"pth-or-section\">\u2014 OR \u2014<\/div>\r\n                    <div class=\"pth-url-group\">\r\n                        <input type=\"text\" id=\"pth-up-url-input\" placeholder=\"https:\/\/example.com\/image.jpg\" aria-label=\"Image URL\">\r\n                        <button class=\"pth-btn primary\" id=\"pth-up-load-url-btn\" aria-label=\"Load image from URL\">\ud83d\udd17 Load URL<\/button>\r\n                        <button class=\"pth-btn primary\" id=\"pth-up-paste-btn\" aria-label=\"Paste image from clipboard\">\ud83d\udccb Paste<\/button>\r\n                        <button class=\"pth-btn\" id=\"pth-up-load-sample-btn\" style=\"background: #f59e0b; color: white;\" aria-label=\"Try a sample image\">\ud83d\uddbc\ufe0f Try Sample<\/button>\r\n                    <\/div>\r\n                <\/div>\r\n               \r\n                <div class=\"pth-orig-preview-area\" id=\"pth-up-orig-preview-area\">\r\n                    <h3 style=\"margin-top:0; color:#0f172a;\">\ud83d\udcf8 Original Image Ready<\/h3>\r\n                    <div class=\"pth-orig-img-wrap\">\r\n                        <img decoding=\"async\" id=\"pth-up-img-preview-only\" src=\"\" alt=\"ai image upscaler original\">\r\n                    <\/div>\r\n                    <p style=\"font-size:0.85rem; color:#64748b; margin-bottom: 15px;\">Original Size: <strong id=\"pth-up-orig-size-label\">0 x 0 px<\/strong><\/p>\r\n                   \r\n                    <div class=\"pth-scale-control\">\r\n                        <label>\ud83d\udd22 AI Upscale Factor<\/label>\r\n                        <select id=\"pth-up-scale-select\" aria-label=\"AI upscale factor\">\r\n                            <option value=\"2\" selected>2\u00d7 \u2014 Fast & Balanced (Recommended)<\/option>\r\n                            <option value=\"3\">3\u00d7 \u2014 More Detail<\/option>\r\n                            <option value=\"4\">4\u00d7 \u2014 Maximum Detail (2-Pass AI)<\/option>\r\n                        <\/select>\r\n                    <\/div>\r\n                   \r\n                    <div class=\"pth-actions-row\">\r\n                        <button class=\"pth-btn primary\" id=\"pth-up-start-ai-btn\" style=\"font-size: 1rem; padding: 12px 24px; background: #8b5cf6;\" aria-label=\"Upscale image with AI now\">\u2728 Upscale with AI Now<\/button>\r\n                        <button class=\"pth-btn danger\" id=\"pth-up-cancel-preview-btn\" aria-label=\"Cancel preview\">Cancel<\/button>\r\n                    <\/div>\r\n                <\/div>\r\n               \r\n                <div class=\"pth-progress-area\" id=\"pth-up-progress-area\">\r\n                    <h3 class=\"pth-progress-title\" id=\"pth-up-progress-heading\">\ud83e\udd16 AI is Initializing...<\/h3>\r\n                    \r\n                    <div class=\"pth-scanning-wrapper\" id=\"pth-up-scanning-wrapper\">\r\n                        <img decoding=\"async\" id=\"pth-up-scanning-img\" class=\"pth-scanning-img\" src=\"\" alt=\"\">\r\n                        <div class=\"pth-scanner-line\"><\/div>\r\n                    <\/div>\r\n\r\n                    <div class=\"pth-progress-bar-wrap\" id=\"pth-up-prog-bar-wrap\">\r\n                        <div class=\"pth-progress-bar\" id=\"pth-up-progress-bar\"><\/div>\r\n                    <\/div>\r\n                    \r\n                    <p class=\"pth-progress-sub\" id=\"pth-up-progress-sub\">Preparing Environment...<\/p>\r\n                    \r\n                    <div class=\"pth-first-time-note\" id=\"pth-up-first-time-note\">\r\n                        \ud83d\udce5 <b>Caching Model:<\/b> The AI Engine is downloading. This only happens on your first visit!\r\n                    <\/div>\r\n                <\/div>\r\n               \r\n                <div class=\"pth-preview-box\" id=\"pth-up-preview-box\">\r\n                    <div class=\"pth-preview-header\">\r\n                        <span>\ud83d\uddbc\ufe0f AI Upscale Result Preview<\/span>\r\n                        <label style=\"display:flex; align-items:center; gap:6px; font-size:0.85rem; cursor:pointer;\">\r\n                            <input type=\"checkbox\" id=\"pth-up-compare-toggle\" checked style=\"accent-color:#3b82f6; width: 16px; height: 16px;\" aria-label=\"Toggle before and after comparison slider\"> Before\/After Slider\r\n                        <\/label>\r\n                    <\/div>\r\n                    <div class=\"pth-checkerboard\" id=\"pth-up-checkerboard\">\r\n                        <div class=\"pth-compare-wrap\" id=\"pth-up-compare-wrap\">\r\n                            <img decoding=\"async\" id=\"pth-up-img-result\" class=\"pth-img-result\" src=\"\" alt=\"ai image upscaler result\">\r\n                            <div class=\"pth-img-before\" id=\"pth-up-img-before-box\">\r\n                                <img decoding=\"async\" id=\"pth-up-img-orig-compare\" src=\"\" alt=\"ai image upscaler original pixelated\">\r\n                            <\/div>\r\n                            <input type=\"range\" min=\"0\" max=\"100\" value=\"50\" class=\"pth-compare-slider\" id=\"pth-up-compare-slider\">\r\n                        <\/div>\r\n                    <\/div>\r\n                    <div class=\"pth-info-bar\" style=\"display:flex; justify-content: space-between; background: #f1f5f9; padding: 12px 16px; border-top: 1px solid #e2e8f0; font-size: 0.85rem; color: #475569; flex-wrap: wrap; gap:10px;\">\r\n                        <div>\ud83d\udccf Upscaled Size: <strong id=\"pth-up-dimensions-new\">\u2014 \u00d7 \u2014 px<\/strong><\/div>\r\n                        <div>\u23f1\ufe0f Processing Time: <strong id=\"pth-up-proc-time\">0.0s<\/strong><\/div>\r\n                    <\/div>\r\n                   \r\n                    <div class=\"pth-filters-panel\" id=\"pth-up-filters-panel\">\r\n                        <h4 style=\"margin:0 0 12px 0; font-size:0.95rem;\">\ud83c\udf9b\ufe0f Live Fine-Tune Filters<\/h4>\r\n                        <div class=\"pth-filter-row\">\r\n                            <label for=\"pth-up-brightness\">Brightness<\/label>\r\n                            <input type=\"range\" id=\"pth-up-brightness\" min=\"50\" max=\"150\" value=\"100\" style=\"flex:1;\" aria-label=\"Brightness percentage\">\r\n                            <span id=\"pth-up-bright-val\" style=\"width:38px; text-align:right;\">100%<\/span>\r\n                        <\/div>\r\n                        <div class=\"pth-filter-row\">\r\n                            <label for=\"pth-up-contrast\">Contrast<\/label>\r\n                            <input type=\"range\" id=\"pth-up-contrast\" min=\"50\" max=\"150\" value=\"100\" style=\"flex:1;\" aria-label=\"Contrast percentage\">\r\n                            <span id=\"pth-up-contrast-val\" style=\"width:38px; text-align:right;\">100%<\/span>\r\n                        <\/div>\r\n                        <div class=\"pth-filter-row\">\r\n                            <label for=\"pth-up-saturation\">Saturation<\/label>\r\n                            <input type=\"range\" id=\"pth-up-saturation\" min=\"50\" max=\"150\" value=\"100\" style=\"flex:1;\" aria-label=\"Saturation percentage\">\r\n                            <span id=\"pth-up-sat-val\" style=\"width:38px; text-align:right;\">100%<\/span>\r\n                        <\/div>\r\n                        <div class=\"pth-filter-row\">\r\n                            <label for=\"pth-up-sharpen\">Sharpen<\/label>\r\n                            <input type=\"range\" id=\"pth-up-sharpen\" min=\"0\" max=\"100\" value=\"0\" style=\"flex:1;\" aria-label=\"Sharpen intensity\">\r\n                            <span id=\"pth-up-sharpen-val\" style=\"width:38px; text-align:right;\">0%<\/span>\r\n                        <\/div>\r\n                        <button class=\"pth-btn danger\" id=\"pth-up-reset-filters\" style=\"margin-top:8px;\" aria-label=\"Reset all fine-tune filters\">\ud83d\udd04 Reset Filters<\/button>\r\n                    <\/div>\r\n                   \r\n                    <div style=\"padding: 15px; background: #fff; border-top: 1px solid #e2e8f0; display:flex; justify-content:center; gap:10px; flex-wrap:wrap;\">\r\n                        <button class=\"pth-btn primary\" id=\"pth-up-download-btn\" style=\"background: #10b981;\" aria-label=\"Download HD image\">\ud83d\udce5 Download HD Image<\/button>\r\n                        <button class=\"pth-btn primary\" id=\"pth-up-copy-btn\" aria-label=\"Copy image to clipboard\">\ud83d\udccb Copy Image<\/button>\r\n                        <button class=\"pth-btn primary\" id=\"pth-up-print-btn\" style=\"background: #64748b;\" aria-label=\"Print image\">\ud83d\udda8\ufe0f Print Image<\/button>\r\n                    <\/div>\r\n                <\/div>\r\n               \r\n                <div class=\"pth-settings-grid\" id=\"pth-up-settings-area\">\r\n                    <label style=\"font-size: 0.85rem; font-weight: 700; color: #475569; text-transform: uppercase;\">\ud83d\udce4 Export Settings<\/label>\r\n                    <div class=\"pth-output-control\" style=\"margin-top: 10px;\">\r\n                        <label>Format<\/label>\r\n                        <select id=\"pth-up-output-format\" aria-label=\"Output image format\">\r\n                            <option value=\"image\/png\">PNG (Lossless)<\/option>\r\n                            <option value=\"image\/jpeg\" selected>JPG<\/option>\r\n                            <option value=\"image\/webp\">WebP<\/option>\r\n                        <\/select>\r\n                    <\/div>\r\n                    <div class=\"pth-output-control\" id=\"pth-up-quality-row\">\r\n                        <label>Quality <span id=\"pth-up-quality-val\">95<\/span>%<\/label>\r\n                        <input type=\"range\" id=\"pth-up-quality-slider\" min=\"1\" max=\"100\" value=\"95\" aria-label=\"Output image quality\">\r\n                    <\/div>\r\n                <\/div>\r\n            <\/div>\r\n           \r\n            <div class=\"pth-sidebar-col\" id=\"pth-up-upscaler-sidebar\">\r\n                <div class=\"pth-sidebar\">\r\n                    <h4>\ud83d\udca1 Pro Upscaling Tips<\/h4>\r\n                    <ul>\r\n                        <li>\u2728 <b>New 4\u00d7 Mode:<\/b> Two-pass AI for ultra-sharp results on portraits, product photos & text.<\/li>\r\n                        <li>\ud83c\udf9b\ufe0f <b>Live Filters:<\/b> Real-time brightness, contrast & saturation \u2014 perfect for final polish.<\/li>\r\n                        <li>\ud83d\ude80 <b>GPU Powered:<\/b> Uses your browser\u2019s WebGL for maximum speed.<\/li>\r\n                        <li>\ud83d\udd12 <b>100% Private:<\/b> Everything runs locally \u2014 zero server uploads.<\/li>\r\n                    <\/ul>\r\n                   \r\n                    <h4 style=\"margin-top:30px;\">\ud83d\udd17 Related Prime Tools<\/h4>\r\n                    <ul>\r\n                        <li>\ud83d\uddbc\ufe0f <a href=\"\/free-advanced-image-studio-pro\/\" style=\"color:#3b82f6; text-decoration:none;\">Advanced Image Studio<\/a> \u2014 Edit and compress files.<\/li>\r\n                        <li>\u2702\ufe0f <a href=\"\/free-ai-background-remover\/\" style=\"color:#3b82f6; text-decoration:none;\">Background Remover<\/a> \u2014 One-click transparent PNGs.<\/li>\r\n                        <li>\ud83c\udfa8 <a href=\"\/svg-to-png-converter\/\" style=\"color:#3b82f6; text-decoration:none;\">SVG Vector Converter<\/a> \u2014 Export crisp graphics.<\/li>\r\n                    <\/ul>\r\n                   \r\n                    <div style=\"margin-top: 20px; padding: 15px; background: #e0f2fe; border-radius: 8px; border: 1px solid #bae6fd;\">\r\n                        <strong style=\"color: #0369a1; display:block; margin-bottom:5px;\">\ud83d\udd12 100% Privacy \u2022 Offline Capable<\/strong>\r\n                        <span style=\"font-size: 0.85rem; color: #0c4a6e;\">All AI processing happens inside your browser.<\/span>\r\n                    <\/div>\r\n                <\/div>\r\n            <\/div>\r\n        <\/div>\r\n    <\/div>\r\n<\/div>\r\n\r\n<script data-no-optimize=\"1\" data-no-minify=\"1\" data-cfasync=\"false\" data-pagespeed-no-defer=\"1\" class=\"cmplz-native\">\r\n(function() {\r\n    window.pthUpscalerApp = {\r\n        initialized: false,\r\n        upscalerInstance: null,\r\n        originalImgObj: null,\r\n        resultImgData: null,\r\n        startTime: 0,\r\n        currentFilters: { brightness: 100, contrast: 100, saturation: 100, sharpen: 0 },\r\n        sampleBase64: \"data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAACXSURBVHgB7VRRDoMgDLUfHkBP1rP1rA4e0G6zX9osYyNtYyP7yEvIJwkhm1JKG2Psg3iT8x5hGE4YY2y+741S2iGlhBCCtW2LrusqY+yNcz5zzvG+b2OM8T2iKHrGGF\/P81TTNEVRFDUw51wTQiCEEI1zLqWU9\/s90jSNVlW11nVNV1UV9X1\/u+rYI+d8TNM0L2YcT3I7Pwg7sX4u2eT5AAAAAElFTkSuQmCC\",\r\n        \r\n        init: function() {\r\n            this.cacheDOM();\r\n            this.attachEvents();\r\n        },\r\n        \r\n        cacheDOM: function() {\r\n            this.UI = {\r\n                wrapper: document.getElementById('pth-up-upscaler-wrapper'),\r\n                inputArea: document.getElementById('pth-up-input-area'),\r\n                origPrevArea: document.getElementById('pth-up-orig-preview-area'),\r\n                imgPreviewOnly: document.getElementById('pth-up-img-preview-only'),\r\n                origSizeLabel: document.getElementById('pth-up-orig-size-label'),\r\n                scaleSelect: document.getElementById('pth-up-scale-select'),\r\n                startAiBtn: document.getElementById('pth-up-start-ai-btn'),\r\n                cancelPrevBtn: document.getElementById('pth-up-cancel-preview-btn'),\r\n                dz: document.getElementById('pth-up-drop-zone'),\r\n                fileIn: document.getElementById('pth-up-image-file'),\r\n                urlInput: document.getElementById('pth-up-url-input'),\r\n                loadUrlBtn: document.getElementById('pth-up-load-url-btn'),\r\n                pasteBtn: document.getElementById('pth-up-paste-btn'),\r\n                sampleBtn: document.getElementById('pth-up-load-sample-btn'),\r\n                progArea: document.getElementById('pth-up-progress-area'),\r\n                progHeading: document.getElementById('pth-up-progress-heading'),\r\n                progBarWrap: document.getElementById('pth-up-prog-bar-wrap'),\r\n                progBar: document.getElementById('pth-up-progress-bar'),\r\n                progSub: document.getElementById('pth-up-progress-sub'),\r\n                scanningWrapper: document.getElementById('pth-up-scanning-wrapper'),\r\n                scanningImg: document.getElementById('pth-up-scanning-img'),\r\n                firstTimeNote: document.getElementById('pth-up-first-time-note'),\r\n                prevBox: document.getElementById('pth-up-preview-box'),\r\n                imgOrigCompare: document.getElementById('pth-up-img-orig-compare'),\r\n                imgRes: document.getElementById('pth-up-img-result'),\r\n                beforeBox: document.getElementById('pth-up-img-before-box'),\r\n                slider: document.getElementById('pth-up-compare-slider'),\r\n                togComp: document.getElementById('pth-up-compare-toggle'),\r\n                filtersPanel: document.getElementById('pth-up-filters-panel'),\r\n                brightness: document.getElementById('pth-up-brightness'),\r\n                contrast: document.getElementById('pth-up-contrast'),\r\n                saturation: document.getElementById('pth-up-saturation'),\r\n                brightVal: document.getElementById('pth-up-bright-val'),\r\n                contrastVal: document.getElementById('pth-up-contrast-val'),\r\n                satVal: document.getElementById('pth-up-sat-val'),\r\n                sharpen: document.getElementById('pth-up-sharpen'),\r\n                sharpenVal: document.getElementById('pth-up-sharpen-val'),\r\n                sharpenKernel: document.getElementById('pth-up-sharpen-kernel'),\r\n                resetFiltersBtn: document.getElementById('pth-up-reset-filters'),\r\n                settings: document.getElementById('pth-up-settings-area'),\r\n                dimNew: document.getElementById('pth-up-dimensions-new'),\r\n                procTime: document.getElementById('pth-up-proc-time'),\r\n                clrBtn: document.getElementById('pth-up-clear-btn'),\r\n                dwnBtn: document.getElementById('pth-up-download-btn'),\r\n                copyBtn: document.getElementById('pth-up-copy-btn'),\r\n                printBtn: document.getElementById('pth-up-print-btn'),\r\n                fullBtn: document.getElementById('pth-up-fw-btn-upscaler'),\r\n                toast: document.getElementById('pth-up-toast-upscaler'),\r\n                outputFormat: document.getElementById('pth-up-output-format'),\r\n                qualitySlider: document.getElementById('pth-up-quality-slider'),\r\n                qualityVal: document.getElementById('pth-up-quality-val'),\r\n            };\r\n        },\r\n\r\n        showToast: function(msg, isError) {\r\n            if (!this.UI.toast) return;\r\n            this.UI.toast.innerText = msg;\r\n            this.UI.toast.style.background = isError ? '#ef4444' : '#10b981';\r\n            this.UI.toast.classList.add('show');\r\n            var t = this.UI.toast;\r\n            setTimeout(function() { t.classList.remove('show'); }, 3500);\r\n        },\r\n\r\n        attachEvents: function() {\r\n            var self = this;\r\n            \r\n            if(this.UI.fullBtn) {\r\n                this.UI.fullBtn.addEventListener('click', function() {\r\n                    self.UI.wrapper.classList.toggle('is-fullscreen');\r\n                    self.UI.fullBtn.innerHTML = self.UI.wrapper.classList.contains('is-fullscreen') ? 'Exit Full Screen' : 'Full Screen';\r\n                    if (self.resultImgData) self.syncSliderWidth();\r\n                });\r\n            }\r\n            \r\n            if(this.UI.dz) {\r\n                this.UI.dz.addEventListener('click', function() { self.UI.fileIn.click(); });\r\n                this.UI.dz.addEventListener('dragover', function(e) { e.preventDefault(); self.UI.dz.classList.add('active'); });\r\n                this.UI.dz.addEventListener('dragleave', function() { self.UI.dz.classList.remove('active'); });\r\n                this.UI.dz.addEventListener('drop', function(e) { \r\n                    e.preventDefault(); self.UI.dz.classList.remove('active'); \r\n                    if (e.dataTransfer.files.length) self.handleFile(e.dataTransfer.files[0]); \r\n                });\r\n            }\r\n\r\n            if(this.UI.fileIn) {\r\n                this.UI.fileIn.addEventListener('change', function(e) { \r\n                    if (e.target.files.length) self.handleFile(e.target.files[0]); \r\n                });\r\n            }\r\n            \r\n            if(this.UI.loadUrlBtn) {\r\n                this.UI.loadUrlBtn.addEventListener('click', async function() {\r\n                    var url = self.UI.urlInput.value.trim();\r\n                    if (!url) return self.showToast('Please enter an image URL', true);\r\n                    self.UI.loadUrlBtn.innerText = 'Loading...';\r\n                    try {\r\n                        var res = await fetch(url, { mode: 'cors' });\r\n                        if (!res.ok) throw new Error();\r\n                        var blob = await res.blob();\r\n                        self.handleFile(blob);\r\n                    } catch (err) { self.showToast('Failed to load URL (CORS Blocked).', true); }\r\n                    self.UI.loadUrlBtn.innerText = 'Load URL';\r\n                });\r\n            }\r\n            \r\n            if(this.UI.sampleBtn) {\r\n                this.UI.sampleBtn.addEventListener('click', async function() {\r\n                    self.UI.sampleBtn.innerText = 'Loading...';\r\n                    try {\r\n                        var res = await fetch('https:\/\/schoolict.net\/tools\/sampledata\/bgsample.jpg');\r\n                        var blob = await res.blob();\r\n                        self.handleFile(blob);\r\n                    } catch (err) {\r\n                        fetch(self.sampleBase64).then(function(r) { return r.blob(); }).then(function(b) { self.handleFile(b); });\r\n                    }\r\n                    self.UI.sampleBtn.innerText = 'Try Sample';\r\n                });\r\n            }\r\n            \r\n            if(this.UI.pasteBtn) {\r\n                this.UI.pasteBtn.addEventListener('click', async function() {\r\n                    try {\r\n                        var items = await navigator.clipboard.read();\r\n                        for (var i=0; i<items.length; i++) {\r\n                            var item = items[i];\r\n                            if (item.types.some(function(t) { return t.startsWith('image\/'); })) {\r\n                                var blob = await item.getType(item.types.find(function(t) { return t.startsWith('image\/'); }));\r\n                                self.handleFile(blob); return;\r\n                            }\r\n                        }\r\n                        self.showToast('No image in clipboard.', true);\r\n                    } catch (err) { self.showToast('Clipboard access denied.', true); }\r\n                });\r\n            }\r\n            \r\n            if(this.UI.cancelPrevBtn) this.UI.cancelPrevBtn.addEventListener('click', function() { self.resetTool(); });\r\n            if(this.UI.clrBtn) this.UI.clrBtn.addEventListener('click', function() { self.resetTool(); });\r\n            if(this.UI.startAiBtn) this.UI.startAiBtn.addEventListener('click', function() { self.startAiProcessing(); });\r\n            \r\n            if(this.UI.slider) {\r\n                this.UI.slider.addEventListener('input', function(e) { self.UI.beforeBox.style.width = e.target.value + '%'; });\r\n            }\r\n            if(this.UI.togComp) {\r\n                this.UI.togComp.addEventListener('change', function(e) {\r\n                    var show = e.target.checked;\r\n                    self.UI.slider.style.display = show ? 'block' : 'none';\r\n                    self.UI.beforeBox.style.display = show ? 'block' : 'none';\r\n                });\r\n            }\r\n            \r\n            var updateSharpenKernel = function() {\r\n                if (!self.UI.sharpenKernel) return;\r\n                var k = (self.currentFilters.sharpen || 0) \/ 100; \/\/ 0..1\r\n                var c = 1 + 4 * k;\r\n                self.UI.sharpenKernel.setAttribute('kernelMatrix',\r\n                    '0 ' + (-k) + ' 0 ' + (-k) + ' ' + c + ' ' + (-k) + ' 0 ' + (-k) + ' 0');\r\n            };\r\n            var buildFilterString = function() {\r\n                var f = 'brightness(' + self.currentFilters.brightness + '%) contrast(' + self.currentFilters.contrast + '%) saturate(' + self.currentFilters.saturation + '%)';\r\n                if (self.currentFilters.sharpen > 0) f += ' url(#pth-up-sharpen-svg)';\r\n                return f;\r\n            };\r\n            var applyFilters = function() {\r\n                updateSharpenKernel();\r\n                self.UI.imgRes.style.filter = buildFilterString();\r\n            };\r\n            this.buildFilterString = buildFilterString;\r\n            this.updateSharpenKernel = updateSharpenKernel;\r\n            if(this.UI.brightness) {\r\n                this.UI.brightness.addEventListener('input', function() { self.currentFilters.brightness = parseInt(self.UI.brightness.value); self.UI.brightVal.textContent = self.currentFilters.brightness + '%'; applyFilters(); });\r\n            }\r\n            if(this.UI.contrast) {\r\n                this.UI.contrast.addEventListener('input', function() { self.currentFilters.contrast = parseInt(self.UI.contrast.value); self.UI.contrastVal.textContent = self.currentFilters.contrast + '%'; applyFilters(); });\r\n            }\r\n            if(this.UI.saturation) {\r\n                this.UI.saturation.addEventListener('input', function() { self.currentFilters.saturation = parseInt(self.UI.saturation.value); self.UI.satVal.textContent = self.currentFilters.saturation + '%'; applyFilters(); });\r\n            }\r\n            if(this.UI.sharpen) {\r\n                this.UI.sharpen.addEventListener('input', function() { self.currentFilters.sharpen = parseInt(self.UI.sharpen.value); self.UI.sharpenVal.textContent = self.currentFilters.sharpen + '%'; applyFilters(); });\r\n            }\r\n            \r\n            if(this.UI.resetFiltersBtn) {\r\n                this.UI.resetFiltersBtn.addEventListener('click', function() {\r\n                    self.currentFilters = { brightness: 100, contrast: 100, saturation: 100, sharpen: 0 };\r\n                    self.UI.brightness.value = 100; self.UI.brightVal.textContent = '100%';\r\n                    self.UI.contrast.value = 100; self.UI.contrastVal.textContent = '100%';\r\n                    self.UI.saturation.value = 100; self.UI.satVal.textContent = '100%';\r\n                    if(self.UI.sharpen) { self.UI.sharpen.value = 0; self.UI.sharpenVal.textContent = '0%'; }\r\n                    applyFilters();\r\n                });\r\n            }\r\n            \r\n            window.addEventListener('resize', function() { if(self.resultImgData) self.syncSliderWidth(); });\r\n            \r\n            if(this.UI.qualitySlider) {\r\n                this.UI.qualitySlider.addEventListener('input', function() { self.UI.qualityVal.textContent = self.UI.qualitySlider.value; });\r\n            }\r\n            if(this.UI.dwnBtn) this.UI.dwnBtn.addEventListener('click', function() { self.downloadImage(); });\r\n            if(this.UI.copyBtn) this.UI.copyBtn.addEventListener('click', function() { self.copyImage(); });\r\n            if(this.UI.printBtn) this.UI.printBtn.addEventListener('click', function() { self.printImage(); });\r\n        },\r\n\r\n        handleFile: function(fileOrBlob) {\r\n            var file = fileOrBlob instanceof File ? fileOrBlob : new File([fileOrBlob], 'image.jpg', { type: fileOrBlob.type });\r\n            if (!file.type.startsWith('image\/')) return this.showToast('Invalid image format.', true);\r\n            var url = URL.createObjectURL(file);\r\n            this.originalImgObj = new Image();\r\n            var self = this;\r\n            this.originalImgObj.onload = function() {\r\n                self.UI.inputArea.style.display = 'none';\r\n                self.UI.origPrevArea.style.display = 'block';\r\n                self.UI.clrBtn.style.display = 'inline-flex';\r\n                self.UI.imgPreviewOnly.src = url;\r\n                self.UI.origSizeLabel.innerText = self.originalImgObj.width + \" x \" + self.originalImgObj.height + \" px\";\r\n            };\r\n            this.originalImgObj.src = url;\r\n        },\r\n\r\n        loadScriptDynamic: function(src) {\r\n            return new Promise(function(resolve, reject) {\r\n                if(src.indexOf('tf.min.js') !== -1 && window.tf) return resolve();\r\n                if(src.indexOf('upscaler.min.js') !== -1 && window.Upscaler) return resolve();\r\n                var script = document.createElement('script');\r\n                script.src = src;\r\n                script.setAttribute('data-cfasync', 'false');\r\n                script.setAttribute('data-no-optimize', '1');\r\n                script.onload = resolve;\r\n                script.onerror = reject;\r\n                document.head.appendChild(script);\r\n            });\r\n        },\r\n\r\n        startAiProcessing: async function() {\r\n            if (!this.originalImgObj) return;\r\n            this.UI.origPrevArea.style.display = 'none';\r\n            this.UI.progArea.style.display = 'block';\r\n            this.UI.progBar.style.width = '0%';\r\n            this.UI.progBarWrap.style.display = 'block';\r\n            this.UI.firstTimeNote.style.display = 'none';\r\n            this.UI.scanningWrapper.style.display = 'none';\r\n            this.UI.scanningImg.src = this.originalImgObj.src; \r\n            \r\n            this.startTime = Date.now();\r\n            var self = this;\r\n            var scaleFactor = parseInt(this.UI.scaleSelect.value);\r\n            \/\/ 2x & 3x = single AI pass (fast); only 4x needs the heavy 2-pass engine.\r\n            \/\/ 3x then does a quick canvas resize-up from the 2x AI result.\r\n            var passes = scaleFactor <= 3 ? 1 : 2;\r\n            \r\n            try {\r\n                if (typeof window.Upscaler === 'undefined') {\r\n                    this.UI.firstTimeNote.style.display = 'block';\r\n                    this.UI.progHeading.innerText = 'Caching AI Engine...';\r\n                    this.UI.progSub.innerText = '1\/3 Downloading TensorFlow.js...';\r\n                    await this.loadScriptDynamic(\"https:\/\/cdn.jsdelivr.net\/npm\/@tensorflow\/tfjs\/dist\/tf.min.js\");\r\n                    \r\n                    this.UI.progSub.innerText = '2\/3 Downloading Default Model...';\r\n                    await this.loadScriptDynamic(\"https:\/\/cdn.jsdelivr.net\/npm\/@upscalerjs\/default-model\/dist\/umd\/index.min.js\");\r\n\r\n                    this.UI.progSub.innerText = '3\/3 Downloading Upscaler Core...';\r\n                    await this.loadScriptDynamic(\"https:\/\/cdn.jsdelivr.net\/npm\/upscaler\/dist\/browser\/umd\/upscaler.min.js\");\r\n                }\r\n\r\n                if (typeof window.Upscaler === 'undefined') throw new Error(\"Upscaler JS missing\");\r\n                \r\n                this.UI.firstTimeNote.style.display = 'none';\r\n\r\n                if (!this.upscalerInstance) {\r\n                    this.upscalerInstance = new window.Upscaler({\r\n                        model: window['@upscalerjs\/default-model']\r\n                    });\r\n                }\r\n                \r\n                this.UI.progBarWrap.style.display = 'none';\r\n                this.UI.scanningWrapper.style.display = 'block';\r\n                \r\n                var currentSrc = this.originalImgObj;\r\n                var finalSrc = null;\r\n                \r\n                for (var pass = 1; pass <= passes; pass++) {\r\n                    this.UI.progHeading.innerText = 'AI Pass ' + pass + '\/' + passes + ' \\u2014 Enhancing Pixels...';\r\n                    this.UI.progSub.innerText = 'AI is actively redrawing the image. Please wait...';\r\n                    \r\n                    finalSrc = await this.upscalerInstance.upscale(currentSrc, {\r\n                        output: 'base64',\r\n                        patchSize: 64,\r\n                        padding: 2,\r\n                        progress: function(amount) {\r\n                            var pct = Math.round(amount * 100);\r\n                            self.UI.progSub.innerText = 'Calculating blocks: ' + pct + '% completed...';\r\n                        }\r\n                    });\r\n                    \r\n                    if (pass < passes) {\r\n                        var tempImg = new Image();\r\n                        tempImg.src = finalSrc;\r\n                        await new Promise(function(r) { tempImg.onload = r; });\r\n                        currentSrc = tempImg;\r\n                    }\r\n                }\r\n                \r\n                \/\/ AI model works in 2x steps; resize to the exact requested factor (e.g. genuine 3x)\r\n                var aiScale = Math.pow(2, passes);\r\n                if (aiScale !== scaleFactor && self.originalImgObj) {\r\n                    var exactW = Math.round(self.originalImgObj.naturalWidth * scaleFactor);\r\n                    var exactH = Math.round(self.originalImgObj.naturalHeight * scaleFactor);\r\n                    finalSrc = await self.resizeDataUrl(finalSrc, exactW, exactH);\r\n                }\r\n                \r\n                this.resultImgData = finalSrc;\r\n                var procTime = ((Date.now() - this.startTime) \/ 1000).toFixed(1);\r\n                \r\n                this.UI.imgRes.onload = function() {\r\n                    self.syncSliderWidth();\r\n                    self.UI.dimNew.textContent = self.UI.imgRes.naturalWidth + ' \\u00D7 ' + self.UI.imgRes.naturalHeight + ' px';\r\n                    self.UI.imgOrigCompare.src = self.originalImgObj.src;\r\n                    self.UI.imgOrigCompare.style.width = self.UI.imgRes.offsetWidth + 'px';\r\n                    self.UI.imgOrigCompare.style.height = self.UI.imgRes.offsetHeight + 'px';\r\n                    \r\n                    self.UI.filtersPanel.style.display = 'block';\r\n                    self.currentFilters = { brightness: 100, contrast: 100, saturation: 100, sharpen: 0 };\r\n                    if(self.UI.brightness) self.UI.brightness.value = 100;\r\n                    if(self.UI.contrast) self.UI.contrast.value = 100;\r\n                    if(self.UI.saturation) self.UI.saturation.value = 100;\r\n                    if(self.UI.sharpen) { self.UI.sharpen.value = 0; self.UI.sharpenVal.textContent = '0%'; }\r\n                    self.UI.imgRes.style.filter = 'none';\r\n                };\r\n                this.UI.imgRes.src = finalSrc;\r\n                \r\n                this.UI.progArea.style.display = 'none';\r\n                this.UI.prevBox.style.display = 'block';\r\n                this.UI.settings.style.display = 'block';\r\n                this.UI.procTime.textContent = procTime + 's';\r\n                this.showToast('Image successfully upscaled ' + scaleFactor + 'x with AI!');\r\n                \r\n            } catch (error) {\r\n                console.error(error);\r\n                this.showToast('Processing failed. Image may be too large.', true);\r\n                this.UI.progArea.style.display = 'none';\r\n                this.UI.inputArea.style.display = 'block';\r\n            }\r\n        },\r\n\r\n        syncSliderWidth: function() {\r\n            if (this.UI.imgRes.offsetWidth) {\r\n                this.UI.imgOrigCompare.style.width = this.UI.imgRes.offsetWidth + 'px';\r\n                this.UI.imgOrigCompare.style.height = this.UI.imgRes.offsetHeight + 'px';\r\n            }\r\n        },\r\n\r\n        resetTool: function() {\r\n            this.UI.fileIn.value = ''; this.UI.urlInput.value = '';\r\n            this.resultImgData = null; this.originalImgObj = null;\r\n            this.UI.inputArea.style.display = 'block';\r\n            this.UI.origPrevArea.style.display = 'none';\r\n            this.UI.progArea.style.display = 'none';\r\n            this.UI.prevBox.style.display = 'none';\r\n            this.UI.settings.style.display = 'none';\r\n            this.UI.filtersPanel.style.display = 'none';\r\n            this.UI.clrBtn.style.display = 'none';\r\n            this.UI.slider.value = 50; this.UI.beforeBox.style.width = '50%';\r\n        },\r\n\r\n        resizeDataUrl: function(src, w, h) {\r\n            return new Promise(function(resolve) {\r\n                var im = new Image();\r\n                im.onload = function() {\r\n                    var c = document.createElement('canvas');\r\n                    c.width = w; c.height = h;\r\n                    var cx = c.getContext('2d');\r\n                    cx.imageSmoothingEnabled = true;\r\n                    cx.imageSmoothingQuality = 'high';\r\n                    cx.drawImage(im, 0, 0, w, h);\r\n                    resolve(c.toDataURL('image\/png'));\r\n                };\r\n                im.src = src;\r\n            });\r\n        },\r\n\r\n        downloadImage: function() {\r\n            if (!this.resultImgData) return;\r\n            var format = this.UI.outputFormat.value;\r\n            var quality = this.UI.qualitySlider.value \/ 100;\r\n            var ext = format === 'image\/jpeg' ? 'jpg' : (format === 'image\/webp' ? 'webp' : 'png');\r\n            var canvas = document.createElement('canvas');\r\n            var ctx = canvas.getContext('2d');\r\n            var img = new Image();\r\n            var self = this;\r\n            img.onload = function() {\r\n                canvas.width = img.width; canvas.height = img.height;\r\n                var dlFilter = 'brightness(' + self.currentFilters.brightness + '%) contrast(' + self.currentFilters.contrast + '%) saturate(' + self.currentFilters.saturation + '%)';\r\n                if (self.currentFilters.sharpen > 0) dlFilter += ' url(#pth-up-sharpen-svg)';\r\n                ctx.filter = dlFilter;\r\n                ctx.drawImage(img, 0, 0);\r\n                var dataUrl = canvas.toDataURL(format, quality);\r\n                var a = document.createElement('a');\r\n                a.href = dataUrl;\r\n                a.download = 'PTH-AI-Upscaled-' + self.UI.scaleSelect.value + 'x.' + ext;\r\n                a.click();\r\n                self.showToast('Image downloaded with filters!');\r\n            };\r\n            img.src = this.resultImgData;\r\n        },\r\n\r\n        copyImage: async function() {\r\n            if (!this.resultImgData) return;\r\n            try {\r\n                var res = await fetch(this.resultImgData);\r\n                var blob = await res.blob();\r\n                await navigator.clipboard.write([new ClipboardItem({ 'image\/png': blob })]);\r\n                this.showToast('Image copied to clipboard!');\r\n            } catch (err) { this.showToast('Clipboard copy failed.', true); }\r\n        },\r\n\r\n        printImage: function() {\r\n            if (!this.resultImgData) return;\r\n            var printWin = window.open('');\r\n            var filterStr = 'brightness(' + this.currentFilters.brightness + '%) contrast(' + this.currentFilters.contrast + '%) saturate(' + this.currentFilters.saturation + '%)';\r\n            \r\n            \/\/ BULLETPROOF HTML STRING SPLITTING (Parser Bug Fix)\r\n            var printContent = '\\x3Chtml\\x3E' +\r\n                '\\x3Chead\\x3E\\x3Ctitle\\x3EPrint Image - Prime Tool Hub\\x3C\/title\\x3E\\x3C\/head\\x3E' +\r\n                '\\x3Cstyle\\x3E@media print { @page { margin: 0; } body { margin: 0; } img { max-width: 100%; height: auto; display: block; margin: auto; filter: ' + filterStr + '; } }\\x3C\/style\\x3E' +\r\n                '\\x3Cbody\\x3E' +\r\n                '\\x3Cimg src=\"' + this.resultImgData + '\" alt=\"ai image upscaler print\"\\x3E' +\r\n                '\\x3C\/body\\x3E' +\r\n                '\\x3C\/html\\x3E';\r\n\r\n            printWin.document.write(printContent);\r\n            printWin.document.close();\r\n            printWin.focus();\r\n            setTimeout(function() { printWin.print(); }, 500);\r\n        }\r\n    };\r\n\r\n    \/\/ ULTIMATE CACHE-BUSTER INIT SYSTEM\r\n    function forceInitPthUpscaler() {\r\n        if (!window.pthUpscalerApp.initialized) {\r\n            if (document.getElementById('pth-up-upscaler-wrapper')) {\r\n                window.pthUpscalerApp.initialized = true;\r\n                window.pthUpscalerApp.init();\r\n                console.log(\"\u2705 PTH AI Upscaler Initialized!\");\r\n            }\r\n        }\r\n    }\r\n\r\n    \/\/ Strategy A: Standard DOM Ready\r\n    document.addEventListener('DOMContentLoaded', forceInitPthUpscaler);\r\n    \r\n    \/\/ Strategy B: Interactive Check\r\n    if (document.readyState === 'interactive' || document.readyState === 'complete') {\r\n        setTimeout(forceInitPthUpscaler, 1);\r\n    }\r\n    \r\n    \/\/ Strategy C: Window Load\r\n    window.addEventListener('load', forceInitPthUpscaler);\r\n\r\n    \/\/ Strategy D: Aggressive Fallback for Delay JS Execution\r\n    ['mousemove', 'scroll', 'touchstart', 'click', 'keydown'].forEach(function(evt) {\r\n        window.addEventListener(evt, forceInitPthUpscaler, { once: true, passive: true });\r\n    });\r\n})();\r\n<\/script>\r\n<script data-no-optimize=\"1\" data-no-minify=\"1\" data-cfasync=\"false\">\r\n(function () {\r\n  'use strict';\r\n  function mount() {\r\n    var panel = document.getElementById('pth-ie-tab-upscale');\r\n    var tool  = document.getElementById('pth-up-upscaler-wrapper');\r\n    if (!panel || !tool) return false;\r\n    if (tool.parentNode !== panel) {\r\n      var ph = document.getElementById('pth-ie-empty-upscale');\r\n      if (ph && ph.parentNode) ph.parentNode.removeChild(ph);\r\n      tool.style.margin = '0';\r\n      panel.appendChild(tool);\r\n    }\r\n    return true;\r\n  }\r\n  if (mount()) return;\r\n  if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', mount);\r\n  window.addEventListener('load', function () { setTimeout(mount, 60); });\r\n  if (typeof MutationObserver !== 'undefined') {\r\n    var o = new MutationObserver(function () { if (mount()) o.disconnect(); });\r\n    o.observe(document.body || document.documentElement, { childList: true, subtree: true });\r\n    setTimeout(function () { o.disconnect(); }, 10000);\r\n  }\r\n})();\r\n<\/script>\n\n\n\n<style>\n.pth-container{max-width:1480px;margin:0 auto;padding:0 20px;box-sizing:border-box}\n.pth-feature-wrap{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:20px;margin-bottom:40px}\n.pth-feat-box{border:1px solid #e2e8f0;background:#fff;padding:24px;border-radius:12px;box-shadow:0 4px 6px -1px rgba(0,0,0,0.02);transition:all .3s ease}\n.pth-feat-box:hover{border-color:#bfdbfe;transform:translateY(-3px);box-shadow:0 10px 15px -3px rgba(0,0,0,0.05)}\n.pth-feat-title{font-size:1.05rem;font-weight:800;color:#0f172a;margin:0 0 10px;display:flex;align-items:center;gap:10px}\n.pth-feat-text{font-size:.9rem;color:#1e293b;line-height:1.6;margin:0;font-weight:500}\n.pth-steps-wrap{border:1px solid #e2e8f0;background:#fff;padding:40px 30px;border-radius:16px;text-align:center;box-shadow:0 4px 6px -1px rgba(0,0,0,0.02);margin-bottom:40px;width:100%;box-sizing:border-box}\n.pth-steps-title{font-size:1.2rem;font-weight:800;color:#0f172a;text-transform:uppercase;margin:0 0 35px;letter-spacing:1px}\n.pth-steps-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:30px}\n.pth-step-item{display:flex;flex-direction:column;align-items:center}\n.pth-step-num{width:45px;height:45px;background:#2563eb;color:#fff;border-radius:50%;display:flex;align-items:center;justify-content:center;font-weight:800;font-size:1.2rem;margin-bottom:15px;box-shadow:0 4px 10px rgba(37,99,235,.3)}\n.pth-step-name{font-weight:800;color:#0f172a;margin:0 0 8px;font-size:1rem}\n.pth-step-desc{font-size:.9rem;color:#1e293b;line-height:1.5;margin:0;font-weight:500}\n<\/style>\n<div class=\"pth-container\">\n  <div class=\"pth-feature-wrap\">\n    <div class=\"pth-feat-box\">\n      <p class=\"pth-feat-title\"><span aria-hidden=\"true\">\ud83d\udfe2<\/span> Three Tools, One Photo<\/p>\n      <p class=\"pth-feat-text\">Cut out a background, erase a photobomber, and upscale the result without leaving the page or re-uploading. Each job hands its output to the next tab.<\/p>\n    <\/div>\n    <div class=\"pth-feat-box\">\n      <p class=\"pth-feat-title\"><span aria-hidden=\"true\">\ud83d\udd35<\/span> Nothing Leaves Your Device<\/p>\n      <p class=\"pth-feat-text\">Every pixel is processed in your browser using WebGL and JavaScript. No sign-up, no upload, no watermark stamped across your export.<\/p>\n    <\/div>\n    <div class=\"pth-feat-box\">\n      <p class=\"pth-feat-title\"><span aria-hidden=\"true\">\ud83d\udfe3<\/span> Fine-Tune Before You Save<\/p>\n      <p class=\"pth-feat-text\">The upscaler adds live brightness, contrast, saturation and a sharpen slider, so you can crisp up a soft result instead of settling for the raw output.<\/p>\n    <\/div>\n  <\/div>\n  <div class=\"pth-steps-wrap\">\n    <p class=\"pth-steps-title\">How to Use the AI Image Eraser<\/p>\n    <div class=\"pth-steps-grid\">\n      <div class=\"pth-step-item\">\n        <div class=\"pth-step-num\" aria-hidden=\"true\">1<\/div>\n        <p class=\"pth-step-name\">Pick a Tab<\/p>\n        <p class=\"pth-step-desc\">Background Remover, Magic Eraser, or AI Upscaler \u2014 choose the job you need first.<\/p>\n      <\/div>\n      <div class=\"pth-step-item\">\n        <div class=\"pth-step-num\" aria-hidden=\"true\">2<\/div>\n        <p class=\"pth-step-name\">Drop Your Image<\/p>\n        <p class=\"pth-step-desc\">Drag a file in or paste a URL. Processing starts locally, nothing uploads.<\/p>\n      <\/div>\n      <div class=\"pth-step-item\">\n        <div class=\"pth-step-num\" aria-hidden=\"true\">3<\/div>\n        <p class=\"pth-step-name\">Erase or Enhance<\/p>\n        <p class=\"pth-step-desc\">Let the AI cut the background, brush over an object, or upscale 2\u00d7\u20134\u00d7.<\/p>\n      <\/div>\n      <div class=\"pth-step-item\">\n        <div class=\"pth-step-num\" aria-hidden=\"true\">4<\/div>\n        <p class=\"pth-step-name\">Adjust and Download<\/p>\n        <p class=\"pth-step-desc\">Tune the result, pick PNG\/JPG\/WebP, and save it straight to your device.<\/p>\n      <\/div>\n    <\/div>\n  <\/div>\n<\/div>\n\n\n<div id=\"start-seo-article\"><\/div>\n\n\n<p class=\"wp-block-paragraph\">Last updated: July 2026<\/p>\n\n\n\n<h2 id=\"\ud83d\udd34-one-photo-three-jobs-no-round-trips\" class=\"wp-block-heading\">\ud83d\udd34 <strong>One Photo, Three Jobs, No Round Trips<\/strong><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Most people don&#8217;t need a background remover OR an object eraser OR an upscaler \u2014 they need all three on the same picture, in a row. You cut a product out of its cluttered background, erase a stray cable someone left in the shot, then upscale the clean version for a print listing. Doing that across three separate sites means exporting and re-uploading twice. Here the three tabs share the workspace, so the output of one becomes the input for the next.<\/p>\n\n\n\n<h2 id=\"\ud83d\udfe1-when-each-tab-earns-its-place\" class=\"wp-block-heading\">\ud83d\udfe1 <strong>When Each Tab Earns Its Place<\/strong><\/h2>\n\n\n<figure class=\"pth-article-figure pth-img-left\" style=\"float:left; width:700px; max-width:100%; margin:4px 28px 16px 0; clear:left;\"><img decoding=\"async\" src=\"https:\/\/schoolict.net\/tools\/wp-content\/uploads\/2026\/07\/ai-image-eraser-workflow-800x447.jpeg\" alt=\"Three-step photo workflow: remove background, erase object, upscale\" width=\"700\" height=\"394\" loading=\"lazy\" data-no-lazy=\"1\" class=\"pth-article-img\" style=\"width:100%;height:auto;display:block;border-radius:10px;border:1px solid #e2e8f0;\"><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">The <strong>Background Remover<\/strong> is for product shots and profile pictures \u2014 anything that needs a clean transparent PNG. The <strong>Magic Eraser<\/strong> is for removing one specific thing: a bystander, a trash can, a date stamp burned into the corner. The <strong>AI Upscaler<\/strong> is for when your only copy of an image is small or slightly blurry and you need it larger without it turning to mush. A common real workflow: remove the background of a sneaker photo, erase the price tag still clipped to the laces, then upscale to 3\u00d7 for a marketplace that rejects low-resolution images.<\/p>\n\n\n\n<h3 id=\"\ud83d\udfe2-a-real-example\" class=\"wp-block-heading\">\ud83d\udfe2 <strong>A Real Example<\/strong><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Say you photograph a 900\u00d7900 px handmade mug on a messy kitchen counter. Background Remover isolates the mug on transparency in a few seconds. You switch to Magic Eraser and brush out a smudge on the rim. Then the Upscaler takes it to 3\u00d7 (2700\u00d72700) so it meets a print-on-demand site&#8217;s minimum. The upscaled edge looks a touch soft, so you nudge the new Sharpen slider to about 30% and it reads crisp. Total time: under a minute, and the photo never left your laptop.<\/p>\n\n\n\n<h2 id=\"\ud83d\udd34-where-it-struggles-and-what-to-do\" class=\"wp-block-heading\">\ud83d\udd34 <strong>Where It Struggles \u2014 and What to Do<\/strong><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Background removal is weakest on fine detail like flyaway hair, fur, or glass, where the edge between subject and background is genuinely ambiguous \u2014 check those edges before you trust the cut. The Magic Eraser fills the erased area by guessing from surrounding pixels, so it shines on simple backgrounds (a wall, grass, sky) and struggles when the object sits in front of a busy, detailed scene. And the 4\u00d7 upscale runs a two-pass AI model, which is genuinely slow on large images since all of it happens on your device&#8217;s graphics processor, not a server farm. For very large source files, 2\u00d7 or 3\u00d7 finishes far faster and is usually enough.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If you also need to resize, crop, or compress the final file, our <a href=\"\/free-advanced-image-studio-pro\/\">Advanced Image Studio<\/a> handles that side of the job, and you can convert vector art with the <a href=\"\/svg-to-png-converter\/\">SVG to PNG Converter<\/a>. For a wider look at what runs fully in your browser, see our roundup of <a href=\"\/top-10-client-side-offline-web-developer-tools\/\">the best client-side offline tools<\/a>.<\/p>\n\n\n\n<style>\n.pth-faq-section{margin:50px auto 40px;font-family:inherit;max-width:1480px;padding:0 20px;box-sizing:border-box}\n.pth-faq-header{font-size:1.8rem;font-weight:800;color:#0f172a;margin-bottom:25px;border-bottom:2px solid #e2e8f0;padding-bottom:10px;display:flex;align-items:center;gap:10px}\n.pth-faq-grid{display:grid;grid-template-columns:1fr;gap:20px}\n@media(min-width:768px){.pth-faq-grid{grid-template-columns:repeat(2,1fr)}}\n@media(min-width:1024px){.pth-faq-grid{grid-template-columns:repeat(3,1fr)}}\n.pth-faq-card{background:#f8fafc;padding:24px;border-radius:12px;border:1px solid #e2e8f0;transition:transform .2s ease;break-inside:avoid}\n.pth-faq-card:hover{transform:translateY(-3px);box-shadow:0 4px 12px rgba(0,0,0,.05)}\n.pth-faq-q{color:#0f172a;font-size:1rem;font-weight:700;margin:0 0 12px;line-height:1.4}\n.pth-faq-a{margin:0;font-size:.95rem;color:#1e293b;line-height:1.6;font-weight:500}\n<\/style>\n<div class=\"pth-faq-section\">\n  <div class=\"pth-faq-header\">\u2753 Frequently Asked Questions<\/div>\n  <div class=\"pth-faq-grid\">\n    <div class=\"pth-faq-card\">\n      <p class=\"pth-faq-q\">Do my images get uploaded to a server?<\/p>\n      <p class=\"pth-faq-a\">No. All three tools run in your browser using JavaScript and WebGL. Your photo stays on your device from start to finish.<\/p>\n    <\/div>\n    <div class=\"pth-faq-card\">\n      <p class=\"pth-faq-q\">Can I use the output of one tab in another?<\/p>\n      <p class=\"pth-faq-a\">Yes \u2014 that&#8217;s the point of combining them. Remove a background, then switch tabs to erase an object or upscale the same result.<\/p>\n    <\/div>\n    <div class=\"pth-faq-card\">\n      <p class=\"pth-faq-q\">Why is the background cut rough around hair?<\/p>\n      <p class=\"pth-faq-a\">Fine strands sit on the hardest edge for any AI to judge. Zoom in and check hair, fur, and glass before relying on the cutout.<\/p>\n    <\/div>\n    <div class=\"pth-faq-card\">\n      <p class=\"pth-faq-q\">Why does the erased area look smudged?<\/p>\n      <p class=\"pth-faq-a\">The eraser rebuilds the gap from nearby pixels. It works best over plain backgrounds; busy, detailed scenes are harder to fill convincingly.<\/p>\n    <\/div>\n    <div class=\"pth-faq-card\">\n      <p class=\"pth-faq-q\">Which format should I download?<\/p>\n      <p class=\"pth-faq-a\">Use PNG to keep a transparent background, JPG for the smallest photo files, and WebP for a good balance of quality and size.<\/p>\n    <\/div>\n    <div class=\"pth-faq-card\">\n      <p class=\"pth-faq-q\">Why is 4\u00d7 upscaling slow?<\/p>\n      <p class=\"pth-faq-a\">It runs a two-pass AI model on your device&#8217;s GPU. For big images, 2\u00d7 or 3\u00d7 is much quicker and often enough.<\/p>\n    <\/div>\n    <div class=\"pth-faq-card\">\n      <p class=\"pth-faq-q\">Is there a watermark on my downloads?<\/p>\n      <p class=\"pth-faq-a\">No watermark and no sign-up. What you export is exactly what you see in the preview.<\/p>\n    <\/div>\n  <\/div>\n<\/div>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n","protected":false},"excerpt":{"rendered":"<p>AI Image Eraser \u2014 Remove Background, Erase Objects &#038; Upscale Need a free AI background remover? Instantly remove backgrounds from images offline in your browser. 100% private, no uploads, and unlimited free cutouts. \ud83d\udfe2 Three Tools, One Photo Cut out a background, erase a photobomber, and upscale the result without leaving the page or re-uploading. &#8230; <a title=\"Free AI Background Remover | AI Image Eraser |  Erase Objects &amp; Upscale\" class=\"read-more\" href=\"https:\/\/schoolict.net\/tools\/free-ai-background-remover\/\" aria-label=\"Read more about Free AI Background Remover | AI Image Eraser |  Erase Objects &amp; Upscale\">Read more<\/a><\/p>\n","protected":false},"author":1,"featured_media":2357,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-2353","page","type-page","status-publish","has-post-thumbnail"],"_links":{"self":[{"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/pages\/2353","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/comments?post=2353"}],"version-history":[{"count":0,"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/pages\/2353\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/media\/2357"}],"wp:attachment":[{"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/media?parent=2353"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}