@pixldocs/canvas-renderer 0.5.143 → 0.5.146

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.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- const index = require("./index-r5VzSOHa.cjs");
3
+ const index = require("./index-DoPXmxDJ.cjs");
4
4
  exports.FONT_FALLBACK_DEVANAGARI = index.FONT_FALLBACK_DEVANAGARI;
5
5
  exports.FONT_FALLBACK_MATH = index.FONT_FALLBACK_MATH;
6
6
  exports.FONT_FALLBACK_SYMBOLS = index.FONT_FALLBACK_SYMBOLS;
package/dist/index.d.ts CHANGED
@@ -259,7 +259,7 @@ export declare function normalizeFontFamily(fontStack: string): string;
259
259
  * Package version banner. Bump alongside package.json so we can confirm
260
260
  * (via browser:log) that the deployed bundle matches the expected build.
261
261
  */
262
- export declare const PACKAGE_VERSION = "0.5.143";
262
+ export declare const PACKAGE_VERSION = "0.5.145";
263
263
 
264
264
  export declare interface PageSettings {
265
265
  backgroundColor?: string;
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { F, o, q, s, P, t, u, v, w, x, y, z, B, C, D, E, G, H, I, J, K, b, L, M, N, O, Q, R, S, U, V, W, X, Y, Z } from "./index-CUpy7HO9.js";
1
+ import { F, o, q, s, P, t, u, v, w, x, y, z, B, C, D, E, G, H, I, J, K, b, L, M, N, O, Q, R, S, U, V, W, X, Y, Z } from "./index-oR6VOGAL.js";
2
2
  export {
3
3
  F as FONT_FALLBACK_DEVANAGARI,
4
4
  o as FONT_FALLBACK_MATH,
@@ -1,7 +1,7 @@
1
1
  import { jsPDF, ShadingPattern } from "jspdf";
2
2
  import { svg2pdf } from "svg2pdf.js";
3
3
  import * as fabric from "fabric";
4
- import { g as getCanvasForPage, c as captureFabricCanvasSvgForPdf, f as findNodeById, a as getAbsoluteBounds, p as parseTextMarkdown, r as renderSmartElementToSvg, n as normalizeShapeType, h as hasEdgeFade, b as getProxiedImageUrl, d as bakeEdgeFade, i as isElement, e as isGroup, j as buildRoundedTrianglePath, A as API_URL, k as getImageProxyFetchOptions, l as getRoundedRectRadii, T as TRIANGLE_STROKE_MITER_LIMIT, m as getTrianglePoints } from "./index-CUpy7HO9.js";
4
+ import { g as getCanvasForPage, c as captureFabricCanvasSvgForPdf, f as findNodeById, a as getAbsoluteBounds, p as parseTextMarkdown, r as renderSmartElementToSvg, n as normalizeShapeType, h as hasEdgeFade, b as getProxiedImageUrl, d as bakeEdgeFade, i as isElement, e as isGroup, j as buildRoundedTrianglePath, A as API_URL, k as getImageProxyFetchOptions, l as getRoundedRectRadii, T as TRIANGLE_STROKE_MITER_LIMIT, m as getTrianglePoints } from "./index-oR6VOGAL.js";
5
5
  import { resetPdfFontRegistry, FONT_FALLBACK_SYMBOLS, FONT_FALLBACK_MATH, FONT_FALLBACK_DEVANAGARI, embedFontWithGoogleFallback, getEmbeddedVariantsList, isFontAvailable, isFamilyEmbedded, resolveBestRegisteredVariant, getEmbeddedJsPDFFontName, resolveFontWeight, doesVariantSupportChar } from "./pdfFonts-b3_bv7F0.js";
6
6
  async function embedFontsForSvg(pdf, svgStr) {
7
7
  var _a;
@@ -123,6 +123,33 @@ const yieldToUI = () => new Promise((resolve) => {
123
123
  requestAnimationFrame(() => setTimeout(resolve, 0));
124
124
  });
125
125
  const SHADOW_RASTER_ALPHA_COMPENSATION = 0.84;
126
+ function collectFontSpecsFromShadowMarkup(markup) {
127
+ const specs = /* @__PURE__ */ new Set();
128
+ const re = /<(?:text|tspan)\b[^>]*>/gi;
129
+ let match;
130
+ while ((match = re.exec(markup)) !== null) {
131
+ const tag = match[0];
132
+ const get = (attr) => {
133
+ const m = tag.match(new RegExp(`\\s${attr}\\s*=\\s*"([^"]*)"`, "i"));
134
+ if (m) return m[1];
135
+ const styleM = tag.match(/\sstyle\s*=\s*"([^"]*)"/i);
136
+ if (styleM) {
137
+ const sm = styleM[1].match(new RegExp(`${attr}\\s*:\\s*([^;]+)`, "i"));
138
+ if (sm) return sm[1].trim();
139
+ }
140
+ return null;
141
+ };
142
+ const family = (get("font-family") || "").split(",")[0].replace(/['"]/g, "").trim();
143
+ if (!family) continue;
144
+ const weight = get("font-weight") || "400";
145
+ const style = get("font-style") || "normal";
146
+ const size = get("font-size") || "16px";
147
+ const sizePx = /[a-z%]/i.test(size) ? size : `${size}px`;
148
+ const famSpec = /\s/.test(family) ? `"${family}"` : family;
149
+ specs.add(`${style} ${weight} ${sizePx} ${famSpec}`);
150
+ }
151
+ return Array.from(specs);
152
+ }
126
153
  let debugSvgDrawSequence = 0;
127
154
  function debugLog(...args) {
128
155
  }
@@ -1208,6 +1235,105 @@ async function bakeTextAnchorPositionsFromLiveSvg(svg) {
1208
1235
  }
1209
1236
  }
1210
1237
  }
1238
+ async function logTextMeasurementDiagnostic(svg) {
1239
+ var _a, _b, _c, _d, _e;
1240
+ if (typeof window === "undefined" || typeof document === "undefined") return;
1241
+ try {
1242
+ const params = new URLSearchParams(((_a = window.location) == null ? void 0 : _a.search) || "");
1243
+ if (params.get("pdfdiag") !== "1") return;
1244
+ } catch {
1245
+ return;
1246
+ }
1247
+ if (!svg) return;
1248
+ const tempContainer = document.createElement("div");
1249
+ tempContainer.style.cssText = "position:fixed;left:-9999px;top:-9999px;visibility:hidden;pointer-events:none;";
1250
+ const clone = svg.cloneNode(true);
1251
+ for (const tn of clone.querySelectorAll("text, tspan, textPath")) {
1252
+ const sf = tn.getAttribute("data-source-font-family");
1253
+ const sw = tn.getAttribute("data-source-font-weight");
1254
+ const ss = tn.getAttribute("data-source-font-style");
1255
+ if (sf) tn.setAttribute("font-family", sf);
1256
+ if (sw) tn.setAttribute("font-weight", sw);
1257
+ if (ss) tn.setAttribute("font-style", ss);
1258
+ }
1259
+ tempContainer.appendChild(clone);
1260
+ document.body.appendChild(tempContainer);
1261
+ const measureCanvas = document.createElement("canvas");
1262
+ const mctx = measureCanvas.getContext("2d");
1263
+ try {
1264
+ const liveTexts = Array.from(clone.querySelectorAll("text"));
1265
+ const srcTexts = Array.from(svg.querySelectorAll("text"));
1266
+ const rows = [];
1267
+ for (let i = 0; i < liveTexts.length; i++) {
1268
+ const live = liveTexts[i];
1269
+ const src = srcTexts[i];
1270
+ if (!live || !src) continue;
1271
+ const liveTspans = Array.from(live.querySelectorAll("tspan"));
1272
+ const srcTspans = Array.from(src.querySelectorAll("tspan"));
1273
+ const tspans = liveTspans.length ? liveTspans : [live];
1274
+ const srcs = srcTspans.length ? srcTspans : [src];
1275
+ for (let j = 0; j < tspans.length; j++) {
1276
+ const ln = tspans[j];
1277
+ const sn = srcs[j];
1278
+ const text = ln.textContent || "";
1279
+ const fam = (ln.getAttribute("font-family") || "").replace(/['"]/g, "").trim();
1280
+ const wt = ln.getAttribute("font-weight") || "400";
1281
+ const sty = ln.getAttribute("font-style") || "normal";
1282
+ const sz = parseFloat(ln.getAttribute("font-size") || src.getAttribute("font-size") || "16") || 16;
1283
+ let domX = null;
1284
+ let bboxW = null;
1285
+ try {
1286
+ if (ln.getNumberOfChars && ln.getNumberOfChars() > 0) {
1287
+ domX = ln.getStartPositionOfChar(0).x;
1288
+ }
1289
+ } catch {
1290
+ }
1291
+ try {
1292
+ bboxW = ((_b = ln.getBBox) == null ? void 0 : _b.call(ln).width) ?? null;
1293
+ } catch {
1294
+ }
1295
+ let canvasW = null;
1296
+ if (mctx) {
1297
+ mctx.font = `${sty} ${wt} ${sz}px "${fam}"`;
1298
+ try {
1299
+ canvasW = mctx.measureText(text).width;
1300
+ } catch {
1301
+ }
1302
+ }
1303
+ rows.push({
1304
+ line: text.length > 40 ? text.slice(0, 37) + "..." : text,
1305
+ font: `${fam} ${wt} ${sty}`,
1306
+ size: sz,
1307
+ srcAnchor: sn.getAttribute("text-anchor") || ((_c = sn.parentElement) == null ? void 0 : _c.getAttribute("text-anchor")) || "",
1308
+ srcX: sn.getAttribute("x") || ((_d = sn.parentElement) == null ? void 0 : _d.getAttribute("x")) || "",
1309
+ domX: domX !== null ? +domX.toFixed(2) : null,
1310
+ bboxW: bboxW !== null ? +bboxW.toFixed(2) : null,
1311
+ measureCtxW: canvasW !== null ? +canvasW.toFixed(2) : null
1312
+ });
1313
+ }
1314
+ }
1315
+ if (rows.length > 0) {
1316
+ console.log("[PDF-DIAG] ===== text measurement diagnostic =====");
1317
+ console.log(
1318
+ "[PDF-DIAG] env=",
1319
+ typeof navigator !== "undefined" ? navigator.userAgent.slice(0, 80) : "n/a",
1320
+ "dpr=",
1321
+ window.devicePixelRatio,
1322
+ "fontsReady=",
1323
+ !!((_e = document.fonts) == null ? void 0 : _e.ready)
1324
+ );
1325
+ for (const r of rows) {
1326
+ console.log("[PDF-DIAG]", JSON.stringify(r));
1327
+ }
1328
+ console.log("[PDF-DIAG] ===== end =====");
1329
+ }
1330
+ } finally {
1331
+ try {
1332
+ document.body.removeChild(tempContainer);
1333
+ } catch {
1334
+ }
1335
+ }
1336
+ }
1211
1337
  async function _convertTextDecorationsToLines_impl(svg) {
1212
1338
  const doc = svg.ownerDocument;
1213
1339
  if (!doc) return;
@@ -1404,7 +1530,7 @@ async function convertSvgTextDecorationsToLinesString(svgStr) {
1404
1530
  }
1405
1531
  }
1406
1532
  async function rasterizeShadowMarkers(svg) {
1407
- var _a, _b, _c, _d, _e;
1533
+ var _a, _b, _c, _d, _e, _f;
1408
1534
  if (typeof window === "undefined" || typeof document === "undefined") return;
1409
1535
  const markers = Array.from(svg.querySelectorAll("g.__pdShadowRaster"));
1410
1536
  if (markers.length === 0) return;
@@ -1431,6 +1557,17 @@ async function rasterizeShadowMarkers(svg) {
1431
1557
  const innerXml = restoreSourceFontsForShadowRaster(
1432
1558
  Array.from(marker.childNodes).map((n) => n instanceof Element ? new XMLSerializer().serializeToString(n) : "").join("")
1433
1559
  );
1560
+ try {
1561
+ const fontSpecs = collectFontSpecsFromShadowMarkup(innerXml);
1562
+ if (fontSpecs.length > 0 && ((_c = document.fonts) == null ? void 0 : _c.load)) {
1563
+ await Promise.all(
1564
+ fontSpecs.map(
1565
+ (spec) => document.fonts.load(spec).catch(() => void 0)
1566
+ )
1567
+ );
1568
+ }
1569
+ } catch {
1570
+ }
1434
1571
  const scale = 2;
1435
1572
  const pxW = Math.min(4096, Math.max(8, Math.ceil(bw * scale)));
1436
1573
  const pxH = Math.min(4096, Math.max(8, Math.ceil(bh * scale)));
@@ -1440,7 +1577,7 @@ async function rasterizeShadowMarkers(svg) {
1440
1577
  const miniSvg = `<svg xmlns="${SVG_NS}" xmlns:xlink="${XLINK_NS}" width="${pxW}" height="${pxH}" viewBox="${bx} ${by} ${bw} ${bh}">${styleBlock}<defs><filter id="${filterId}" filterUnits="userSpaceOnUse" x="${bx}" y="${by}" width="${bw}" height="${bh}" color-interpolation-filters="sRGB"><feOffset dx="${ox}" dy="${oy}" result="offsetShadow" /><feGaussianBlur in="offsetShadow" stdDeviation="${stdDev}" /></filter></defs><g filter="url(#${filterId})">${innerXml}</g></svg>`;
1441
1578
  const dataUrl = await rasterSvgToPngDataUrl(miniSvg, pxW, pxH);
1442
1579
  if (!dataUrl) {
1443
- (_c = marker.parentNode) == null ? void 0 : _c.removeChild(marker);
1580
+ (_d = marker.parentNode) == null ? void 0 : _d.removeChild(marker);
1444
1581
  continue;
1445
1582
  }
1446
1583
  const img = svg.ownerDocument.createElementNS(SVG_NS, "image");
@@ -1452,11 +1589,11 @@ async function rasterizeShadowMarkers(svg) {
1452
1589
  img.setAttribute("preserveAspectRatio", "none");
1453
1590
  img.setAttributeNS(XLINK_NS, "xlink:href", dataUrl);
1454
1591
  img.setAttribute("href", dataUrl);
1455
- (_d = marker.parentNode) == null ? void 0 : _d.replaceChild(img, marker);
1592
+ (_e = marker.parentNode) == null ? void 0 : _e.replaceChild(img, marker);
1456
1593
  } catch (error) {
1457
1594
  console.warn("[Vector PDF] text shadow rasterization failed for one marker:", error);
1458
1595
  try {
1459
- (_e = marker.parentNode) == null ? void 0 : _e.removeChild(marker);
1596
+ (_f = marker.parentNode) == null ? void 0 : _f.removeChild(marker);
1460
1597
  } catch {
1461
1598
  }
1462
1599
  }
@@ -1658,6 +1795,7 @@ async function prepareLiveCanvasSvgForPdf(rawSvg, pageWidth, pageHeight, pageKey
1658
1795
  }
1659
1796
  sanitizeSvgTreeForPdf(svgToDraw);
1660
1797
  try {
1798
+ await logTextMeasurementDiagnostic(svgToDraw);
1661
1799
  await bakeTextAnchorPositionsFromLiveSvg(svgToDraw);
1662
1800
  } catch (e) {
1663
1801
  console.warn("[Vector PDF] anchor-bake pass failed (continuing):", e);
@@ -2248,7 +2386,7 @@ async function fetchSvgAsElement(imageUrl, colorMap) {
2248
2386
  async function getRecoloredSvgDataUrl(imageUrl, colorMap) {
2249
2387
  if (!colorMap || Object.keys(colorMap).length === 0) return null;
2250
2388
  try {
2251
- const { getNormalizedSvgUrl } = await import("./index-CUpy7HO9.js").then((n) => n._);
2389
+ const { getNormalizedSvgUrl } = await import("./index-oR6VOGAL.js").then((n) => n._);
2252
2390
  return await getNormalizedSvgUrl(imageUrl, colorMap);
2253
2391
  } catch {
2254
2392
  return null;
@@ -3029,7 +3167,7 @@ async function fetchImageAsBase64(imageUrl, opts = {}) {
3029
3167
  }
3030
3168
  let fetchUrl = imageUrl;
3031
3169
  if (imageUrl.startsWith("http://") || imageUrl.startsWith("https://")) {
3032
- const { isPrivateUrl } = await import("./index-CUpy7HO9.js").then((n) => n._);
3170
+ const { isPrivateUrl } = await import("./index-oR6VOGAL.js").then((n) => n._);
3033
3171
  if (isPrivateUrl(imageUrl)) return null;
3034
3172
  const proxyUrl = new URL(`${API_URL}/image-proxy`);
3035
3173
  proxyUrl.searchParams.set("url", imageUrl);
@@ -5009,7 +5147,8 @@ export {
5009
5147
  embedFontsForSvg,
5010
5148
  exportFabricCanvasToVectorPdf,
5011
5149
  exportMultiPagePdf,
5150
+ logTextMeasurementDiagnostic,
5012
5151
  preparePagesForExport,
5013
5152
  rewriteSvgFontsForJsPDFWithSourceMeta
5014
5153
  };
5015
- //# sourceMappingURL=vectorPdfExport-GvaizFte.js.map
5154
+ //# sourceMappingURL=vectorPdfExport-DI7k8pt7.js.map