64 lines
1.3 KiB
JavaScript
64 lines
1.3 KiB
JavaScript
#!/usr/bin/env node
|
|
|
|
import { readFileSync, writeFileSync } from "node:fs";
|
|
import { Resvg } from "@resvg/resvg-js";
|
|
|
|
const input = process.argv[2];
|
|
const output = process.argv[3];
|
|
const margin = Number.parseFloat(process.argv[4] ?? "0");
|
|
const bg = process.argv[5] ?? null;
|
|
|
|
if (!input || !output) {
|
|
process.exit(1);
|
|
}
|
|
|
|
const raw = readFileSync(input, "utf8");
|
|
|
|
// Render once to compute tight bounding box
|
|
const resvg = new Resvg(raw, {
|
|
fitTo: {
|
|
mode: "original"
|
|
}
|
|
});
|
|
|
|
const { width, height } = resvg.render();
|
|
|
|
// Resvg gives us rendered size, but we need geometry bounds.
|
|
// Use bounding box API instead:
|
|
|
|
const bbox = resvg.getBBox();
|
|
|
|
if (!bbox) {
|
|
process.exit(1);
|
|
}
|
|
|
|
const x = bbox.x - margin;
|
|
const y = bbox.y - margin;
|
|
const w = bbox.width + margin * 2;
|
|
const h = bbox.height + margin * 2;
|
|
|
|
// Rewrite root SVG viewBox safely
|
|
const updated = raw
|
|
.replace(/viewBox="[^"]*"/, `viewBox="${x} ${y} ${w} ${h}"`)
|
|
.replace(/\swidth="[^"]*"/, "")
|
|
.replace(/\sheight="[^"]*"/, "");
|
|
|
|
let finalSvg = updated;
|
|
|
|
if (bg) {
|
|
finalSvg = finalSvg.replace(
|
|
/<svg\b([^>]*)>/,
|
|
(match, attrs) => {
|
|
if (/style=/.test(attrs)) {
|
|
return `<svg${attrs.replace(
|
|
/style="([^"]*)"/,
|
|
(_, style) => `style="${style};background:${bg}"`
|
|
)}>`;
|
|
}
|
|
return `<svg${attrs} style="background:${bg}">`;
|
|
}
|
|
);
|
|
}
|
|
|
|
writeFileSync(output, finalSvg);
|