{"id":2333,"date":"2026-04-07T11:37:55","date_gmt":"2026-04-07T11:37:55","guid":{"rendered":"https:\/\/primetoolhub.com\/?page_id=2333"},"modified":"2026-07-04T06:02:54","modified_gmt":"2026-07-04T06:02:54","slug":"svg-to-png-converter","status":"publish","type":"page","link":"https:\/\/schoolict.net\/tools\/svg-to-png-converter\/","title":{"rendered":"Free SVG to PNG Converter &#8211; High Quality Offline Rasterizer"},"content":{"rendered":"<div class=\"pth-hero-section\">\n<div class=\"pth-hero-content\">\n<h2>Free SVG to PNG Converter &#8211; High Quality Offline Rasterizer<\/h2>\n<p>Need a fast SVG to PNG converter? Convert SVG vector graphics to high-quality PNG, JPG, or WebP offline instantly with custom sizing and transparency.<\/p>\n<div id=\"pth-toc-placeholder\"><\/div>\n<\/p>\n<\/div>\n<div class=\"pth-hero-image\">\n    <img data-no-lazy=\"1\"\n         src=\"https:\/\/schoolict.net\/tools\/wp-content\/uploads\/2026\/04\/SVG-to-PNG-Converter-2-800x447.jpeg\"\n         width=\"800\"\n         height=\"447\"\n         alt=\"SVG to PNG converter\"\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-svg-rasterization-vs-vectorization-what-actually-happens-inside-the-browser\">\ud83d\udd34 SVG Rasterization vs Vectorization \u2014 What Actually Happens Inside the Browser<\/a><\/li><li><a href=\"#\ud83d\udfe1-the-svg-editor-tab-live-code-editing-color-swapping-and-jsx-export\">\ud83d\udfe1 The SVG Editor Tab \u2014 Live Code Editing, Color Swapping, and JSX Export<\/a><ul><li><a href=\"#\ud83d\udfe2-color-palette-extractor-one-click-rebranding\">\ud83d\udfe2 Color Palette Extractor \u2014 One-Click Rebranding<\/a><\/li><\/ul><\/li><li><a href=\"#\ud83d\udfe2-filters-optimization-and-batch-export-the-production-workflow\">\ud83d\udfe2 Filters, Optimization, and Batch Export \u2014 The Production Workflow<\/a><ul><li><a href=\"#\ud83d\udfe2-optimize-tab-what-each-action-does-to-your-svg-bytes\">\ud83d\udfe2 Optimize Tab \u2014 What Each Action Does to Your SVG Bytes<\/a><\/li><\/ul><\/li><\/ul><\/nav><\/div>\n\n\n<style>\r\n\/* ==========================================================================\r\n   PTH SVG STUDIO PRO v3.0\r\n   AdSense + PageSpeed 100 + WCAG 2.1 AA + WP\/LiteSpeed Safe\r\n   ========================================================================== *\/\r\n#pth-svg-studio-wrapper {\r\n  font-family: 'Inter', system-ui, -apple-system, sans-serif;\r\n  width: 100%; max-width: 1400px; margin: 0 auto;\r\n  box-sizing: border-box; background: #f8fafc;\r\n  padding: 20px; border-radius: 16px;\r\n  color: #1e293b; font-weight: 500; opacity: 1;\r\n}\r\n#pth-svg-studio-wrapper * { box-sizing: border-box; min-width: 0; }\r\n#pth-svg-studio-wrapper h2, #pth-svg-studio-wrapper h3, #pth-svg-studio-wrapper h4 {\r\n  color: #0f172a; font-weight: 800; margin-top: 0;\r\n}\r\n#pth-svg-studio-wrapper .pth-tool-title {\r\n  font-size: 24px; font-weight: 800; color: #1d4ed8; margin: 0;\r\n  display: flex; align-items: center; gap: 8px;\r\n}\r\n\r\n\/* --- Meta Bar --- *\/\r\n#pth-svg-studio-wrapper .pth-tool-meta-bar {\r\n  display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 16px;\r\n}\r\n#pth-svg-studio-wrapper .pth-version-badge {\r\n  background: #eff6ff; color: #1d4ed8; border: 1px solid #bfdbfe;\r\n  font-size: 11px; font-weight: 700; padding: 2px 8px; border-radius: 4px;\r\n}\r\n#pth-svg-studio-wrapper .pth-status-offline {\r\n  background: #f0fdf4; color: #15803d; border: 1px solid #bbf7d0;\r\n  font-size: 11px; font-weight: 700; padding: 2px 8px; border-radius: 4px;\r\n}\r\n\r\n\/* --- Card --- *\/\r\n#pth-svg-studio-wrapper .pth-card {\r\n  background: #fff; border: 1px solid #e2e8f0;\r\n  border-radius: 12px; padding: 22px; margin-bottom: 18px;\r\n  box-shadow: 0 4px 6px -1px rgba(0,0,0,0.04);\r\n}\r\n\r\n\/* --- Layout --- *\/\r\n#pth-svg-studio-wrapper .pth-flex-layout {\r\n  display: grid; grid-template-columns: 1.8fr 1fr; gap: 20px; align-items: start;\r\n}\r\n#pth-svg-studio-wrapper .pth-flex-layout.pth-full-width { grid-template-columns: 100%; }\r\n#pth-svg-studio-wrapper .pth-flex-layout.pth-full-width .pth-sidebar-col { display: none; }\r\n\r\n\/* --- Buttons --- *\/\r\n#pth-svg-studio-wrapper .pth-btn {\r\n  padding: 10px 18px; border-radius: 8px; font-weight: 700; cursor: pointer;\r\n  border: none; font-family: 'Inter', sans-serif; font-size: 13px;\r\n  transition: background 0.2s, transform 0.15s;\r\n  display: inline-flex; align-items: center; justify-content: center; gap: 6px;\r\n}\r\n#pth-svg-studio-wrapper .pth-btn-primary { background: #2563eb; color: #fff; }\r\n#pth-svg-studio-wrapper .pth-btn-primary:hover { background: #1d4ed8; transform: translateY(-1px); }\r\n#pth-svg-studio-wrapper .pth-btn-secondary { background: #f1f5f9; color: #0f172a; border: 1px solid #e2e8f0; }\r\n#pth-svg-studio-wrapper .pth-btn-secondary:hover { background: #e2e8f0; }\r\n#pth-svg-studio-wrapper .pth-btn-danger { background: #fef2f2; color: #991b1b; border: 1px solid #fecaca; }\r\n#pth-svg-studio-wrapper .pth-btn-danger:hover { background: #fee2e2; }\r\n#pth-svg-studio-wrapper .pth-btn-success { background: #f0fdf4; color: #047857; border: 1px solid #bbf7d0; }\r\n#pth-svg-studio-wrapper .pth-btn-success:hover { background: #dcfce7; }\r\n#pth-svg-studio-wrapper .pth-sample-btn {\r\n  background: #d1fae5; color: #047857; border: 1px solid #6ee7b7;\r\n  font-size: 0.75rem; padding: 5px 12px; border-radius: 6px;\r\n  font-weight: 700; cursor: pointer; transition: background 0.2s;\r\n  display: inline-flex; align-items: center; gap: 4px;\r\n}\r\n#pth-svg-studio-wrapper .pth-sample-btn:hover { background: #a7f3d0; }\r\n\r\n\/* --- Tabs --- *\/\r\n#pth-svg-studio-wrapper .pth-tab-bar {\r\n  display: flex; gap: 4px; background: #e2e8f0;\r\n  padding: 5px; border-radius: 10px; margin-bottom: 20px; flex-wrap: wrap;\r\n}\r\n#pth-svg-studio-wrapper .pth-tab-btn {\r\n  flex: 1; min-width: 130px; padding: 10px 12px; border: none; background: transparent;\r\n  color: #334155; font-weight: 700; font-size: 13px; border-radius: 7px;\r\n  cursor: pointer; transition: all 0.2s; font-family: 'Inter', sans-serif;\r\n  white-space: nowrap;\r\n}\r\n#pth-svg-studio-wrapper .pth-tab-btn.active {\r\n  background: #fff; color: #1d4ed8;\r\n  box-shadow: 0 2px 6px rgba(0,0,0,0.1);\r\n}\r\n#pth-svg-studio-wrapper .pth-tab-btn:hover:not(.active) { background: #f1f5f9; }\r\n#pth-svg-studio-wrapper .pth-tab-panel { display: none; }\r\n#pth-svg-studio-wrapper .pth-tab-panel.active { display: block; }\r\n\r\n\/* --- Drop Zone --- *\/\r\n#pth-svg-studio-wrapper .pth-drop-zone {\r\n  border: 2px dashed #93c5fd; border-radius: 12px;\r\n  padding: 36px 20px; text-align: center; background: #eff6ff;\r\n  cursor: pointer; margin-bottom: 18px; transition: border-color 0.2s, background 0.2s;\r\n}\r\n#pth-svg-studio-wrapper .pth-drop-zone:hover,\r\n#pth-svg-studio-wrapper .pth-drop-zone.pth-dz-over { border-color: #2563eb; background: #dbeafe; }\r\n#pth-svg-studio-wrapper .pth-dz-icon { font-size: 38px; margin-bottom: 8px; }\r\n#pth-svg-studio-wrapper .pth-dz-text { font-size: 1rem; font-weight: 800; color: #1d4ed8; margin: 0 0 4px; }\r\n#pth-svg-studio-wrapper .pth-dz-sub { font-size: 0.82rem; color: #334155; margin: 0; }\r\n\r\n\/* --- Form Elements --- *\/\r\n#pth-svg-studio-wrapper label {\r\n  font-weight: 700; color: #0f172a; margin-bottom: 5px;\r\n  display: block; font-size: 12px; text-transform: uppercase; letter-spacing: 0.4px;\r\n}\r\n#pth-svg-studio-wrapper input[type=\"text\"],\r\n#pth-svg-studio-wrapper input[type=\"number\"],\r\n#pth-svg-studio-wrapper select,\r\n#pth-svg-studio-wrapper textarea {\r\n  width: 100%; padding: 9px 13px; border: 2px solid #e2e8f0;\r\n  border-radius: 8px; font-family: 'Inter', sans-serif;\r\n  color: #0f172a; background: #fff; font-size: 0.9rem; transition: border-color 0.2s;\r\n}\r\n#pth-svg-studio-wrapper input[type=\"text\"]:focus,\r\n#pth-svg-studio-wrapper input[type=\"number\"]:focus,\r\n#pth-svg-studio-wrapper select:focus,\r\n#pth-svg-studio-wrapper textarea:focus {\r\n  border-color: #2563eb; outline: none; box-shadow: 0 0 0 3px rgba(37,99,235,0.1);\r\n}\r\n#pth-svg-studio-wrapper input[type=\"range\"] { accent-color: #2563eb; width: 100%; }\r\n#pth-svg-studio-wrapper input[type=\"color\"] {\r\n  height: 38px; padding: 2px; cursor: pointer; border-radius: 6px;\r\n  border: 2px solid #e2e8f0; width: 100%;\r\n}\r\n#pth-svg-studio-wrapper input[type=\"checkbox\"] { accent-color: #2563eb; width: 15px; height: 15px; }\r\n\r\n\/* --- Settings Grid --- *\/\r\n#pth-svg-studio-wrapper .pth-settings-grid {\r\n  display: grid; grid-template-columns: 1fr 1fr; gap: 14px;\r\n  background: #f8fafc; padding: 16px; border-radius: 10px;\r\n  border: 1px solid #e2e8f0; margin-bottom: 16px;\r\n}\r\n#pth-svg-studio-wrapper .pth-settings-grid .pth-full-col { grid-column: 1 \/ -1; }\r\n#pth-svg-studio-wrapper .pth-field { display: flex; flex-direction: column; gap: 5px; }\r\n#pth-svg-studio-wrapper .pth-check-row {\r\n  display: flex; align-items: center; gap: 7px;\r\n  font-size: 0.85rem; font-weight: 600; color: #334155; cursor: pointer;\r\n}\r\n\r\n\/* --- Presets --- *\/\r\n#pth-svg-studio-wrapper .pth-presets { display: flex; flex-wrap: wrap; gap: 5px; }\r\n#pth-svg-studio-wrapper .pth-preset-btn {\r\n  padding: 5px 12px; font-size: 0.78rem; background: #f1f5f9;\r\n  border: 1px solid #cbd5e1; border-radius: 6px; cursor: pointer;\r\n  font-weight: 700; color: #0f172a; transition: all 0.18s; font-family: 'Inter', sans-serif;\r\n}\r\n#pth-svg-studio-wrapper .pth-preset-btn:hover { background: #dbeafe; border-color: #2563eb; color: #1d4ed8; }\r\n#pth-svg-studio-wrapper .pth-preset-btn.active { background: #2563eb; color: #fff; border-color: #2563eb; }\r\n\r\n\/* --- Slider Row --- *\/\r\n#pth-svg-studio-wrapper .pth-slider-row {\r\n  display: flex; align-items: center; gap: 10px; margin-top: 4px;\r\n}\r\n#pth-svg-studio-wrapper .pth-slider-val {\r\n  font-family: monospace; font-weight: 700; font-size: 0.85rem;\r\n  min-width: 42px; text-align: right; color: #1d4ed8;\r\n}\r\n\r\n\/* --- Preview Area --- *\/\r\n#pth-svg-studio-wrapper .pth-preview-box {\r\n  border: 1px solid #e2e8f0; border-radius: 12px; overflow: hidden; margin-top: 16px;\r\n}\r\n#pth-svg-studio-wrapper .pth-preview-header {\r\n  background: #f1f5f9; padding: 10px 16px; border-bottom: 1px solid #e2e8f0;\r\n  font-weight: 800; color: #0f172a; display: flex;\r\n  justify-content: space-between; align-items: center; font-size: 13px;\r\n}\r\n#pth-svg-studio-wrapper .pth-checker-light {\r\n  background-image: linear-gradient(45deg, #e2e8f0 25%, transparent 25%),\r\n    linear-gradient(-45deg, #e2e8f0 25%, transparent 25%),\r\n    linear-gradient(45deg, transparent 75%, #e2e8f0 75%),\r\n    linear-gradient(-45deg, transparent 75%, #e2e8f0 75%);\r\n  background-size: 20px 20px;\r\n  background-position: 0 0, 0 10px, 10px -10px, -10px 0px;\r\n  padding: 20px; display: flex; justify-content: center;\r\n  align-items: center; min-height: 240px; transition: background 0.2s;\r\n}\r\n#pth-svg-studio-wrapper .pth-checker-dark {\r\n  background-color: #1e293b;\r\n  padding: 20px; display: flex; justify-content: center;\r\n  align-items: center; min-height: 240px;\r\n}\r\n#pth-svg-studio-wrapper .pth-preview-img {\r\n  max-width: 100%; height: auto; max-height: 360px;\r\n  border: 1px solid rgba(0,0,0,0.08);\r\n  box-shadow: 0 4px 15px rgba(0,0,0,0.1);\r\n}\r\n#pth-svg-studio-wrapper .pth-file-badge {\r\n  font-size: 0.75rem; color: #334155; font-family: monospace;\r\n  background: #e2e8f0; padding: 2px 8px; border-radius: 4px;\r\n}\r\n#pth-svg-studio-wrapper .pth-download-bar {\r\n  padding: 12px 16px; background: #f8fafc;\r\n  border-top: 1px solid #e2e8f0;\r\n  display: flex; justify-content: center; gap: 8px; flex-wrap: wrap;\r\n}\r\n\r\n\/* --- SVG Editor --- *\/\r\n#pth-svg-studio-wrapper .pth-editor-header {\r\n  background: #0f172a; padding: 10px 14px; display: flex;\r\n  justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 8px;\r\n  border-radius: 10px 10px 0 0;\r\n}\r\n#pth-svg-studio-wrapper .pth-editor-title { color: #94a3b8; font-size: 12px; font-weight: 700; font-family: monospace; }\r\n#pth-svg-studio-wrapper .pth-code-area {\r\n  font-family: 'Courier New', monospace; font-size: 0.82rem;\r\n  line-height: 1.5; resize: vertical; min-height: 200px;\r\n  border: none; border-radius: 0 0 10px 10px; width: 100%;\r\n  padding: 14px; background: #1e293b; color: #e2e8f0;\r\n  border: 1px solid #334155; border-top: none;\r\n}\r\n#pth-svg-studio-wrapper .pth-code-area:focus { outline: none; }\r\n\r\n\/* --- Color Palette --- *\/\r\n#pth-svg-studio-wrapper .pth-palette-grid {\r\n  display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px;\r\n}\r\n#pth-svg-studio-wrapper .pth-color-swatch {\r\n  width: 42px; height: 42px; border-radius: 8px; cursor: pointer;\r\n  border: 2px solid #e2e8f0; position: relative;\r\n  box-shadow: 0 2px 4px rgba(0,0,0,0.1); transition: transform 0.15s;\r\n  display: flex; align-items: flex-end; justify-content: center;\r\n}\r\n#pth-svg-studio-wrapper .pth-color-swatch:hover { transform: scale(1.15); border-color: #2563eb; }\r\n#pth-svg-studio-wrapper .pth-swatch-hex {\r\n  font-size: 8px; font-weight: 700; color: #fff;\r\n  text-shadow: 0 1px 2px rgba(0,0,0,0.8); padding: 2px; line-height: 1;\r\n}\r\n\r\n\/* --- Filter FX Presets --- *\/\r\n#pth-svg-studio-wrapper .pth-fx-presets { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 14px; }\r\n#pth-svg-studio-wrapper .pth-fx-btn {\r\n  padding: 6px 14px; font-size: 0.8rem; border-radius: 20px; cursor: pointer;\r\n  font-weight: 700; border: 1px solid #e2e8f0; background: #f8fafc;\r\n  color: #334155; font-family: 'Inter', sans-serif; transition: all 0.18s;\r\n}\r\n#pth-svg-studio-wrapper .pth-fx-btn:hover { border-color: #2563eb; color: #1d4ed8; background: #eff6ff; }\r\n#pth-svg-studio-wrapper .pth-fx-btn.active { background: #2563eb; color: #fff; border-color: #2563eb; }\r\n\r\n\/* --- SVG Info Stats --- *\/\r\n#pth-svg-studio-wrapper .pth-stats-row {\r\n  display: grid; grid-template-columns: repeat(auto-fit, minmax(90px, 1fr));\r\n  gap: 10px; margin-bottom: 16px;\r\n}\r\n#pth-svg-studio-wrapper .pth-stat-box {\r\n  background: #f8fafc; border: 1px solid #e2e8f0; border-radius: 8px;\r\n  padding: 10px 8px; text-align: center;\r\n}\r\n#pth-svg-studio-wrapper .pth-stat-num {\r\n  font-size: 1.2rem; font-weight: 800; color: #1d4ed8; display: block;\r\n}\r\n#pth-svg-studio-wrapper .pth-stat-label {\r\n  font-size: 0.7rem; color: #334155; font-weight: 600; text-transform: uppercase;\r\n}\r\n\r\n\/* --- Sidebar --- *\/\r\n#pth-svg-studio-wrapper .pth-sidebar-card {\r\n  background: #fff; border: 1px solid #e2e8f0; border-radius: 12px;\r\n  overflow: hidden; margin-bottom: 16px;\r\n}\r\n#pth-svg-studio-wrapper .pth-sidebar-head {\r\n  background: #f8fafc; padding: 10px 14px; border-bottom: 1px solid #e2e8f0;\r\n  font-size: 12px; font-weight: 800; color: #1d4ed8; text-transform: uppercase;\r\n  letter-spacing: 0.5px;\r\n}\r\n#pth-svg-studio-wrapper .pth-sidebar-body { padding: 14px; }\r\n#pth-svg-studio-wrapper .pth-tip-item {\r\n  display: flex; gap: 10px; margin-bottom: 12px; align-items: flex-start;\r\n}\r\n#pth-svg-studio-wrapper .pth-tip-item:last-child { margin-bottom: 0; }\r\n#pth-svg-studio-wrapper .pth-tip-icon { font-size: 20px; flex-shrink: 0; margin-top: 2px; }\r\n#pth-svg-studio-wrapper .pth-tip-text { font-size: 0.83rem; color: #334155; line-height: 1.5; }\r\n#pth-svg-studio-wrapper .pth-tip-text strong { color: #0f172a; display: block; margin-bottom: 2px; font-weight: 700; }\r\n\r\n\/* --- Error Box --- *\/\r\n#pth-svg-studio-wrapper .pth-error-box {\r\n  display: none; background: #fef2f2; border-left: 4px solid #ef4444;\r\n  color: #991b1b; padding: 12px 14px; margin-bottom: 14px;\r\n  border-radius: 8px; font-weight: 700; font-size: 13px;\r\n}\r\n\r\n\/* --- Optimize Stats --- *\/\r\n#pth-svg-studio-wrapper .pth-opt-result {\r\n  background: #f0fdf4; border: 1px solid #bbf7d0;\r\n  border-radius: 8px; padding: 12px 14px; margin-top: 12px;\r\n  font-size: 0.85rem; color: #047857; font-weight: 700; display: none;\r\n}\r\n\r\n\/* --- Separator --- *\/\r\n#pth-svg-studio-wrapper .pth-sep {\r\n  border: none; border-top: 1px dashed #e2e8f0; margin: 16px 0;\r\n}\r\n\r\n\/* --- Mobile --- *\/\r\n@media (max-width: 768px) {\r\n  #pth-svg-studio-wrapper { padding: 10px; border-radius: 0; background: transparent; }\r\n  #pth-svg-studio-wrapper .pth-card { padding: 14px; margin-bottom: 12px; }\r\n  #pth-svg-studio-wrapper .pth-flex-layout { grid-template-columns: 100% !important; gap: 12px; }\r\n  #pth-svg-studio-wrapper .pth-tool-title { font-size: 19px; }\r\n  #pth-svg-studio-wrapper .pth-settings-grid { grid-template-columns: 1fr; }\r\n  #pth-svg-studio-wrapper .pth-tab-btn { font-size: 11px; padding: 8px 8px; min-width: 80px; }\r\n}\r\n@media (max-width: 480px) {\r\n  #pth-svg-studio-wrapper .pth-tab-bar { gap: 3px; }\r\n}\r\n<\/style>\r\n\r\n<!-- Toast Container -->\r\n<div id=\"pth-svg-studio-toast\" role=\"status\" aria-live=\"polite\"\r\n  style=\"position:fixed;bottom:24px;right:24px;z-index:9999;display:flex;flex-direction:column;gap:8px;pointer-events:none;\"><\/div>\r\n\r\n<div id=\"pth-svg-studio-wrapper\">\r\n  <div class=\"pth-flex-layout\" id=\"pth-svg-studio-layout\">\r\n\r\n    <!-- ======================== MAIN COLUMN ======================== -->\r\n    <div class=\"pth-main-col\">\r\n      <div class=\"pth-card\">\r\n\r\n        <!-- Header -->\r\n        <div style=\"display:flex;justify-content:space-between;align-items:flex-start;margin-bottom:12px;flex-wrap:wrap;gap:10px;\">\r\n          <h2 class=\"pth-tool-title\">\ud83c\udfa8 SVG Studio Pro<\/h2>\r\n          <button class=\"pth-btn pth-btn-secondary\" id=\"pth-svg-fw-btn\" aria-label=\"Toggle full width layout\">\u26f6 Full Width<\/button>\r\n        <\/div>\r\n\r\n        <!-- Meta Bar -->\r\n        <div class=\"pth-tool-meta-bar\">\r\n          <span class=\"pth-version-badge\">v3.0<\/span>\r\n          <span class=\"pth-status-offline\">\ud83d\udd12 100% Offline<\/span>\r\n        <\/div>\r\n\r\n        <!-- Action Bar -->\r\n        <div style=\"display:flex;gap:8px;margin-bottom:16px;flex-wrap:wrap;align-items:center;\">\r\n          <button class=\"pth-sample-btn\" id=\"pth-svg-sample-btn\" aria-label=\"Load sample SVG\">\ud83d\udca1 Load Sample<\/button>\r\n          <button class=\"pth-btn pth-btn-danger\" id=\"pth-svg-clear-btn\" style=\"font-size:0.75rem;padding:5px 12px;border-radius:6px;\" aria-label=\"Clear all\">\ud83d\uddd1\ufe0f Clear<\/button>\r\n        <\/div>\r\n\r\n        <!-- Error -->\r\n        <div class=\"pth-error-box\" id=\"pth-svg-error\" role=\"alert\" aria-live=\"assertive\"><\/div>\r\n\r\n        <!-- Drop Zone -->\r\n        <div class=\"pth-drop-zone\" id=\"pth-svg-dropzone\" role=\"button\" tabindex=\"0\" aria-label=\"Upload SVG or image file\">\r\n          <div class=\"pth-dz-icon\">\ud83d\udcc2<\/div>\r\n          <div class=\"pth-dz-text\" id=\"pth-svg-dz-title\">Click or Drag & Drop your SVG file here<\/div>\r\n          <p class=\"pth-dz-sub\">SVG, PNG, JPG, WebP \u2014 100% Offline Processing<\/p>\r\n        <\/div>\r\n        <input type=\"file\" id=\"pth-svg-file-input\" accept=\".svg,.png,.jpg,.jpeg,.webp\" style=\"display:none;\" aria-label=\"File upload input\">\r\n\r\n        <!-- SVG Stats Row (shown after load) -->\r\n        <div class=\"pth-stats-row\" id=\"pth-svg-stats\" style=\"display:none;\">\r\n          <div class=\"pth-stat-box\"><span class=\"pth-stat-num\" id=\"pth-stat-w\">\u2014<\/span><span class=\"pth-stat-label\">Width<\/span><\/div>\r\n          <div class=\"pth-stat-box\"><span class=\"pth-stat-num\" id=\"pth-stat-h\">\u2014<\/span><span class=\"pth-stat-label\">Height<\/span><\/div>\r\n          <div class=\"pth-stat-box\"><span class=\"pth-stat-num\" id=\"pth-stat-els\">\u2014<\/span><span class=\"pth-stat-label\">Elements<\/span><\/div>\r\n          <div class=\"pth-stat-box\"><span class=\"pth-stat-num\" id=\"pth-stat-size\">\u2014<\/span><span class=\"pth-stat-label\">File Size<\/span><\/div>\r\n          <div class=\"pth-stat-box\"><span class=\"pth-stat-num\" id=\"pth-stat-colors\">\u2014<\/span><span class=\"pth-stat-label\">Colors<\/span><\/div>\r\n        <\/div>\r\n\r\n        <!-- ===== TABS ===== -->\r\n        <div id=\"pth-svg-tabs-area\" style=\"display:none;\">\r\n          <div class=\"pth-tab-bar\" role=\"tablist\">\r\n            <button class=\"pth-tab-btn active\" id=\"pth-tab-rasterize\" role=\"tab\" aria-selected=\"true\" aria-controls=\"pth-panel-rasterize\">\ud83d\uddbc\ufe0f Rasterize<\/button>\r\n            <button class=\"pth-tab-btn\" id=\"pth-tab-editor\" role=\"tab\" aria-selected=\"false\" aria-controls=\"pth-panel-editor\">\u270f\ufe0f SVG Editor<\/button>\r\n            <button class=\"pth-tab-btn\" id=\"pth-tab-filters\" role=\"tab\" aria-selected=\"false\" aria-controls=\"pth-panel-filters\">\ud83c\udfa8 Filters & FX<\/button>\r\n            <button class=\"pth-tab-btn\" id=\"pth-tab-optimize\" role=\"tab\" aria-selected=\"false\" aria-controls=\"pth-panel-optimize\">\ud83d\udcd0 Optimize<\/button>\r\n          <\/div>\r\n\r\n          <!-- ======== TAB 1: RASTERIZE ======== -->\r\n          <div class=\"pth-tab-panel active\" id=\"pth-panel-rasterize\" role=\"tabpanel\" aria-labelledby=\"pth-tab-rasterize\">\r\n\r\n            <div class=\"pth-settings-grid\">\r\n              <!-- Output Format -->\r\n              <div class=\"pth-field\">\r\n                <label for=\"pth-out-format\">Output Format<\/label>\r\n                <select id=\"pth-out-format\" aria-label=\"Output image format\">\r\n                  <option value=\"png\">PNG (Transparent)<\/option>\r\n                  <option value=\"jpeg\">JPG \/ JPEG<\/option>\r\n                  <option value=\"webp\">WebP (Modern)<\/option>\r\n                <\/select>\r\n              <\/div>\r\n\r\n              <!-- Background Color -->\r\n              <div class=\"pth-field\">\r\n                <label for=\"pth-out-bg\">Background Color<\/label>\r\n                <div style=\"display:flex;gap:8px;align-items:center;\">\r\n                  <input type=\"color\" id=\"pth-out-bg\" value=\"#ffffff\" aria-label=\"Background color picker\" style=\"flex:1;\">\r\n                  <label class=\"pth-check-row\" style=\"flex:1;\">\r\n                    <input type=\"checkbox\" id=\"pth-out-transparent\" checked aria-label=\"Use transparent background\">\r\n                    <span>Transparent<\/span>\r\n                  <\/label>\r\n                <\/div>\r\n              <\/div>\r\n\r\n              <!-- Width -->\r\n              <div class=\"pth-field\">\r\n                <label for=\"pth-out-w\">Width (px)<\/label>\r\n                <input type=\"number\" id=\"pth-out-w\" placeholder=\"Auto\" min=\"1\" max=\"8192\" aria-label=\"Output width in pixels\">\r\n              <\/div>\r\n\r\n              <!-- Height -->\r\n              <div class=\"pth-field\">\r\n                <label for=\"pth-out-h\">Height (px)<\/label>\r\n                <input type=\"number\" id=\"pth-out-h\" placeholder=\"Auto\" min=\"1\" max=\"8192\" aria-label=\"Output height in pixels\">\r\n                <label class=\"pth-check-row\" style=\"margin-top:4px;\">\r\n                  <input type=\"checkbox\" id=\"pth-lock-aspect\" checked aria-label=\"Lock aspect ratio\">\r\n                  <span>Lock Aspect Ratio<\/span>\r\n                <\/label>\r\n              <\/div>\r\n\r\n              <!-- Quality -->\r\n              <div class=\"pth-field pth-full-col\" id=\"pth-quality-field\" style=\"display:none;\">\r\n                <label for=\"pth-quality\">Quality (JPG \/ WebP)<\/label>\r\n                <div class=\"pth-slider-row\">\r\n                  <input type=\"range\" id=\"pth-quality\" min=\"10\" max=\"100\" value=\"95\" aria-label=\"Output quality percentage\">\r\n                  <span class=\"pth-slider-val\" id=\"pth-quality-val\">95%<\/span>\r\n                <\/div>\r\n              <\/div>\r\n\r\n              <!-- Size Presets -->\r\n              <div class=\"pth-field pth-full-col\">\r\n                <label>Quick Size Presets<\/label>\r\n                <div class=\"pth-presets\" id=\"pth-size-presets\">\r\n                  <button class=\"pth-preset-btn\" data-w=\"16\" data-h=\"16\" aria-label=\"Set size 16x16\">16\u00d716<\/button>\r\n                  <button class=\"pth-preset-btn\" data-w=\"32\" data-h=\"32\" aria-label=\"Set size 32x32\">32\u00d732<\/button>\r\n                  <button class=\"pth-preset-btn\" data-w=\"64\" data-h=\"64\" aria-label=\"Set size 64x64\">64\u00d764<\/button>\r\n                  <button class=\"pth-preset-btn\" data-w=\"256\" data-h=\"256\" aria-label=\"Set size 256x256\">256\u00d7256<\/button>\r\n                  <button class=\"pth-preset-btn\" data-w=\"512\" data-h=\"512\" aria-label=\"Set size 512x512\">512\u00d7512<\/button>\r\n                  <button class=\"pth-preset-btn\" data-w=\"1024\" data-h=\"1024\" aria-label=\"Set size 1024x1024\">1024\u00d71024<\/button>\r\n                  <button class=\"pth-preset-btn\" data-w=\"2048\" data-h=\"2048\" aria-label=\"Set size 2048x2048\">2048\u00d72048<\/button>\r\n                  <button class=\"pth-preset-btn\" data-w=\"1200\" data-h=\"630\" aria-label=\"Set size OG 1200x630\">OG 1200\u00d7630<\/button>\r\n                  <button class=\"pth-preset-btn\" data-w=\"1080\" data-h=\"1080\" aria-label=\"Set size Instagram 1080x1080\">Instagram<\/button>\r\n                  <button class=\"pth-preset-btn\" data-w=\"820\" data-h=\"312\" aria-label=\"Set size Facebook Cover\">FB Cover<\/button>\r\n                  <button class=\"pth-preset-btn active\" data-w=\"0\" data-h=\"0\" aria-label=\"Use original SVG size\">Original<\/button>\r\n                <\/div>\r\n              <\/div>\r\n            <\/div>\r\n\r\n            <button class=\"pth-btn pth-btn-primary\" id=\"pth-render-btn\" style=\"width:100%;padding:13px;font-size:0.95rem;margin-bottom:16px;\" aria-label=\"Render SVG to image\">\u2728 Render to Image<\/button>\r\n\r\n            <!-- Preview -->\r\n            <div class=\"pth-preview-box\" id=\"pth-raster-preview\" style=\"display:none;\">\r\n              <div class=\"pth-preview-header\">\r\n                <span>\ud83d\uddbc\ufe0f Output Preview<\/span>\r\n                <div style=\"display:flex;gap:8px;align-items:center;\">\r\n                  <span class=\"pth-file-badge\" id=\"pth-raster-info\">\u2014<\/span>\r\n                  <button class=\"pth-preset-btn\" id=\"pth-bg-toggle-btn\" aria-label=\"Toggle preview background\">\u2600\ufe0f Light BG<\/button>\r\n                <\/div>\r\n              <\/div>\r\n              <div id=\"pth-raster-canvas-wrap\" class=\"pth-checker-light\">\r\n                <canvas id=\"pth-render-canvas\" style=\"display:none;\" width=\"1\" height=\"1\"><\/canvas>\r\n                <img decoding=\"async\" id=\"pth-raster-img\" class=\"pth-preview-img\" src=\"\" alt=\"SVG rasterized preview output\" width=\"400\" height=\"300\" data-no-lazy=\"1\">\r\n              <\/div>\r\n              <div class=\"pth-download-bar\" id=\"pth-raster-download-bar\"><\/div>\r\n            <\/div>\r\n          <\/div>\r\n\r\n          <!-- ======== TAB 2: SVG EDITOR ======== -->\r\n          <div class=\"pth-tab-panel\" id=\"pth-panel-editor\" role=\"tabpanel\" aria-labelledby=\"pth-tab-editor\">\r\n\r\n            <!-- Color Palette Extractor -->\r\n            <div style=\"margin-bottom:16px;\">\r\n              <label>\ud83c\udfa8 Color Palette (click to replace in SVG)<\/label>\r\n              <div class=\"pth-palette-grid\" id=\"pth-palette-grid\">\r\n                <span style=\"font-size:0.82rem;color:#334155;\">Load an SVG to extract colors.<\/span>\r\n              <\/div>\r\n            <\/div>\r\n            <!-- Color Replace -->\r\n            <div class=\"pth-settings-grid\" id=\"pth-color-replace-area\" style=\"display:none;\">\r\n              <div class=\"pth-field\">\r\n                <label for=\"pth-old-color\">Replace Color<\/label>\r\n                <input type=\"color\" id=\"pth-old-color\" value=\"#000000\" aria-label=\"Color to replace\">\r\n              <\/div>\r\n              <div class=\"pth-field\">\r\n                <label for=\"pth-new-color\">With New Color<\/label>\r\n                <input type=\"color\" id=\"pth-new-color\" value=\"#2563eb\" aria-label=\"Replacement color\">\r\n              <\/div>\r\n              <div class=\"pth-field pth-full-col\" style=\"flex-direction:row;gap:8px;align-items:flex-end;\">\r\n                <button class=\"pth-btn pth-btn-primary\" id=\"pth-replace-color-btn\" style=\"flex:1;\" aria-label=\"Apply color replacement\">\ud83d\udd04 Replace Color<\/button>\r\n                <button class=\"pth-btn pth-btn-secondary\" id=\"pth-revert-color-btn\" style=\"flex:1;\" aria-label=\"Revert all color changes\">\u21a9\ufe0f Revert<\/button>\r\n              <\/div>\r\n            <\/div>\r\n\r\n            <hr class=\"pth-sep\">\r\n\r\n            <!-- Editor -->\r\n            <label>\u270f\ufe0f SVG Source Code<\/label>\r\n            <div style=\"border-radius:10px;overflow:hidden;margin-top:6px;\">\r\n              <div class=\"pth-editor-header\">\r\n                <span class=\"pth-editor-title\">\ud83d\udcc4 SVG Source<\/span>\r\n                <div style=\"display:flex;gap:6px;\">\r\n                  <button class=\"pth-btn pth-btn-secondary\" id=\"pth-optimize-space-btn\" style=\"padding:5px 10px;font-size:0.75rem;background:#334155;color:#e2e8f0;border:none;\" aria-label=\"Minify SVG source\">\u26a1 Minify<\/button>\r\n                  <button class=\"pth-btn pth-btn-secondary\" id=\"pth-beautify-btn\" style=\"padding:5px 10px;font-size:0.75rem;background:#334155;color:#e2e8f0;border:none;\" aria-label=\"Beautify SVG source\">\u2728 Beautify<\/button>\r\n                  <button class=\"pth-btn pth-btn-primary\" id=\"pth-apply-editor-btn\" style=\"padding:5px 10px;font-size:0.75rem;\" aria-label=\"Apply editor changes to SVG\">\u2705 Apply<\/button>\r\n                <\/div>\r\n              <\/div>\r\n              <textarea class=\"pth-code-area\" id=\"pth-svg-code-area\" spellcheck=\"false\" aria-label=\"SVG source code editor\" placeholder=\"SVG source will appear here after loading a file...\"><\/textarea>\r\n            <\/div>\r\n\r\n            <!-- Copy \/ Download SVG -->\r\n            <div style=\"display:flex;gap:8px;margin-top:12px;flex-wrap:wrap;\">\r\n              <button class=\"pth-btn pth-btn-secondary\" id=\"pth-copy-svg-btn\" aria-label=\"Copy SVG code to clipboard\">\ud83d\udccb Copy SVG Code<\/button>\r\n              <button class=\"pth-btn pth-btn-secondary\" id=\"pth-copy-jsx-btn\" aria-label=\"Copy SVG as React JSX\">\u269b\ufe0f Copy as JSX<\/button>\r\n              <button class=\"pth-btn pth-btn-success\" id=\"pth-download-svg-btn\" aria-label=\"Download SVG file\">\ud83d\udcc4 Download SVG<\/button>\r\n            <\/div>\r\n\r\n            <!-- SVG Preview in Editor -->\r\n            <div class=\"pth-preview-box\" id=\"pth-editor-preview\" style=\"margin-top:16px;display:none;\">\r\n              <div class=\"pth-preview-header\">\r\n                <span>\ud83d\udc41\ufe0f Live SVG Preview<\/span>\r\n                <span class=\"pth-file-badge\" id=\"pth-editor-info\">\u2014<\/span>\r\n              <\/div>\r\n              <div class=\"pth-checker-light\" id=\"pth-editor-canvas-wrap\">\r\n                <img decoding=\"async\" id=\"pth-editor-img\" class=\"pth-preview-img\" src=\"\" alt=\"SVG live editor preview\" width=\"400\" height=\"300\" data-no-lazy=\"1\">\r\n              <\/div>\r\n            <\/div>\r\n          <\/div>\r\n\r\n          <!-- ======== TAB 3: FILTERS & FX ======== -->\r\n          <div class=\"pth-tab-panel\" id=\"pth-panel-filters\" role=\"tabpanel\" aria-labelledby=\"pth-tab-filters\">\r\n\r\n            <label>\ud83c\udfac Filter Presets<\/label>\r\n            <div class=\"pth-fx-presets\" id=\"pth-fx-presets\" style=\"margin-top:6px;\">\r\n              <button class=\"pth-fx-btn active\" data-preset=\"none\" aria-label=\"No filter preset\">\ud83c\udf1f Original<\/button>\r\n              <button class=\"pth-fx-btn\" data-preset=\"vintage\" aria-label=\"Vintage filter preset\">\ud83d\udfe4 Vintage<\/button>\r\n              <button class=\"pth-fx-btn\" data-preset=\"drama\" aria-label=\"Drama filter preset\">\ud83c\udfad Drama<\/button>\r\n              <button class=\"pth-fx-btn\" data-preset=\"cool\" aria-label=\"Cool filter preset\">\ud83e\uddca Cool<\/button>\r\n              <button class=\"pth-fx-btn\" data-preset=\"warm\" aria-label=\"Warm filter preset\">\ud83d\udd25 Warm<\/button>\r\n              <button class=\"pth-fx-btn\" data-preset=\"bw\" aria-label=\"Black and white filter preset\">\u2b1b B&W<\/button>\r\n              <button class=\"pth-fx-btn\" data-preset=\"sepia\" aria-label=\"Sepia filter preset\">\ud83d\udcf7 Sepia<\/button>\r\n              <button class=\"pth-fx-btn\" data-preset=\"invert\" aria-label=\"Invert colors filter preset\">\ud83d\udd04 Invert<\/button>\r\n            <\/div>\r\n\r\n            <hr class=\"pth-sep\">\r\n\r\n            <div class=\"pth-settings-grid\">\r\n              <div class=\"pth-field\">\r\n                <label for=\"pth-fx-brightness\">Brightness<\/label>\r\n                <div class=\"pth-slider-row\">\r\n                  <input type=\"range\" id=\"pth-fx-brightness\" min=\"0\" max=\"200\" value=\"100\" aria-label=\"Brightness control\">\r\n                  <span class=\"pth-slider-val\" id=\"pth-fxv-brightness\">100%<\/span>\r\n                <\/div>\r\n              <\/div>\r\n              <div class=\"pth-field\">\r\n                <label for=\"pth-fx-contrast\">Contrast<\/label>\r\n                <div class=\"pth-slider-row\">\r\n                  <input type=\"range\" id=\"pth-fx-contrast\" min=\"0\" max=\"200\" value=\"100\" aria-label=\"Contrast control\">\r\n                  <span class=\"pth-slider-val\" id=\"pth-fxv-contrast\">100%<\/span>\r\n                <\/div>\r\n              <\/div>\r\n              <div class=\"pth-field\">\r\n                <label for=\"pth-fx-saturation\">Saturation<\/label>\r\n                <div class=\"pth-slider-row\">\r\n                  <input type=\"range\" id=\"pth-fx-saturation\" min=\"0\" max=\"200\" value=\"100\" aria-label=\"Saturation control\">\r\n                  <span class=\"pth-slider-val\" id=\"pth-fxv-saturation\">100%<\/span>\r\n                <\/div>\r\n              <\/div>\r\n              <div class=\"pth-field\">\r\n                <label for=\"pth-fx-hue\">Hue Rotate<\/label>\r\n                <div class=\"pth-slider-row\">\r\n                  <input type=\"range\" id=\"pth-fx-hue\" min=\"0\" max=\"360\" value=\"0\" aria-label=\"Hue rotation control\">\r\n                  <span class=\"pth-slider-val\" id=\"pth-fxv-hue\">0\u00b0<\/span>\r\n                <\/div>\r\n              <\/div>\r\n              <div class=\"pth-field\">\r\n                <label for=\"pth-fx-blur\">Blur<\/label>\r\n                <div class=\"pth-slider-row\">\r\n                  <input type=\"range\" id=\"pth-fx-blur\" min=\"0\" max=\"20\" value=\"0\" step=\"0.5\" aria-label=\"Blur control\">\r\n                  <span class=\"pth-slider-val\" id=\"pth-fxv-blur\">0px<\/span>\r\n                <\/div>\r\n              <\/div>\r\n              <div class=\"pth-field\">\r\n                <label for=\"pth-fx-sepia\">Sepia<\/label>\r\n                <div class=\"pth-slider-row\">\r\n                  <input type=\"range\" id=\"pth-fx-sepia\" min=\"0\" max=\"100\" value=\"0\" aria-label=\"Sepia control\">\r\n                  <span class=\"pth-slider-val\" id=\"pth-fxv-sepia\">0%<\/span>\r\n                <\/div>\r\n              <\/div>\r\n              <div class=\"pth-field pth-full-col\" style=\"flex-direction:row;gap:16px;flex-wrap:wrap;\">\r\n                <label class=\"pth-check-row\">\r\n                  <input type=\"checkbox\" id=\"pth-fx-grayscale\" aria-label=\"Grayscale effect\">\r\n                  <span>Grayscale<\/span>\r\n                <\/label>\r\n                <label class=\"pth-check-row\">\r\n                  <input type=\"checkbox\" id=\"pth-fx-invert\" aria-label=\"Invert colors effect\">\r\n                  <span>Invert Colors<\/span>\r\n                <\/label>\r\n              <\/div>\r\n            <\/div>\r\n\r\n            <button class=\"pth-btn pth-btn-secondary\" id=\"pth-reset-filters-btn\" style=\"margin-bottom:14px;\" aria-label=\"Reset all filters to default\">\u21a9\ufe0f Reset All Filters<\/button>\r\n\r\n            <!-- FX Preview -->\r\n            <div class=\"pth-preview-box\" id=\"pth-fx-preview\" style=\"display:none;\">\r\n              <div class=\"pth-preview-header\">\r\n                <span>\ud83c\udfa8 Filter Preview<\/span>\r\n                <span class=\"pth-file-badge\" id=\"pth-fx-filter-string\">filter: none<\/span>\r\n              <\/div>\r\n              <div class=\"pth-checker-light\">\r\n                <img decoding=\"async\" id=\"pth-fx-img\" class=\"pth-preview-img\" src=\"\" alt=\"SVG with applied filters preview\" width=\"400\" height=\"300\" data-no-lazy=\"1\" style=\"transition:filter 0.25s;\">\r\n              <\/div>\r\n              <div class=\"pth-download-bar\">\r\n                <button class=\"pth-btn pth-btn-primary\" id=\"pth-fx-export-btn\" aria-label=\"Export with applied filters\">\ud83d\udce5 Export with Filters<\/button>\r\n                <button class=\"pth-btn pth-btn-secondary\" id=\"pth-fx-copy-css-btn\" aria-label=\"Copy filter as CSS string\">\ud83d\udccb Copy as CSS<\/button>\r\n              <\/div>\r\n            <\/div>\r\n          <\/div>\r\n\r\n          <!-- ======== TAB 4: OPTIMIZE ======== -->\r\n          <div class=\"pth-tab-panel\" id=\"pth-panel-optimize\" role=\"tabpanel\" aria-labelledby=\"pth-tab-optimize\">\r\n\r\n            <!-- ViewBox Editor -->\r\n            <div style=\"margin-bottom:16px;\">\r\n              <label>\ud83d\udcd0 ViewBox Editor<\/label>\r\n              <div style=\"display:grid;grid-template-columns:1fr 1fr 1fr 1fr;gap:8px;margin-top:6px;\">\r\n                <div class=\"pth-field\">\r\n                  <label for=\"pth-vb-x\">min-x<\/label>\r\n                  <input type=\"number\" id=\"pth-vb-x\" value=\"0\" aria-label=\"ViewBox min-x\">\r\n                <\/div>\r\n                <div class=\"pth-field\">\r\n                  <label for=\"pth-vb-y\">min-y<\/label>\r\n                  <input type=\"number\" id=\"pth-vb-y\" value=\"0\" aria-label=\"ViewBox min-y\">\r\n                <\/div>\r\n                <div class=\"pth-field\">\r\n                  <label for=\"pth-vb-w\">width<\/label>\r\n                  <input type=\"number\" id=\"pth-vb-w\" value=\"0\" aria-label=\"ViewBox width\">\r\n                <\/div>\r\n                <div class=\"pth-field\">\r\n                  <label for=\"pth-vb-h\">height<\/label>\r\n                  <input type=\"number\" id=\"pth-vb-h\" value=\"0\" aria-label=\"ViewBox height\">\r\n                <\/div>\r\n              <\/div>\r\n              <button class=\"pth-btn pth-btn-secondary\" id=\"pth-apply-viewbox-btn\" style=\"margin-top:8px;\" aria-label=\"Apply viewBox changes\">\ud83d\udcd0 Apply ViewBox<\/button>\r\n            <\/div>\r\n\r\n            <hr class=\"pth-sep\">\r\n\r\n            <!-- SVG Optimize Actions -->\r\n            <label>\u26a1 Optimize Actions<\/label>\r\n            <div style=\"display:flex;flex-wrap:wrap;gap:8px;margin:8px 0 16px;\">\r\n              <button class=\"pth-btn pth-btn-secondary\" id=\"pth-remove-comments-btn\" aria-label=\"Remove SVG comments\">\ud83d\udcac Remove Comments<\/button>\r\n              <button class=\"pth-btn pth-btn-secondary\" id=\"pth-remove-metadata-btn\" aria-label=\"Remove SVG metadata\">\ud83d\uddd1\ufe0f Strip Metadata<\/button>\r\n              <button class=\"pth-btn pth-btn-secondary\" id=\"pth-strip-ids-btn\" aria-label=\"Strip unnecessary IDs\">\ud83c\udd94 Strip IDs<\/button>\r\n              <button class=\"pth-btn pth-btn-primary\" id=\"pth-full-optimize-btn\" aria-label=\"Full SVG optimization\">\ud83d\ude80 Full Optimize<\/button>\r\n            <\/div>\r\n\r\n            <div class=\"pth-opt-result\" id=\"pth-opt-result\"><\/div>\r\n\r\n            <hr class=\"pth-sep\">\r\n\r\n            <!-- Batch Export -->\r\n            <label>\ud83d\udce6 Batch Export Pack<\/label>\r\n            <div style=\"margin:8px 0 16px;\">\r\n              <div class=\"pth-fx-presets\" id=\"pth-export-pack-btns\">\r\n                <button class=\"pth-fx-btn\" id=\"pth-export-favicon-btn\" aria-label=\"Export favicon pack\">\ud83c\udf10 Favicon Pack<\/button>\r\n                <button class=\"pth-fx-btn\" id=\"pth-export-social-btn\" aria-label=\"Export social media pack\">\ud83d\udcf1 Social Pack<\/button>\r\n                <button class=\"pth-fx-btn\" id=\"pth-export-icons-btn\" aria-label=\"Export icon sizes pack\">\ud83c\udfaf Icon Sizes<\/button>\r\n              <\/div>\r\n            <\/div>\r\n\r\n            <hr class=\"pth-sep\">\r\n\r\n            <!-- Vectorize (pure canvas, offline) -->\r\n            <label>\ud83e\ude84 Bitmap \u2192 SVG Vectorizer (Offline)<\/label>\r\n            <p style=\"font-size:0.82rem;color:#334155;margin:4px 0 10px;\">Load a PNG\/JPG first, then trace it to an SVG vector. All processing done in-browser with Canvas API.<\/p>\r\n            <div class=\"pth-settings-grid\">\r\n              <div class=\"pth-field\">\r\n                <label for=\"pth-trace-threshold\">Edge Threshold<\/label>\r\n                <div class=\"pth-slider-row\">\r\n                  <input type=\"range\" id=\"pth-trace-threshold\" min=\"10\" max=\"240\" value=\"128\" aria-label=\"Edge detection threshold\">\r\n                  <span class=\"pth-slider-val\" id=\"pth-trace-thresh-val\">128<\/span>\r\n                <\/div>\r\n              <\/div>\r\n              <div class=\"pth-field\">\r\n                <label for=\"pth-trace-colors\">Color Mode<\/label>\r\n                <select id=\"pth-trace-colors\" aria-label=\"Vectorize color mode\">\r\n                  <option value=\"bw\">Black & White<\/option>\r\n                  <option value=\"color\">Multi-Color (4-pass)<\/option>\r\n                <\/select>\r\n              <\/div>\r\n            <\/div>\r\n            <button class=\"pth-btn pth-btn-primary\" id=\"pth-vectorize-btn\" style=\"width:100%;padding:12px;font-size:0.9rem;\" aria-label=\"Vectorize bitmap to SVG\">\ud83e\ude84 Vectorize to SVG<\/button>\r\n          <\/div>\r\n\r\n        <\/div><!-- end tabs area -->\r\n      <\/div><!-- end main card -->\r\n    <\/div><!-- end main col -->\r\n\r\n    <!-- ======================== SIDEBAR ======================== -->\r\n    <div class=\"pth-sidebar-col\" id=\"pth-svg-studio-sidebar\">\r\n\r\n      <div class=\"pth-sidebar-card\">\r\n        <div class=\"pth-sidebar-head\">\ud83d\ude80 What's New in v3.0<\/div>\r\n        <div class=\"pth-sidebar-body\">\r\n          <div class=\"pth-tip-item\">\r\n            <span class=\"pth-tip-icon\">\ud83c\udfa8<\/span>\r\n            <div class=\"pth-tip-text\"><strong>Color Palette Extractor<\/strong>Scan SVG and swap any color with one click. Perfect for logo rebranding.<\/div>\r\n          <\/div>\r\n          <div class=\"pth-tip-item\">\r\n            <span class=\"pth-tip-icon\">\ud83c\udfad<\/span>\r\n            <div class=\"pth-tip-text\"><strong>8 Filter Presets<\/strong>Vintage, Drama, Cool, Warm, B&W, Sepia, Invert \u2014 plus full manual controls.<\/div>\r\n          <\/div>\r\n          <div class=\"pth-tip-item\">\r\n            <span class=\"pth-tip-icon\">\ud83e\ude84<\/span>\r\n            <div class=\"pth-tip-text\"><strong>Offline Vectorizer<\/strong>Bitmap \u2192 SVG using Canvas edge detection. Zero CDN, zero upload.<\/div>\r\n          <\/div>\r\n          <div class=\"pth-tip-item\">\r\n            <span class=\"pth-tip-icon\">\ud83d\udce6<\/span>\r\n            <div class=\"pth-tip-text\"><strong>Batch Export Packs<\/strong>Favicon Pack, Social Pack, Icon Sizes \u2014 all downloaded in one click.<\/div>\r\n          <\/div>\r\n          <div class=\"pth-tip-item\">\r\n            <span class=\"pth-tip-icon\">\ud83d\udcd0<\/span>\r\n            <div class=\"pth-tip-text\"><strong>ViewBox Editor<\/strong>Precisely crop or reframe your SVG without touching code.<\/div>\r\n          <\/div>\r\n        <\/div>\r\n      <\/div>\r\n\r\n      <div class=\"pth-sidebar-card\">\r\n        <div class=\"pth-sidebar-head\">\ud83d\udca1 Pro Tips<\/div>\r\n        <div class=\"pth-sidebar-body\">\r\n          <div class=\"pth-tip-item\">\r\n            <span class=\"pth-tip-icon\">\u26a1<\/span>\r\n            <div class=\"pth-tip-text\"><strong>Optimize before export<\/strong>Run Full Optimize first to shrink SVG by 30\u201360% with zero visual loss.<\/div>\r\n          <\/div>\r\n          <div class=\"pth-tip-item\">\r\n            <span class=\"pth-tip-icon\">\ud83c\udf10<\/span>\r\n            <div class=\"pth-tip-text\"><strong>Favicon Pack<\/strong>Generates 16\u00d716, 32\u00d732, 64\u00d764, 180\u00d7180 (Apple Touch) + 192\u00d7192 in one batch.<\/div>\r\n          <\/div>\r\n          <div class=\"pth-tip-item\">\r\n            <span class=\"pth-tip-icon\">\ud83d\udd12<\/span>\r\n            <div class=\"pth-tip-text\"><strong>Your files stay local<\/strong>Nothing leaves your browser. Safe for client logos and proprietary assets.<\/div>\r\n          <\/div>\r\n        <\/div>\r\n      <\/div>\r\n\r\n      <div class=\"pth-sidebar-card\">\r\n        <div class=\"pth-sidebar-head\">\ud83d\udcca SVG Format Guide<\/div>\r\n        <div class=\"pth-sidebar-body\">\r\n          <div class=\"pth-tip-item\">\r\n            <span class=\"pth-tip-icon\">\ud83d\uddbc\ufe0f<\/span>\r\n            <div class=\"pth-tip-text\"><strong>PNG<\/strong>Best for transparency, icons, UI assets. Lossless quality.<\/div>\r\n          <\/div>\r\n          <div class=\"pth-tip-item\">\r\n            <span class=\"pth-tip-icon\">\ud83d\udcf8<\/span>\r\n            <div class=\"pth-tip-text\"><strong>JPG<\/strong>Best for photos and OG images. Use 85\u201395% quality.<\/div>\r\n          <\/div>\r\n          <div class=\"pth-tip-item\">\r\n            <span class=\"pth-tip-icon\">\ud83c\udf10<\/span>\r\n            <div class=\"pth-tip-text\"><strong>WebP<\/strong>30% smaller than JPG\/PNG. Modern browsers only.<\/div>\r\n          <\/div>\r\n        <\/div>\r\n      <\/div>\r\n\r\n    <\/div><!-- end sidebar -->\r\n  <\/div><!-- end flex layout -->\r\n<\/div><!-- end wrapper -->\r\n\r\n<script data-no-optimize=\"1\" data-no-minify=\"1\" data-cfasync=\"false\">\r\n(function() {\r\n  'use strict';\r\n\r\n  window.pthSvgStudioApp = {\r\n    initialized: false,\r\n    svgContent: null,\r\n    origSvgContent: null,\r\n    rasterDataUrl: null,\r\n    origWidth: 0,\r\n    origHeight: 0,\r\n    aspectRatio: 1,\r\n    currentBgDark: false,\r\n    filterValues: { brightness: 100, contrast: 100, saturation: 100, hue: 0, blur: 0, sepia: 0, grayscale: false, invert: false },\r\n\r\n    sampleSvg: '<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" viewBox=\"0 0 200 200\" width=\"200\" height=\"200\"><defs><linearGradient id=\"g1\" x1=\"0%\" y1=\"0%\" x2=\"100%\" y2=\"100%\"><stop offset=\"0%\" style=\"stop-color:#2563eb;stop-opacity:1\"\/><stop offset=\"100%\" style=\"stop-color:#7c3aed;stop-opacity:1\"\/><\/linearGradient><\/defs><rect width=\"200\" height=\"200\" fill=\"none\" rx=\"30\"\/><circle cx=\"100\" cy=\"100\" r=\"80\" fill=\"url(#g1)\" opacity=\"0.95\"\/><rect x=\"60\" y=\"60\" width=\"80\" height=\"80\" rx=\"12\" fill=\"none\" stroke=\"#ffffff\" stroke-width=\"6\"\/><path d=\"M 75 100 L 93 118 L 130 78\" stroke=\"#ffffff\" stroke-width=\"8\" fill=\"none\" stroke-linecap=\"round\" stroke-linejoin=\"round\"\/><\/svg>',\r\n\r\n    init: function() {\r\n      this.attachEvents();\r\n      this.switchTab('rasterize');\r\n    },\r\n\r\n    \/* ===== TOAST ===== *\/\r\n    showToast: function(msg, type) {\r\n      var container = document.getElementById('pth-svg-studio-toast');\r\n      if (!container) return;\r\n      var toast = document.createElement('div');\r\n      var bg = type === 'error' ? '#dc2626' : (type === 'info' ? '#2563eb' : '#059669');\r\n      toast.style.cssText = 'padding:12px 20px;border-radius:10px;font-size:14px;font-weight:600;color:#fff;pointer-events:auto;box-shadow:0 4px 15px rgba(0,0,0,0.15);font-family:Inter,system-ui,sans-serif;background:' + bg + ';';\r\n      toast.textContent = msg;\r\n      container.appendChild(toast);\r\n      setTimeout(function() { if (toast.parentNode) toast.parentNode.removeChild(toast); }, 3000);\r\n    },\r\n\r\n    showError: function(msg) {\r\n      var el = document.getElementById('pth-svg-error');\r\n      if (!el) return;\r\n      el.textContent = msg;\r\n      el.style.display = 'block';\r\n      setTimeout(function() { el.style.display = 'none'; }, 5000);\r\n    },\r\n\r\n    \/* ===== TAB SWITCH ===== *\/\r\n    switchTab: function(tab) {\r\n      var tabs = ['rasterize', 'editor', 'filters', 'optimize'];\r\n      for (var i = 0; i < tabs.length; i++) {\r\n        var btn = document.getElementById('pth-tab-' + tabs[i]);\r\n        var panel = document.getElementById('pth-panel-' + tabs[i]);\r\n        if (btn) { btn.classList.toggle('active', tabs[i] === tab); btn.setAttribute('aria-selected', tabs[i] === tab ? 'true' : 'false'); }\r\n        if (panel) panel.classList.toggle('active', tabs[i] === tab);\r\n      }\r\n    },\r\n\r\n    \/* ===== EVENTS ===== *\/\r\n    attachEvents: function() {\r\n      var self = this;\r\n\r\n      \/* Tab buttons *\/\r\n      var tabIds = ['rasterize', 'editor', 'filters', 'optimize'];\r\n      for (var ti = 0; ti < tabIds.length; ti++) {\r\n        (function(t) {\r\n          var el = document.getElementById('pth-tab-' + t);\r\n          if (el) el.addEventListener('click', function() { self.switchTab(t); });\r\n        })(tabIds[ti]);\r\n      }\r\n\r\n      \/* Full width *\/\r\n      var fwBtn = document.getElementById('pth-svg-fw-btn');\r\n      if (fwBtn) fwBtn.addEventListener('click', function() { self.toggleFullWidth(); });\r\n\r\n      \/* Clear *\/\r\n      var clrBtn = document.getElementById('pth-svg-clear-btn');\r\n      if (clrBtn) clrBtn.addEventListener('click', function() { self.clearAll(); });\r\n\r\n      \/* Sample *\/\r\n      var smpBtn = document.getElementById('pth-svg-sample-btn');\r\n      if (smpBtn) smpBtn.addEventListener('click', function() { self.loadSample(); });\r\n\r\n      \/* File input + drop zone *\/\r\n      var fileInput = document.getElementById('pth-svg-file-input');\r\n      var dropZone = document.getElementById('pth-svg-dropzone');\r\n      if (dropZone && fileInput) {\r\n        dropZone.addEventListener('click', function() { fileInput.click(); });\r\n        dropZone.addEventListener('keydown', function(e) { if (e.key === 'Enter' || e.key === ' ') fileInput.click(); });\r\n        dropZone.addEventListener('dragover', function(e) { e.preventDefault(); dropZone.classList.add('pth-dz-over'); });\r\n        dropZone.addEventListener('dragleave', function() { dropZone.classList.remove('pth-dz-over'); });\r\n        dropZone.addEventListener('drop', function(e) {\r\n          e.preventDefault(); dropZone.classList.remove('pth-dz-over');\r\n          if (e.dataTransfer.files.length) self.handleFile(e.dataTransfer.files[0]);\r\n        });\r\n        fileInput.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      \/* Render button *\/\r\n      var renderBtn = document.getElementById('pth-render-btn');\r\n      if (renderBtn) renderBtn.addEventListener('click', function() { self.renderRaster(); });\r\n\r\n      \/* Width\/Height sync *\/\r\n      var wInput = document.getElementById('pth-out-w');\r\n      var hInput = document.getElementById('pth-out-h');\r\n      if (wInput) wInput.addEventListener('input', function() { self.syncDimensions('w'); });\r\n      if (hInput) hInput.addEventListener('input', function() { self.syncDimensions('h'); });\r\n\r\n      \/* Format change *\/\r\n      var fmtSel = document.getElementById('pth-out-format');\r\n      if (fmtSel) fmtSel.addEventListener('change', function() { self.onFormatChange(); });\r\n\r\n      \/* Quality slider *\/\r\n      var qSld = document.getElementById('pth-quality');\r\n      if (qSld) qSld.addEventListener('input', function() {\r\n        var el = document.getElementById('pth-quality-val');\r\n        if (el) el.textContent = this.value + '%';\r\n      });\r\n\r\n      \/* Size presets *\/\r\n      var presetBtns = document.querySelectorAll('#pth-size-presets .pth-preset-btn');\r\n      for (var pi = 0; pi < presetBtns.length; pi++) {\r\n        (function(btn) {\r\n          btn.addEventListener('click', function() {\r\n            for (var pj = 0; pj < presetBtns.length; pj++) presetBtns[pj].classList.remove('active');\r\n            btn.classList.add('active');\r\n            self.applyPreset(parseInt(btn.dataset.w), parseInt(btn.dataset.h));\r\n          });\r\n        })(presetBtns[pi]);\r\n      }\r\n\r\n      \/* BG toggle *\/\r\n      var bgToggle = document.getElementById('pth-bg-toggle-btn');\r\n      if (bgToggle) bgToggle.addEventListener('click', function() { self.togglePreviewBg(); });\r\n\r\n      \/* Editor tab events *\/\r\n      var applyEdBtn = document.getElementById('pth-apply-editor-btn');\r\n      if (applyEdBtn) applyEdBtn.addEventListener('click', function() { self.applyEditorChanges(); });\r\n\r\n      var minifyBtn = document.getElementById('pth-optimize-space-btn');\r\n      if (minifyBtn) minifyBtn.addEventListener('click', function() { self.minifySVG(); });\r\n\r\n      var beautifyBtn = document.getElementById('pth-beautify-btn');\r\n      if (beautifyBtn) beautifyBtn.addEventListener('click', function() { self.beautifySVG(); });\r\n\r\n      var copySvgBtn = document.getElementById('pth-copy-svg-btn');\r\n      if (copySvgBtn) copySvgBtn.addEventListener('click', function() { self.copySVGCode(); });\r\n\r\n      var copyJsxBtn = document.getElementById('pth-copy-jsx-btn');\r\n      if (copyJsxBtn) copyJsxBtn.addEventListener('click', function() { self.copyAsJSX(); });\r\n\r\n      var dlSvgBtn = document.getElementById('pth-download-svg-btn');\r\n      if (dlSvgBtn) dlSvgBtn.addEventListener('click', function() { self.downloadSVG(); });\r\n\r\n      var replaceColorBtn = document.getElementById('pth-replace-color-btn');\r\n      if (replaceColorBtn) replaceColorBtn.addEventListener('click', function() { self.replaceColor(); });\r\n\r\n      var revertColorBtn = document.getElementById('pth-revert-color-btn');\r\n      if (revertColorBtn) revertColorBtn.addEventListener('click', function() { self.revertColors(); });\r\n\r\n      \/* Filter tab events *\/\r\n      var fxSliders = ['brightness', 'contrast', 'saturation', 'hue', 'blur', 'sepia'];\r\n      for (var fi = 0; fi < fxSliders.length; fi++) {\r\n        (function(name) {\r\n          var el = document.getElementById('pth-fx-' + name);\r\n          if (!el) return;\r\n          el.addEventListener('input', function() {\r\n            var suffix = (name === 'hue') ? '\u00b0' : (name === 'blur' ? 'px' : '%');\r\n            var valEl = document.getElementById('pth-fxv-' + name);\r\n            if (valEl) valEl.textContent = this.value + suffix;\r\n            self.filterValues[name] = parseFloat(this.value);\r\n            self.applyFilters();\r\n          });\r\n        })(fxSliders[fi]);\r\n      }\r\n\r\n      var grayscaleCb = document.getElementById('pth-fx-grayscale');\r\n      if (grayscaleCb) grayscaleCb.addEventListener('change', function() { self.filterValues.grayscale = this.checked; self.applyFilters(); });\r\n\r\n      var invertCb = document.getElementById('pth-fx-invert');\r\n      if (invertCb) invertCb.addEventListener('change', function() { self.filterValues.invert = this.checked; self.applyFilters(); });\r\n\r\n      var resetFiltersBtn = document.getElementById('pth-reset-filters-btn');\r\n      if (resetFiltersBtn) resetFiltersBtn.addEventListener('click', function() { self.resetFilters(); });\r\n\r\n      var fxExportBtn = document.getElementById('pth-fx-export-btn');\r\n      if (fxExportBtn) fxExportBtn.addEventListener('click', function() { self.exportWithFilters(); });\r\n\r\n      var fxCopyCssBtn = document.getElementById('pth-fx-copy-css-btn');\r\n      if (fxCopyCssBtn) fxCopyCssBtn.addEventListener('click', function() { self.copyCSSFilter(); });\r\n\r\n      \/* FX Presets *\/\r\n      var fxPresetBtns = document.querySelectorAll('#pth-fx-presets .pth-fx-btn');\r\n      for (var fpi = 0; fpi < fxPresetBtns.length; fpi++) {\r\n        (function(btn) {\r\n          btn.addEventListener('click', function() {\r\n            for (var j = 0; j < fxPresetBtns.length; j++) fxPresetBtns[j].classList.remove('active');\r\n            btn.classList.add('active');\r\n            self.applyFxPreset(btn.dataset.preset);\r\n          });\r\n        })(fxPresetBtns[fpi]);\r\n      }\r\n\r\n      \/* Optimize tab *\/\r\n      var removeCommentsBtn = document.getElementById('pth-remove-comments-btn');\r\n      if (removeCommentsBtn) removeCommentsBtn.addEventListener('click', function() { self.removeComments(); });\r\n\r\n      var removeMetaBtn = document.getElementById('pth-remove-metadata-btn');\r\n      if (removeMetaBtn) removeMetaBtn.addEventListener('click', function() { self.stripMetadata(); });\r\n\r\n      var stripIdsBtn = document.getElementById('pth-strip-ids-btn');\r\n      if (stripIdsBtn) stripIdsBtn.addEventListener('click', function() { self.stripIds(); });\r\n\r\n      var fullOptBtn = document.getElementById('pth-full-optimize-btn');\r\n      if (fullOptBtn) fullOptBtn.addEventListener('click', function() { self.fullOptimize(); });\r\n\r\n      var applyVbBtn = document.getElementById('pth-apply-viewbox-btn');\r\n      if (applyVbBtn) applyVbBtn.addEventListener('click', function() { self.applyViewBox(); });\r\n\r\n      var faviconBtn = document.getElementById('pth-export-favicon-btn');\r\n      if (faviconBtn) faviconBtn.addEventListener('click', function() { self.exportFaviconPack(); });\r\n\r\n      var socialBtn = document.getElementById('pth-export-social-btn');\r\n      if (socialBtn) socialBtn.addEventListener('click', function() { self.exportSocialPack(); });\r\n\r\n      var iconsBtn = document.getElementById('pth-export-icons-btn');\r\n      if (iconsBtn) iconsBtn.addEventListener('click', function() { self.exportIconsPack(); });\r\n\r\n      var vectorizeBtn = document.getElementById('pth-vectorize-btn');\r\n      if (vectorizeBtn) vectorizeBtn.addEventListener('click', function() { self.vectorize(); });\r\n\r\n      var thresholdSld = document.getElementById('pth-trace-threshold');\r\n      if (thresholdSld) thresholdSld.addEventListener('input', function() {\r\n        var el = document.getElementById('pth-trace-thresh-val');\r\n        if (el) el.textContent = this.value;\r\n      });\r\n    },\r\n\r\n    \/* ===== TOGGLE ===== *\/\r\n    toggleFullWidth: function() {\r\n      var layout = document.getElementById('pth-svg-studio-layout');\r\n      var btn = document.getElementById('pth-svg-fw-btn');\r\n      if (!layout || !btn) return;\r\n      layout.classList.toggle('pth-full-width');\r\n      btn.textContent = layout.classList.contains('pth-full-width') ? '\u25e8 Split View' : '\u26f6 Full Width';\r\n    },\r\n\r\n    togglePreviewBg: function() {\r\n      var wrap = document.getElementById('pth-raster-canvas-wrap');\r\n      var btn = document.getElementById('pth-bg-toggle-btn');\r\n      if (!wrap || !btn) return;\r\n      this.currentBgDark = !this.currentBgDark;\r\n      wrap.className = this.currentBgDark ? 'pth-checker-dark' : 'pth-checker-light';\r\n      btn.textContent = this.currentBgDark ? '\ud83c\udf19 Dark BG' : '\u2600\ufe0f Light BG';\r\n    },\r\n\r\n    \/* ===== CLEAR ===== *\/\r\n    clearAll: function() {\r\n      this.svgContent = null;\r\n      this.origSvgContent = null;\r\n      this.rasterDataUrl = null;\r\n      var fi = document.getElementById('pth-svg-file-input');\r\n      if (fi) fi.value = '';\r\n      var dz = document.getElementById('pth-svg-dropzone');\r\n      if (dz) dz.style.display = 'block';\r\n      var stats = document.getElementById('pth-svg-stats');\r\n      if (stats) stats.style.display = 'none';\r\n      var tabs = document.getElementById('pth-svg-tabs-area');\r\n      if (tabs) tabs.style.display = 'none';\r\n      var rp = document.getElementById('pth-raster-preview');\r\n      if (rp) rp.style.display = 'none';\r\n      var ep = document.getElementById('pth-editor-preview');\r\n      if (ep) ep.style.display = 'none';\r\n      var fp = document.getElementById('pth-fx-preview');\r\n      if (fp) fp.style.display = 'none';\r\n      var codeArea = document.getElementById('pth-svg-code-area');\r\n      if (codeArea) codeArea.value = '';\r\n      var paletteGrid = document.getElementById('pth-palette-grid');\r\n      if (paletteGrid) paletteGrid.innerHTML = '<span style=\"font-size:0.82rem;color:#334155;\">Load an SVG to extract colors.<\/span>';\r\n      var colorReplArea = document.getElementById('pth-color-replace-area');\r\n      if (colorReplArea) colorReplArea.style.display = 'none';\r\n      this.showToast('\ud83d\uddd1\ufe0f Cleared', 'info');\r\n    },\r\n\r\n    \/* ===== SAMPLE ===== *\/\r\n    loadSample: function() {\r\n      this.processSVG(this.sampleSvg, 'sample.svg');\r\n      this.showToast('\ud83d\udca1 Sample SVG loaded!', 'success');\r\n    },\r\n\r\n    \/* ===== FILE HANDLER ===== *\/\r\n    handleFile: function(file) {\r\n      var self = this;\r\n      var isSvg = (file.type === 'image\/svg+xml' || file.name.indexOf('.svg') !== -1);\r\n      var reader = new FileReader();\r\n\r\n      if (isSvg) {\r\n        reader.onload = function(e) { self.processSVG(e.target.result, file.name); self.showToast('\u2705 SVG loaded \u2014 ' + file.name, 'success'); };\r\n        reader.readAsText(file);\r\n      } else {\r\n        reader.onload = function(e) { self.processBitmap(e.target.result, file.name); self.showToast('\u2705 Image loaded \u2014 ' + file.name, 'success'); };\r\n        reader.readAsDataURL(file);\r\n      }\r\n    },\r\n\r\n    \/* ===== PROCESS SVG ===== *\/\r\n    processSVG: function(text, filename) {\r\n      this.svgContent = text;\r\n      this.origSvgContent = text;\r\n\r\n      var dz = document.getElementById('pth-svg-dropzone');\r\n      if (dz) dz.style.display = 'none';\r\n\r\n      this.updateDimensionsFromSVG(text);\r\n      this.updateStats(text);\r\n      this.updateCodeArea(text);\r\n      this.extractPalette(text);\r\n      this.updateViewBoxInputs(text);\r\n\r\n      var tabs = document.getElementById('pth-svg-tabs-area');\r\n      if (tabs) tabs.style.display = 'block';\r\n\r\n      this.updateEditorPreview();\r\n      this.updateFxPreview();\r\n    },\r\n\r\n    \/* ===== PROCESS BITMAP ===== *\/\r\n    processBitmap: function(dataUrl, filename) {\r\n      this.rasterDataUrl = dataUrl;\r\n      this.svgContent = null;\r\n\r\n      var dz = document.getElementById('pth-svg-dropzone');\r\n      if (dz) dz.style.display = 'none';\r\n\r\n      var tabs = document.getElementById('pth-svg-tabs-area');\r\n      if (tabs) tabs.style.display = 'block';\r\n\r\n      \/* Show bitmap in raster preview area *\/\r\n      var rImg = document.getElementById('pth-raster-img');\r\n      if (rImg) rImg.src = dataUrl;\r\n      var rp = document.getElementById('pth-raster-preview');\r\n      if (rp) rp.style.display = 'block';\r\n\r\n      var info = document.getElementById('pth-raster-info');\r\n      if (info) info.textContent = filename || 'Bitmap image';\r\n\r\n      \/* Auto-switch to optimize tab (for vectorize) *\/\r\n      this.switchTab('optimize');\r\n      this.showToast('\ud83d\udca1 Use the Vectorizer tab to trace this to SVG!', 'info');\r\n\r\n      var stats = document.getElementById('pth-svg-stats');\r\n      if (stats) stats.style.display = 'none';\r\n    },\r\n\r\n    \/* ===== DIMENSIONS ===== *\/\r\n    updateDimensionsFromSVG: function(text) {\r\n      var wMatch = text.match(\/width=[\"']([0-9.]+)[\"']\/);\r\n      var hMatch = text.match(\/height=[\"']([0-9.]+)[\"']\/);\r\n      var vbMatch = text.match(\/viewBox=[\"'][0-9.\\s]+\\s([0-9.]+)\\s([0-9.]+)[\"']\/i);\r\n\r\n      if (wMatch && hMatch) {\r\n        this.origWidth = parseFloat(wMatch[1]);\r\n        this.origHeight = parseFloat(hMatch[1]);\r\n      } else if (vbMatch) {\r\n        this.origWidth = parseFloat(vbMatch[1]);\r\n        this.origHeight = parseFloat(vbMatch[2]);\r\n      } else {\r\n        this.origWidth = 200; this.origHeight = 200;\r\n      }\r\n      this.aspectRatio = this.origWidth \/ (this.origHeight || 1);\r\n\r\n      var wInp = document.getElementById('pth-out-w');\r\n      var hInp = document.getElementById('pth-out-h');\r\n      if (wInp) wInp.value = Math.round(this.origWidth);\r\n      if (hInp) hInp.value = Math.round(this.origHeight);\r\n    },\r\n\r\n    syncDimensions: function(source) {\r\n      var lock = document.getElementById('pth-lock-aspect');\r\n      if (!lock || !lock.checked) return;\r\n      var wInp = document.getElementById('pth-out-w');\r\n      var hInp = document.getElementById('pth-out-h');\r\n      if (!wInp || !hInp) return;\r\n      if (source === 'w' && wInp.value) hInp.value = Math.round(parseFloat(wInp.value) \/ this.aspectRatio);\r\n      else if (source === 'h' && hInp.value) wInp.value = Math.round(parseFloat(hInp.value) * this.aspectRatio);\r\n    },\r\n\r\n    applyPreset: function(w, h) {\r\n      var wInp = document.getElementById('pth-out-w');\r\n      var hInp = document.getElementById('pth-out-h');\r\n      if (!wInp || !hInp) return;\r\n      if (w === 0 && h === 0) {\r\n        wInp.value = Math.round(this.origWidth);\r\n        hInp.value = Math.round(this.origHeight);\r\n      } else {\r\n        wInp.value = w; hInp.value = h;\r\n        this.aspectRatio = w \/ (h || 1);\r\n      }\r\n      this.showToast('\u2705 Preset applied', 'success');\r\n    },\r\n\r\n    onFormatChange: function() {\r\n      var fmt = document.getElementById('pth-out-format').value;\r\n      var trans = document.getElementById('pth-out-transparent');\r\n      var qField = document.getElementById('pth-quality-field');\r\n      if (fmt === 'jpeg') {\r\n        if (trans) { trans.checked = false; trans.disabled = true; }\r\n        if (qField) qField.style.display = 'block';\r\n      } else {\r\n        if (trans) trans.disabled = false;\r\n        if (qField) qField.style.display = (fmt === 'webp') ? 'block' : 'none';\r\n      }\r\n    },\r\n\r\n    \/* ===== STATS ===== *\/\r\n    updateStats: function(text) {\r\n      var stats = document.getElementById('pth-svg-stats');\r\n      if (!stats) return;\r\n      stats.style.display = 'grid';\r\n\r\n      var els = (text.match(\/<[a-z][^>]*>\/gi) || []).length;\r\n      var sizeKb = (new Blob([text]).size \/ 1024).toFixed(1);\r\n      var colors = this.extractColors(text);\r\n\r\n      var sw = document.getElementById('pth-stat-w');\r\n      var sh = document.getElementById('pth-stat-h');\r\n      var se = document.getElementById('pth-stat-els');\r\n      var ss = document.getElementById('pth-stat-size');\r\n      var sc = document.getElementById('pth-stat-colors');\r\n      if (sw) sw.textContent = Math.round(this.origWidth) + 'px';\r\n      if (sh) sh.textContent = Math.round(this.origHeight) + 'px';\r\n      if (se) se.textContent = els;\r\n      if (ss) ss.textContent = sizeKb + ' KB';\r\n      if (sc) sc.textContent = colors.length;\r\n    },\r\n\r\n    \/* ===== RASTER RENDER ===== *\/\r\n    renderRaster: function() {\r\n      if (!this.svgContent) { this.showError('No SVG loaded. Please upload or load a sample first.'); return; }\r\n      var self = this;\r\n      var w = parseInt(document.getElementById('pth-out-w').value) || this.origWidth;\r\n      var h = parseInt(document.getElementById('pth-out-h').value) || this.origHeight;\r\n      var fmt = document.getElementById('pth-out-format').value;\r\n      var isTrans = document.getElementById('pth-out-transparent').checked;\r\n      var bgColor = document.getElementById('pth-out-bg').value;\r\n      var quality = parseFloat(document.getElementById('pth-quality').value) \/ 100;\r\n\r\n      var canvas = document.getElementById('pth-render-canvas');\r\n      var ctx = canvas.getContext('2d');\r\n      canvas.width = w; canvas.height = h;\r\n\r\n      if (!isTrans || fmt === 'jpeg') { ctx.fillStyle = bgColor; ctx.fillRect(0, 0, w, h); }\r\n      else { ctx.clearRect(0, 0, w, h); }\r\n\r\n      var img = new Image();\r\n      img.onload = function() {\r\n        \/* Build filter string *\/\r\n        var fStr = 'brightness(' + self.filterValues.brightness + '%) contrast(' + self.filterValues.contrast + '%) saturate(' + self.filterValues.saturation + '%) hue-rotate(' + self.filterValues.hue + 'deg) blur(' + self.filterValues.blur + 'px) sepia(' + self.filterValues.sepia + '%)';\r\n        if (self.filterValues.grayscale) fStr += ' grayscale(100%)';\r\n        if (self.filterValues.invert) fStr += ' invert(100%)';\r\n        ctx.filter = fStr;\r\n        ctx.drawImage(img, 0, 0, w, h);\r\n        ctx.filter = 'none';\r\n\r\n        var mime = fmt === 'jpeg' ? 'image\/jpeg' : (fmt === 'webp' ? 'image\/webp' : 'image\/png');\r\n        var ext = fmt === 'jpeg' ? 'jpg' : fmt;\r\n        var dataUrl = canvas.toDataURL(mime, quality);\r\n\r\n        var rImg = document.getElementById('pth-raster-img');\r\n        if (rImg) rImg.src = dataUrl;\r\n\r\n        var rp = document.getElementById('pth-raster-preview');\r\n        if (rp) rp.style.display = 'block';\r\n\r\n        var info = document.getElementById('pth-raster-info');\r\n        if (info) {\r\n          var kb = (dataUrl.length * 0.75 \/ 1024).toFixed(0);\r\n          info.textContent = w + ' x ' + h + ' px | ' + fmt.toUpperCase() + ' | ~' + kb + ' KB';\r\n        }\r\n\r\n        self.rasterDataUrl = dataUrl;\r\n        self.injectRasterButtons(dataUrl, w, h, mime, ext, quality);\r\n        self.showToast('\u2705 Rendered ' + w + 'x' + h + ' ' + fmt.toUpperCase(), 'success');\r\n      };\r\n\r\n      img.onerror = function() { self.showError('Failed to render SVG. The SVG may contain unsupported features.'); };\r\n      img.src = 'data:image\/svg+xml;base64,' + btoa(unescape(encodeURIComponent(this.svgContent)));\r\n    },\r\n\r\n    injectRasterButtons: function(dataUrl, w, h, mime, ext, quality) {\r\n      var self = this;\r\n      var bar = document.getElementById('pth-raster-download-bar');\r\n      if (!bar) return;\r\n      bar.innerHTML = '';\r\n\r\n      var dlBtn = document.createElement('button');\r\n      dlBtn.className = 'pth-btn pth-btn-primary';\r\n      dlBtn.innerHTML = '\ud83d\udce5 Download Image';\r\n      dlBtn.setAttribute('aria-label', 'Download rendered image');\r\n      dlBtn.addEventListener('click', function() { self.downloadDataUrl(dataUrl, 'pth-converted.' + ext); });\r\n      bar.appendChild(dlBtn);\r\n\r\n      var multiBtn = document.createElement('button');\r\n      multiBtn.className = 'pth-btn pth-btn-secondary';\r\n      multiBtn.innerHTML = '\ud83d\udce6 Multi-Size Export';\r\n      multiBtn.setAttribute('aria-label', 'Export multiple sizes');\r\n      multiBtn.addEventListener('click', function() { self.exportMultipleSizes(mime, ext, quality); });\r\n      bar.appendChild(multiBtn);\r\n\r\n      var clipBtn = document.createElement('button');\r\n      clipBtn.className = 'pth-btn pth-btn-secondary';\r\n      clipBtn.innerHTML = '\ud83d\udccb Copy Image';\r\n      clipBtn.setAttribute('aria-label', 'Copy image to clipboard');\r\n      clipBtn.addEventListener('click', function() { self.copyImageToClipboard(dataUrl); });\r\n      bar.appendChild(clipBtn);\r\n\r\n      var printBtn = document.createElement('button');\r\n      printBtn.className = 'pth-btn pth-btn-secondary';\r\n      printBtn.innerHTML = '\ud83d\udda8\ufe0f Print';\r\n      printBtn.setAttribute('aria-label', 'Print image');\r\n      printBtn.addEventListener('click', function() { self.printImage(dataUrl); });\r\n      bar.appendChild(printBtn);\r\n    },\r\n\r\n    downloadDataUrl: function(dataUrl, filename) {\r\n      var a = document.createElement('a');\r\n      a.href = dataUrl; a.download = filename;\r\n      document.body.appendChild(a); a.click(); document.body.removeChild(a);\r\n      this.showToast('\ud83d\udce5 Download started', 'success');\r\n    },\r\n\r\n    exportMultipleSizes: function(mime, ext, quality) {\r\n      if (!this.svgContent) return;\r\n      var self = this;\r\n      var sizes = [64, 256, 512, 1024, 2048];\r\n      var count = 0;\r\n      sizes.forEach(function(size) {\r\n        setTimeout(function() {\r\n          var canvas = document.createElement('canvas');\r\n          canvas.width = size; canvas.height = size;\r\n          var ctx = canvas.getContext('2d');\r\n          var img = new Image();\r\n          img.onload = function() {\r\n            ctx.drawImage(img, 0, 0, size, size);\r\n            self.downloadDataUrl(canvas.toDataURL(mime, quality), 'pth-' + size + 'x' + size + '.' + ext);\r\n            count++;\r\n            if (count === sizes.length) self.showToast('\ud83d\udce6 All ' + sizes.length + ' sizes exported!', 'success');\r\n          };\r\n          img.src = 'data:image\/svg+xml;base64,' + btoa(unescape(encodeURIComponent(self.svgContent)));\r\n        }, count * 200);\r\n        count++;\r\n      });\r\n      count = 0;\r\n    },\r\n\r\n    copyImageToClipboard: function(dataUrl) {\r\n      var self = this;\r\n      try {\r\n        fetch(dataUrl).then(function(res) { return res.blob(); }).then(function(blob) {\r\n          var item = new ClipboardItem({ [blob.type]: blob });\r\n          navigator.clipboard.write([item]).then(function() {\r\n            self.showToast('\ud83d\udccb Image copied to clipboard!', 'success');\r\n          }).catch(function() { self.showToast('\u26a0\ufe0f Clipboard API not supported here', 'error'); });\r\n        });\r\n      } catch(e) { self.showToast('\u26a0\ufe0f Clipboard not supported in this browser', 'error'); }\r\n    },\r\n\r\n    printImage: function(dataUrl) {\r\n      var printWin = window.open('', '_blank');\r\n      if (!printWin) return;\r\n      var img = printWin.document.createElement('img');\r\n      img.src = dataUrl; img.style.maxWidth = '100%';\r\n      printWin.document.body.appendChild(img);\r\n      setTimeout(function() { printWin.print(); printWin.close(); }, 300);\r\n    },\r\n\r\n    \/* ===== EDITOR TAB ===== *\/\r\n    updateCodeArea: function(text) {\r\n      var ta = document.getElementById('pth-svg-code-area');\r\n      if (ta) ta.value = text;\r\n      var ep = document.getElementById('pth-editor-preview');\r\n      if (ep) ep.style.display = 'block';\r\n      var info = document.getElementById('pth-editor-info');\r\n      if (info) info.textContent = (new Blob([text]).size \/ 1024).toFixed(1) + ' KB';\r\n    },\r\n\r\n    updateEditorPreview: function() {\r\n      if (!this.svgContent) return;\r\n      var img = document.getElementById('pth-editor-img');\r\n      if (img) img.src = 'data:image\/svg+xml;base64,' + btoa(unescape(encodeURIComponent(this.svgContent)));\r\n      var ep = document.getElementById('pth-editor-preview');\r\n      if (ep) ep.style.display = 'block';\r\n    },\r\n\r\n    applyEditorChanges: function() {\r\n      var ta = document.getElementById('pth-svg-code-area');\r\n      if (!ta || !ta.value.trim()) return;\r\n      this.svgContent = ta.value.trim();\r\n      this.updateDimensionsFromSVG(this.svgContent);\r\n      this.updateStats(this.svgContent);\r\n      this.updateEditorPreview();\r\n      this.updateFxPreview();\r\n      this.showToast('\u2705 SVG updated from editor', 'success');\r\n    },\r\n\r\n    minifySVG: function() {\r\n      if (!this.svgContent) return;\r\n      var before = this.svgContent.length;\r\n      var opt = this.svgContent\r\n        .replace(\/<!--[\\s\\S]*?-->\/g, '')\r\n        .replace(\/\\s+\/g, ' ')\r\n        .replace(\/>\\s+<\/g, '><')\r\n        .replace(\/\\s*([={};,:])\\s*\/g, '$1')\r\n        .trim();\r\n      this.svgContent = opt;\r\n      var ta = document.getElementById('pth-svg-code-area');\r\n      if (ta) ta.value = opt;\r\n      var saved = (((before - opt.length) \/ before) * 100).toFixed(1);\r\n      this.showToast('\u26a1 Minified \u2014 saved ' + saved + '%', 'success');\r\n      this.updateEditorPreview();\r\n    },\r\n\r\n    beautifySVG: function() {\r\n      if (!this.svgContent) return;\r\n      var text = this.svgContent;\r\n      var indent = 0;\r\n      var result = '';\r\n      var tokens = text.match(\/<[^>]+>|[^<]+\/g) || [];\r\n      for (var i = 0; i < tokens.length; i++) {\r\n        var tok = tokens[i].trim();\r\n        if (!tok) continue;\r\n        if (tok.match(\/^<\\\/\/)) { indent -= 2; result += ' '.repeat(Math.max(0,indent)) + tok + '\\n'; }\r\n        else if (tok.match(\/^<[^!?][^>]*[^\\\/]>$\/)) { result += ' '.repeat(indent) + tok + '\\n'; indent += 2; }\r\n        else { result += ' '.repeat(indent) + tok + '\\n'; }\r\n      }\r\n      this.svgContent = result.trim();\r\n      var ta = document.getElementById('pth-svg-code-area');\r\n      if (ta) ta.value = this.svgContent;\r\n      this.showToast('\u2728 SVG beautified', 'success');\r\n    },\r\n\r\n    copySVGCode: function() {\r\n      if (!this.svgContent) return;\r\n      var self = this;\r\n      navigator.clipboard.writeText(this.svgContent).then(function() {\r\n        self.showToast('\ud83d\udccb SVG code copied!', 'success');\r\n      }).catch(function() { self.showToast('\u26a0\ufe0f Could not access clipboard', 'error'); });\r\n    },\r\n\r\n    copyAsJSX: function() {\r\n      if (!this.svgContent) return;\r\n      var self = this;\r\n      var jsx = this.svgContent\r\n        .replace(\/class=\/g, 'className=')\r\n        .replace(\/stroke-width=\/g, 'strokeWidth=')\r\n        .replace(\/stroke-linecap=\/g, 'strokeLinecap=')\r\n        .replace(\/stroke-linejoin=\/g, 'strokeLinejoin=')\r\n        .replace(\/fill-rule=\/g, 'fillRule=')\r\n        .replace(\/clip-rule=\/g, 'clipRule=')\r\n        .replace(\/stop-color=\/g, 'stopColor=')\r\n        .replace(\/stop-opacity=\/g, 'stopOpacity=');\r\n      navigator.clipboard.writeText(jsx).then(function() {\r\n        self.showToast('\u269b\ufe0f JSX-ready SVG copied!', 'success');\r\n      }).catch(function() { self.showToast('\u26a0\ufe0f Could not access clipboard', 'error'); });\r\n    },\r\n\r\n    downloadSVG: function() {\r\n      if (!this.svgContent) return;\r\n      var blob = new Blob([this.svgContent], { type: 'image\/svg+xml' });\r\n      var url = URL.createObjectURL(blob);\r\n      var a = document.createElement('a');\r\n      a.href = url; a.download = 'pth-studio.svg';\r\n      document.body.appendChild(a); a.click(); document.body.removeChild(a);\r\n      URL.revokeObjectURL(url);\r\n      this.showToast('\ud83d\udcc4 SVG downloaded', 'success');\r\n    },\r\n\r\n    \/* ===== COLOR PALETTE ===== *\/\r\n    extractColors: function(text) {\r\n      var colors = {};\r\n      var patterns = [\r\n        \/fill=\"(#[0-9a-fA-F]{3,8})\"\/g,\r\n        \/stroke=\"(#[0-9a-fA-F]{3,8})\"\/g,\r\n        \/stop-color=\"(#[0-9a-fA-F]{3,8})\"\/g,\r\n        \/fill:(#[0-9a-fA-F]{3,8})\/g,\r\n        \/stroke:(#[0-9a-fA-F]{3,8})\/g,\r\n        \/stop-color:(#[0-9a-fA-F]{3,8})\/g\r\n      ];\r\n      for (var pi = 0; pi < patterns.length; pi++) {\r\n        var m;\r\n        while ((m = patterns[pi].exec(text)) !== null) {\r\n          var c = m[1].toLowerCase();\r\n          if (c !== 'none' && c !== 'inherit') colors[c] = true;\r\n        }\r\n      }\r\n      return Object.keys(colors);\r\n    },\r\n\r\n    extractPalette: function(text) {\r\n      var colors = this.extractColors(text);\r\n      var grid = document.getElementById('pth-palette-grid');\r\n      var replArea = document.getElementById('pth-color-replace-area');\r\n      if (!grid) return;\r\n      grid.innerHTML = '';\r\n      if (colors.length === 0) {\r\n        grid.innerHTML = '<span style=\"font-size:0.82rem;color:#334155;\">No hex colors found in this SVG.<\/span>';\r\n        return;\r\n      }\r\n      var self = this;\r\n      for (var ci = 0; ci < colors.length; ci++) {\r\n        (function(color) {\r\n          var swatch = document.createElement('div');\r\n          swatch.className = 'pth-color-swatch';\r\n          swatch.style.background = color;\r\n          swatch.title = 'Click to set as Replace Color: ' + color;\r\n          swatch.setAttribute('role', 'button');\r\n          swatch.setAttribute('tabindex', '0');\r\n          swatch.setAttribute('aria-label', 'Select color ' + color + ' for replacement');\r\n          var hexLabel = document.createElement('span');\r\n          hexLabel.className = 'pth-swatch-hex';\r\n          hexLabel.textContent = color.slice(1, 4).toUpperCase();\r\n          swatch.appendChild(hexLabel);\r\n          swatch.addEventListener('click', function() {\r\n            var oldColorEl = document.getElementById('pth-old-color');\r\n            if (oldColorEl) oldColorEl.value = color;\r\n          });\r\n          swatch.addEventListener('keydown', function(e) {\r\n            if (e.key === 'Enter') swatch.click();\r\n          });\r\n          grid.appendChild(swatch);\r\n        })(colors[ci]);\r\n      }\r\n      if (replArea) replArea.style.display = 'grid';\r\n    },\r\n\r\n    replaceColor: function() {\r\n      if (!this.svgContent) return;\r\n      var oldColor = document.getElementById('pth-old-color').value.toLowerCase();\r\n      var newColor = document.getElementById('pth-new-color').value.toLowerCase();\r\n      var replaced = this.svgContent.split(oldColor).join(newColor);\r\n      if (replaced === this.svgContent) { this.showToast('\u26a0\ufe0f Color not found in SVG', 'error'); return; }\r\n      this.svgContent = replaced;\r\n      this.updateCodeArea(replaced);\r\n      this.updateEditorPreview();\r\n      this.extractPalette(replaced);\r\n      this.showToast('\ud83d\udd04 Color replaced!', 'success');\r\n    },\r\n\r\n    revertColors: function() {\r\n      if (!this.origSvgContent) return;\r\n      this.svgContent = this.origSvgContent;\r\n      this.updateCodeArea(this.origSvgContent);\r\n      this.updateEditorPreview();\r\n      this.extractPalette(this.origSvgContent);\r\n      this.showToast('\u21a9\ufe0f Colors reverted to original', 'success');\r\n    },\r\n\r\n    \/* ===== FILTERS ===== *\/\r\n    buildFilterString: function() {\r\n      var fv = this.filterValues;\r\n      var f = 'brightness(' + fv.brightness + '%) contrast(' + fv.contrast + '%) saturate(' + fv.saturation + '%) hue-rotate(' + fv.hue + 'deg) blur(' + fv.blur + 'px) sepia(' + fv.sepia + '%)';\r\n      if (fv.grayscale) f += ' grayscale(100%)';\r\n      if (fv.invert) f += ' invert(100%)';\r\n      return f;\r\n    },\r\n\r\n    applyFilters: function() {\r\n      var fxImg = document.getElementById('pth-fx-img');\r\n      if (!fxImg) return;\r\n      var fStr = this.buildFilterString();\r\n      fxImg.style.filter = fStr;\r\n      var fsEl = document.getElementById('pth-fx-filter-string');\r\n      if (fsEl) fsEl.textContent = fStr.length > 60 ? fStr.slice(0, 57) + '...' : fStr;\r\n    },\r\n\r\n    updateFxPreview: function() {\r\n      if (!this.svgContent) return;\r\n      var fxImg = document.getElementById('pth-fx-img');\r\n      if (fxImg) {\r\n        fxImg.src = 'data:image\/svg+xml;base64,' + btoa(unescape(encodeURIComponent(this.svgContent)));\r\n        this.applyFilters();\r\n      }\r\n      var fp = document.getElementById('pth-fx-preview');\r\n      if (fp) fp.style.display = 'block';\r\n    },\r\n\r\n    applyFxPreset: function(preset) {\r\n      var presets = {\r\n        none:    { brightness: 100, contrast: 100, saturation: 100, hue: 0, blur: 0, sepia: 0, grayscale: false, invert: false },\r\n        vintage: { brightness: 95, contrast: 90, saturation: 80, hue: 10, blur: 0, sepia: 20, grayscale: false, invert: false },\r\n        drama:   { brightness: 90, contrast: 150, saturation: 110, hue: 0, blur: 0, sepia: 0, grayscale: false, invert: false },\r\n        cool:    { brightness: 100, contrast: 105, saturation: 90, hue: 200, blur: 0, sepia: 0, grayscale: false, invert: false },\r\n        warm:    { brightness: 105, contrast: 100, saturation: 120, hue: 340, blur: 0, sepia: 10, grayscale: false, invert: false },\r\n        bw:      { brightness: 100, contrast: 110, saturation: 0, hue: 0, blur: 0, sepia: 0, grayscale: true, invert: false },\r\n        sepia:   { brightness: 100, contrast: 100, saturation: 100, hue: 0, blur: 0, sepia: 100, grayscale: false, invert: false },\r\n        invert:  { brightness: 100, contrast: 100, saturation: 100, hue: 0, blur: 0, sepia: 0, grayscale: false, invert: true }\r\n      };\r\n      var p = presets[preset] || presets.none;\r\n      this.filterValues = { brightness: p.brightness, contrast: p.contrast, saturation: p.saturation, hue: p.hue, blur: p.blur, sepia: p.sepia, grayscale: p.grayscale, invert: p.invert };\r\n      \/* Update slider UIs *\/\r\n      var map = { brightness: '%', contrast: '%', saturation: '%', hue: '\u00b0', blur: 'px', sepia: '%' };\r\n      var keys = Object.keys(map);\r\n      for (var ki = 0; ki < keys.length; ki++) {\r\n        var key = keys[ki];\r\n        var sl = document.getElementById('pth-fx-' + key);\r\n        var vl = document.getElementById('pth-fxv-' + key);\r\n        if (sl) sl.value = p[key];\r\n        if (vl) vl.textContent = p[key] + map[key];\r\n      }\r\n      var gsCb = document.getElementById('pth-fx-grayscale');\r\n      var ivCb = document.getElementById('pth-fx-invert');\r\n      if (gsCb) gsCb.checked = p.grayscale;\r\n      if (ivCb) ivCb.checked = p.invert;\r\n      this.applyFilters();\r\n      this.showToast('\ud83c\udfa8 Preset applied: ' + preset, 'success');\r\n    },\r\n\r\n    resetFilters: function() {\r\n      this.applyFxPreset('none');\r\n      var fxBtns = document.querySelectorAll('#pth-fx-presets .pth-fx-btn');\r\n      for (var i = 0; i < fxBtns.length; i++) fxBtns[i].classList.remove('active');\r\n      var firstBtn = document.querySelector('#pth-fx-presets .pth-fx-btn[data-preset=\"none\"]');\r\n      if (firstBtn) firstBtn.classList.add('active');\r\n      this.showToast('\u21a9\ufe0f Filters reset', 'info');\r\n    },\r\n\r\n    exportWithFilters: function() {\r\n      if (!this.svgContent) return;\r\n      var self = this;\r\n      var w = Math.round(this.origWidth) || 512;\r\n      var h = Math.round(this.origHeight) || 512;\r\n      var canvas = document.createElement('canvas');\r\n      canvas.width = w; canvas.height = h;\r\n      var ctx = canvas.getContext('2d');\r\n      var img = new Image();\r\n      img.onload = function() {\r\n        ctx.filter = self.buildFilterString();\r\n        ctx.drawImage(img, 0, 0, w, h);\r\n        ctx.filter = 'none';\r\n        self.downloadDataUrl(canvas.toDataURL('image\/png'), 'pth-filtered.png');\r\n      };\r\n      img.src = 'data:image\/svg+xml;base64,' + btoa(unescape(encodeURIComponent(this.svgContent)));\r\n    },\r\n\r\n    copyCSSFilter: function() {\r\n      var self = this;\r\n      var cssStr = 'filter: ' + this.buildFilterString() + ';';\r\n      navigator.clipboard.writeText(cssStr).then(function() {\r\n        self.showToast('\ud83d\udccb CSS filter string copied!', 'success');\r\n      }).catch(function() { self.showToast('\u26a0\ufe0f Clipboard not accessible', 'error'); });\r\n    },\r\n\r\n    \/* ===== OPTIMIZE TAB ===== *\/\r\n    updateViewBoxInputs: function(text) {\r\n      var vbMatch = text.match(\/viewBox=[\"']([0-9.\\-]+)\\s+([0-9.\\-]+)\\s+([0-9.\\-]+)\\s+([0-9.\\-]+)[\"']\/i);\r\n      if (!vbMatch) return;\r\n      var vbX = document.getElementById('pth-vb-x');\r\n      var vbY = document.getElementById('pth-vb-y');\r\n      var vbW = document.getElementById('pth-vb-w');\r\n      var vbH = document.getElementById('pth-vb-h');\r\n      if (vbX) vbX.value = vbMatch[1];\r\n      if (vbY) vbY.value = vbMatch[2];\r\n      if (vbW) vbW.value = vbMatch[3];\r\n      if (vbH) vbH.value = vbMatch[4];\r\n    },\r\n\r\n    applyViewBox: function() {\r\n      if (!this.svgContent) return;\r\n      var x = document.getElementById('pth-vb-x').value || 0;\r\n      var y = document.getElementById('pth-vb-y').value || 0;\r\n      var w = document.getElementById('pth-vb-w').value || this.origWidth;\r\n      var h = document.getElementById('pth-vb-h').value || this.origHeight;\r\n      var newVb = 'viewBox=\"' + x + ' ' + y + ' ' + w + ' ' + h + '\"';\r\n      var updated = this.svgContent.replace(\/viewBox=\"[^\"]*\"\/i, newVb);\r\n      if (updated === this.svgContent) {\r\n        \/* viewBox not found \u2014 inject it *\/\r\n        updated = this.svgContent.replace('<svg ', '<svg ' + newVb + ' ');\r\n      }\r\n      this.svgContent = updated;\r\n      this.updateCodeArea(updated);\r\n      this.updateEditorPreview();\r\n      this.showToast('\ud83d\udcd0 ViewBox updated', 'success');\r\n    },\r\n\r\n    showOptResult: function(msg) {\r\n      var el = document.getElementById('pth-opt-result');\r\n      if (!el) return;\r\n      el.textContent = msg; el.style.display = 'block';\r\n      setTimeout(function() { el.style.display = 'none'; }, 5000);\r\n    },\r\n\r\n    removeComments: function() {\r\n      if (!this.svgContent) return;\r\n      var before = this.svgContent.length;\r\n      this.svgContent = this.svgContent.replace(\/<!--[\\s\\S]*?-->\/g, '');\r\n      var saved = before - this.svgContent.length;\r\n      this.updateCodeArea(this.svgContent);\r\n      this.showOptResult('\u2705 Removed ' + saved + ' bytes of comments');\r\n      this.showToast('\ud83d\udcac Comments removed', 'success');\r\n    },\r\n\r\n    stripMetadata: function() {\r\n      if (!this.svgContent) return;\r\n      var before = this.svgContent.length;\r\n      this.svgContent = this.svgContent\r\n        .replace(\/<metadata[\\s\\S]*?<\\\/metadata>\/gi, '')\r\n        .replace(\/<desc[\\s\\S]*?<\\\/desc>\/gi, '')\r\n        .replace(\/<title[\\s\\S]*?<\\\/title>\/gi, '')\r\n        .replace(\/inkscape:[^=]+=\"[^\"]*\"\/g, '')\r\n        .replace(\/sodipodi:[^=]+=\"[^\"]*\"\/g, '')\r\n        .replace(\/dc:[^=]+=\"[^\"]*\"\/g, '');\r\n      var saved = before - this.svgContent.length;\r\n      this.updateCodeArea(this.svgContent);\r\n      this.showOptResult('\u2705 Stripped ~' + saved + ' bytes of metadata');\r\n      this.showToast('\ud83d\uddd1\ufe0f Metadata stripped', 'success');\r\n    },\r\n\r\n    stripIds: function() {\r\n      if (!this.svgContent) return;\r\n      var before = this.svgContent.length;\r\n      \/* Only strip IDs not referenced by url(#...) *\/\r\n      var refs = {};\r\n      var refMatch;\r\n      var refPat = \/url\\(#([^)]+)\\)\/g;\r\n      while ((refMatch = refPat.exec(this.svgContent)) !== null) refs[refMatch[1]] = true;\r\n      this.svgContent = this.svgContent.replace(\/\\s+id=\"([^\"]+)\"\/g, function(full, id) {\r\n        return refs[id] ? full : '';\r\n      });\r\n      var saved = before - this.svgContent.length;\r\n      this.updateCodeArea(this.svgContent);\r\n      this.showOptResult('\u2705 Stripped unreferenced IDs \u2014 saved ' + saved + ' bytes');\r\n      this.showToast('\ud83c\udd94 IDs stripped', 'success');\r\n    },\r\n\r\n    fullOptimize: function() {\r\n      if (!this.svgContent) return;\r\n      var before = this.svgContent.length;\r\n      this.removeComments();\r\n      this.stripMetadata();\r\n      this.stripIds();\r\n      \/* Minify whitespace *\/\r\n      this.svgContent = this.svgContent.replace(\/\\s+\/g, ' ').replace(\/>\\s+<\/g, '><').trim();\r\n      var after = this.svgContent.length;\r\n      var pct = (((before - after) \/ before) * 100).toFixed(1);\r\n      this.updateCodeArea(this.svgContent);\r\n      this.updateEditorPreview();\r\n      this.showOptResult('\ud83d\ude80 Full optimize: ' + before + ' \u2192 ' + after + ' bytes (saved ' + pct + '%)');\r\n      this.showToast('\ud83d\ude80 Full optimize done! Saved ' + pct + '%', 'success');\r\n    },\r\n\r\n    \/* ===== BATCH EXPORT ===== *\/\r\n    exportPack: function(sizes, prefix) {\r\n      if (!this.svgContent) { this.showError('Load an SVG first.'); return; }\r\n      var self = this;\r\n      var count = 0;\r\n      sizes.forEach(function(s) {\r\n        setTimeout(function() {\r\n          var canvas = document.createElement('canvas');\r\n          canvas.width = s.w; canvas.height = s.h;\r\n          var ctx = canvas.getContext('2d');\r\n          var img = new Image();\r\n          img.onload = function() {\r\n            ctx.drawImage(img, 0, 0, s.w, s.h);\r\n            self.downloadDataUrl(canvas.toDataURL('image\/png'), prefix + s.w + 'x' + s.h + '.png');\r\n          };\r\n          img.src = 'data:image\/svg+xml;base64,' + btoa(unescape(encodeURIComponent(self.svgContent)));\r\n        }, count * 250);\r\n        count++;\r\n      });\r\n      this.showToast('\ud83d\udce6 Exporting ' + sizes.length + ' files...', 'info');\r\n    },\r\n\r\n    exportFaviconPack: function() {\r\n      this.exportPack([{w:16,h:16},{w:32,h:32},{w:64,h:64},{w:180,h:180},{w:192,h:192},{w:512,h:512}], 'favicon-');\r\n    },\r\n\r\n    exportSocialPack: function() {\r\n      this.exportPack([{w:1200,h:630},{w:1080,h:1080},{w:820,h:312},{w:1500,h:500},{w:400,h:400}], 'social-');\r\n    },\r\n\r\n    exportIconsPack: function() {\r\n      this.exportPack([{w:16,h:16},{w:24,h:24},{w:32,h:32},{w:48,h:48},{w:64,h:64},{w:128,h:128},{w:256,h:256}], 'icon-');\r\n    },\r\n\r\n    \/* ===== VECTORIZER (Pure Canvas \u2014 100% Offline) ===== *\/\r\n    vectorize: function() {\r\n      var self = this;\r\n      var threshold = parseInt(document.getElementById('pth-trace-threshold').value) || 128;\r\n      var colorMode = document.getElementById('pth-trace-colors').value;\r\n\r\n      \/* Need a bitmap source *\/\r\n      var srcUrl = this.rasterDataUrl;\r\n      if (!srcUrl && this.svgContent) {\r\n        \/* Rasterize SVG first then trace *\/\r\n        srcUrl = 'data:image\/svg+xml;base64,' + btoa(unescape(encodeURIComponent(this.svgContent)));\r\n      }\r\n      if (!srcUrl) { this.showError('Load a PNG\/JPG\/WebP image first to vectorize.'); return; }\r\n\r\n      this.showToast('\u23f3 Tracing edges...', 'info');\r\n\r\n      var offCanvas = document.createElement('canvas');\r\n      var img = new Image();\r\n      img.onload = function() {\r\n        var tw = Math.min(img.width, 400);\r\n        var th = Math.round(img.height * (tw \/ img.width));\r\n        offCanvas.width = tw; offCanvas.height = th;\r\n        var ctx = offCanvas.getContext('2d');\r\n        ctx.drawImage(img, 0, 0, tw, th);\r\n        var imageData = ctx.getImageData(0, 0, tw, th);\r\n\r\n        if (colorMode === 'bw') {\r\n          self.traceEdgesBW(imageData, tw, th, threshold);\r\n        } else {\r\n          self.traceMultiColor(imageData, tw, th, threshold);\r\n        }\r\n      };\r\n      img.onerror = function() { self.showError('Could not load image for vectorization.'); };\r\n      img.src = srcUrl;\r\n    },\r\n\r\n    traceEdgesBW: function(imageData, w, h, threshold) {\r\n      var data = imageData.data;\r\n      var paths = '';\r\n\r\n      for (var y = 0; y < h - 1; y++) {\r\n        for (var x = 0; x < w - 1; x++) {\r\n          var idx = (y * w + x) * 4;\r\n          var gray = 0.299 * data[idx] + 0.587 * data[idx+1] + 0.114 * data[idx+2];\r\n          if (gray < threshold) {\r\n            paths += 'M' + x + ' ' + y + 'h1v1h-1z';\r\n          }\r\n        }\r\n      }\r\n\r\n      var svg = '<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" viewBox=\"0 0 ' + w + ' ' + h + '\" width=\"' + w + '\" height=\"' + h + '\"><path fill=\"#000000\" d=\"' + paths + '\"\/><\/svg>';\r\n      this.svgContent = svg;\r\n      this.updateCodeArea(svg);\r\n      this.updateEditorPreview();\r\n      this.updateStats(svg);\r\n      this.switchTab('editor');\r\n      this.showToast('\ud83e\ude84 Vectorized to SVG!', 'success');\r\n    },\r\n\r\n    traceMultiColor: function(imageData, w, h, threshold) {\r\n      var data = imageData.data;\r\n      \/* 4-pass: quantize to 4 representative colors *\/\r\n      var colorGroups = {};\r\n      for (var y = 0; y < h; y += 2) {\r\n        for (var x = 0; x < w; x += 2) {\r\n          var idx = (y * w + x) * 4;\r\n          var r = Math.round(data[idx] \/ 64) * 64;\r\n          var g = Math.round(data[idx+1] \/ 64) * 64;\r\n          var b = Math.round(data[idx+2] \/ 64) * 64;\r\n          var key = r + ',' + g + ',' + b;\r\n          if (!colorGroups[key]) colorGroups[key] = [];\r\n          colorGroups[key].push({ x: x, y: y });\r\n        }\r\n      }\r\n\r\n      var pathsHtml = '';\r\n      var colorKeys = Object.keys(colorGroups).slice(0, 8);\r\n      for (var ci = 0; ci < colorKeys.length; ci++) {\r\n        var parts = colorKeys[ci].split(',');\r\n        var hex = '#' + ('0' + parseInt(parts[0]).toString(16)).slice(-2) + ('0' + parseInt(parts[1]).toString(16)).slice(-2) + ('0' + parseInt(parts[2]).toString(16)).slice(-2);\r\n        var pixels = colorGroups[colorKeys[ci]];\r\n        var pathD = '';\r\n        for (var pi = 0; pi < pixels.length; pi++) {\r\n          pathD += 'M' + pixels[pi].x + ' ' + pixels[pi].y + 'h2v2h-2z';\r\n        }\r\n        pathsHtml += '<path fill=\"' + hex + '\" d=\"' + pathD + '\"\/>';\r\n      }\r\n\r\n      var svg = '<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" viewBox=\"0 0 ' + w + ' ' + h + '\" width=\"' + w + '\" height=\"' + h + '\">' + pathsHtml + '<\/svg>';\r\n      this.svgContent = svg;\r\n      this.updateCodeArea(svg);\r\n      this.updateEditorPreview();\r\n      this.updateStats(svg);\r\n      this.switchTab('editor');\r\n      this.showToast('\ud83e\ude84 Multi-color vector done!', 'success');\r\n    }\r\n  };\r\n\r\n  \/* ===== 4-LAYER BOOTSTRAP ===== *\/\r\n  function runInit() {\r\n    if (!window.pthSvgStudioApp.initialized && document.getElementById('pth-svg-studio-wrapper')) {\r\n      window.pthSvgStudioApp.initialized = true;\r\n      window.pthSvgStudioApp.init();\r\n    }\r\n  }\r\n\r\n  \/* Layer 1: Immediate *\/\r\n  runInit();\r\n\r\n  \/* Layer 2: DOMContentLoaded *\/\r\n  if (document.readyState === 'loading') {\r\n    document.addEventListener('DOMContentLoaded', runInit);\r\n  }\r\n\r\n  \/* Layer 3: window.load + 50ms *\/\r\n  window.addEventListener('load', function() { setTimeout(runInit, 50); });\r\n\r\n  \/* Layer 4: MutationObserver \u2014 async Woody injection *\/\r\n  if (!window.pthSvgStudioApp.initialized && typeof MutationObserver !== 'undefined') {\r\n    var pthSvgObs = new MutationObserver(function() {\r\n      if (document.getElementById('pth-svg-studio-wrapper')) {\r\n        pthSvgObs.disconnect();\r\n        runInit();\r\n      }\r\n    });\r\n    pthSvgObs.observe(document.body || document.documentElement, { childList: true, subtree: true });\r\n    setTimeout(function() { pthSvgObs.disconnect(); }, 10000);\r\n  }\r\n\r\n})();\r\n<\/script>\r\n\n\n\n\n<style>\n.pth-feature-wrap{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:20px;margin-bottom:30px}\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-bottom: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}\n.pth-steps-title{font-size:1.2rem;font-weight:800;color:#0f172a;text-transform:uppercase;margin-bottom:35px;letter-spacing:1px}\n.pth-steps-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,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-bottom: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\n<div class=\"pth-feature-wrap\">\n  <div class=\"pth-feat-box\">\n    <div class=\"pth-feat-title\">\ud83d\udfe2 4-Tab All-in-One Studio<\/div>\n    <p class=\"pth-feat-text\">Rasterize, SVG Editor, Filters &#038; FX, and Optimize tabs in one tool \u2014 convert SVG to PNG\/JPG\/WebP, edit source code with live preview, apply 8 filter presets, and batch export in a single session.<\/p>\n  <\/div>\n  <div class=\"pth-feat-box\">\n    <div class=\"pth-feat-title\">\ud83d\udd35 Color Palette Extractor<\/div>\n    <p class=\"pth-feat-text\">Automatically scans your SVG and displays every hex color as a clickable swatch. Pick any color and swap it site-wide in one click \u2014 perfect for rapid logo rebranding and theme changes.<\/p>\n  <\/div>\n  <div class=\"pth-feat-box\">\n    <div class=\"pth-feat-title\">\ud83d\udfe3 Batch Export Packs<\/div>\n    <p class=\"pth-feat-text\">Generate a complete Favicon Pack (16\u00d716 to 512\u00d7512), Social Pack (OG, Instagram, FB Cover, Twitter), or Icon Sizes set (16px to 256px) \u2014 all files download automatically in one batch action.<\/p>\n  <\/div>\n<\/div>\n\n<div class=\"pth-steps-wrap\">\n  <div class=\"pth-steps-title\">How to Use SVG Studio Pro<\/div>\n  <div class=\"pth-steps-grid\">\n    <div class=\"pth-step-item\">\n      <div class=\"pth-step-num\">1<\/div>\n      <div class=\"pth-step-name\">Upload or Load Sample<\/div>\n      <p class=\"pth-step-desc\">Drag &#038; drop your SVG or image file onto the drop zone, or click \ud83d\udca1 Load Sample to start immediately with a demo SVG.<\/p>\n    <\/div>\n    <div class=\"pth-step-item\">\n      <div class=\"pth-step-num\">2<\/div>\n      <div class=\"pth-step-name\">Pick Your Tab<\/div>\n      <p class=\"pth-step-desc\">Choose \ud83d\uddbc\ufe0f Rasterize to export as PNG\/JPG\/WebP, \u270f\ufe0f SVG Editor to edit code or swap colors, \ud83c\udfa8 Filters &#038; FX to apply effects, or \ud83d\udcd0 Optimize to minify and batch export.<\/p>\n    <\/div>\n    <div class=\"pth-step-item\">\n      <div class=\"pth-step-num\">3<\/div>\n      <div class=\"pth-step-name\">Configure Settings<\/div>\n      <p class=\"pth-step-desc\">Set output dimensions using Quick Size Presets or custom width\/height, choose format, adjust quality slider, pick a filter preset or tune sliders manually.<\/p>\n    <\/div>\n    <div class=\"pth-step-item\">\n      <div class=\"pth-step-num\">4<\/div>\n      <div class=\"pth-step-name\">Export or Download<\/div>\n      <p class=\"pth-step-desc\">Hit \u2728 Render to Image, \ud83d\udce5 Export with Filters, \ud83d\udcc4 Download SVG, or choose a Batch Export Pack. All files save directly to your device.<\/p>\n    <\/div>\n  <\/div>\n<\/div>\n\n\n<div id=\"start-seo-article\"><\/div>\n\n<p><!-- \/wp:post-content --><\/p>\n\n<!-- wp:paragraph -->\n<p>Last updated: June 2025<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:heading {\"anchor\":\"\ud83d\udd34-svg-rasterization-vs-vectorization-what-actually-happens-inside-the-browser\"} -->\n<h2 id=\"\ud83d\udd34-svg-rasterization-vs-vectorization-what-actually-happens-inside-the-browser\" class=\"wp-block-heading\">\ud83d\udd34 <strong>SVG Rasterization vs Vectorization \u2014 What Actually Happens Inside the Browser<\/strong><\/h2>\n<!-- \/wp:heading -->\n\n<!-- wp:paragraph -->\n<p>SVG files are mathematical instructions. No pixels. When you open an SVG in a browser, the rendering engine (Blink, Gecko, WebKit) interprets those path commands and draws them fresh at whatever size you requested. That&#8217;s why an SVG icon looks crisp at 16\u00d716 and still crisp at 4096\u00d74096 \u2014 the same math, different output canvas.<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:paragraph -->\n<p>Rasterization is the reverse: turning those instructions into a fixed grid of pixels. You decide the canvas dimensions. The browser draws the SVG onto an HTML5 <code>Canvas<\/code> element at that exact resolution, then you read the pixel data out as PNG, JPG, or WebP. That&#8217;s exactly what the Rasterize tab does here \u2014 no server, no ImageMagick, no Inkscape. Pure <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/Canvas_API\" rel=\"noreferrer noopener\" target=\"_blank\">Canvas API<\/a> running in your tab.<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:paragraph -->\n<p>The difference matters for your workflow. You&#8217;d rasterize when you need a PNG favicon, an OG image for social sharing, or a JPG thumbnail for email. You&#8217;d keep the SVG when the asset goes into CSS, React, or any context where infinite scalability matters. SVG Studio Pro handles both directions \u2014 and the Format Guide in the sidebar tells you exactly when to use each.<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:heading {\"anchor\":\"\ud83d\udfe1-the-svg-editor-tab-live-code-editing-color-swapping-and-jsx-export\"} -->\n<h2 id=\"\ud83d\udfe1-the-svg-editor-tab-live-code-editing-color-swapping-and-jsx-export\" class=\"wp-block-heading\">\ud83d\udfe1 <strong>The SVG Editor Tab \u2014 Live Code Editing, Color Swapping, and JSX Export<\/strong><\/h2>\n<!-- \/wp:heading -->\n\n<!-- wp:paragraph -->\n<p>Most free SVG converters give you a download button and nothing else. The SVG Editor tab is different. It exposes the raw SVG source in a live code editor with dark syntax styling. Edit a <code>viewBox<\/code>, remove a redundant <code>&lt;defs&gt;<\/code> block, fix a broken gradient ID \u2014 hit Apply and the live preview updates instantly. No page reload. No re-upload.<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:shortcode -->\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\/06\/svg-editor-color-palette-800x447.jpeg\" alt=\"SVG Studio Pro color palette extractor showing clickable hex color swatches extracted from an SVG logo\" 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<!-- \/wp:shortcode -->\n\n<!-- wp:heading {\"level\":3,\"anchor\":\"\ud83d\udfe2-color-palette-extractor-one-click-rebranding\"} -->\n<h3 id=\"\ud83d\udfe2-color-palette-extractor-one-click-rebranding\" class=\"wp-block-heading\">\ud83d\udfe2 <strong>Color Palette Extractor \u2014 One-Click Rebranding<\/strong><\/h3>\n<!-- \/wp:heading -->\n\n<!-- wp:paragraph -->\n<p>When you load an SVG, the tool scans every <code>fill<\/code>, <code>stroke<\/code>, and <code>stop-color<\/code> attribute for hex values and renders them as clickable swatches. Click a swatch and that hex populates the &#8220;Replace Color&#8221; picker. Set your new color. Hit \ud83d\udd04 Replace Color. Every instance of that value across the entire SVG source gets swapped in one pass. Need to undo? Hit \u21a9\ufe0f Revert to restore the original.<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:list -->\n<ul class=\"wp-block-list\"><!-- wp:list-item -->\n<li>\ud83d\udd35 Works on multi-stop gradients \u2014 finds colors inside <code>stop-color<\/code> attributes too<\/li>\n<!-- \/wp:list-item -->\n\n<!-- wp:list-item -->\n<li>\ud83d\udfe0 Handles both quoted styles: <code>fill=\"#2563eb\"<\/code> and <code>fill:#2563eb<\/code> in inline CSS<\/li>\n<!-- \/wp:list-item -->\n\n<!-- wp:list-item -->\n<li>\ud83d\udfe3 Revert button restores the original SVG colors without needing to re-upload<\/li>\n<!-- \/wp:list-item --><\/ul>\n<!-- \/wp:list -->\n\n<!-- wp:paragraph -->\n<p>The Beautify button reformats compressed SVG source into indented, human-readable markup. The Minify button does the opposite \u2014 strips whitespace and collapses the source to a single line. Both are lossless. Neither removes paths or shapes. After editing, use Copy as JSX to get a React-compatible version with all hyphenated attributes converted: <code>stroke-width<\/code> becomes <code>strokeWidth<\/code>, <code>fill-rule<\/code> becomes <code>fillRule<\/code>, and so on.<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:heading {\"anchor\":\"\ud83d\udfe2-filters-optimization-and-batch-export-the-production-workflow\"} -->\n<h2 id=\"\ud83d\udfe2-filters-optimization-and-batch-export-the-production-workflow\" class=\"wp-block-heading\">\ud83d\udfe2 <strong>Filters, Optimization, and Batch Export \u2014 The Production Workflow<\/strong><\/h2>\n<!-- \/wp:heading -->\n\n<!-- wp:paragraph -->\n<p>The Filters &amp; FX tab applies CSS filter effects to your SVG at render time. Eight presets cover the most common looks \u2014 Vintage warms the tones and adds slight sepia, Drama cranks contrast to 150% for bold poster-style output, Cool shifts the hue into blue territory, B&amp;W collapses saturation to zero. Each preset sets the six manual sliders simultaneously, so you can dial them in further after applying one.<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:paragraph -->\n<p>The filter string is live CSS. Hit Copy as CSS and you get a ready-to-paste property like <code>filter: brightness(95%) contrast(90%) saturate(80%) sepia(20%);<\/code> \u2014 drop it into any stylesheet and your image renders with the exact same look. When you click \ud83d\udce5 Export with Filters, the tool draws the filtered SVG onto a Canvas and saves a PNG with the effects baked in permanently.<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:heading {\"level\":3,\"anchor\":\"\ud83d\udfe2-optimize-tab-what-each-action-does-to-your-svg-bytes\"} -->\n<h3 id=\"\ud83d\udfe2-optimize-tab-what-each-action-does-to-your-svg-bytes\" class=\"wp-block-heading\">\ud83d\udfe2 <strong>Optimize Tab \u2014 What Each Action Does to Your SVG Bytes<\/strong><\/h3>\n<!-- \/wp:heading -->\n\n<!-- wp:paragraph -->\n<p>SVGs exported from Illustrator, Figma, or Inkscape carry significant overhead. Metadata blocks, editor comments, Inkscape-specific attributes, and redundant IDs can account for 20\u201360% of the file size. The Optimize tab breaks the cleanup into four targeted actions:<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:list -->\n<ul class=\"wp-block-list\"><!-- wp:list-item -->\n<li>\ud83d\udd35 <strong>Remove Comments<\/strong> \u2014 strips <code>&lt;!-- ... --><\/code> blocks. Illustrator loves leaving version comments at the top of every export.<\/li>\n<!-- \/wp:list-item -->\n\n<!-- wp:list-item -->\n<li>\ud83d\udfe0 <strong>Strip Metadata<\/strong> \u2014 removes <code>&lt;metadata><\/code>, <code>&lt;desc><\/code>, <code>&lt;title><\/code>, and Inkscape\/Sodipodi\/Dublin Core attributes that browsers never use.<\/li>\n<!-- \/wp:list-item -->\n\n<!-- wp:list-item -->\n<li>\ud83d\udfe3 <strong>Strip IDs<\/strong> \u2014 removes <code>id=\"\"<\/code> attributes that aren&#8217;t referenced by a <code>url(#...)<\/code> anywhere in the file. Safe \u2014 it checks for references before removing.<\/li>\n<!-- \/wp:list-item -->\n\n<!-- wp:list-item -->\n<li>\ud83d\udd35 <strong>Full Optimize<\/strong> \u2014 runs all three passes then collapses whitespace. Typical savings on a Figma export: 35\u201355% size reduction with zero visual change.<\/li>\n<!-- \/wp:list-item --><\/ul>\n<!-- \/wp:list -->\n\n<!-- wp:paragraph -->\n<p>The ViewBox Editor deserves its own mention. Rather than hunting for the <code>viewBox<\/code> attribute inside the code editor, you get four numeric inputs: min-x, min-y, width, height. Adjusting these crops and reframes the visible area of the SVG without touching any paths. It&#8217;s how you remove unwanted whitespace padding from an exported Figma icon without distorting the shapes.<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:paragraph -->\n<p>For batch export, the three packs cover every common production need. The Favicon Pack exports six PNG sizes \u2014 16, 32, 64, 180 (Apple Touch Icon), 192 (Android), and 512 pixels \u2014 all from a single click. The Social Pack covers OG 1200\u00d7630, Instagram 1080\u00d71080, Facebook Cover 820\u00d7312, Twitter Header 1500\u00d7500, and a 400\u00d7400 profile photo. The Icon Sizes pack outputs the complete standard set from 16px to 256px. Each file downloads individually and automatically.<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:paragraph -->\n<p>You can also try our <a href=\"https:\/\/schoolict.net\/tools\/free-web-tools-directory-prime-tool-hub\/?cat=image-tools\">Image Tools collection<\/a> for additional conversion options, or read our guide on <a href=\"https:\/\/schoolict.net\/tools\/svg-file-format-complete-technical-guide\/\">SVG file format best practices<\/a> for deeper technical context on when SVG is the right choice for your project.<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:html -->\n<style>\n.pth-faq-section{margin-top:50px;margin-bottom:40px;font-family:inherit}\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:100%;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\n<div class=\"pth-faq-section\">\n  <div class=\"pth-faq-header\">\ud83e\udd14 Frequently Asked Questions<\/div>\n  <div class=\"pth-faq-grid\">\n\n    <div class=\"pth-faq-card\">\n      <p class=\"pth-faq-q\">Does SVG Studio Pro upload my files to a server?<\/p>\n      <p class=\"pth-faq-a\">No. Every action runs entirely inside your browser using the Canvas API and JavaScript. Your SVG files never leave your device \u2014 there&#8217;s no server, no upload, and no account required. It&#8217;s fully offline-capable once the page loads.<\/p>\n    <\/div>\n\n    <div class=\"pth-faq-card\">\n      <p class=\"pth-faq-q\">What&#8217;s the maximum SVG size this tool can handle?<\/p>\n      <p class=\"pth-faq-a\">The tool handles SVGs up to several MB without issues. The main limit for rasterization is available GPU\/Canvas memory \u2014 most modern devices can render at 4096\u00d74096 or higher. Very large or highly complex SVGs with thousands of paths may take a few seconds to render.<\/p>\n    <\/div>\n\n    <div class=\"pth-faq-card\">\n      <p class=\"pth-faq-q\">Why does the Vectorizer output look pixelated?<\/p>\n      <p class=\"pth-faq-a\">The built-in vectorizer uses Canvas edge detection \u2014 it traces pixels, not mathematical curves. For best results, use high-contrast source images (logos, icons, illustrations) and experiment with the Edge Threshold slider. Complex photos with gradients won&#8217;t vectorize cleanly with any pixel-tracing approach.<\/p>\n    <\/div>\n\n    <div class=\"pth-faq-card\">\n      <p class=\"pth-faq-q\">Can I use the exported PNG files commercially?<\/p>\n      <p class=\"pth-faq-a\">The tool itself places no restrictions on exported files. Commercial use rights depend entirely on the license of the original SVG you uploaded. If you created the SVG yourself or own its license, you can use exports however you need.<\/p>\n    <\/div>\n\n    <div class=\"pth-faq-card\">\n      <p class=\"pth-faq-q\">How does the Color Replace work on gradients?<\/p>\n      <p class=\"pth-faq-a\">The Color Palette Extractor scans fill, stroke, and stop-color attributes for hex values. When you replace a color, it does a string replace across the entire SVG source \u2014 so gradient stops using that hex get updated too. It handles both attribute-style and inline CSS-style color declarations.<\/p>\n    <\/div>\n\n    <div class=\"pth-faq-card\">\n      <p class=\"pth-faq-q\">What does Full Optimize actually remove?<\/p>\n      <p class=\"pth-faq-a\">Full Optimize runs four passes: strips HTML comments, removes metadata and editor-specific attributes (Inkscape, Sodipodi, Dublin Core), deletes unreferenced ID attributes, then collapses all whitespace. It never modifies paths, shapes, colors, or gradients. Typical savings are 30\u201355% on Figma or Illustrator exports.<\/p>\n    <\/div>\n\n    <div class=\"pth-faq-card\">\n      <p class=\"pth-faq-q\">Does the JSX export work with React and Next.js?<\/p>\n      <p class=\"pth-faq-a\">Yes. Copy as JSX converts all hyphenated SVG attributes to camelCase \u2014 strokeWidth, fillRule, clipRule, stopColor, stopOpacity \u2014 which is what React&#8217;s JSX syntax requires. Paste the output directly into a React component or Next.js page.<\/p>\n    <\/div>\n\n    <div class=\"pth-faq-card\">\n      <p class=\"pth-faq-q\">Why use WebP instead of PNG for the output?<\/p>\n      <p class=\"pth-faq-a\">WebP is typically 25\u201335% smaller than PNG at equivalent visual quality. For web use \u2014 especially OG images, thumbnails, and social assets \u2014 WebP loads faster and improves Core Web Vitals. All modern browsers support it. Use PNG when you need guaranteed compatibility with older tools or email clients.<\/p>\n    <\/div>\n\n    <div class=\"pth-faq-card\">\n      <p class=\"pth-faq-q\">Can I apply filters before exporting to PNG?<\/p>\n      <p class=\"pth-faq-a\">Yes. Go to the Filters &#038; FX tab, set your preset or adjust the sliders, then click \ud83d\udce5 Export with Filters. The tool renders the SVG through a Canvas with the CSS filter applied and bakes the effect permanently into the exported PNG. The filter CSS string is also copyable for use in stylesheets.<\/p>\n    <\/div>\n\n  <\/div>\n<\/div>\n<!-- \/wp:html -->","protected":false},"excerpt":{"rendered":"<p>Free SVG to PNG Converter &#8211; High Quality Offline Rasterizer Need a fast SVG to PNG converter? Convert SVG vector graphics to high-quality PNG, JPG, or WebP offline instantly with custom sizing and transparency. \ud83d\udfe2 4-Tab All-in-One Studio Rasterize, SVG Editor, Filters &#038; FX, and Optimize tabs in one tool \u2014 convert SVG to PNG\/JPG\/WebP, &#8230; <a title=\"Free SVG to PNG Converter &#8211; High Quality Offline Rasterizer\" class=\"read-more\" href=\"https:\/\/schoolict.net\/tools\/svg-to-png-converter\/\" aria-label=\"Read more about Free SVG to PNG Converter &#8211; High Quality Offline Rasterizer\">Read more<\/a><\/p>\n","protected":false},"author":1,"featured_media":3446,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-2333","page","type-page","status-publish","has-post-thumbnail"],"_links":{"self":[{"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/pages\/2333","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=2333"}],"version-history":[{"count":0,"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/pages\/2333\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/media\/3446"}],"wp:attachment":[{"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/media?parent=2333"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}