Make background-exporter work with multiple <image> instances

This commit is contained in:
2026-05-10 02:22:17 +02:00
parent 2abd6c529c
commit 7d72d2540a
+47 -46
View File
@@ -11,54 +11,55 @@ async function inlineAndExport() {
const bgDoc = parser.parseFromString(bgText, "image/svg+xml"); const bgDoc = parser.parseFromString(bgText, "image/svg+xml");
const svg = bgDoc.documentElement; const svg = bgDoc.documentElement;
// Find the <image> referencing the logo (first one) // Find ALL <image> elements
const imgEl = svg.querySelector("image[href], image[xlink\\:href]"); const imageEls = svg.querySelectorAll("image[href], image[xlink\\:href]");
if (!imgEl) {
console.error("No <image> element found in background.svg"); for (const imgEl of imageEls) {
return; const href = imgEl.getAttribute("href") || imgEl.getAttribute("xlink:href");
// Only inline SVG images (skip PNG/JPG/etc.)
if (!href.endsWith(".svg")) continue;
// Load the referenced SVG
const logoText = await (await fetch(href)).text();
const logoDoc = parser.parseFromString(logoText, "image/svg+xml");
const logoSvg = logoDoc.documentElement;
// Extract inner content
const logoInner = Array.from(logoSvg.childNodes)
.filter(n => n.nodeType === 1)
.map(n => n.outerHTML)
.join("");
// Read viewBox
const vb = logoSvg.getAttribute("viewBox").split(" ").map(Number);
const vbWidth = vb[2];
const vbHeight = vb[3];
// Read <image> geometry
const x = parseFloat(imgEl.getAttribute("x") || 0);
const y = parseFloat(imgEl.getAttribute("y") || 0);
const w = parseFloat(imgEl.getAttribute("width"));
const h = parseFloat(imgEl.getAttribute("height"));
// Compute scale
const scaleX = w / vbWidth;
const scaleY = h / vbHeight;
// Create <g> wrapper
const g = bgDoc.createElementNS("http://www.w3.org/2000/svg", "g");
g.setAttribute("transform", `translate(${x},${y}) scale(${scaleX},${scaleY})`);
// Preserve width/height
g.setAttribute("width", imgEl.getAttribute("width"));
g.setAttribute("height", imgEl.getAttribute("height"));
g.innerHTML = logoInner;
// Replace <image> with <g>
imgEl.replaceWith(g);
} }
const logoHref = imgEl.getAttribute("href") || imgEl.getAttribute("xlink:href");
// Load logo
const logoText = await (await fetch(logoHref)).text();
const logoDoc = parser.parseFromString(logoText, "image/svg+xml");
const logoSvg = logoDoc.documentElement;
// Extract inner content of logo.svg
const logoInner = Array.from(logoSvg.childNodes)
.filter(n => n.nodeType === 1)
.map(n => n.outerHTML)
.join("");
// Read logo viewBox
const vb = logoSvg.getAttribute("viewBox").split(" ").map(Number);
const vbWidth = vb[2];
const vbHeight = vb[3];
// Read <image> geometry
const x = parseFloat(imgEl.getAttribute("x") || 0);
const y = parseFloat(imgEl.getAttribute("y") || 0);
const w = parseFloat(imgEl.getAttribute("width"));
const h = parseFloat(imgEl.getAttribute("height"));
// Compute scale
const scaleX = w / vbWidth;
const scaleY = h / vbHeight;
// Create <g> with correct transform
const g = bgDoc.createElementNS("http://www.w3.org/2000/svg", "g");
g.setAttribute("transform", `translate(${x},${y}) scale(${scaleX},${scaleY})`);
// ⭐ NEW: preserve width/height from the original <image>
g.setAttribute("width", imgEl.getAttribute("width"));
g.setAttribute("height", imgEl.getAttribute("height"));
g.innerHTML = logoInner;
// Replace <image> with <g>
imgEl.replaceWith(g);
// Serialize final SVG // Serialize final SVG
const finalSVG = new XMLSerializer().serializeToString(svg); const finalSVG = new XMLSerializer().serializeToString(svg);
const svg64 = btoa(unescape(encodeURIComponent(finalSVG))); const svg64 = btoa(unescape(encodeURIComponent(finalSVG)));