@pixldocs/canvas-renderer 0.5.128 → 0.5.131

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.
@@ -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-Ds1WDn3c.cjs");
6
+ const index = require("./index-Cc5u_TJx.cjs");
7
7
  const pdfFonts = require("./pdfFonts-Cr8l-y3z.cjs");
8
8
  function _interopNamespaceDefault(e) {
9
9
  const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
@@ -1097,6 +1097,112 @@ function stripSuspiciousFullPageOverlayNodes(svg) {
1097
1097
  }
1098
1098
  }
1099
1099
  async function convertTextDecorationsToLines(svg) {
1100
+ return _convertTextDecorationsToLines_impl(svg);
1101
+ }
1102
+ async function bakeTextAnchorPositionsFromLiveSvg(svg) {
1103
+ var _a;
1104
+ if (typeof document === "undefined" || typeof window === "undefined") return;
1105
+ if (!svg) return;
1106
+ const _resolveAnchor = (el) => {
1107
+ let cur = el;
1108
+ while (cur) {
1109
+ const a = cur.getAttribute("text-anchor");
1110
+ if (a) return a.trim().toLowerCase();
1111
+ const style = cur.getAttribute("style") || "";
1112
+ const m = style.match(/(?:^|;)\s*text-anchor\s*:\s*([^;]+)/i);
1113
+ if (m) return m[1].trim().toLowerCase();
1114
+ cur = cur.parentElement;
1115
+ }
1116
+ return "start";
1117
+ };
1118
+ const allTextish = Array.from(svg.querySelectorAll("text, tspan"));
1119
+ let needsBake = false;
1120
+ for (const el of allTextish) {
1121
+ const a = _resolveAnchor(el);
1122
+ if (a === "middle" || a === "end") {
1123
+ needsBake = true;
1124
+ break;
1125
+ }
1126
+ }
1127
+ if (!needsBake) return;
1128
+ try {
1129
+ if ((_a = document.fonts) == null ? void 0 : _a.ready) await document.fonts.ready;
1130
+ } catch {
1131
+ }
1132
+ const tempContainer = document.createElement("div");
1133
+ tempContainer.style.cssText = "position:fixed;left:-9999px;top:-9999px;visibility:hidden;pointer-events:none;";
1134
+ const clone = svg.cloneNode(true);
1135
+ for (const tn of clone.querySelectorAll("text, tspan, textPath")) {
1136
+ const sf = tn.getAttribute("data-source-font-family");
1137
+ const sw = tn.getAttribute("data-source-font-weight");
1138
+ const ss = tn.getAttribute("data-source-font-style");
1139
+ if (sf) tn.setAttribute("font-family", sf);
1140
+ if (sw) tn.setAttribute("font-weight", sw);
1141
+ if (ss) tn.setAttribute("font-style", ss);
1142
+ const inlineStyle = tn.getAttribute("style") || "";
1143
+ if (sf || sw || ss) {
1144
+ const stylePairs = inlineStyle.split(";").map((p) => p.trim()).filter(Boolean).filter((p) => !/^font-(family|weight|style)\s*:/i.test(p));
1145
+ if (sf) stylePairs.push(`font-family: ${sf}`);
1146
+ if (sw) stylePairs.push(`font-weight: ${sw}`);
1147
+ if (ss) stylePairs.push(`font-style: ${ss}`);
1148
+ if (stylePairs.length > 0) tn.setAttribute("style", stylePairs.join("; "));
1149
+ }
1150
+ }
1151
+ tempContainer.appendChild(clone);
1152
+ document.body.appendChild(tempContainer);
1153
+ let baked = 0;
1154
+ try {
1155
+ const srcTexts = Array.from(svg.querySelectorAll("text"));
1156
+ const liveTexts = Array.from(clone.querySelectorAll("text"));
1157
+ for (let i = 0; i < srcTexts.length; i++) {
1158
+ const srcText = srcTexts[i];
1159
+ const liveText = liveTexts[i];
1160
+ if (!liveText) continue;
1161
+ const srcTspans = Array.from(srcText.querySelectorAll("tspan"));
1162
+ const liveTspans = Array.from(liveText.querySelectorAll("tspan"));
1163
+ const bakeNode = (srcNode, liveNode, isTspan) => {
1164
+ const anchor = _resolveAnchor(srcNode);
1165
+ if (anchor !== "middle" && anchor !== "end") return;
1166
+ try {
1167
+ const n = typeof liveNode.getNumberOfChars === "function" ? liveNode.getNumberOfChars() : 0;
1168
+ if (!n) return;
1169
+ const start = liveNode.getStartPositionOfChar(0);
1170
+ if (!Number.isFinite(start == null ? void 0 : start.x)) return;
1171
+ srcNode.setAttribute("x", String(start.x));
1172
+ srcNode.setAttribute("text-anchor", "start");
1173
+ const style = srcNode.getAttribute("style") || "";
1174
+ if (/text-anchor\s*:/i.test(style)) {
1175
+ const cleaned = style.split(";").map((p) => p.trim()).filter(Boolean).filter((p) => !/^text-anchor\s*:/i.test(p)).join("; ");
1176
+ if (cleaned) srcNode.setAttribute("style", cleaned);
1177
+ else srcNode.removeAttribute("style");
1178
+ }
1179
+ baked++;
1180
+ } catch {
1181
+ }
1182
+ };
1183
+ if (srcTspans.length > 0) {
1184
+ bakeNode(srcText, liveText, false);
1185
+ for (let j = 0; j < srcTspans.length; j++) {
1186
+ if (liveTspans[j]) bakeNode(srcTspans[j], liveTspans[j], true);
1187
+ }
1188
+ } else {
1189
+ bakeNode(srcText, liveText, false);
1190
+ }
1191
+ }
1192
+ } finally {
1193
+ try {
1194
+ document.body.removeChild(tempContainer);
1195
+ } catch {
1196
+ }
1197
+ }
1198
+ if (baked > 0) {
1199
+ try {
1200
+ console.log(`[Vector PDF][parity] baked text-anchor → start on ${baked} node(s) using live canvas measurement`);
1201
+ } catch {
1202
+ }
1203
+ }
1204
+ }
1205
+ async function _convertTextDecorationsToLines_impl(svg) {
1100
1206
  const doc = svg.ownerDocument;
1101
1207
  if (!doc) return;
1102
1208
  const resolveInheritedSvgValue = (el, attr, styleProp = attr) => {
@@ -1514,7 +1620,7 @@ async function collectInlinedFontFaceCss() {
1514
1620
  return cachedInlinedFontFaceCss;
1515
1621
  }
1516
1622
  async function prepareLiveCanvasSvgForPdf(rawSvg, pageWidth, pageHeight, pageKey, options) {
1517
- var _a;
1623
+ var _a, _b;
1518
1624
  try {
1519
1625
  const parser = new DOMParser();
1520
1626
  const processedSvg = inlineNestedSvgImageDataUris(rawSvg, parser);
@@ -1545,11 +1651,39 @@ async function prepareLiveCanvasSvgForPdf(rawSvg, pageWidth, pageHeight, pageKey
1545
1651
  stripRootPageBackgroundFromSvg(svgToDraw);
1546
1652
  }
1547
1653
  sanitizeSvgTreeForPdf(svgToDraw);
1654
+ try {
1655
+ await bakeTextAnchorPositionsFromLiveSvg(svgToDraw);
1656
+ } catch (e) {
1657
+ console.warn("[Vector PDF] anchor-bake pass failed (continuing):", e);
1658
+ }
1659
+ try {
1660
+ const hasShadowText = !!svgToDraw.querySelector("[data-pd-shadow-blur]") || !!svgToDraw.querySelector("g.__pdShadowRaster text");
1661
+ if (hasShadowText) {
1662
+ const { convertAllTextToPath } = await Promise.resolve().then(() => require("./svgTextToPath-DcI_oipn.cjs"));
1663
+ const serialized = new XMLSerializer().serializeToString(svgToDraw);
1664
+ const outlined = await convertAllTextToPath(serialized, void 0, { mode: "shadow-bound" });
1665
+ const reparsed = parser.parseFromString(outlined, "image/svg+xml");
1666
+ if (!reparsed.querySelector("parsererror") && ((_a = reparsed.documentElement) == null ? void 0 : _a.tagName.toLowerCase()) === "svg") {
1667
+ while (svgToDraw.firstChild) svgToDraw.removeChild(svgToDraw.firstChild);
1668
+ for (const child of Array.from(reparsed.documentElement.childNodes)) {
1669
+ svgToDraw.appendChild(svgToDraw.ownerDocument.importNode(child, true));
1670
+ }
1671
+ for (const attr of Array.from(reparsed.documentElement.attributes)) {
1672
+ try {
1673
+ svgToDraw.setAttribute(attr.name, attr.value);
1674
+ } catch {
1675
+ }
1676
+ }
1677
+ }
1678
+ }
1679
+ } catch (e) {
1680
+ console.warn("[Vector PDF] shadow-bound text outlining failed (continuing without parity outlining):", e);
1681
+ }
1548
1682
  await rasterizeShadowMarkers(svgToDraw);
1549
1683
  await convertTextDecorationsToLines(svgToDraw);
1550
1684
  const rewritten = rewriteSvgFontsForJsPDFWithSourceMeta(new XMLSerializer().serializeToString(svgToDraw));
1551
1685
  const rewrittenDoc = parser.parseFromString(rewritten, "image/svg+xml");
1552
- if (!rewrittenDoc.querySelector("parsererror") && ((_a = rewrittenDoc.documentElement) == null ? void 0 : _a.tagName.toLowerCase()) === "svg") {
1686
+ if (!rewrittenDoc.querySelector("parsererror") && ((_b = rewrittenDoc.documentElement) == null ? void 0 : _b.tagName.toLowerCase()) === "svg") {
1553
1687
  return rewrittenDoc.documentElement;
1554
1688
  }
1555
1689
  return svgToDraw;
@@ -2131,7 +2265,7 @@ async function fetchSvgAsElement(imageUrl, colorMap) {
2131
2265
  async function getRecoloredSvgDataUrl(imageUrl, colorMap) {
2132
2266
  if (!colorMap || Object.keys(colorMap).length === 0) return null;
2133
2267
  try {
2134
- const { getNormalizedSvgUrl } = await Promise.resolve().then(() => require("./index-Ds1WDn3c.cjs")).then((n) => n.canvasImageLoader);
2268
+ const { getNormalizedSvgUrl } = await Promise.resolve().then(() => require("./index-Cc5u_TJx.cjs")).then((n) => n.canvasImageLoader);
2135
2269
  return await getNormalizedSvgUrl(imageUrl, colorMap);
2136
2270
  } catch {
2137
2271
  return null;
@@ -2912,7 +3046,7 @@ async function fetchImageAsBase64(imageUrl, opts = {}) {
2912
3046
  }
2913
3047
  let fetchUrl = imageUrl;
2914
3048
  if (imageUrl.startsWith("http://") || imageUrl.startsWith("https://")) {
2915
- const { isPrivateUrl } = await Promise.resolve().then(() => require("./index-Ds1WDn3c.cjs")).then((n) => n.canvasImageLoader);
3049
+ const { isPrivateUrl } = await Promise.resolve().then(() => require("./index-Cc5u_TJx.cjs")).then((n) => n.canvasImageLoader);
2916
3050
  if (isPrivateUrl(imageUrl)) return null;
2917
3051
  const proxyUrl = new URL(`${index.API_URL}/image-proxy`);
2918
3052
  proxyUrl.searchParams.set("url", imageUrl);
@@ -4885,6 +5019,7 @@ async function exportMultiPagePdf(pages, options) {
4885
5019
  }
4886
5020
  pdf.save(filename);
4887
5021
  }
5022
+ exports.bakeTextAnchorPositionsFromLiveSvg = bakeTextAnchorPositionsFromLiveSvg;
4888
5023
  exports.convertSvgTextDecorationsToLinesString = convertSvgTextDecorationsToLinesString;
4889
5024
  exports.drawPreparedLiveCanvasSvgPageToPdf = drawPreparedLiveCanvasSvgPageToPdf;
4890
5025
  exports.embedFontsForSvg = embedFontsForSvg;
@@ -4892,4 +5027,4 @@ exports.exportFabricCanvasToVectorPdf = exportFabricCanvasToVectorPdf;
4892
5027
  exports.exportMultiPagePdf = exportMultiPagePdf;
4893
5028
  exports.preparePagesForExport = preparePagesForExport;
4894
5029
  exports.rewriteSvgFontsForJsPDFWithSourceMeta = rewriteSvgFontsForJsPDFWithSourceMeta;
4895
- //# sourceMappingURL=vectorPdfExport-De27t708.cjs.map
5030
+ //# sourceMappingURL=vectorPdfExport-CA5X2N63.cjs.map