@pixldocs/canvas-renderer 0.5.222 → 0.5.225
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/dist/{index-BKJxI43i.cjs → index-6nrov1rx.cjs} +1488 -525
- package/dist/index-6nrov1rx.cjs.map +1 -0
- package/dist/{index-DxL--cfL.js → index-BpViFQMO.js} +1488 -525
- package/dist/index-BpViFQMO.js.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.js +1 -1
- package/dist/{vectorPdfExport-CDMnc_eW.cjs → vectorPdfExport-CVeK--lR.cjs} +325 -30
- package/dist/vectorPdfExport-CVeK--lR.cjs.map +1 -0
- package/dist/{vectorPdfExport-CTPOHXtQ.js → vectorPdfExport-D46sZGKA.js} +325 -30
- package/dist/vectorPdfExport-D46sZGKA.js.map +1 -0
- package/package.json +1 -1
- package/dist/index-BKJxI43i.cjs.map +0 -1
- package/dist/index-DxL--cfL.js.map +0 -1
- package/dist/vectorPdfExport-CDMnc_eW.cjs.map +0 -1
- package/dist/vectorPdfExport-CTPOHXtQ.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
-
const index = require("./index-
|
|
3
|
+
const index = require("./index-6nrov1rx.cjs");
|
|
4
4
|
exports.DEPLOYMENT_VERSION_MARKER = index.DEPLOYMENT_VERSION_MARKER;
|
|
5
5
|
exports.FONT_FALLBACK_DEVANAGARI = index.FONT_FALLBACK_DEVANAGARI;
|
|
6
6
|
exports.FONT_FALLBACK_MATH = index.FONT_FALLBACK_MATH;
|
package/dist/index.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ import { isBundledAssetUrl } from '../../../src/lib/canvasImageLoader';
|
|
|
9
9
|
import { isPrivateUrl } from '../../../src/lib/canvasImageLoader';
|
|
10
10
|
import { jsPDF } from 'jspdf';
|
|
11
11
|
import { JSX as JSX_2 } from 'react/jsx-runtime';
|
|
12
|
+
import { ReactNode } from 'react';
|
|
12
13
|
import { resolveBlurElementExactIdsFromFlatFormKeys } from '../../../src/lib/previewBlur';
|
|
13
14
|
import { ResolveBlurOptions } from '../../../src/lib/previewBlur';
|
|
14
15
|
import { SectionFormState } from '../../../src/lib/inferFormSchemaFromTemplate';
|
|
@@ -430,6 +431,8 @@ declare interface PixldocsPreviewBaseProps {
|
|
|
430
431
|
onReady?: () => void;
|
|
431
432
|
/** Called when resolution or rendering fails */
|
|
432
433
|
onError?: (error: Error) => void;
|
|
434
|
+
/** Optional custom UI shown while the live preview is preparing */
|
|
435
|
+
loadingFallback?: ReactNode;
|
|
433
436
|
/** Allow package previews to skip the blocking font-ready wait used by app preview */
|
|
434
437
|
skipFontReadyWait?: boolean;
|
|
435
438
|
/**
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { D, F, o, q, s, P, t, u, v, w, x, y, z, B, C, E, G, H, I, J, K, L, M, b, N, O, Q, R, S, U, V, W, X, Y, Z, _, $, a0, a1, a2, a3, a4, a5 } from "./index-
|
|
1
|
+
import { D, F, o, q, s, P, t, u, v, w, x, y, z, B, C, E, G, H, I, J, K, L, M, b, N, O, Q, R, S, U, V, W, X, Y, Z, _, $, a0, a1, a2, a3, a4, a5 } from "./index-BpViFQMO.js";
|
|
2
2
|
export {
|
|
3
3
|
D as DEPLOYMENT_VERSION_MARKER,
|
|
4
4
|
F as FONT_FALLBACK_DEVANAGARI,
|
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
|
3
3
|
const jspdf = require("jspdf");
|
|
4
4
|
const svg2pdf_js = require("svg2pdf.js");
|
|
5
5
|
const fabric = require("fabric");
|
|
6
|
-
const index = require("./index-
|
|
6
|
+
const index = require("./index-6nrov1rx.cjs");
|
|
7
7
|
const pdfFonts = require("./pdfFonts-BTj2f465.cjs");
|
|
8
8
|
function _interopNamespaceDefault(e) {
|
|
9
9
|
const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
|
|
@@ -1003,6 +1003,100 @@ function parseInlineSvgStyleDeclarations(styleText) {
|
|
|
1003
1003
|
};
|
|
1004
1004
|
}).filter((x) => !!x);
|
|
1005
1005
|
}
|
|
1006
|
+
function shortPdfDebug(value, max = 180) {
|
|
1007
|
+
if (!value) return null;
|
|
1008
|
+
const str = String(value).replace(/\s+/g, " ").trim();
|
|
1009
|
+
return str.length > max ? `${str.slice(0, max)}…` : str;
|
|
1010
|
+
}
|
|
1011
|
+
function logSvgGradientClipDiagnostics(stage, svg, context) {
|
|
1012
|
+
try {
|
|
1013
|
+
const gradients = Array.from(svg.querySelectorAll("linearGradient, radialGradient"));
|
|
1014
|
+
const images = Array.from(svg.querySelectorAll("image"));
|
|
1015
|
+
const nestedSvgs = Array.from(svg.querySelectorAll("svg")).filter((node) => node !== svg);
|
|
1016
|
+
const gradientRefs = [];
|
|
1017
|
+
Array.from(svg.querySelectorAll("*")).forEach((el) => {
|
|
1018
|
+
const fill = el.getAttribute("fill") || getInlineStyleValue(el, "fill");
|
|
1019
|
+
const stroke = el.getAttribute("stroke") || getInlineStyleValue(el, "stroke");
|
|
1020
|
+
const fillId = extractGradientIdFromPaint(fill);
|
|
1021
|
+
const strokeId = extractGradientIdFromPaint(stroke);
|
|
1022
|
+
if (!fillId && !strokeId) return;
|
|
1023
|
+
gradientRefs.push({
|
|
1024
|
+
tag: el.tagName,
|
|
1025
|
+
id: el.getAttribute("id"),
|
|
1026
|
+
className: el.getAttribute("class"),
|
|
1027
|
+
fill: shortPdfDebug(fill, 80),
|
|
1028
|
+
stroke: shortPdfDebug(stroke, 80),
|
|
1029
|
+
fillRule: el.getAttribute("fill-rule") || getInlineStyleValue(el, "fill-rule"),
|
|
1030
|
+
transform: shortPdfDebug(el.getAttribute("transform"), 120),
|
|
1031
|
+
dStart: shortPdfDebug(el.getAttribute("d"), 160)
|
|
1032
|
+
});
|
|
1033
|
+
});
|
|
1034
|
+
console.log("[client-pdf-export][gradient-svg-diag]", {
|
|
1035
|
+
stage,
|
|
1036
|
+
...context,
|
|
1037
|
+
root: {
|
|
1038
|
+
width: svg.getAttribute("width"),
|
|
1039
|
+
height: svg.getAttribute("height"),
|
|
1040
|
+
viewBox: svg.getAttribute("viewBox")
|
|
1041
|
+
},
|
|
1042
|
+
counts: {
|
|
1043
|
+
gradients: gradients.length,
|
|
1044
|
+
gradientRefs: gradientRefs.length,
|
|
1045
|
+
images: images.length,
|
|
1046
|
+
nestedSvgs: nestedSvgs.length,
|
|
1047
|
+
paths: svg.querySelectorAll("path").length,
|
|
1048
|
+
clips: svg.querySelectorAll("clipPath").length,
|
|
1049
|
+
masks: svg.querySelectorAll("mask").length
|
|
1050
|
+
},
|
|
1051
|
+
gradients: gradients.slice(0, 8).map((g) => ({
|
|
1052
|
+
tag: g.tagName,
|
|
1053
|
+
id: g.getAttribute("id"),
|
|
1054
|
+
units: g.getAttribute("gradientUnits"),
|
|
1055
|
+
transform: g.getAttribute("gradientTransform"),
|
|
1056
|
+
x1: g.getAttribute("x1"),
|
|
1057
|
+
y1: g.getAttribute("y1"),
|
|
1058
|
+
x2: g.getAttribute("x2"),
|
|
1059
|
+
y2: g.getAttribute("y2"),
|
|
1060
|
+
stops: Array.from(g.querySelectorAll("stop")).map((s) => ({ offset: s.getAttribute("offset"), color: s.getAttribute("stop-color"), opacity: s.getAttribute("stop-opacity") })).slice(0, 5)
|
|
1061
|
+
})),
|
|
1062
|
+
images: images.slice(0, 8).map((img) => ({
|
|
1063
|
+
id: img.getAttribute("id"),
|
|
1064
|
+
href: shortPdfDebug(getSvgImageHref(img), 220),
|
|
1065
|
+
x: img.getAttribute("x"),
|
|
1066
|
+
y: img.getAttribute("y"),
|
|
1067
|
+
width: img.getAttribute("width"),
|
|
1068
|
+
height: img.getAttribute("height"),
|
|
1069
|
+
transform: shortPdfDebug(img.getAttribute("transform"), 140),
|
|
1070
|
+
clipPath: img.getAttribute("clip-path"),
|
|
1071
|
+
preserveAspectRatio: img.getAttribute("preserveAspectRatio")
|
|
1072
|
+
})),
|
|
1073
|
+
clipPaths: Array.from(svg.querySelectorAll("clipPath")).slice(0, 8).map((clip) => ({
|
|
1074
|
+
id: clip.getAttribute("id"),
|
|
1075
|
+
units: clip.getAttribute("clipPathUnits"),
|
|
1076
|
+
transform: shortPdfDebug(clip.getAttribute("transform"), 140),
|
|
1077
|
+
rects: Array.from(clip.querySelectorAll("rect")).slice(0, 3).map((rect) => ({
|
|
1078
|
+
x: rect.getAttribute("x"),
|
|
1079
|
+
y: rect.getAttribute("y"),
|
|
1080
|
+
width: rect.getAttribute("width"),
|
|
1081
|
+
height: rect.getAttribute("height"),
|
|
1082
|
+
transform: shortPdfDebug(rect.getAttribute("transform"), 140)
|
|
1083
|
+
}))
|
|
1084
|
+
})),
|
|
1085
|
+
nestedSvgs: nestedSvgs.slice(0, 8).map((node) => ({
|
|
1086
|
+
id: node.getAttribute("id"),
|
|
1087
|
+
x: node.getAttribute("x"),
|
|
1088
|
+
y: node.getAttribute("y"),
|
|
1089
|
+
width: node.getAttribute("width"),
|
|
1090
|
+
height: node.getAttribute("height"),
|
|
1091
|
+
viewBox: node.getAttribute("viewBox"),
|
|
1092
|
+
transform: shortPdfDebug(node.getAttribute("transform"), 140)
|
|
1093
|
+
})),
|
|
1094
|
+
gradientRefs: gradientRefs.slice(0, 10)
|
|
1095
|
+
});
|
|
1096
|
+
} catch (err) {
|
|
1097
|
+
console.warn("[client-pdf-export][gradient-svg-diag] failed", { stage, err });
|
|
1098
|
+
}
|
|
1099
|
+
}
|
|
1006
1100
|
function logGradientBindingDiagnostics(svg) {
|
|
1007
1101
|
const gradientCount = svg.querySelectorAll("linearGradient, radialGradient").length;
|
|
1008
1102
|
if (gradientCount === 0) return;
|
|
@@ -1366,7 +1460,39 @@ function decodeSvgDataUri(href) {
|
|
|
1366
1460
|
}
|
|
1367
1461
|
}
|
|
1368
1462
|
}
|
|
1369
|
-
function
|
|
1463
|
+
async function readNestedSvgImageMarkup(href) {
|
|
1464
|
+
if (!href) return null;
|
|
1465
|
+
if (href.startsWith("data:image/svg+xml")) return decodeSvgDataUri(href);
|
|
1466
|
+
if (/\.svg(?:[?#]|$)/i.test(href) || href.startsWith("blob:")) {
|
|
1467
|
+
const urls = [];
|
|
1468
|
+
const addUrl = (url) => {
|
|
1469
|
+
if (url && !urls.includes(url)) urls.push(url);
|
|
1470
|
+
};
|
|
1471
|
+
if (href.startsWith("blob:")) {
|
|
1472
|
+
addUrl(href);
|
|
1473
|
+
} else {
|
|
1474
|
+
addUrl(index.getProxiedImageUrl(href));
|
|
1475
|
+
addUrl(href);
|
|
1476
|
+
try {
|
|
1477
|
+
const proxyUrl = new URL(`${index.API_URL}/image-proxy`);
|
|
1478
|
+
proxyUrl.searchParams.set("url", href);
|
|
1479
|
+
addUrl(proxyUrl.toString());
|
|
1480
|
+
} catch {
|
|
1481
|
+
}
|
|
1482
|
+
}
|
|
1483
|
+
for (const url of urls) {
|
|
1484
|
+
try {
|
|
1485
|
+
const res = await fetch(url, { cache: "no-store", ...index.getImageProxyFetchOptions() });
|
|
1486
|
+
if (!res.ok) continue;
|
|
1487
|
+
const text = await res.text();
|
|
1488
|
+
if (/<svg[\s>]/i.test(text)) return text;
|
|
1489
|
+
} catch {
|
|
1490
|
+
}
|
|
1491
|
+
}
|
|
1492
|
+
}
|
|
1493
|
+
return null;
|
|
1494
|
+
}
|
|
1495
|
+
async function inlineNestedSvgImageDataUris(svgString, domParser = new DOMParser()) {
|
|
1370
1496
|
var _a;
|
|
1371
1497
|
try {
|
|
1372
1498
|
const doc = domParser.parseFromString(svgString, "image/svg+xml");
|
|
@@ -1374,42 +1500,102 @@ function inlineNestedSvgImageDataUris(svgString, domParser = new DOMParser()) {
|
|
|
1374
1500
|
const root = doc.documentElement;
|
|
1375
1501
|
if (!root || root.tagName.toLowerCase() !== "svg") return svgString;
|
|
1376
1502
|
let changed = false;
|
|
1503
|
+
let inlined = 0;
|
|
1504
|
+
let failed = 0;
|
|
1377
1505
|
const images = Array.from(doc.querySelectorAll("image"));
|
|
1378
|
-
|
|
1506
|
+
logSvgGradientClipDiagnostics("inline-pass:start", root, { imageCount: images.length });
|
|
1507
|
+
for (const [imageIndex, img] of images.entries()) {
|
|
1379
1508
|
const href = img.getAttribute("href") || img.getAttributeNS("http://www.w3.org/1999/xlink", "href");
|
|
1380
|
-
if (!href
|
|
1509
|
+
if (!href) continue;
|
|
1381
1510
|
try {
|
|
1382
|
-
const svgContent =
|
|
1383
|
-
if (!svgContent || !/<svg[\s>]/i.test(svgContent))
|
|
1511
|
+
const svgContent = await readNestedSvgImageMarkup(href);
|
|
1512
|
+
if (!svgContent || !/<svg[\s>]/i.test(svgContent)) {
|
|
1513
|
+
if (/\.svg(?:[?#]|$)/i.test(href) || href.startsWith("blob:") || href.startsWith("data:image/svg+xml")) {
|
|
1514
|
+
console.warn("[client-pdf-export][gradient-svg-diag] inline source not readable", {
|
|
1515
|
+
imageIndex,
|
|
1516
|
+
href: shortPdfDebug(href, 260),
|
|
1517
|
+
x: img.getAttribute("x"),
|
|
1518
|
+
y: img.getAttribute("y"),
|
|
1519
|
+
width: img.getAttribute("width"),
|
|
1520
|
+
height: img.getAttribute("height"),
|
|
1521
|
+
transform: shortPdfDebug(img.getAttribute("transform"), 160)
|
|
1522
|
+
});
|
|
1523
|
+
}
|
|
1524
|
+
continue;
|
|
1525
|
+
}
|
|
1384
1526
|
const innerDoc = domParser.parseFromString(svgContent, "image/svg+xml");
|
|
1385
1527
|
if (innerDoc.querySelector("parsererror")) continue;
|
|
1386
1528
|
const innerSvg = innerDoc.documentElement;
|
|
1387
1529
|
if (!innerSvg || innerSvg.tagName.toLowerCase() !== "svg") continue;
|
|
1530
|
+
const sourceId = img.getAttribute("id") || `image-${imageIndex}`;
|
|
1531
|
+
prefixSvgIds(innerSvg, `inline-${sourceId}`);
|
|
1388
1532
|
const ix = parseFloat(img.getAttribute("x") || "0") || 0;
|
|
1389
1533
|
const iy = parseFloat(img.getAttribute("y") || "0") || 0;
|
|
1390
1534
|
const iw = parseFloat(img.getAttribute("width") || "0");
|
|
1391
1535
|
const ih = parseFloat(img.getAttribute("height") || "0");
|
|
1392
|
-
if (!(iw > 0 && ih > 0))
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1536
|
+
if (!(iw > 0 && ih > 0)) {
|
|
1537
|
+
console.warn("[client-pdf-export][gradient-svg-diag] inline skipped: image has invalid frame", {
|
|
1538
|
+
imageIndex,
|
|
1539
|
+
href: shortPdfDebug(href, 260),
|
|
1540
|
+
x: img.getAttribute("x"),
|
|
1541
|
+
y: img.getAttribute("y"),
|
|
1542
|
+
width: img.getAttribute("width"),
|
|
1543
|
+
height: img.getAttribute("height"),
|
|
1544
|
+
innerViewBox: innerSvg.getAttribute("viewBox")
|
|
1545
|
+
});
|
|
1546
|
+
continue;
|
|
1397
1547
|
}
|
|
1398
|
-
nestedSvg.setAttribute("x", "0");
|
|
1399
|
-
nestedSvg.setAttribute("y", "0");
|
|
1400
|
-
nestedSvg.setAttribute("width", String(iw));
|
|
1401
|
-
nestedSvg.setAttribute("height", String(ih));
|
|
1402
|
-
nestedSvg.setAttribute(
|
|
1403
|
-
"preserveAspectRatio",
|
|
1404
|
-
img.getAttribute("preserveAspectRatio") || nestedSvg.getAttribute("preserveAspectRatio") || "xMidYMid meet"
|
|
1405
|
-
);
|
|
1406
1548
|
const g = doc.createElementNS("http://www.w3.org/2000/svg", "g");
|
|
1407
1549
|
const existingTransform = img.getAttribute("transform") || "";
|
|
1550
|
+
const vb = (innerSvg.getAttribute("viewBox") || "").trim().split(/[\s,]+/).map((n) => Number.parseFloat(n));
|
|
1551
|
+
const [vbX, vbY, vbW, vbH] = vb.length === 4 && vb.every((n) => Number.isFinite(n)) && vb[2] > 0 && vb[3] > 0 ? vb : [0, 0, iw, ih];
|
|
1552
|
+
const par = img.getAttribute("preserveAspectRatio") || innerSvg.getAttribute("preserveAspectRatio") || "xMidYMid meet";
|
|
1553
|
+
const parParts = par.trim().split(/\s+/).filter(Boolean);
|
|
1554
|
+
const align = parParts[0] === "defer" ? parParts[1] || "xMidYMid" : parParts[0] || "xMidYMid";
|
|
1555
|
+
const meetOrSlice = parParts[0] === "defer" ? parParts[2] || "meet" : parParts[1] || "meet";
|
|
1556
|
+
let sx = iw / vbW;
|
|
1557
|
+
let sy = ih / vbH;
|
|
1558
|
+
let ox = 0;
|
|
1559
|
+
let oy = 0;
|
|
1560
|
+
if (align !== "none") {
|
|
1561
|
+
const s = meetOrSlice === "slice" ? Math.max(sx, sy) : Math.min(sx, sy);
|
|
1562
|
+
sx = s;
|
|
1563
|
+
sy = s;
|
|
1564
|
+
const extraW = iw - vbW * s;
|
|
1565
|
+
const extraH = ih - vbH * s;
|
|
1566
|
+
if (align.includes("xMid")) ox = extraW / 2;
|
|
1567
|
+
else if (align.includes("xMax")) ox = extraW;
|
|
1568
|
+
if (align.includes("YMid")) oy = extraH / 2;
|
|
1569
|
+
else if (align.includes("YMax")) oy = extraH;
|
|
1570
|
+
}
|
|
1408
1571
|
let transform = existingTransform;
|
|
1409
|
-
transform += `${transform ? " " : ""}translate(${ix},${iy})`;
|
|
1572
|
+
transform += `${transform ? " " : ""}translate(${ix + ox},${iy + oy}) scale(${sx},${sy}) translate(${-vbX},${-vbY})`;
|
|
1410
1573
|
if (transform) {
|
|
1411
1574
|
g.setAttribute("transform", transform);
|
|
1412
1575
|
}
|
|
1576
|
+
logSvgGradientClipDiagnostics("inline-pass:image-inlined", innerSvg, {
|
|
1577
|
+
imageIndex,
|
|
1578
|
+
sourceId,
|
|
1579
|
+
href: shortPdfDebug(href, 260),
|
|
1580
|
+
imageFrame: { x: ix, y: iy, width: iw, height: ih },
|
|
1581
|
+
innerRoot: {
|
|
1582
|
+
width: innerSvg.getAttribute("width"),
|
|
1583
|
+
height: innerSvg.getAttribute("height"),
|
|
1584
|
+
viewBox: innerSvg.getAttribute("viewBox"),
|
|
1585
|
+
preserveAspectRatio: innerSvg.getAttribute("preserveAspectRatio")
|
|
1586
|
+
},
|
|
1587
|
+
appliedTransform: transform
|
|
1588
|
+
});
|
|
1589
|
+
const imageClipPath = img.getAttribute("clip-path") || getInlineStyleValue(img, "clip-path");
|
|
1590
|
+
const dropImageClipPath = isRedundantImageClipPathForInlineSvg(root, imageClipPath, ix, iy, iw, ih);
|
|
1591
|
+
if (dropImageClipPath) {
|
|
1592
|
+
console.log("[client-pdf-export][gradient-svg-diag] dropped redundant inline SVG image clipPath", {
|
|
1593
|
+
imageIndex,
|
|
1594
|
+
sourceId,
|
|
1595
|
+
clipPath: imageClipPath,
|
|
1596
|
+
imageFrame: { x: ix, y: iy, width: iw, height: ih }
|
|
1597
|
+
});
|
|
1598
|
+
}
|
|
1413
1599
|
const passthroughAttrs = /* @__PURE__ */ new Set([
|
|
1414
1600
|
"id",
|
|
1415
1601
|
"class",
|
|
@@ -1423,21 +1609,123 @@ function inlineNestedSvgImageDataUris(svgString, domParser = new DOMParser()) {
|
|
|
1423
1609
|
"pointer-events"
|
|
1424
1610
|
]);
|
|
1425
1611
|
Array.from(img.attributes).forEach((attr) => {
|
|
1612
|
+
if (dropImageClipPath && attr.name === "clip-path") return;
|
|
1613
|
+
if (dropImageClipPath && attr.name === "style") {
|
|
1614
|
+
const kept = parseInlineSvgStyleDeclarations(attr.value).filter((decl) => decl.key !== "clip-path").map((decl) => `${decl.key}: ${decl.value}`).join("; ");
|
|
1615
|
+
if (kept) g.setAttribute("style", kept);
|
|
1616
|
+
return;
|
|
1617
|
+
}
|
|
1426
1618
|
if (passthroughAttrs.has(attr.name)) {
|
|
1427
1619
|
g.setAttribute(attr.name, attr.value);
|
|
1428
1620
|
}
|
|
1429
1621
|
});
|
|
1430
|
-
|
|
1622
|
+
for (const child of Array.from(innerSvg.childNodes)) {
|
|
1623
|
+
g.appendChild(doc.importNode(child, true));
|
|
1624
|
+
}
|
|
1431
1625
|
(_a = img.parentNode) == null ? void 0 : _a.replaceChild(g, img);
|
|
1432
1626
|
changed = true;
|
|
1627
|
+
inlined++;
|
|
1433
1628
|
} catch {
|
|
1629
|
+
failed++;
|
|
1434
1630
|
}
|
|
1435
1631
|
}
|
|
1632
|
+
if (inlined > 0 || failed > 0) {
|
|
1633
|
+
console.log("[client-pdf-export] nested SVG image inline pass", { inlined, failed, imageCount: images.length, changed });
|
|
1634
|
+
logSvgGradientClipDiagnostics("inline-pass:done", doc.documentElement, { inlined, failed, imageCount: images.length, changed });
|
|
1635
|
+
}
|
|
1436
1636
|
return changed ? new XMLSerializer().serializeToString(doc.documentElement) : svgString;
|
|
1437
1637
|
} catch {
|
|
1438
1638
|
return svgString;
|
|
1439
1639
|
}
|
|
1440
1640
|
}
|
|
1641
|
+
function parseSvgLength(value, fallback) {
|
|
1642
|
+
if (!value) return fallback;
|
|
1643
|
+
const trimmed = value.trim();
|
|
1644
|
+
if (!trimmed || trimmed.endsWith("%")) return fallback;
|
|
1645
|
+
const parsed = Number.parseFloat(trimmed);
|
|
1646
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
|
|
1647
|
+
}
|
|
1648
|
+
function isIdentitySvgMatrix(value) {
|
|
1649
|
+
var _a;
|
|
1650
|
+
if (!value) return true;
|
|
1651
|
+
const nums = ((_a = value.match(/-?\d*\.?\d+(?:e[-+]?\d+)?/gi)) == null ? void 0 : _a.map(Number)) ?? [];
|
|
1652
|
+
return nums.length === 6 && Math.abs(nums[0] - 1) < 1e-3 && Math.abs(nums[1]) < 1e-3 && Math.abs(nums[2]) < 1e-3 && Math.abs(nums[3] - 1) < 1e-3 && Math.abs(nums[4]) < 1e-3 && Math.abs(nums[5]) < 1e-3;
|
|
1653
|
+
}
|
|
1654
|
+
function isRedundantImageClipPathForInlineSvg(root, clipPathRef, ix, iy, iw, ih) {
|
|
1655
|
+
const clipId = extractGradientIdFromPaint(clipPathRef);
|
|
1656
|
+
if (!clipId || !(iw > 0 && ih > 0)) return false;
|
|
1657
|
+
let clip = null;
|
|
1658
|
+
for (const el of root.querySelectorAll("[id]")) {
|
|
1659
|
+
if (el.getAttribute("id") === clipId) {
|
|
1660
|
+
clip = el;
|
|
1661
|
+
break;
|
|
1662
|
+
}
|
|
1663
|
+
}
|
|
1664
|
+
if (!clip || clip.tagName.toLowerCase() !== "clippath") return false;
|
|
1665
|
+
const units = (clip.getAttribute("clipPathUnits") || "userSpaceOnUse").toLowerCase();
|
|
1666
|
+
const rects = Array.from(clip.children).filter((el) => el.tagName.toLowerCase() === "rect");
|
|
1667
|
+
if (rects.length !== 1 || rects[0].parentElement !== clip) return false;
|
|
1668
|
+
const rect = rects[0];
|
|
1669
|
+
if (!isIdentitySvgMatrix(rect.getAttribute("transform"))) return false;
|
|
1670
|
+
const rx = Number.parseFloat(rect.getAttribute("x") || "0") || 0;
|
|
1671
|
+
const ry = Number.parseFloat(rect.getAttribute("y") || "0") || 0;
|
|
1672
|
+
const rw = Number.parseFloat(rect.getAttribute("width") || "0");
|
|
1673
|
+
const rh = Number.parseFloat(rect.getAttribute("height") || "0");
|
|
1674
|
+
if (!(rw > 0 && rh > 0)) return false;
|
|
1675
|
+
const near = (a, b) => Math.abs(a - b) <= Math.max(1, Math.max(Math.abs(a), Math.abs(b)) * 0.01);
|
|
1676
|
+
if (units === "objectboundingbox") return near(rx, 0) && near(ry, 0) && near(rw, 1) && near(rh, 1);
|
|
1677
|
+
return near(rx, ix) && near(ry, iy) && near(rw, iw) && near(rh, ih);
|
|
1678
|
+
}
|
|
1679
|
+
function flattenNestedSvgViewports(rootSvg) {
|
|
1680
|
+
const nestedSvgs = Array.from(rootSvg.querySelectorAll("svg")).filter((svg) => svg !== rootSvg).reverse();
|
|
1681
|
+
if (nestedSvgs.length === 0) return;
|
|
1682
|
+
let flattened = 0;
|
|
1683
|
+
for (const nestedSvg of nestedSvgs) {
|
|
1684
|
+
const parent = nestedSvg.parentNode;
|
|
1685
|
+
const doc = nestedSvg.ownerDocument;
|
|
1686
|
+
if (!parent || !doc) continue;
|
|
1687
|
+
const vb = (nestedSvg.getAttribute("viewBox") || "").trim().split(/[\s,]+/).map((n) => Number.parseFloat(n));
|
|
1688
|
+
const hasViewBox = vb.length === 4 && vb.every((n) => Number.isFinite(n)) && vb[2] > 0 && vb[3] > 0;
|
|
1689
|
+
const [vbX, vbY, vbW, vbH] = hasViewBox ? vb : [0, 0, 0, 0];
|
|
1690
|
+
const width = parseSvgLength(nestedSvg.getAttribute("width"), hasViewBox ? vbW : 0);
|
|
1691
|
+
const height = parseSvgLength(nestedSvg.getAttribute("height"), hasViewBox ? vbH : 0);
|
|
1692
|
+
if (!(width > 0 && height > 0)) continue;
|
|
1693
|
+
const x = Number.parseFloat(nestedSvg.getAttribute("x") || "0") || 0;
|
|
1694
|
+
const y = Number.parseFloat(nestedSvg.getAttribute("y") || "0") || 0;
|
|
1695
|
+
const par = nestedSvg.getAttribute("preserveAspectRatio") || "xMidYMid meet";
|
|
1696
|
+
const parParts = par.trim().split(/\s+/).filter(Boolean);
|
|
1697
|
+
const align = parParts[0] === "defer" ? parParts[1] || "xMidYMid" : parParts[0] || "xMidYMid";
|
|
1698
|
+
const meetOrSlice = parParts[0] === "defer" ? parParts[2] || "meet" : parParts[1] || "meet";
|
|
1699
|
+
let sx = hasViewBox ? width / vbW : 1;
|
|
1700
|
+
let sy = hasViewBox ? height / vbH : 1;
|
|
1701
|
+
let ox = 0;
|
|
1702
|
+
let oy = 0;
|
|
1703
|
+
if (hasViewBox && align !== "none") {
|
|
1704
|
+
const s = meetOrSlice === "slice" ? Math.max(sx, sy) : Math.min(sx, sy);
|
|
1705
|
+
sx = s;
|
|
1706
|
+
sy = s;
|
|
1707
|
+
const extraW = width - vbW * s;
|
|
1708
|
+
const extraH = height - vbH * s;
|
|
1709
|
+
if (align.includes("xMid")) ox = extraW / 2;
|
|
1710
|
+
else if (align.includes("xMax")) ox = extraW;
|
|
1711
|
+
if (align.includes("YMid")) oy = extraH / 2;
|
|
1712
|
+
else if (align.includes("YMax")) oy = extraH;
|
|
1713
|
+
}
|
|
1714
|
+
const g = doc.createElementNS("http://www.w3.org/2000/svg", "g");
|
|
1715
|
+
const existingTransform = nestedSvg.getAttribute("transform") || "";
|
|
1716
|
+
const viewBoxTransform = hasViewBox ? `translate(${x + ox},${y + oy}) scale(${sx},${sy}) translate(${-vbX},${-vbY})` : `translate(${x},${y})`;
|
|
1717
|
+
g.setAttribute("transform", `${existingTransform}${existingTransform ? " " : ""}${viewBoxTransform}`);
|
|
1718
|
+
for (const attr of Array.from(nestedSvg.attributes)) {
|
|
1719
|
+
if (["id", "class", "style", "opacity", "display", "visibility", "clip-path", "mask", "filter", "pointer-events"].includes(attr.name)) {
|
|
1720
|
+
g.setAttribute(attr.name, attr.value);
|
|
1721
|
+
}
|
|
1722
|
+
}
|
|
1723
|
+
for (const child of Array.from(nestedSvg.childNodes)) g.appendChild(child);
|
|
1724
|
+
parent.replaceChild(g, nestedSvg);
|
|
1725
|
+
flattened++;
|
|
1726
|
+
}
|
|
1727
|
+
if (flattened > 0) console.log("[client-pdf-export] flattened nested SVG viewport(s)", { flattened });
|
|
1728
|
+
}
|
|
1441
1729
|
function hasInvalidSvgNumericToken(value) {
|
|
1442
1730
|
return typeof value === "string" && /\b(?:NaN|-?Infinity|undefined|null)\b/.test(value);
|
|
1443
1731
|
}
|
|
@@ -2319,11 +2607,12 @@ async function prepareLiveCanvasSvgForPdf(rawSvg, pageWidth, pageHeight, pageKey
|
|
|
2319
2607
|
var _a;
|
|
2320
2608
|
try {
|
|
2321
2609
|
const parser = new DOMParser();
|
|
2322
|
-
const processedSvg = inlineNestedSvgImageDataUris(rawSvg, parser);
|
|
2610
|
+
const processedSvg = await inlineNestedSvgImageDataUris(rawSvg, parser);
|
|
2323
2611
|
const doc = parser.parseFromString(processedSvg, "image/svg+xml");
|
|
2324
2612
|
if (doc.querySelector("parsererror")) return null;
|
|
2325
2613
|
const svg = doc.documentElement;
|
|
2326
2614
|
if (!svg || svg.tagName.toLowerCase() !== "svg") return null;
|
|
2615
|
+
logSvgGradientClipDiagnostics("prepare:parsed-after-inline", svg, { pageKey, pageWidth, pageHeight, processedLength: processedSvg.length });
|
|
2327
2616
|
svg.setAttribute("xmlns", "http://www.w3.org/2000/svg");
|
|
2328
2617
|
if (/xlink:href/i.test(processedSvg) && !svg.getAttribute("xmlns:xlink")) {
|
|
2329
2618
|
svg.setAttribute("xmlns:xlink", "http://www.w3.org/1999/xlink");
|
|
@@ -2333,14 +2622,18 @@ async function prepareLiveCanvasSvgForPdf(rawSvg, pageWidth, pageHeight, pageKey
|
|
|
2333
2622
|
svg.setAttribute("viewBox", `0 0 ${pageWidth} ${pageHeight}`);
|
|
2334
2623
|
sanitizeSvgTreeForPdf(svg);
|
|
2335
2624
|
normalizeSvgViewBoxOrigin(svg);
|
|
2625
|
+
flattenNestedSvgViewports(svg);
|
|
2626
|
+
logSvgGradientClipDiagnostics("prepare:after-flatten-nested-viewports", svg, { pageKey, pageWidth, pageHeight });
|
|
2336
2627
|
disambiguateNestedSvgIds(svg);
|
|
2337
2628
|
expandSvgUseElements(svg, pageKey);
|
|
2338
2629
|
let svgToDraw = normalizeSvgExplicitColors(svg);
|
|
2630
|
+
logSvgGradientClipDiagnostics("prepare:after-explicit-colors", svgToDraw, { pageKey, pageWidth, pageHeight });
|
|
2339
2631
|
inlineComputedStyles(svgToDraw);
|
|
2340
2632
|
sanitizeSvgTreeForPdf(svgToDraw);
|
|
2341
2633
|
normalizeSvgGradientStopOffsets(svgToDraw);
|
|
2342
2634
|
expandSvgGradientHrefs(svgToDraw);
|
|
2343
2635
|
prefixSvgIds(svgToDraw, pageKey);
|
|
2636
|
+
logSvgGradientClipDiagnostics("prepare:after-gradient-normalize-prefix", svgToDraw, { pageKey, pageWidth, pageHeight });
|
|
2344
2637
|
bakeGroupOpacityIntoChildren(svgToDraw);
|
|
2345
2638
|
stripSuspiciousFullPageOverlayNodes(svgToDraw);
|
|
2346
2639
|
if (options == null ? void 0 : options.stripPageBackground) {
|
|
@@ -2362,8 +2655,10 @@ async function prepareLiveCanvasSvgForPdf(rawSvg, pageWidth, pageHeight, pageKey
|
|
|
2362
2655
|
const rewritten = rewriteSvgFontsForJsPDFWithSourceMeta(new XMLSerializer().serializeToString(svgToDraw));
|
|
2363
2656
|
const rewrittenDoc = parser.parseFromString(rewritten, "image/svg+xml");
|
|
2364
2657
|
if (!rewrittenDoc.querySelector("parsererror") && ((_a = rewrittenDoc.documentElement) == null ? void 0 : _a.tagName.toLowerCase()) === "svg") {
|
|
2658
|
+
logSvgGradientClipDiagnostics("prepare:final-before-svg2pdf", rewrittenDoc.documentElement, { pageKey, pageWidth, pageHeight, rewrittenLength: rewritten.length });
|
|
2365
2659
|
return rewrittenDoc.documentElement;
|
|
2366
2660
|
}
|
|
2661
|
+
logSvgGradientClipDiagnostics("prepare:final-before-svg2pdf", svgToDraw, { pageKey, pageWidth, pageHeight });
|
|
2367
2662
|
return svgToDraw;
|
|
2368
2663
|
} catch {
|
|
2369
2664
|
return null;
|
|
@@ -2787,7 +3082,7 @@ function resolveSvgGradientRefsToSolid(svg, elementId) {
|
|
|
2787
3082
|
function disambiguateNestedSvgIds(rootSvg) {
|
|
2788
3083
|
const nestedSvgs = Array.from(rootSvg.querySelectorAll("svg"));
|
|
2789
3084
|
const toProcess = nestedSvgs.filter((s) => s !== rootSvg);
|
|
2790
|
-
if (toProcess.length
|
|
3085
|
+
if (toProcess.length === 0) return;
|
|
2791
3086
|
toProcess.forEach((nested, idx) => {
|
|
2792
3087
|
prefixSvgIds(nested, `n${idx}`);
|
|
2793
3088
|
});
|
|
@@ -2902,6 +3197,8 @@ function normalizeSvgViewBoxOrigin(svg) {
|
|
|
2902
3197
|
if (parts.length !== 4) return;
|
|
2903
3198
|
const [vx, vy, vw, vh] = parts;
|
|
2904
3199
|
if (vw <= 0 || vh <= 0) return;
|
|
3200
|
+
svg.setAttribute("width", String(vw));
|
|
3201
|
+
svg.setAttribute("height", String(vh));
|
|
2905
3202
|
if (Math.abs(vx) < 1e-3 && Math.abs(vy) < 1e-3) return;
|
|
2906
3203
|
const doc = svg.ownerDocument;
|
|
2907
3204
|
if (!doc) return;
|
|
@@ -2974,7 +3271,7 @@ async function fetchSvgAsElement(imageUrl, colorMap) {
|
|
|
2974
3271
|
async function getRecoloredSvgDataUrl(imageUrl, colorMap) {
|
|
2975
3272
|
if (!colorMap || Object.keys(colorMap).length === 0) return null;
|
|
2976
3273
|
try {
|
|
2977
|
-
const { getNormalizedSvgUrl } = await Promise.resolve().then(() => require("./index-
|
|
3274
|
+
const { getNormalizedSvgUrl } = await Promise.resolve().then(() => require("./index-6nrov1rx.cjs")).then((n) => n.canvasImageLoader);
|
|
2978
3275
|
return await getNormalizedSvgUrl(imageUrl, colorMap);
|
|
2979
3276
|
} catch {
|
|
2980
3277
|
return null;
|
|
@@ -3783,7 +4080,7 @@ async function fetchImageAsBase64(imageUrl, opts = {}) {
|
|
|
3783
4080
|
}
|
|
3784
4081
|
let fetchUrl = imageUrl;
|
|
3785
4082
|
if (imageUrl.startsWith("http://") || imageUrl.startsWith("https://")) {
|
|
3786
|
-
const { isPrivateUrl } = await Promise.resolve().then(() => require("./index-
|
|
4083
|
+
const { isPrivateUrl } = await Promise.resolve().then(() => require("./index-6nrov1rx.cjs")).then((n) => n.canvasImageLoader);
|
|
3787
4084
|
if (isPrivateUrl(imageUrl)) return null;
|
|
3788
4085
|
const proxyUrl = new URL(`${index.API_URL}/image-proxy`);
|
|
3789
4086
|
proxyUrl.searchParams.set("url", imageUrl);
|
|
@@ -5288,9 +5585,8 @@ async function exportFabricCanvasToVectorPdf(_fabricCanvas, options) {
|
|
|
5288
5585
|
const orientation = width > height ? "landscape" : "portrait";
|
|
5289
5586
|
const pdf = new jspdf.jsPDF({
|
|
5290
5587
|
orientation,
|
|
5291
|
-
unit: "
|
|
5588
|
+
unit: "pt",
|
|
5292
5589
|
format: [width, height],
|
|
5293
|
-
hotfixes: ["px_scaling"],
|
|
5294
5590
|
compress: true
|
|
5295
5591
|
});
|
|
5296
5592
|
if (title) {
|
|
@@ -5467,9 +5763,8 @@ async function __exportMultiPagePdfInner(pages, options) {
|
|
|
5467
5763
|
const orientation = firstPage.width > firstPage.height ? "landscape" : "portrait";
|
|
5468
5764
|
const pdf = new jspdf.jsPDF({
|
|
5469
5765
|
orientation,
|
|
5470
|
-
unit: "
|
|
5766
|
+
unit: "pt",
|
|
5471
5767
|
format: [firstPage.width, firstPage.height],
|
|
5472
|
-
hotfixes: ["px_scaling"],
|
|
5473
5768
|
// Always keep PDF object/stream compression on. The UI's image-compression
|
|
5474
5769
|
// switch controls raster resampling/JPEG quality, not lossless PDF packing;
|
|
5475
5770
|
// disabling this made "uncompressed image" PDFs balloon with no quality gain.
|
|
@@ -5882,4 +6177,4 @@ exports.exportMultiPagePdf = exportMultiPagePdf;
|
|
|
5882
6177
|
exports.logTextMeasurementDiagnostic = logTextMeasurementDiagnostic;
|
|
5883
6178
|
exports.preparePagesForExport = preparePagesForExport;
|
|
5884
6179
|
exports.rewriteSvgFontsForJsPDFWithSourceMeta = rewriteSvgFontsForJsPDFWithSourceMeta;
|
|
5885
|
-
//# sourceMappingURL=vectorPdfExport-
|
|
6180
|
+
//# sourceMappingURL=vectorPdfExport-CVeK--lR.cjs.map
|