@pixldocs/canvas-renderer 0.3.27 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +35 -0
- package/dist/index.cjs +1064 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +51 -1
- package/dist/index.js +1064 -1
- package/dist/index.js.map +1 -1
- package/package.json +5 -1
package/dist/index.cjs
CHANGED
|
@@ -9,6 +9,8 @@ const reactDom = require("react-dom");
|
|
|
9
9
|
const zustand = require("zustand");
|
|
10
10
|
const fabric = require("fabric");
|
|
11
11
|
const client = require("react-dom/client");
|
|
12
|
+
const jspdf = require("jspdf");
|
|
13
|
+
const svg2pdf_js = require("svg2pdf.js");
|
|
12
14
|
function _interopNamespaceDefault(e) {
|
|
13
15
|
const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
|
|
14
16
|
if (e) {
|
|
@@ -10766,8 +10768,38 @@ class PixldocsRenderer {
|
|
|
10766
10768
|
return this.renderAllPageSvgs(configToRender);
|
|
10767
10769
|
}
|
|
10768
10770
|
/**
|
|
10769
|
-
*
|
|
10771
|
+
* Render a pre-resolved template config to a vector PDF.
|
|
10772
|
+
* Returns a Blob and ArrayBuffer.
|
|
10770
10773
|
*/
|
|
10774
|
+
async renderPdf(templateConfig, options) {
|
|
10775
|
+
const svgs = await this.renderAllPageSvgs(templateConfig);
|
|
10776
|
+
const { assemblePdfFromSvgs: assemblePdfFromSvgs2 } = await Promise.resolve().then(() => pdfExport);
|
|
10777
|
+
return assemblePdfFromSvgs2(svgs, { title: options == null ? void 0 : options.title });
|
|
10778
|
+
}
|
|
10779
|
+
/**
|
|
10780
|
+
* Resolve from V2 sectionState and render a vector PDF.
|
|
10781
|
+
* This is the primary PDF export API — mirrors renderFromForm() but returns a PDF.
|
|
10782
|
+
*/
|
|
10783
|
+
async renderPdfFromForm(options) {
|
|
10784
|
+
const { templateId, formSchemaId, sectionState, themeId, watermark, title } = options;
|
|
10785
|
+
const resolved = await resolveFromForm({
|
|
10786
|
+
templateId,
|
|
10787
|
+
formSchemaId,
|
|
10788
|
+
sectionState,
|
|
10789
|
+
themeId,
|
|
10790
|
+
supabaseUrl: this.config.supabaseUrl,
|
|
10791
|
+
supabaseAnonKey: this.config.supabaseAnonKey
|
|
10792
|
+
});
|
|
10793
|
+
const shouldWatermark = watermark ?? resolved.price > 0;
|
|
10794
|
+
let configToRender = resolved.config;
|
|
10795
|
+
if (shouldWatermark) {
|
|
10796
|
+
const { injectWatermark } = await Promise.resolve().then(() => require("./canvasWatermark-DAZIQ_IR.cjs"));
|
|
10797
|
+
configToRender = injectWatermark(configToRender);
|
|
10798
|
+
}
|
|
10799
|
+
const svgs = await this.renderAllPageSvgs(configToRender);
|
|
10800
|
+
const { assemblePdfFromSvgs: assemblePdfFromSvgs2 } = await Promise.resolve().then(() => pdfExport);
|
|
10801
|
+
return assemblePdfFromSvgs2(svgs, { title: title ?? resolved.config.name });
|
|
10802
|
+
}
|
|
10771
10803
|
async renderById(templateId, formData, options) {
|
|
10772
10804
|
const resolved = await resolveTemplateData({
|
|
10773
10805
|
templateId,
|
|
@@ -11220,6 +11252,1036 @@ class PixldocsRenderer {
|
|
|
11220
11252
|
return null;
|
|
11221
11253
|
}
|
|
11222
11254
|
}
|
|
11255
|
+
const SVG_DRAWABLE_TAGS = /* @__PURE__ */ new Set([
|
|
11256
|
+
"path",
|
|
11257
|
+
"rect",
|
|
11258
|
+
"circle",
|
|
11259
|
+
"ellipse",
|
|
11260
|
+
"polygon",
|
|
11261
|
+
"polyline",
|
|
11262
|
+
"line",
|
|
11263
|
+
"text",
|
|
11264
|
+
"tspan"
|
|
11265
|
+
]);
|
|
11266
|
+
const SVG_DEFINITION_CONTAINER_TAGS = /* @__PURE__ */ new Set([
|
|
11267
|
+
"defs",
|
|
11268
|
+
"clippath",
|
|
11269
|
+
"mask",
|
|
11270
|
+
"pattern",
|
|
11271
|
+
"marker",
|
|
11272
|
+
"symbol",
|
|
11273
|
+
"filter",
|
|
11274
|
+
"lineargradient",
|
|
11275
|
+
"radialgradient"
|
|
11276
|
+
]);
|
|
11277
|
+
const SVG_STYLE_PROPS = /* @__PURE__ */ new Set([
|
|
11278
|
+
"fill",
|
|
11279
|
+
"stroke",
|
|
11280
|
+
"color",
|
|
11281
|
+
"opacity",
|
|
11282
|
+
"fill-opacity",
|
|
11283
|
+
"stroke-opacity",
|
|
11284
|
+
"fill-rule",
|
|
11285
|
+
"stroke-width",
|
|
11286
|
+
"stroke-linecap",
|
|
11287
|
+
"stroke-linejoin",
|
|
11288
|
+
"stroke-miterlimit",
|
|
11289
|
+
"stroke-dasharray",
|
|
11290
|
+
"stroke-dashoffset",
|
|
11291
|
+
"display",
|
|
11292
|
+
"visibility",
|
|
11293
|
+
"stop-color",
|
|
11294
|
+
"stop-opacity",
|
|
11295
|
+
"clip-rule",
|
|
11296
|
+
"clip-path",
|
|
11297
|
+
"mask",
|
|
11298
|
+
"filter"
|
|
11299
|
+
]);
|
|
11300
|
+
const GRADIENT_ATTRS_LINEAR = ["x1", "y1", "x2", "y2", "gradientUnits", "gradientTransform", "spreadMethod"];
|
|
11301
|
+
const GRADIENT_ATTRS_RADIAL = ["cx", "cy", "r", "fx", "fy", "gradientUnits", "gradientTransform", "spreadMethod"];
|
|
11302
|
+
const URL_GRADIENT_RE = /^\s*url\s*\(\s*(['"]?)([^)]+?)\1\s*\)/i;
|
|
11303
|
+
function parseColor(color) {
|
|
11304
|
+
if (!color) return null;
|
|
11305
|
+
const raw = color.trim().toLowerCase();
|
|
11306
|
+
if (!raw || raw === "transparent" || raw === "none") return null;
|
|
11307
|
+
const clamp2 = (value) => Math.max(0, Math.min(255, Math.round(value)));
|
|
11308
|
+
const parseNumeric = (token) => {
|
|
11309
|
+
const value = parseFloat(token);
|
|
11310
|
+
return Number.isFinite(value) ? value : NaN;
|
|
11311
|
+
};
|
|
11312
|
+
const parseRgbComponent = (token) => {
|
|
11313
|
+
const value = parseNumeric(token);
|
|
11314
|
+
if (!Number.isFinite(value)) return NaN;
|
|
11315
|
+
return token.endsWith("%") ? value / 100 * 255 : value;
|
|
11316
|
+
};
|
|
11317
|
+
const parseAlpha = (token) => {
|
|
11318
|
+
if (!token) return 1;
|
|
11319
|
+
const value = parseNumeric(token);
|
|
11320
|
+
if (!Number.isFinite(value)) return 1;
|
|
11321
|
+
return token.endsWith("%") ? value / 100 : value;
|
|
11322
|
+
};
|
|
11323
|
+
const toRgbFromHsl = (h, s, l) => {
|
|
11324
|
+
const hue = (h % 360 + 360) % 360;
|
|
11325
|
+
const sat = Math.max(0, Math.min(1, s));
|
|
11326
|
+
const light = Math.max(0, Math.min(1, l));
|
|
11327
|
+
if (sat === 0) {
|
|
11328
|
+
const gray = clamp2(light * 255);
|
|
11329
|
+
return { r: gray, g: gray, b: gray };
|
|
11330
|
+
}
|
|
11331
|
+
const q = light < 0.5 ? light * (1 + sat) : light + sat - light * sat;
|
|
11332
|
+
const p = 2 * light - q;
|
|
11333
|
+
const hueToRgb = (t) => {
|
|
11334
|
+
let tt = t;
|
|
11335
|
+
if (tt < 0) tt += 1;
|
|
11336
|
+
if (tt > 1) tt -= 1;
|
|
11337
|
+
if (tt < 1 / 6) return p + (q - p) * 6 * tt;
|
|
11338
|
+
if (tt < 1 / 2) return q;
|
|
11339
|
+
if (tt < 2 / 3) return p + (q - p) * (2 / 3 - tt) * 6;
|
|
11340
|
+
return p;
|
|
11341
|
+
};
|
|
11342
|
+
return {
|
|
11343
|
+
r: clamp2(hueToRgb(hue / 360 + 1 / 3) * 255),
|
|
11344
|
+
g: clamp2(hueToRgb(hue / 360) * 255),
|
|
11345
|
+
b: clamp2(hueToRgb(hue / 360 - 1 / 3) * 255)
|
|
11346
|
+
};
|
|
11347
|
+
};
|
|
11348
|
+
if (raw.startsWith("#")) {
|
|
11349
|
+
const hex = raw.slice(1);
|
|
11350
|
+
const expanded = hex.length === 3 || hex.length === 4 ? hex.split("").map((char) => char + char).join("") : hex;
|
|
11351
|
+
if (expanded.length !== 6 && expanded.length !== 8) return null;
|
|
11352
|
+
const intValue = parseInt(expanded.slice(0, 6), 16);
|
|
11353
|
+
if (!Number.isFinite(intValue)) return null;
|
|
11354
|
+
if (expanded.length === 8) {
|
|
11355
|
+
const alphaHex = parseInt(expanded.slice(6, 8), 16);
|
|
11356
|
+
if (Number.isFinite(alphaHex) && alphaHex <= 0) return null;
|
|
11357
|
+
}
|
|
11358
|
+
return { r: intValue >> 16 & 255, g: intValue >> 8 & 255, b: intValue & 255 };
|
|
11359
|
+
}
|
|
11360
|
+
const rgbMatch = raw.match(/^rgba?\((.+)\)$/);
|
|
11361
|
+
if (rgbMatch) {
|
|
11362
|
+
const normalized = rgbMatch[1].replace(/\//g, " ").replace(/,/g, " ");
|
|
11363
|
+
const parts = normalized.split(/\s+/).filter(Boolean);
|
|
11364
|
+
if (parts.length >= 3) {
|
|
11365
|
+
const alpha = parseAlpha(parts[3]);
|
|
11366
|
+
if (alpha <= 0) return null;
|
|
11367
|
+
const r = parseRgbComponent(parts[0]);
|
|
11368
|
+
const g = parseRgbComponent(parts[1]);
|
|
11369
|
+
const b = parseRgbComponent(parts[2]);
|
|
11370
|
+
if (Number.isFinite(r) && Number.isFinite(g) && Number.isFinite(b)) {
|
|
11371
|
+
return { r: clamp2(r), g: clamp2(g), b: clamp2(b) };
|
|
11372
|
+
}
|
|
11373
|
+
}
|
|
11374
|
+
}
|
|
11375
|
+
const hslMatch = raw.match(/^hsla?\((.+)\)$/);
|
|
11376
|
+
if (hslMatch) {
|
|
11377
|
+
const normalized = hslMatch[1].replace(/\//g, " ").replace(/,/g, " ");
|
|
11378
|
+
const parts = normalized.split(/\s+/).filter(Boolean);
|
|
11379
|
+
if (parts.length >= 3) {
|
|
11380
|
+
const alpha = parseAlpha(parts[3]);
|
|
11381
|
+
if (alpha <= 0) return null;
|
|
11382
|
+
const h = parseNumeric(parts[0].replace(/deg$/, ""));
|
|
11383
|
+
const sRaw = parseNumeric(parts[1].replace(/%$/, ""));
|
|
11384
|
+
const lRaw = parseNumeric(parts[2].replace(/%$/, ""));
|
|
11385
|
+
if (Number.isFinite(h) && Number.isFinite(sRaw) && Number.isFinite(lRaw)) {
|
|
11386
|
+
return toRgbFromHsl(h, sRaw / 100, lRaw / 100);
|
|
11387
|
+
}
|
|
11388
|
+
}
|
|
11389
|
+
}
|
|
11390
|
+
return null;
|
|
11391
|
+
}
|
|
11392
|
+
function rgbToHex(r, g, b) {
|
|
11393
|
+
return "#" + [r, g, b].map((x) => Math.max(0, Math.min(255, Math.round(x))).toString(16).padStart(2, "0")).join("");
|
|
11394
|
+
}
|
|
11395
|
+
function cssColorToHex(css) {
|
|
11396
|
+
var _a;
|
|
11397
|
+
const s = css.trim();
|
|
11398
|
+
if (/^#[0-9a-f]{3}$/i.test(s)) {
|
|
11399
|
+
const r = s[1] + s[1], g = s[2] + s[2], b = s[3] + s[3];
|
|
11400
|
+
return "#" + r + g + b;
|
|
11401
|
+
}
|
|
11402
|
+
if (/^#[0-9a-f]{6}$/i.test(s)) return s;
|
|
11403
|
+
if (/^#[0-9a-f]{8}$/i.test(s)) return "#" + s.slice(1, 7);
|
|
11404
|
+
const rgb = s.match(/^rgba?\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)/i);
|
|
11405
|
+
if (rgb) {
|
|
11406
|
+
const r = Number(rgb[1]).toString(16).padStart(2, "0");
|
|
11407
|
+
const g = Number(rgb[2]).toString(16).padStart(2, "0");
|
|
11408
|
+
const b = Number(rgb[3]).toString(16).padStart(2, "0");
|
|
11409
|
+
return "#" + r + g + b;
|
|
11410
|
+
}
|
|
11411
|
+
if (typeof document === "undefined") return null;
|
|
11412
|
+
const div = document.createElement("div");
|
|
11413
|
+
div.style.color = s;
|
|
11414
|
+
const computed = (_a = document.defaultView) == null ? void 0 : _a.getComputedStyle(div).color;
|
|
11415
|
+
if (!computed || !computed.startsWith("rgb")) return null;
|
|
11416
|
+
const m = computed.match(/\d+/g);
|
|
11417
|
+
if (!m || m.length < 3) return null;
|
|
11418
|
+
return "#" + [m[0], m[1], m[2]].map((v) => Number(v).toString(16).padStart(2, "0")).join("");
|
|
11419
|
+
}
|
|
11420
|
+
function isInSvgDefinitionSubtree(el) {
|
|
11421
|
+
var _a;
|
|
11422
|
+
let current = el;
|
|
11423
|
+
while (current) {
|
|
11424
|
+
if (SVG_DEFINITION_CONTAINER_TAGS.has(((_a = current.tagName) == null ? void 0 : _a.toLowerCase()) ?? "")) return true;
|
|
11425
|
+
current = current.parentElement;
|
|
11426
|
+
}
|
|
11427
|
+
return false;
|
|
11428
|
+
}
|
|
11429
|
+
function parseInlineSvgStyleDeclarations(styleText) {
|
|
11430
|
+
return styleText.split(";").map((part) => part.trim()).filter(Boolean).map((part) => {
|
|
11431
|
+
const idx = part.indexOf(":");
|
|
11432
|
+
if (idx <= 0) return null;
|
|
11433
|
+
return { key: part.slice(0, idx).trim().toLowerCase(), value: part.slice(idx + 1).trim() };
|
|
11434
|
+
}).filter((x) => !!x);
|
|
11435
|
+
}
|
|
11436
|
+
function extractGradientIdFromPaint(value) {
|
|
11437
|
+
if (!value) return null;
|
|
11438
|
+
const match = value.trim().match(URL_GRADIENT_RE);
|
|
11439
|
+
if (!match) return null;
|
|
11440
|
+
const rawRef = (match[2] || "").trim();
|
|
11441
|
+
if (!rawRef) return null;
|
|
11442
|
+
const hashIdx = rawRef.lastIndexOf("#");
|
|
11443
|
+
if (hashIdx < 0 || hashIdx === rawRef.length - 1) return null;
|
|
11444
|
+
const id = rawRef.slice(hashIdx + 1).trim();
|
|
11445
|
+
if (!id) return null;
|
|
11446
|
+
return id.replace(/[\s"')].*$/, "");
|
|
11447
|
+
}
|
|
11448
|
+
function normalizeGradientPaintRef(value) {
|
|
11449
|
+
const id = extractGradientIdFromPaint(value);
|
|
11450
|
+
return id ? `url(#${id})` : value;
|
|
11451
|
+
}
|
|
11452
|
+
function findGradientInTree(svgRoot, gradientId) {
|
|
11453
|
+
for (const el of svgRoot.querySelectorAll("[id]")) {
|
|
11454
|
+
if (el.getAttribute("id") === gradientId) return el;
|
|
11455
|
+
}
|
|
11456
|
+
return null;
|
|
11457
|
+
}
|
|
11458
|
+
function getInlineStyleValue(el, key) {
|
|
11459
|
+
const style = el.getAttribute("style") || "";
|
|
11460
|
+
if (!style) return null;
|
|
11461
|
+
const hit = parseInlineSvgStyleDeclarations(style).find((decl) => decl.key === key);
|
|
11462
|
+
return (hit == null ? void 0 : hit.value) ?? null;
|
|
11463
|
+
}
|
|
11464
|
+
function isTransparentColorToken(value) {
|
|
11465
|
+
if (!value) return false;
|
|
11466
|
+
const s = value.trim().toLowerCase();
|
|
11467
|
+
if (!s || s === "none" || s === "transparent") return true;
|
|
11468
|
+
if (/^#[0-9a-f]{8}$/i.test(s)) {
|
|
11469
|
+
return Number.parseInt(s.slice(7, 9), 16) === 0;
|
|
11470
|
+
}
|
|
11471
|
+
const rgba = s.match(/^rgba\s*\(([^)]+)\)$/i);
|
|
11472
|
+
if (rgba) {
|
|
11473
|
+
const parts = rgba[1].split(",").map((part) => part.trim());
|
|
11474
|
+
if (parts.length >= 4) {
|
|
11475
|
+
const alpha = parseSvgOpacity(parts[3]);
|
|
11476
|
+
return alpha != null && alpha <= 1e-4;
|
|
11477
|
+
}
|
|
11478
|
+
}
|
|
11479
|
+
return false;
|
|
11480
|
+
}
|
|
11481
|
+
function parseSvgOpacity(value) {
|
|
11482
|
+
if (!value) return null;
|
|
11483
|
+
const raw = value.trim();
|
|
11484
|
+
if (!raw) return null;
|
|
11485
|
+
if (raw.endsWith("%")) {
|
|
11486
|
+
const pct = Number.parseFloat(raw.slice(0, -1));
|
|
11487
|
+
if (!Number.isFinite(pct)) return null;
|
|
11488
|
+
return Math.max(0, Math.min(1, pct / 100));
|
|
11489
|
+
}
|
|
11490
|
+
const n = Number.parseFloat(raw);
|
|
11491
|
+
if (!Number.isFinite(n)) return null;
|
|
11492
|
+
return Math.max(0, Math.min(1, n));
|
|
11493
|
+
}
|
|
11494
|
+
function formatSvgOpacity(value) {
|
|
11495
|
+
return Number(Math.max(0, Math.min(1, value)).toFixed(4)).toString();
|
|
11496
|
+
}
|
|
11497
|
+
function multiplySvgOpacityAttr(el, attr, factor) {
|
|
11498
|
+
const existing = parseSvgOpacity(el.getAttribute(attr));
|
|
11499
|
+
el.setAttribute(attr, formatSvgOpacity((existing ?? 1) * factor));
|
|
11500
|
+
}
|
|
11501
|
+
function inlineSvgStyleBlockDeclarations(svg) {
|
|
11502
|
+
const styleNodes = Array.from(svg.querySelectorAll("style"));
|
|
11503
|
+
if (styleNodes.length === 0) return;
|
|
11504
|
+
const cssText = styleNodes.map((node) => node.textContent || "").join("\n").replace(/\/\*[\s\S]*?\*\//g, " ");
|
|
11505
|
+
if (!cssText.trim()) return;
|
|
11506
|
+
const allElements = [svg, ...Array.from(svg.querySelectorAll("*"))];
|
|
11507
|
+
const classIndex = /* @__PURE__ */ new Map();
|
|
11508
|
+
allElements.forEach((el) => {
|
|
11509
|
+
(el.getAttribute("class") || "").split(/\s+/).map((t) => t.trim()).filter(Boolean).forEach((token) => {
|
|
11510
|
+
const list = classIndex.get(token) ?? [];
|
|
11511
|
+
list.push(el);
|
|
11512
|
+
classIndex.set(token, list);
|
|
11513
|
+
});
|
|
11514
|
+
});
|
|
11515
|
+
const normalizePresentationValue = (key, value) => {
|
|
11516
|
+
if (["fill", "stroke", "clip-path", "mask", "filter"].includes(key)) return normalizeGradientPaintRef(value);
|
|
11517
|
+
return value;
|
|
11518
|
+
};
|
|
11519
|
+
const applyDeclarations = (elements, declarations) => {
|
|
11520
|
+
for (const el of elements) {
|
|
11521
|
+
const inlineDeclMap = new Map(
|
|
11522
|
+
parseInlineSvgStyleDeclarations(el.getAttribute("style") || "").map(({ key, value }) => [key, value])
|
|
11523
|
+
);
|
|
11524
|
+
for (const { key, value } of declarations) {
|
|
11525
|
+
if (!value || inlineDeclMap.has(key)) continue;
|
|
11526
|
+
el.setAttribute(key, normalizePresentationValue(key, value));
|
|
11527
|
+
}
|
|
11528
|
+
}
|
|
11529
|
+
};
|
|
11530
|
+
const ruleRegex = /([^{}]+)\{([^}]*)\}/g;
|
|
11531
|
+
let ruleMatch;
|
|
11532
|
+
while (ruleMatch = ruleRegex.exec(cssText)) {
|
|
11533
|
+
const selectors = ruleMatch[1].split(",").map((s) => s.trim()).filter(Boolean);
|
|
11534
|
+
const declarations = parseInlineSvgStyleDeclarations(ruleMatch[2]).filter((d) => SVG_STYLE_PROPS.has(d.key));
|
|
11535
|
+
if (selectors.length === 0 || declarations.length === 0) continue;
|
|
11536
|
+
for (const selector of selectors) {
|
|
11537
|
+
if (!selector || selector.startsWith("@")) continue;
|
|
11538
|
+
const classOnlyMatch = selector.match(/^\.([A-Za-z_][\w-]*)$/);
|
|
11539
|
+
if (classOnlyMatch) {
|
|
11540
|
+
applyDeclarations(classIndex.get(classOnlyMatch[1]) ?? [], declarations);
|
|
11541
|
+
continue;
|
|
11542
|
+
}
|
|
11543
|
+
try {
|
|
11544
|
+
applyDeclarations(svg.querySelectorAll(selector), declarations);
|
|
11545
|
+
} catch {
|
|
11546
|
+
const classMatch = selector.match(/\.([A-Za-z0-9_-]+)/);
|
|
11547
|
+
if (classMatch) applyDeclarations(classIndex.get(classMatch[1]) ?? [], declarations);
|
|
11548
|
+
}
|
|
11549
|
+
}
|
|
11550
|
+
}
|
|
11551
|
+
for (const el of allElements) {
|
|
11552
|
+
const style = el.getAttribute("style");
|
|
11553
|
+
if (!style) continue;
|
|
11554
|
+
const keptDecls = [];
|
|
11555
|
+
let changed = false;
|
|
11556
|
+
for (const { key, value } of parseInlineSvgStyleDeclarations(style)) {
|
|
11557
|
+
if (SVG_STYLE_PROPS.has(key)) {
|
|
11558
|
+
el.setAttribute(key, normalizePresentationValue(key, value));
|
|
11559
|
+
changed = true;
|
|
11560
|
+
} else {
|
|
11561
|
+
keptDecls.push(`${key}: ${value}`);
|
|
11562
|
+
}
|
|
11563
|
+
}
|
|
11564
|
+
if (changed) {
|
|
11565
|
+
if (keptDecls.length > 0) el.setAttribute("style", keptDecls.join("; "));
|
|
11566
|
+
else el.removeAttribute("style");
|
|
11567
|
+
}
|
|
11568
|
+
}
|
|
11569
|
+
for (const styleNode of styleNodes) {
|
|
11570
|
+
const css = styleNode.textContent || "";
|
|
11571
|
+
let cleaned = css;
|
|
11572
|
+
for (const prop of SVG_STYLE_PROPS) {
|
|
11573
|
+
const regex = new RegExp(`${prop.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&")}\\s*:\\s*[^;}{]+;?`, "gi");
|
|
11574
|
+
cleaned = cleaned.replace(regex, "");
|
|
11575
|
+
}
|
|
11576
|
+
styleNode.textContent = cleaned.replace(/;\s*;/g, ";").replace(/\{\s*;/g, "{").replace(/;\s*}/g, "}").replace(/\{\s*}/g, "{}");
|
|
11577
|
+
}
|
|
11578
|
+
}
|
|
11579
|
+
function normalizeSvgExplicitColors(svg) {
|
|
11580
|
+
const clone = svg.cloneNode(true);
|
|
11581
|
+
inlineSvgStyleBlockDeclarations(clone);
|
|
11582
|
+
const getAttr = (el, attr) => {
|
|
11583
|
+
var _a;
|
|
11584
|
+
const v = el.getAttribute(attr) ?? ((_a = el.style) == null ? void 0 : _a.getPropertyValue(attr));
|
|
11585
|
+
if (!v) return null;
|
|
11586
|
+
const s = v.trim().toLowerCase();
|
|
11587
|
+
if (!s || s === "none" || s === "transparent" || s === "currentcolor") return null;
|
|
11588
|
+
return normalizeGradientPaintRef(v);
|
|
11589
|
+
};
|
|
11590
|
+
const hasExplicitNonePaint = (el, attr) => {
|
|
11591
|
+
var _a, _b;
|
|
11592
|
+
const raw = (el.getAttribute(attr) ?? ((_a = el.style) == null ? void 0 : _a.getPropertyValue(attr)) ?? "").trim().toLowerCase();
|
|
11593
|
+
if (raw === "none" || raw === "transparent") return true;
|
|
11594
|
+
const rawOpacity = (el.getAttribute(`${attr}-opacity`) ?? ((_b = el.style) == null ? void 0 : _b.getPropertyValue(`${attr}-opacity`)) ?? "").trim().toLowerCase();
|
|
11595
|
+
return rawOpacity === "0" || rawOpacity === "0%" || rawOpacity === "0.0";
|
|
11596
|
+
};
|
|
11597
|
+
function walk(el, parentFill, parentStroke, parentColor) {
|
|
11598
|
+
var _a;
|
|
11599
|
+
if (isInSvgDefinitionSubtree(el)) {
|
|
11600
|
+
for (let i = 0; i < el.children.length; i++) walk(el.children[i], null, null, null);
|
|
11601
|
+
return;
|
|
11602
|
+
}
|
|
11603
|
+
const tag = ((_a = el.tagName) == null ? void 0 : _a.toLowerCase()) ?? "";
|
|
11604
|
+
const isDrawable = SVG_DRAWABLE_TAGS.has(tag);
|
|
11605
|
+
let fill = getAttr(el, "fill");
|
|
11606
|
+
let stroke = getAttr(el, "stroke");
|
|
11607
|
+
const color = getAttr(el, "color") ?? parentColor;
|
|
11608
|
+
const fillNone = hasExplicitNonePaint(el, "fill");
|
|
11609
|
+
const strokeNone = hasExplicitNonePaint(el, "stroke");
|
|
11610
|
+
const inheritedFill = parentFill === "none" ? null : parentFill;
|
|
11611
|
+
const inheritedStroke = parentStroke === "none" ? null : parentStroke;
|
|
11612
|
+
if (isDrawable) {
|
|
11613
|
+
if (fillNone) {
|
|
11614
|
+
el.setAttribute("fill", "none");
|
|
11615
|
+
fill = null;
|
|
11616
|
+
} else {
|
|
11617
|
+
const resolved = fill ?? color ?? inheritedFill;
|
|
11618
|
+
if (resolved) {
|
|
11619
|
+
el.setAttribute("fill", resolved);
|
|
11620
|
+
fill = resolved;
|
|
11621
|
+
} else if (tag !== "text" && tag !== "tspan") {
|
|
11622
|
+
el.setAttribute("fill", "none");
|
|
11623
|
+
fill = null;
|
|
11624
|
+
}
|
|
11625
|
+
}
|
|
11626
|
+
}
|
|
11627
|
+
if (isDrawable) {
|
|
11628
|
+
if (strokeNone) {
|
|
11629
|
+
el.setAttribute("stroke", "none");
|
|
11630
|
+
stroke = null;
|
|
11631
|
+
} else if (stroke != null || color != null || inheritedStroke != null) {
|
|
11632
|
+
const resolved = stroke ?? color ?? inheritedStroke;
|
|
11633
|
+
if (resolved) {
|
|
11634
|
+
el.setAttribute("stroke", resolved);
|
|
11635
|
+
stroke = resolved;
|
|
11636
|
+
}
|
|
11637
|
+
}
|
|
11638
|
+
}
|
|
11639
|
+
const nextColor = color ?? parentColor;
|
|
11640
|
+
const nextFill = fillNone ? "none" : fill ?? inheritedFill;
|
|
11641
|
+
const nextStroke = strokeNone ? "none" : stroke ?? inheritedStroke;
|
|
11642
|
+
for (let i = 0; i < el.children.length; i++) walk(el.children[i], nextFill, nextStroke, nextColor);
|
|
11643
|
+
}
|
|
11644
|
+
const rootColor = getAttr(clone, "color") ?? (clone.getAttribute("color") || null);
|
|
11645
|
+
const rootFill = getAttr(clone, "fill") ?? rootColor;
|
|
11646
|
+
const rootStroke = getAttr(clone, "stroke") ?? rootColor;
|
|
11647
|
+
const rootFillNone = hasExplicitNonePaint(clone, "fill");
|
|
11648
|
+
const rootStrokeNone = hasExplicitNonePaint(clone, "stroke");
|
|
11649
|
+
if (rootFillNone) clone.setAttribute("fill", "none");
|
|
11650
|
+
else if (rootFill) clone.setAttribute("fill", rootFill);
|
|
11651
|
+
if (rootStrokeNone) clone.setAttribute("stroke", "none");
|
|
11652
|
+
else if (rootStroke) clone.setAttribute("stroke", rootStroke);
|
|
11653
|
+
for (let i = 0; i < clone.children.length; i++) {
|
|
11654
|
+
walk(clone.children[i], rootFillNone ? "none" : rootFill ?? null, rootStrokeNone ? "none" : rootStroke ?? null, rootColor);
|
|
11655
|
+
}
|
|
11656
|
+
return clone;
|
|
11657
|
+
}
|
|
11658
|
+
function bakeGroupOpacityIntoChildren(svg) {
|
|
11659
|
+
const DRAWABLE = /* @__PURE__ */ new Set(["path", "rect", "circle", "ellipse", "polygon", "polyline", "line", "text", "tspan"]);
|
|
11660
|
+
function walkAndBake(el, inheritedOpacity) {
|
|
11661
|
+
var _a, _b, _c;
|
|
11662
|
+
if (isInSvgDefinitionSubtree(el)) {
|
|
11663
|
+
for (let i = 0; i < el.children.length; i++) walkAndBake(el.children[i], 1);
|
|
11664
|
+
return;
|
|
11665
|
+
}
|
|
11666
|
+
const tag = ((_a = el.tagName) == null ? void 0 : _a.toLowerCase()) ?? "";
|
|
11667
|
+
const opacityAttr = parseSvgOpacity(el.getAttribute("opacity"));
|
|
11668
|
+
const styleOpacity = parseSvgOpacity(((_b = el.style) == null ? void 0 : _b.getPropertyValue("opacity")) || null);
|
|
11669
|
+
const ownOpacity = opacityAttr ?? styleOpacity ?? 1;
|
|
11670
|
+
const combinedOpacity = inheritedOpacity * ownOpacity;
|
|
11671
|
+
if (ownOpacity < 0.999) {
|
|
11672
|
+
el.removeAttribute("opacity");
|
|
11673
|
+
if ((_c = el.style) == null ? void 0 : _c.opacity) el.style.removeProperty("opacity");
|
|
11674
|
+
}
|
|
11675
|
+
if (DRAWABLE.has(tag) && combinedOpacity < 0.999) {
|
|
11676
|
+
multiplySvgOpacityAttr(el, "fill-opacity", combinedOpacity);
|
|
11677
|
+
multiplySvgOpacityAttr(el, "stroke-opacity", combinedOpacity);
|
|
11678
|
+
}
|
|
11679
|
+
if (tag === "stop" && ownOpacity < 0.999) {
|
|
11680
|
+
multiplySvgOpacityAttr(el, "stop-opacity", ownOpacity);
|
|
11681
|
+
}
|
|
11682
|
+
for (let i = 0; i < el.children.length; i++) walkAndBake(el.children[i], combinedOpacity);
|
|
11683
|
+
}
|
|
11684
|
+
walkAndBake(svg, 1);
|
|
11685
|
+
}
|
|
11686
|
+
function hasInvalidSvgNumericToken(value) {
|
|
11687
|
+
return typeof value === "string" && /\b(?:NaN|-?Infinity)\b/.test(value);
|
|
11688
|
+
}
|
|
11689
|
+
function sanitizeSvgNumericTokens(value) {
|
|
11690
|
+
return value.replace(/\bNaN\b/g, "0").replace(/\b-?Infinity\b/g, "0");
|
|
11691
|
+
}
|
|
11692
|
+
function sanitizeSvgTreeForPdf(svg) {
|
|
11693
|
+
const attrsToSanitize = [
|
|
11694
|
+
"d",
|
|
11695
|
+
"points",
|
|
11696
|
+
"transform",
|
|
11697
|
+
"gradientTransform",
|
|
11698
|
+
"patternTransform",
|
|
11699
|
+
"viewBox",
|
|
11700
|
+
"x",
|
|
11701
|
+
"y",
|
|
11702
|
+
"x1",
|
|
11703
|
+
"y1",
|
|
11704
|
+
"x2",
|
|
11705
|
+
"y2",
|
|
11706
|
+
"cx",
|
|
11707
|
+
"cy",
|
|
11708
|
+
"r",
|
|
11709
|
+
"rx",
|
|
11710
|
+
"ry",
|
|
11711
|
+
"width",
|
|
11712
|
+
"height",
|
|
11713
|
+
"dx",
|
|
11714
|
+
"dy",
|
|
11715
|
+
"opacity",
|
|
11716
|
+
"fill-opacity",
|
|
11717
|
+
"stroke-opacity",
|
|
11718
|
+
"stroke-width",
|
|
11719
|
+
"stroke-dashoffset",
|
|
11720
|
+
"font-size",
|
|
11721
|
+
"letter-spacing",
|
|
11722
|
+
"word-spacing"
|
|
11723
|
+
];
|
|
11724
|
+
const nodes = [svg, ...Array.from(svg.querySelectorAll("*"))];
|
|
11725
|
+
for (const node of nodes) {
|
|
11726
|
+
for (const attr of attrsToSanitize) {
|
|
11727
|
+
const value = node.getAttribute(attr);
|
|
11728
|
+
if (!hasInvalidSvgNumericToken(value)) continue;
|
|
11729
|
+
node.setAttribute(attr, sanitizeSvgNumericTokens(value));
|
|
11730
|
+
}
|
|
11731
|
+
}
|
|
11732
|
+
}
|
|
11733
|
+
function normalizeSvgGradientStopOffsets(svg) {
|
|
11734
|
+
for (const stop of svg.querySelectorAll("linearGradient stop, radialGradient stop")) {
|
|
11735
|
+
const offset = stop.getAttribute("offset");
|
|
11736
|
+
if (!offset) continue;
|
|
11737
|
+
const trimmed = offset.trim();
|
|
11738
|
+
if (trimmed.endsWith("%")) {
|
|
11739
|
+
const num = parseFloat(trimmed.slice(0, -1)) / 100;
|
|
11740
|
+
if (Number.isFinite(num)) stop.setAttribute("offset", String(Math.max(0, Math.min(1, num))));
|
|
11741
|
+
}
|
|
11742
|
+
}
|
|
11743
|
+
}
|
|
11744
|
+
function copyGradientAttrsFromRef(gradient, ref) {
|
|
11745
|
+
var _a;
|
|
11746
|
+
const tag = (_a = gradient.tagName) == null ? void 0 : _a.toLowerCase();
|
|
11747
|
+
const attrs = tag === "radialgradient" ? GRADIENT_ATTRS_RADIAL : GRADIENT_ATTRS_LINEAR;
|
|
11748
|
+
for (const name of attrs) {
|
|
11749
|
+
if (!gradient.hasAttribute(name) && ref.hasAttribute(name)) {
|
|
11750
|
+
gradient.setAttribute(name, ref.getAttribute(name));
|
|
11751
|
+
}
|
|
11752
|
+
}
|
|
11753
|
+
}
|
|
11754
|
+
function expandSvgGradientHrefs(svg) {
|
|
11755
|
+
const visited = /* @__PURE__ */ new Set();
|
|
11756
|
+
function expand(gradient) {
|
|
11757
|
+
const id = gradient.getAttribute("id");
|
|
11758
|
+
if (!id || visited.has(id)) return;
|
|
11759
|
+
visited.add(id);
|
|
11760
|
+
if (gradient.querySelectorAll("stop").length > 0) return;
|
|
11761
|
+
const href = (gradient.getAttribute("href") || gradient.getAttribute("xlink:href") || "").trim();
|
|
11762
|
+
if (!href.startsWith("#")) return;
|
|
11763
|
+
const ref = findGradientInTree(svg, href.slice(1));
|
|
11764
|
+
if (!ref) return;
|
|
11765
|
+
expand(ref);
|
|
11766
|
+
copyGradientAttrsFromRef(gradient, ref);
|
|
11767
|
+
for (const stop of ref.querySelectorAll("stop")) gradient.appendChild(stop.cloneNode(true));
|
|
11768
|
+
gradient.removeAttribute("href");
|
|
11769
|
+
gradient.removeAttribute("xlink:href");
|
|
11770
|
+
}
|
|
11771
|
+
for (const g of svg.querySelectorAll("linearGradient, radialGradient")) expand(g);
|
|
11772
|
+
}
|
|
11773
|
+
function expandSvgUseElements(svg) {
|
|
11774
|
+
var _a;
|
|
11775
|
+
const doc = svg.ownerDocument;
|
|
11776
|
+
for (const use of Array.from(svg.querySelectorAll("use"))) {
|
|
11777
|
+
const ref = (use.getAttribute("href") || use.getAttribute("xlink:href") || "").trim();
|
|
11778
|
+
if (!ref.startsWith("#")) continue;
|
|
11779
|
+
const target = doc.getElementById(ref.slice(1));
|
|
11780
|
+
if (!target) continue;
|
|
11781
|
+
const x = parseFloat(use.getAttribute("x") || "0") || 0;
|
|
11782
|
+
const y = parseFloat(use.getAttribute("y") || "0") || 0;
|
|
11783
|
+
const w = parseFloat(use.getAttribute("width") || "0") || 0;
|
|
11784
|
+
const h = parseFloat(use.getAttribute("height") || "0") || 0;
|
|
11785
|
+
const g = doc.createElementNS("http://www.w3.org/2000/svg", "g");
|
|
11786
|
+
if (((_a = target.tagName) == null ? void 0 : _a.toLowerCase()) === "symbol") {
|
|
11787
|
+
const viewBox = target.getAttribute("viewBox");
|
|
11788
|
+
for (let i = 0; i < target.children.length; i++) g.appendChild(target.children[i].cloneNode(true));
|
|
11789
|
+
if (viewBox && w && h) {
|
|
11790
|
+
const parts = viewBox.split(/\s+/).map(Number);
|
|
11791
|
+
const vbW = parts[2];
|
|
11792
|
+
const vbH = parts[3];
|
|
11793
|
+
if (vbW && vbH) g.setAttribute("transform", `translate(${x},${y}) scale(${w / vbW},${h / vbH})`);
|
|
11794
|
+
else g.setAttribute("transform", `translate(${x},${y})`);
|
|
11795
|
+
} else if (x || y) g.setAttribute("transform", `translate(${x},${y})`);
|
|
11796
|
+
} else {
|
|
11797
|
+
const clone = target.cloneNode(true);
|
|
11798
|
+
if (x || y) g.setAttribute("transform", `translate(${x},${y})`);
|
|
11799
|
+
g.appendChild(clone);
|
|
11800
|
+
}
|
|
11801
|
+
if (use.parentNode) use.parentNode.replaceChild(g, use);
|
|
11802
|
+
}
|
|
11803
|
+
}
|
|
11804
|
+
function normalizeSvgViewBoxOrigin(svg) {
|
|
11805
|
+
const viewBox = svg.getAttribute("viewBox");
|
|
11806
|
+
if (!viewBox) return;
|
|
11807
|
+
const parts = viewBox.split(/[\s,]+/).map(Number.parseFloat).filter(Number.isFinite);
|
|
11808
|
+
if (parts.length !== 4) return;
|
|
11809
|
+
const [vx, vy, vw, vh] = parts;
|
|
11810
|
+
if (vw <= 0 || vh <= 0) return;
|
|
11811
|
+
if (Math.abs(vx) < 1e-3 && Math.abs(vy) < 1e-3) return;
|
|
11812
|
+
const doc = svg.ownerDocument;
|
|
11813
|
+
if (!doc) return;
|
|
11814
|
+
const keepAtRoot = /* @__PURE__ */ new Set(["defs", "style", "title", "desc", "metadata"]);
|
|
11815
|
+
const translatableChildren = Array.from(svg.children).filter((c) => !keepAtRoot.has(c.tagName.toLowerCase()));
|
|
11816
|
+
if (translatableChildren.length === 0) {
|
|
11817
|
+
svg.setAttribute("viewBox", `0 0 ${vw} ${vh}`);
|
|
11818
|
+
return;
|
|
11819
|
+
}
|
|
11820
|
+
const wrapper = doc.createElementNS("http://www.w3.org/2000/svg", "g");
|
|
11821
|
+
wrapper.setAttribute("transform", `translate(${-vx} ${-vy})`);
|
|
11822
|
+
for (const child of translatableChildren) wrapper.appendChild(child);
|
|
11823
|
+
svg.appendChild(wrapper);
|
|
11824
|
+
svg.setAttribute("viewBox", `0 0 ${vw} ${vh}`);
|
|
11825
|
+
}
|
|
11826
|
+
function stripRootPageBackgroundFromSvg(svg) {
|
|
11827
|
+
for (const child of Array.from(svg.children)) {
|
|
11828
|
+
const tag = child.tagName.toLowerCase();
|
|
11829
|
+
if (tag !== "rect" && tag !== "path") continue;
|
|
11830
|
+
const x = Number.parseFloat(child.getAttribute("x") || "0");
|
|
11831
|
+
const y = Number.parseFloat(child.getAttribute("y") || "0");
|
|
11832
|
+
const width = Number.parseFloat(child.getAttribute("width") || "0");
|
|
11833
|
+
const height = Number.parseFloat(child.getAttribute("height") || "0");
|
|
11834
|
+
const fill = child.getAttribute("fill") || getInlineStyleValue(child, "fill");
|
|
11835
|
+
const stroke = child.getAttribute("stroke") || getInlineStyleValue(child, "stroke");
|
|
11836
|
+
const opacity = parseSvgOpacity(child.getAttribute("opacity")) ?? 1;
|
|
11837
|
+
const isFullPageRect = tag === "rect" && Math.abs(x) < 0.01 && Math.abs(y) < 0.01 && Math.abs(width - Number.parseFloat(svg.getAttribute("width") || "0")) < 0.5 && Math.abs(height - Number.parseFloat(svg.getAttribute("height") || "0")) < 0.5;
|
|
11838
|
+
const isVisiblePaint = opacity > 1e-4 && !isTransparentColorToken(fill) && (!stroke || isTransparentColorToken(stroke));
|
|
11839
|
+
if (isFullPageRect && isVisiblePaint) {
|
|
11840
|
+
child.remove();
|
|
11841
|
+
return;
|
|
11842
|
+
}
|
|
11843
|
+
}
|
|
11844
|
+
}
|
|
11845
|
+
function stripSuspiciousFullPageOverlayNodes(svg) {
|
|
11846
|
+
const pageWidth = Number.parseFloat(svg.getAttribute("width") || "0");
|
|
11847
|
+
const pageHeight = Number.parseFloat(svg.getAttribute("height") || "0");
|
|
11848
|
+
if (!(pageWidth > 0 && pageHeight > 0)) return;
|
|
11849
|
+
const isNear = (a, b, tolerance = 0.75) => Math.abs(a - b) <= tolerance;
|
|
11850
|
+
const isDarkPaint = (value) => {
|
|
11851
|
+
const rgb = value ? parseColor(value) : null;
|
|
11852
|
+
return rgb ? rgb.r <= 32 && rgb.g <= 32 && rgb.b <= 32 : false;
|
|
11853
|
+
};
|
|
11854
|
+
const removeIfSuspicious = (el) => {
|
|
11855
|
+
const opacity = parseSvgOpacity(el.getAttribute("opacity")) ?? parseSvgOpacity(getInlineStyleValue(el, "opacity")) ?? 1;
|
|
11856
|
+
if (opacity <= 1e-3) return;
|
|
11857
|
+
const fill = el.getAttribute("fill") || getInlineStyleValue(el, "fill");
|
|
11858
|
+
const stroke = el.getAttribute("stroke") || getInlineStyleValue(el, "stroke");
|
|
11859
|
+
if (!isDarkPaint(fill) && !isDarkPaint(stroke)) return;
|
|
11860
|
+
const w = Number.parseFloat(el.getAttribute("width") || "0");
|
|
11861
|
+
const h = Number.parseFloat(el.getAttribute("height") || "0");
|
|
11862
|
+
const x = Number.parseFloat(el.getAttribute("x") || "0");
|
|
11863
|
+
const y = Number.parseFloat(el.getAttribute("y") || "0");
|
|
11864
|
+
const isRectLike = el.tagName.toLowerCase() === "rect" && isNear(x, 0) && isNear(y, 0) && isNear(w, pageWidth, 1.5) && isNear(h, pageHeight, 1.5);
|
|
11865
|
+
if (isRectLike) el.remove();
|
|
11866
|
+
};
|
|
11867
|
+
for (const child of Array.from(svg.children)) {
|
|
11868
|
+
const tag = child.tagName.toLowerCase();
|
|
11869
|
+
if (["defs", "style", "title", "desc", "metadata"].includes(tag)) continue;
|
|
11870
|
+
if (tag === "g") {
|
|
11871
|
+
for (const gc of Array.from(child.children)) removeIfSuspicious(gc);
|
|
11872
|
+
}
|
|
11873
|
+
removeIfSuspicious(child);
|
|
11874
|
+
}
|
|
11875
|
+
}
|
|
11876
|
+
function decodeSvgDataUri(href) {
|
|
11877
|
+
if (!href.startsWith("data:image/svg+xml")) return null;
|
|
11878
|
+
const commaIdx = href.indexOf(",");
|
|
11879
|
+
if (commaIdx < 0) return null;
|
|
11880
|
+
const meta = href.slice(0, commaIdx).toLowerCase();
|
|
11881
|
+
const payload = href.slice(commaIdx + 1);
|
|
11882
|
+
try {
|
|
11883
|
+
if (meta.includes(";base64")) {
|
|
11884
|
+
const binary = atob(payload);
|
|
11885
|
+
const bytes = Uint8Array.from(binary, (char) => char.charCodeAt(0));
|
|
11886
|
+
return new TextDecoder("utf-8").decode(bytes);
|
|
11887
|
+
}
|
|
11888
|
+
return decodeURIComponent(payload);
|
|
11889
|
+
} catch {
|
|
11890
|
+
try {
|
|
11891
|
+
return atob(payload);
|
|
11892
|
+
} catch {
|
|
11893
|
+
return null;
|
|
11894
|
+
}
|
|
11895
|
+
}
|
|
11896
|
+
}
|
|
11897
|
+
function inlineNestedSvgImageDataUris(svgString, domParser = new DOMParser()) {
|
|
11898
|
+
var _a;
|
|
11899
|
+
try {
|
|
11900
|
+
const doc = domParser.parseFromString(svgString, "image/svg+xml");
|
|
11901
|
+
if (doc.querySelector("parsererror")) return svgString;
|
|
11902
|
+
const root = doc.documentElement;
|
|
11903
|
+
if (!root || root.tagName.toLowerCase() !== "svg") return svgString;
|
|
11904
|
+
let changed = false;
|
|
11905
|
+
for (const img of Array.from(doc.querySelectorAll("image"))) {
|
|
11906
|
+
const href = img.getAttribute("href") || img.getAttributeNS("http://www.w3.org/1999/xlink", "href");
|
|
11907
|
+
if (!href || !href.startsWith("data:image/svg+xml")) continue;
|
|
11908
|
+
try {
|
|
11909
|
+
const svgContent = decodeSvgDataUri(href);
|
|
11910
|
+
if (!svgContent || !/<svg[\s>]/i.test(svgContent)) continue;
|
|
11911
|
+
const innerDoc = domParser.parseFromString(svgContent, "image/svg+xml");
|
|
11912
|
+
if (innerDoc.querySelector("parsererror")) continue;
|
|
11913
|
+
const innerSvg = innerDoc.documentElement;
|
|
11914
|
+
if (!innerSvg || innerSvg.tagName.toLowerCase() !== "svg") continue;
|
|
11915
|
+
const ix = parseFloat(img.getAttribute("x") || "0") || 0;
|
|
11916
|
+
const iy = parseFloat(img.getAttribute("y") || "0") || 0;
|
|
11917
|
+
const iw = parseFloat(img.getAttribute("width") || "0");
|
|
11918
|
+
const ih = parseFloat(img.getAttribute("height") || "0");
|
|
11919
|
+
if (!(iw > 0 && ih > 0)) continue;
|
|
11920
|
+
const nestedSvg = doc.importNode(innerSvg, true);
|
|
11921
|
+
if (!nestedSvg.getAttribute("viewBox")) nestedSvg.setAttribute("viewBox", `0 0 ${iw} ${ih}`);
|
|
11922
|
+
nestedSvg.setAttribute("x", "0");
|
|
11923
|
+
nestedSvg.setAttribute("y", "0");
|
|
11924
|
+
nestedSvg.setAttribute("width", String(iw));
|
|
11925
|
+
nestedSvg.setAttribute("height", String(ih));
|
|
11926
|
+
nestedSvg.setAttribute("preserveAspectRatio", img.getAttribute("preserveAspectRatio") || nestedSvg.getAttribute("preserveAspectRatio") || "xMidYMid meet");
|
|
11927
|
+
const g = doc.createElementNS("http://www.w3.org/2000/svg", "g");
|
|
11928
|
+
const existingTransform = img.getAttribute("transform") || "";
|
|
11929
|
+
g.setAttribute("transform", `${existingTransform}${existingTransform ? " " : ""}translate(${ix},${iy})`);
|
|
11930
|
+
for (const attr of Array.from(img.attributes)) {
|
|
11931
|
+
if (["id", "class", "style", "opacity", "display", "visibility", "clip-path", "mask", "filter", "pointer-events"].includes(attr.name)) {
|
|
11932
|
+
g.setAttribute(attr.name, attr.value);
|
|
11933
|
+
}
|
|
11934
|
+
}
|
|
11935
|
+
g.appendChild(nestedSvg);
|
|
11936
|
+
(_a = img.parentNode) == null ? void 0 : _a.replaceChild(g, img);
|
|
11937
|
+
changed = true;
|
|
11938
|
+
} catch {
|
|
11939
|
+
}
|
|
11940
|
+
}
|
|
11941
|
+
return changed ? new XMLSerializer().serializeToString(doc.documentElement) : svgString;
|
|
11942
|
+
} catch {
|
|
11943
|
+
return svgString;
|
|
11944
|
+
}
|
|
11945
|
+
}
|
|
11946
|
+
function inlineComputedStyles(svg) {
|
|
11947
|
+
if (typeof document === "undefined") return;
|
|
11948
|
+
const wrap = document.createElement("div");
|
|
11949
|
+
wrap.style.cssText = "position:fixed;left:-9999px;top:0;width:400px;height:400px;overflow:hidden;pointer-events:none";
|
|
11950
|
+
const root = svg;
|
|
11951
|
+
if (!root.hasAttribute("width")) root.setAttribute("width", "400");
|
|
11952
|
+
if (!root.hasAttribute("height")) root.setAttribute("height", "400");
|
|
11953
|
+
wrap.appendChild(root);
|
|
11954
|
+
document.body.appendChild(wrap);
|
|
11955
|
+
try {
|
|
11956
|
+
let walk = function(el) {
|
|
11957
|
+
var _a;
|
|
11958
|
+
const tag = (_a = el.tagName) == null ? void 0 : _a.toLowerCase();
|
|
11959
|
+
if (drawableTags.includes(tag)) {
|
|
11960
|
+
const cs = window.getComputedStyle(el);
|
|
11961
|
+
const fill = cs.fill;
|
|
11962
|
+
const stroke = cs.stroke;
|
|
11963
|
+
if (fill && fill !== "none" && fill !== "rgba(0, 0, 0, 0)") {
|
|
11964
|
+
const parsed = parseColor(fill);
|
|
11965
|
+
if (parsed) el.setAttribute("fill", rgbToHex(parsed.r, parsed.g, parsed.b));
|
|
11966
|
+
} else if (fill === "rgba(0, 0, 0, 0)" || fill === "transparent") {
|
|
11967
|
+
el.setAttribute("fill", "none");
|
|
11968
|
+
}
|
|
11969
|
+
if (stroke && stroke !== "none" && stroke !== "rgba(0, 0, 0, 0)") {
|
|
11970
|
+
const parsed = parseColor(stroke);
|
|
11971
|
+
if (parsed) el.setAttribute("stroke", rgbToHex(parsed.r, parsed.g, parsed.b));
|
|
11972
|
+
}
|
|
11973
|
+
}
|
|
11974
|
+
for (let i = 0; i < el.children.length; i++) walk(el.children[i]);
|
|
11975
|
+
};
|
|
11976
|
+
const drawableTags = ["path", "rect", "circle", "ellipse", "polygon", "polyline", "line", "text", "tspan"];
|
|
11977
|
+
walk(root);
|
|
11978
|
+
root.remove();
|
|
11979
|
+
} finally {
|
|
11980
|
+
if (wrap.parentNode) document.body.removeChild(wrap);
|
|
11981
|
+
}
|
|
11982
|
+
}
|
|
11983
|
+
function prefixSvgIds(svg, prefix) {
|
|
11984
|
+
const safePrefix = String(prefix).replace(/[^a-zA-Z0-9-]/g, "_");
|
|
11985
|
+
const idMap = /* @__PURE__ */ new Map();
|
|
11986
|
+
svg.querySelectorAll("[id]").forEach((el) => {
|
|
11987
|
+
const id = el.getAttribute("id");
|
|
11988
|
+
if (id) idMap.set(id, `${safePrefix}_${id}`);
|
|
11989
|
+
});
|
|
11990
|
+
if (idMap.size === 0) return;
|
|
11991
|
+
idMap.forEach((newId, oldId) => {
|
|
11992
|
+
svg.querySelectorAll(`[id="${oldId}"]`).forEach((el) => el.setAttribute("id", newId));
|
|
11993
|
+
});
|
|
11994
|
+
const replaceUrlRefs = (value) => {
|
|
11995
|
+
return value.replace(/url\(\s*(['"]?)([^)]+?)\1\s*\)/gi, (full, quoteRaw, refRaw) => {
|
|
11996
|
+
const ref = String(refRaw || "").trim();
|
|
11997
|
+
const hashIdx = ref.lastIndexOf("#");
|
|
11998
|
+
if (hashIdx < 0 || hashIdx === ref.length - 1) return full;
|
|
11999
|
+
const base = ref.slice(0, hashIdx + 1);
|
|
12000
|
+
const oldId = ref.slice(hashIdx + 1).trim().replace(/[\s"')].*$/, "");
|
|
12001
|
+
const mapped = idMap.get(oldId);
|
|
12002
|
+
if (!mapped) return full;
|
|
12003
|
+
const quote = String(quoteRaw || "");
|
|
12004
|
+
return `url(${quote}${base}${mapped}${quote})`;
|
|
12005
|
+
});
|
|
12006
|
+
};
|
|
12007
|
+
const replaceHrefRef = (value) => {
|
|
12008
|
+
const trimmed = value.trim();
|
|
12009
|
+
if (trimmed.startsWith("#")) {
|
|
12010
|
+
const mapped = idMap.get(trimmed.slice(1));
|
|
12011
|
+
return mapped ? `#${mapped}` : value;
|
|
12012
|
+
}
|
|
12013
|
+
return replaceUrlRefs(value);
|
|
12014
|
+
};
|
|
12015
|
+
const refAttrs = ["fill", "stroke", "clip-path", "mask", "filter", "href", "xlink:href", "marker-start", "marker-mid", "marker-end"];
|
|
12016
|
+
svg.querySelectorAll("*").forEach((el) => {
|
|
12017
|
+
refAttrs.forEach((attr) => {
|
|
12018
|
+
const val = el.getAttribute(attr);
|
|
12019
|
+
if (!val) return;
|
|
12020
|
+
const next = attr === "href" || attr === "xlink:href" ? replaceHrefRef(val) : replaceUrlRefs(val);
|
|
12021
|
+
if (next !== val) el.setAttribute(attr, next);
|
|
12022
|
+
});
|
|
12023
|
+
const style = el.getAttribute("style");
|
|
12024
|
+
if (style) {
|
|
12025
|
+
const nextStyle = replaceUrlRefs(style);
|
|
12026
|
+
if (nextStyle !== style) el.setAttribute("style", nextStyle);
|
|
12027
|
+
}
|
|
12028
|
+
});
|
|
12029
|
+
svg.querySelectorAll("style").forEach((styleNode) => {
|
|
12030
|
+
const text = styleNode.textContent || "";
|
|
12031
|
+
const next = replaceUrlRefs(text);
|
|
12032
|
+
if (next !== text) styleNode.textContent = next;
|
|
12033
|
+
});
|
|
12034
|
+
}
|
|
12035
|
+
function getFirstExplicitColorFromSvg(svg) {
|
|
12036
|
+
let fill = null;
|
|
12037
|
+
let stroke = null;
|
|
12038
|
+
const isRealColor = (v) => {
|
|
12039
|
+
if (!v || v === "none") return false;
|
|
12040
|
+
const s = v.trim().toLowerCase();
|
|
12041
|
+
return s !== "currentcolor" && s !== "inherit" && (s.startsWith("#") || s.startsWith("rgb"));
|
|
12042
|
+
};
|
|
12043
|
+
const resolveUrl = (v) => {
|
|
12044
|
+
if (!v || v === "none") return null;
|
|
12045
|
+
const gradientId = extractGradientIdFromPaint(v);
|
|
12046
|
+
if (!gradientId) return null;
|
|
12047
|
+
return getGradientStopColorAsHex(svg, gradientId);
|
|
12048
|
+
};
|
|
12049
|
+
function walk(el) {
|
|
12050
|
+
var _a, _b;
|
|
12051
|
+
if (fill && stroke) return;
|
|
12052
|
+
const f = el.getAttribute("fill") ?? ((_a = el.style) == null ? void 0 : _a.getPropertyValue("fill"));
|
|
12053
|
+
const s = el.getAttribute("stroke") ?? ((_b = el.style) == null ? void 0 : _b.getPropertyValue("stroke"));
|
|
12054
|
+
if (!fill) {
|
|
12055
|
+
if (isRealColor(f)) fill = f;
|
|
12056
|
+
else if (f) {
|
|
12057
|
+
const resolved = resolveUrl(f);
|
|
12058
|
+
if (resolved) fill = resolved;
|
|
12059
|
+
}
|
|
12060
|
+
}
|
|
12061
|
+
if (!stroke) {
|
|
12062
|
+
if (isRealColor(s)) stroke = s;
|
|
12063
|
+
else if (s) {
|
|
12064
|
+
const resolved = resolveUrl(s);
|
|
12065
|
+
if (resolved) stroke = resolved;
|
|
12066
|
+
}
|
|
12067
|
+
}
|
|
12068
|
+
for (let i = 0; i < el.children.length; i++) walk(el.children[i]);
|
|
12069
|
+
}
|
|
12070
|
+
walk(svg);
|
|
12071
|
+
return { fill, stroke };
|
|
12072
|
+
}
|
|
12073
|
+
function isNearWhite(hex) {
|
|
12074
|
+
if (!/^#[0-9a-f]{6}$/i.test(hex)) return false;
|
|
12075
|
+
const r = parseInt(hex.slice(1, 3), 16);
|
|
12076
|
+
const g = parseInt(hex.slice(3, 5), 16);
|
|
12077
|
+
const b = parseInt(hex.slice(5, 7), 16);
|
|
12078
|
+
return r >= 250 && g >= 250 && b >= 250;
|
|
12079
|
+
}
|
|
12080
|
+
function getStopColorRaw(stop) {
|
|
12081
|
+
var _a, _b;
|
|
12082
|
+
return stop.getAttribute("stop-color") ?? ((_b = (_a = stop.style) == null ? void 0 : _a.getPropertyValue("stop-color")) == null ? void 0 : _b.trim()) ?? getInlineStyleValue(stop, "stop-color");
|
|
12083
|
+
}
|
|
12084
|
+
function getGradientStopColorAsHex(svgRoot, gradientId, visited = /* @__PURE__ */ new Set()) {
|
|
12085
|
+
var _a;
|
|
12086
|
+
if (visited.has(gradientId)) return null;
|
|
12087
|
+
visited.add(gradientId);
|
|
12088
|
+
const gradient = findGradientInTree(svgRoot, gradientId);
|
|
12089
|
+
if (!gradient) return null;
|
|
12090
|
+
const tag = (_a = gradient.tagName) == null ? void 0 : _a.toLowerCase();
|
|
12091
|
+
if (tag !== "lineargradient" && tag !== "radialgradient") return null;
|
|
12092
|
+
const stops = Array.from(gradient.querySelectorAll("stop"));
|
|
12093
|
+
if (stops.length > 0) {
|
|
12094
|
+
const first = getStopColorRaw(stops[0]);
|
|
12095
|
+
const last = getStopColorRaw(stops[stops.length - 1]);
|
|
12096
|
+
const firstHex = first ? cssColorToHex(first) : null;
|
|
12097
|
+
const lastHex = last ? cssColorToHex(last) : null;
|
|
12098
|
+
if (firstHex && !isNearWhite(firstHex)) return firstHex;
|
|
12099
|
+
if (lastHex && !isNearWhite(lastHex)) return lastHex;
|
|
12100
|
+
return firstHex ?? lastHex;
|
|
12101
|
+
}
|
|
12102
|
+
const href = (gradient.getAttribute("href") || gradient.getAttribute("xlink:href") || "").trim();
|
|
12103
|
+
if (href.startsWith("#")) return getGradientStopColorAsHex(svgRoot, href.slice(1), visited);
|
|
12104
|
+
return null;
|
|
12105
|
+
}
|
|
12106
|
+
function setPdfColorFromSvg(pdf, svg, _elementId) {
|
|
12107
|
+
const { fill, stroke } = getFirstExplicitColorFromSvg(svg);
|
|
12108
|
+
const setColor = (hex, setter) => {
|
|
12109
|
+
if (!hex) return;
|
|
12110
|
+
const c = parseColor(hex);
|
|
12111
|
+
if (c) pdf[setter](c.r, c.g, c.b);
|
|
12112
|
+
};
|
|
12113
|
+
setColor(fill, "setFillColor");
|
|
12114
|
+
setColor(stroke ?? fill, "setDrawColor");
|
|
12115
|
+
}
|
|
12116
|
+
function svg2pdfOpts(x, y, width, height) {
|
|
12117
|
+
const sanitize = (value, fallback) => Number.isFinite(value) ? Number(value.toFixed(3)) : fallback;
|
|
12118
|
+
const w = Math.max(1e-3, sanitize(width, 1));
|
|
12119
|
+
const h = Math.max(1e-3, sanitize(height, 1));
|
|
12120
|
+
return { x: sanitize(x, 0), y: sanitize(y, 0), width: w, height: h };
|
|
12121
|
+
}
|
|
12122
|
+
async function svg2pdfWithDomMount(svg, pdf, opts) {
|
|
12123
|
+
const wrap = document.createElement("div");
|
|
12124
|
+
wrap.style.cssText = "position:fixed;left:-9999px;top:0;width:0;height:0;overflow:hidden;pointer-events:none;opacity:0";
|
|
12125
|
+
wrap.appendChild(svg);
|
|
12126
|
+
document.body.appendChild(wrap);
|
|
12127
|
+
try {
|
|
12128
|
+
await svg2pdf_js.svg2pdf(svg, pdf, opts);
|
|
12129
|
+
} finally {
|
|
12130
|
+
svg.remove();
|
|
12131
|
+
if (wrap.parentNode) document.body.removeChild(wrap);
|
|
12132
|
+
}
|
|
12133
|
+
}
|
|
12134
|
+
function prepareLiveCanvasSvgForPdf(rawSvg, pageWidth, pageHeight, pageKey, options) {
|
|
12135
|
+
try {
|
|
12136
|
+
const parser = new DOMParser();
|
|
12137
|
+
const processedSvg = inlineNestedSvgImageDataUris(rawSvg, parser);
|
|
12138
|
+
const doc = parser.parseFromString(processedSvg, "image/svg+xml");
|
|
12139
|
+
if (doc.querySelector("parsererror")) return null;
|
|
12140
|
+
const svg = doc.documentElement;
|
|
12141
|
+
if (!svg || svg.tagName.toLowerCase() !== "svg") return null;
|
|
12142
|
+
svg.setAttribute("xmlns", "http://www.w3.org/2000/svg");
|
|
12143
|
+
if (/xlink:href/i.test(processedSvg) && !svg.getAttribute("xmlns:xlink")) {
|
|
12144
|
+
svg.setAttribute("xmlns:xlink", "http://www.w3.org/1999/xlink");
|
|
12145
|
+
}
|
|
12146
|
+
svg.setAttribute("width", String(pageWidth));
|
|
12147
|
+
svg.setAttribute("height", String(pageHeight));
|
|
12148
|
+
svg.setAttribute("viewBox", `0 0 ${pageWidth} ${pageHeight}`);
|
|
12149
|
+
sanitizeSvgTreeForPdf(svg);
|
|
12150
|
+
normalizeSvgViewBoxOrigin(svg);
|
|
12151
|
+
expandSvgUseElements(svg);
|
|
12152
|
+
const svgToDraw = normalizeSvgExplicitColors(svg);
|
|
12153
|
+
inlineComputedStyles(svgToDraw);
|
|
12154
|
+
sanitizeSvgTreeForPdf(svgToDraw);
|
|
12155
|
+
normalizeSvgGradientStopOffsets(svgToDraw);
|
|
12156
|
+
expandSvgGradientHrefs(svgToDraw);
|
|
12157
|
+
prefixSvgIds(svgToDraw, pageKey);
|
|
12158
|
+
bakeGroupOpacityIntoChildren(svgToDraw);
|
|
12159
|
+
stripSuspiciousFullPageOverlayNodes(svgToDraw);
|
|
12160
|
+
if (options == null ? void 0 : options.stripPageBackground) stripRootPageBackgroundFromSvg(svgToDraw);
|
|
12161
|
+
sanitizeSvgTreeForPdf(svgToDraw);
|
|
12162
|
+
return svgToDraw;
|
|
12163
|
+
} catch {
|
|
12164
|
+
return null;
|
|
12165
|
+
}
|
|
12166
|
+
}
|
|
12167
|
+
function drawPageBackground(pdf, pageIndex, pageWidth, pageHeight, backgroundColor, backgroundGradient) {
|
|
12168
|
+
var _a, _b;
|
|
12169
|
+
if (backgroundGradient && ((_a = backgroundGradient.stops) == null ? void 0 : _a.length) >= 2) {
|
|
12170
|
+
const grad = backgroundGradient;
|
|
12171
|
+
const colorStops = grad.stops.map((s) => {
|
|
12172
|
+
const c = parseColor(s.color);
|
|
12173
|
+
return {
|
|
12174
|
+
offset: Math.max(0, Math.min(1, Number(s.offset))),
|
|
12175
|
+
color: c ? [c.r, c.g, c.b] : [0, 0, 0]
|
|
12176
|
+
};
|
|
12177
|
+
}).filter((s) => Number.isFinite(s.offset)).sort((a, b) => a.offset - b.offset);
|
|
12178
|
+
const normalizedStops = [...colorStops];
|
|
12179
|
+
if (normalizedStops.length > 0) {
|
|
12180
|
+
if (normalizedStops[0].offset > 0) normalizedStops.unshift({ offset: 0, color: normalizedStops[0].color });
|
|
12181
|
+
if (normalizedStops[normalizedStops.length - 1].offset < 1) normalizedStops.push({ offset: 1, color: normalizedStops[normalizedStops.length - 1].color });
|
|
12182
|
+
}
|
|
12183
|
+
const shadingColors = normalizedStops.map((s) => ({ offset: s.offset, color: s.color }));
|
|
12184
|
+
const patternKey = `bg-grad-${pageIndex}`;
|
|
12185
|
+
try {
|
|
12186
|
+
pdf.advancedAPI((doc) => {
|
|
12187
|
+
const isLinear = grad.type === "linear";
|
|
12188
|
+
const isConic = grad.type === "conic";
|
|
12189
|
+
if (isLinear || isConic) {
|
|
12190
|
+
const angleDeg = grad.angle ?? (isConic ? 0 : 90);
|
|
12191
|
+
const angleRad = angleDeg * Math.PI / 180;
|
|
12192
|
+
const sinA = Math.sin(angleRad);
|
|
12193
|
+
const cosA = Math.cos(angleRad);
|
|
12194
|
+
const corners = [[0, 0], [pageWidth, 0], [pageWidth, pageHeight], [0, pageHeight]];
|
|
12195
|
+
const projs = corners.map(([x, y]) => x * sinA - y * cosA);
|
|
12196
|
+
const minP = Math.min(...projs);
|
|
12197
|
+
const maxP = Math.max(...projs);
|
|
12198
|
+
const halfLen = (maxP - minP) / 2;
|
|
12199
|
+
const midX = pageWidth / 2;
|
|
12200
|
+
const midY = pageHeight / 2;
|
|
12201
|
+
let finalStops = shadingColors;
|
|
12202
|
+
if (isConic && shadingColors.length >= 2) {
|
|
12203
|
+
const reversed = [...shadingColors].reverse().map((s) => ({ offset: 0.5 + (1 - s.offset) * 0.5, color: s.color }));
|
|
12204
|
+
const firstHalf = shadingColors.map((s) => ({ offset: s.offset * 0.5, color: s.color }));
|
|
12205
|
+
finalStops = [...firstHalf, ...reversed.slice(1)];
|
|
12206
|
+
}
|
|
12207
|
+
doc.addShadingPattern(patternKey, new jspdf.ShadingPattern("axial", [
|
|
12208
|
+
midX - sinA * halfLen,
|
|
12209
|
+
midY + cosA * halfLen,
|
|
12210
|
+
midX + sinA * halfLen,
|
|
12211
|
+
midY - cosA * halfLen
|
|
12212
|
+
], finalStops));
|
|
12213
|
+
} else {
|
|
12214
|
+
const cx = (grad.cx ?? 0.5) * pageWidth;
|
|
12215
|
+
const cy = (grad.cy ?? 0.5) * pageHeight;
|
|
12216
|
+
const maxR = (grad.r ?? 0.5) * Math.max(pageWidth, pageHeight);
|
|
12217
|
+
doc.addShadingPattern(patternKey, new jspdf.ShadingPattern("radial", [cx, cy, 0, cx, cy, maxR], shadingColors));
|
|
12218
|
+
}
|
|
12219
|
+
doc.rect(0, 0, pageWidth, pageHeight);
|
|
12220
|
+
doc.fill({ key: patternKey, matrix: doc.Matrix(1, 0, 0, 1, 0, 0) });
|
|
12221
|
+
});
|
|
12222
|
+
} catch {
|
|
12223
|
+
const fallback = ((_b = colorStops[0]) == null ? void 0 : _b.color) || [255, 255, 255];
|
|
12224
|
+
pdf.setFillColor(fallback[0], fallback[1], fallback[2]);
|
|
12225
|
+
pdf.rect(0, 0, pageWidth, pageHeight, "F");
|
|
12226
|
+
}
|
|
12227
|
+
} else {
|
|
12228
|
+
const bgColor = parseColor(backgroundColor && backgroundColor !== "transparent" ? backgroundColor : "#ffffff");
|
|
12229
|
+
if (bgColor) {
|
|
12230
|
+
pdf.setFillColor(bgColor.r, bgColor.g, bgColor.b);
|
|
12231
|
+
pdf.rect(0, 0, pageWidth, pageHeight, "F");
|
|
12232
|
+
}
|
|
12233
|
+
}
|
|
12234
|
+
}
|
|
12235
|
+
async function assemblePdfFromSvgs(svgResults, options = {}) {
|
|
12236
|
+
var _a, _b;
|
|
12237
|
+
if (svgResults.length === 0) throw new Error("No pages to export");
|
|
12238
|
+
const { title, stripPageBackground } = options;
|
|
12239
|
+
const firstPage = svgResults[0];
|
|
12240
|
+
const orientation = firstPage.width > firstPage.height ? "landscape" : "portrait";
|
|
12241
|
+
const pdf = new jspdf.jsPDF({
|
|
12242
|
+
orientation,
|
|
12243
|
+
unit: "px",
|
|
12244
|
+
format: [firstPage.width, firstPage.height],
|
|
12245
|
+
hotfixes: ["px_scaling"],
|
|
12246
|
+
compress: true
|
|
12247
|
+
});
|
|
12248
|
+
if (title) pdf.setProperties({ title, creator: "Pixldocs" });
|
|
12249
|
+
for (let i = 0; i < svgResults.length; i++) {
|
|
12250
|
+
const page = svgResults[i];
|
|
12251
|
+
if (i > 0) {
|
|
12252
|
+
const pageOrientation = page.width > page.height ? "landscape" : "portrait";
|
|
12253
|
+
pdf.addPage([page.width, page.height], pageOrientation);
|
|
12254
|
+
}
|
|
12255
|
+
const hasGradient = !!((_b = (_a = page.backgroundGradient) == null ? void 0 : _a.stops) == null ? void 0 : _b.length);
|
|
12256
|
+
drawPageBackground(pdf, i, page.width, page.height, page.backgroundColor, page.backgroundGradient);
|
|
12257
|
+
const shouldStripBg = stripPageBackground ?? hasGradient;
|
|
12258
|
+
const svgToDraw = prepareLiveCanvasSvgForPdf(page.svg, page.width, page.height, `page-${i + 1}`, {
|
|
12259
|
+
stripPageBackground: shouldStripBg
|
|
12260
|
+
});
|
|
12261
|
+
if (svgToDraw) {
|
|
12262
|
+
pdf.setFillColor(0, 0, 0);
|
|
12263
|
+
pdf.setDrawColor(0, 0, 0);
|
|
12264
|
+
pdf.saveGraphicsState();
|
|
12265
|
+
setPdfColorFromSvg(pdf, svgToDraw);
|
|
12266
|
+
await svg2pdfWithDomMount(svgToDraw, pdf, svg2pdfOpts(0, 0, page.width, page.height));
|
|
12267
|
+
pdf.restoreGraphicsState();
|
|
12268
|
+
pdf.setFillColor(0, 0, 0);
|
|
12269
|
+
pdf.setDrawColor(0, 0, 0);
|
|
12270
|
+
}
|
|
12271
|
+
}
|
|
12272
|
+
const arrayBuffer = pdf.output("arraybuffer");
|
|
12273
|
+
const blob = new Blob([arrayBuffer], { type: "application/pdf" });
|
|
12274
|
+
return {
|
|
12275
|
+
blob,
|
|
12276
|
+
arrayBuffer,
|
|
12277
|
+
totalPages: svgResults.length,
|
|
12278
|
+
pages: svgResults.map((p) => ({ width: p.width, height: p.height }))
|
|
12279
|
+
};
|
|
12280
|
+
}
|
|
12281
|
+
const pdfExport = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
12282
|
+
__proto__: null,
|
|
12283
|
+
assemblePdfFromSvgs
|
|
12284
|
+
}, Symbol.toStringTag, { value: "Module" }));
|
|
11223
12285
|
function collectImageUrls(config) {
|
|
11224
12286
|
const urls = [];
|
|
11225
12287
|
const walk = (nodes) => {
|
|
@@ -11299,6 +12361,7 @@ async function warmTemplateFromForm(options) {
|
|
|
11299
12361
|
exports.PixldocsPreview = PixldocsPreview;
|
|
11300
12362
|
exports.PixldocsRenderer = PixldocsRenderer;
|
|
11301
12363
|
exports.applyThemeToConfig = applyThemeToConfig;
|
|
12364
|
+
exports.assemblePdfFromSvgs = assemblePdfFromSvgs;
|
|
11302
12365
|
exports.collectFontDescriptorsFromConfig = collectFontDescriptorsFromConfig;
|
|
11303
12366
|
exports.collectFontsFromConfig = collectFontsFromConfig;
|
|
11304
12367
|
exports.collectImageUrls = collectImageUrls;
|