@pixldocs/canvas-renderer 0.5.192 → 0.5.193

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.
@@ -16800,6 +16800,23 @@ function stampFabricLineMetricsOnTextSvg(svg, obj) {
16800
16800
  return `<tspan${cleaned} data-pd-line-width="${Number(lineWidth.toFixed(3))}" data-pd-line-start="${Number(lineStart.toFixed(3))}">`;
16801
16801
  });
16802
16802
  }
16803
+ function escapeSvgDataAttr(value) {
16804
+ return value.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
16805
+ }
16806
+ function hasRenderableRasterCandidate(obj) {
16807
+ if (!obj || typeof obj !== "object") return false;
16808
+ const candidates = [obj._element, obj._originalElement, obj._filteredEl, obj._cacheCanvasEl];
16809
+ for (const candidate of candidates) {
16810
+ if (candidate instanceof HTMLImageElement || candidate instanceof HTMLCanvasElement) return true;
16811
+ }
16812
+ const children = Array.isArray(obj == null ? void 0 : obj._objects) ? obj._objects : [];
16813
+ return children.some((child) => hasRenderableRasterCandidate(child));
16814
+ }
16815
+ function stampPixldocsImageIdOnSvg(svg, id) {
16816
+ if (!id || !/<image\b/i.test(svg) || /data-pixldocs-image-id=/i.test(svg)) return svg;
16817
+ const attr = ` data-pixldocs-image-id="${escapeSvgDataAttr(id)}"`;
16818
+ return svg.replace(/<image\b/i, `<image${attr}`);
16819
+ }
16803
16820
  function captureFabricCanvasSvgForPdf(fabricInstance, canvasWidth, canvasHeight) {
16804
16821
  const prevVPT = fabricInstance.viewportTransform ? [...fabricInstance.viewportTransform] : void 0;
16805
16822
  const prevSvgVPT = fabricInstance.svgViewportTransformation;
@@ -16816,14 +16833,20 @@ function captureFabricCanvasSvgForPdf(fabricInstance, canvasWidth, canvasHeight)
16816
16833
  );
16817
16834
  } catch {
16818
16835
  }
16819
- const textSvgPatchRecords = [];
16836
+ const svgPatchRecords = [];
16820
16837
  try {
16821
16838
  const visit = (obj) => {
16822
16839
  if (!obj) return;
16823
- if (isTextboxLike(obj) && typeof obj.toSVG === "function") {
16840
+ const imageId = typeof obj.__docuforgeId === "string" && hasRenderableRasterCandidate(obj) ? obj.__docuforgeId : "";
16841
+ if ((isTextboxLike(obj) || imageId) && typeof obj.toSVG === "function") {
16824
16842
  const originalToSVG = obj.toSVG.bind(obj);
16825
- obj.toSVG = (reviver) => stampFabricLineMetricsOnTextSvg(originalToSVG(reviver), obj);
16826
- textSvgPatchRecords.push({ obj, originalToSVG });
16843
+ obj.toSVG = (reviver) => {
16844
+ let svg = originalToSVG(reviver);
16845
+ if (isTextboxLike(obj)) svg = stampFabricLineMetricsOnTextSvg(svg, obj);
16846
+ if (imageId) svg = stampPixldocsImageIdOnSvg(svg, imageId);
16847
+ return svg;
16848
+ };
16849
+ svgPatchRecords.push({ obj, originalToSVG });
16827
16850
  }
16828
16851
  const children = Array.isArray(obj == null ? void 0 : obj._objects) ? obj._objects : [];
16829
16852
  for (const child of children) visit(child);
@@ -16856,6 +16879,13 @@ function captureFabricCanvasSvgForPdf(fabricInstance, canvasWidth, canvasHeight)
16856
16879
  evented: false,
16857
16880
  objectCaching: false
16858
16881
  });
16882
+ if (typeof obj.__docuforgeId === "string") {
16883
+ replacement.__docuforgeId = obj.__docuforgeId;
16884
+ if (typeof replacement.toSVG === "function") {
16885
+ const originalReplacementToSVG = replacement.toSVG.bind(replacement);
16886
+ replacement.toSVG = (reviver) => stampPixldocsImageIdOnSvg(originalReplacementToSVG(reviver), obj.__docuforgeId);
16887
+ }
16888
+ }
16859
16889
  const insertIndex = fabricInstance._objects.indexOf(obj);
16860
16890
  const prevExclude = obj.excludeFromExport;
16861
16891
  obj.excludeFromExport = true;
@@ -16888,7 +16918,7 @@ function captureFabricCanvasSvgForPdf(fabricInstance, canvasWidth, canvasHeight)
16888
16918
  } catch {
16889
16919
  }
16890
16920
  }
16891
- for (const rec of textSvgPatchRecords) {
16921
+ for (const rec of svgPatchRecords) {
16892
16922
  try {
16893
16923
  rec.obj.toSVG = rec.originalToSVG;
16894
16924
  } catch {
@@ -16907,9 +16937,9 @@ function captureFabricCanvasSvgForPdf(fabricInstance, canvasWidth, canvasHeight)
16907
16937
  }
16908
16938
  return svgString;
16909
16939
  }
16910
- const resolvedPackageVersion = "0.5.192";
16940
+ const resolvedPackageVersion = "0.5.193";
16911
16941
  const PACKAGE_VERSION = resolvedPackageVersion;
16912
- const DEPLOYMENT_VERSION_MARKER = "__PIXLDOCS_CANVAS_RENDERER_VERSION__:0.5.192";
16942
+ const DEPLOYMENT_VERSION_MARKER = "__PIXLDOCS_CANVAS_RENDERER_VERSION__:0.5.193";
16913
16943
  const roundParityValue = (value) => {
16914
16944
  if (typeof value !== "number") return value;
16915
16945
  return Number.isFinite(value) ? Number(value.toFixed(3)) : value;
@@ -17530,13 +17560,13 @@ class PixldocsRenderer {
17530
17560
  );
17531
17561
  });
17532
17562
  await this.waitForCanvasScene(container, cloned, i);
17533
- const expected = this.getExpectedImageCount(cloned, i);
17563
+ const expected = this.getExpectedImageIds(cloned, i);
17534
17564
  await this.waitForCanvasImages(container, expected);
17535
17565
  await this.waitForStableTextMetrics(container, cloned, { clearGlobalCharCache: false });
17536
17566
  await this.waitForCanvasScene(container, cloned, i);
17537
17567
  }
17538
17568
  console.log(`[canvas-renderer][pdf-unified] mounted ${cloned.pages.length} page(s), handing off to client exportMultiPagePdf`);
17539
- const { exportMultiPagePdf, preparePagesForExport } = await Promise.resolve().then(() => require("./vectorPdfExport-O8vRHBlU.cjs"));
17569
+ const { exportMultiPagePdf, preparePagesForExport } = await Promise.resolve().then(() => require("./vectorPdfExport-BHKMcbVb.cjs"));
17540
17570
  const prepared = preparePagesForExport(
17541
17571
  cloned.pages,
17542
17572
  canvasWidth,
@@ -17608,17 +17638,21 @@ class PixldocsRenderer {
17608
17638
  walk(page.children);
17609
17639
  return ids;
17610
17640
  }
17611
- waitForCanvasImages(container, expectedImageCount, maxWaitMs, pollMs = 120) {
17641
+ waitForCanvasImages(container, expectedImages, maxWaitMs, pollMs = 120) {
17612
17642
  const timeout = Math.max(500, maxWaitMs ?? this.config.assetWaitTimeoutMs ?? 15e3);
17613
17643
  const earlyExitMs = Math.max(250, this.config.assetWaitEarlyExitMs ?? 1500);
17614
17644
  const debug = !!this.config.debug;
17615
- return new Promise((resolve) => {
17645
+ const expectedImageIds = Array.isArray(expectedImages) ? [...new Set(expectedImages)] : [];
17646
+ const expectedImageCount = Array.isArray(expectedImages) ? expectedImageIds.length : expectedImages;
17647
+ const strictById = expectedImageIds.length > 0;
17648
+ return new Promise((resolve, reject) => {
17616
17649
  const start = Date.now();
17617
17650
  let stableFrames = 0;
17618
17651
  let lastSummary = "";
17619
- let lastActual = -1;
17652
+ let lastProgressKey = "";
17620
17653
  let lastProgressAt = Date.now();
17621
17654
  const isRenderableImage = (value) => value instanceof HTMLImageElement && value.complete && value.naturalWidth > 0 && value.naturalHeight > 0;
17655
+ const isRenderableCanvas = (value) => value instanceof HTMLCanvasElement && value.width > 0 && value.height > 0;
17622
17656
  const collectRenderableImages = (obj, seen) => {
17623
17657
  if (!obj || typeof obj !== "object") return;
17624
17658
  const candidates = [obj._element, obj._originalElement, obj._filteredEl, obj._cacheCanvasEl];
@@ -17635,6 +17669,25 @@ class PixldocsRenderer {
17635
17669
  }
17636
17670
  return true;
17637
17671
  };
17672
+ const collectRenderableImageIds = (obj, readyIds) => {
17673
+ if (!obj || typeof obj !== "object") return { loaded: false, pending: false };
17674
+ let loaded = false;
17675
+ let pending = false;
17676
+ const candidates = [obj._element, obj._originalElement, obj._filteredEl, obj._cacheCanvasEl];
17677
+ for (const candidate of candidates) {
17678
+ if (isRenderableImage(candidate) || isRenderableCanvas(candidate)) loaded = true;
17679
+ else if (candidate instanceof HTMLImageElement) pending = true;
17680
+ }
17681
+ const nested = Array.isArray(obj._objects) ? obj._objects : Array.isArray(obj.objects) ? obj.objects : [];
17682
+ for (const child of nested) {
17683
+ const childState = collectRenderableImageIds(child, readyIds);
17684
+ loaded = loaded || childState.loaded;
17685
+ pending = pending || childState.pending;
17686
+ }
17687
+ const id = typeof obj.__docuforgeId === "string" ? obj.__docuforgeId : "";
17688
+ if (id && loaded && !pending) readyIds.add(id);
17689
+ return { loaded, pending };
17690
+ };
17638
17691
  const getFabricCanvas = () => {
17639
17692
  const registry2 = window.__fabricCanvasRegistry;
17640
17693
  if (registry2 instanceof Map) {
@@ -17674,17 +17727,21 @@ class PixldocsRenderer {
17674
17727
  const fabricObjects = fabricCanvas && typeof fabricCanvas.getObjects === "function" ? fabricCanvas.getObjects() : [];
17675
17728
  const renderableImages = /* @__PURE__ */ new Set();
17676
17729
  const fabricReady = fabricObjects.every((obj) => collectRenderableImages(obj, renderableImages) !== false);
17730
+ const renderableImageIds = /* @__PURE__ */ new Set();
17731
+ for (const obj of fabricObjects) collectRenderableImageIds(obj, renderableImageIds);
17732
+ const missingImageIds = strictById ? expectedImageIds.filter((id) => !renderableImageIds.has(id)) : [];
17677
17733
  const actualImageCount = Math.max(domImages.length, renderableImages.size);
17678
17734
  const canvasReady = !!fabricCanvas && !!(fabricCanvas.lowerCanvasEl || fabricCanvas.upperCanvasEl);
17679
- const hasExpectedAssets = expectedImageCount === 0 ? true : actualImageCount >= expectedImageCount;
17735
+ const hasExpectedAssets = strictById ? missingImageIds.length === 0 : expectedImageCount === 0 ? true : actualImageCount >= expectedImageCount;
17680
17736
  const ready = allDomLoaded && fabricReady && hasExpectedAssets;
17681
- const summary = `expected=${expectedImageCount} actual=${actualImageCount} dom=${domImages.length} fabricReady=${fabricReady} domReady=${allDomLoaded} canvasReady=${canvasReady}`;
17737
+ const summary = `expected=${expectedImageCount} actual=${actualImageCount} fabricIds=${renderableImageIds.size} dom=${domImages.length} fabricReady=${fabricReady} domReady=${allDomLoaded} canvasReady=${canvasReady}${missingImageIds.length ? ` missing=${missingImageIds.join(",")}` : ""}`;
17682
17738
  if (summary !== lastSummary) {
17683
17739
  lastSummary = summary;
17684
17740
  if (debug) console.log(`[canvas-renderer][asset-wait] ${summary}`);
17685
17741
  }
17686
- if (actualImageCount !== lastActual) {
17687
- lastActual = actualImageCount;
17742
+ const progressKey = strictById ? expectedImageIds.filter((id) => renderableImageIds.has(id)).join("|") : String(actualImageCount);
17743
+ if (progressKey !== lastProgressKey) {
17744
+ lastProgressKey = progressKey;
17688
17745
  lastProgressAt = Date.now();
17689
17746
  }
17690
17747
  if (ready) {
@@ -17699,7 +17756,7 @@ class PixldocsRenderer {
17699
17756
  }
17700
17757
  const sceneSettled = fabricReady && allDomLoaded && canvasReady && fabricObjects.length > 0;
17701
17758
  const idleFor = Date.now() - lastProgressAt;
17702
- if (sceneSettled && actualImageCount < expectedImageCount && idleFor >= earlyExitMs) {
17759
+ if (!strictById && sceneSettled && actualImageCount < expectedImageCount && idleFor >= earlyExitMs) {
17703
17760
  if (debug) {
17704
17761
  console.log(
17705
17762
  `[canvas-renderer][asset-wait] early-exit after ${elapsed}ms (idle=${idleFor}ms, ${summary})`
@@ -17723,6 +17780,10 @@ class PixldocsRenderer {
17723
17780
  console.warn(`[canvas-renderer][asset-wait-timeout] elapsed=${elapsed}ms ${summary}`);
17724
17781
  console.warn("[canvas-renderer][asset-wait-timeout][dom-images]", domImageDebug);
17725
17782
  console.warn("[canvas-renderer][asset-wait-timeout][fabric-images]", fabricImageDebug);
17783
+ if (strictById && missingImageIds.length > 0) {
17784
+ reject(new Error(`[canvas-renderer][asset-wait-timeout] Missing expected image(s): ${missingImageIds.join(", ")}`));
17785
+ return;
17786
+ }
17726
17787
  settle();
17727
17788
  return;
17728
17789
  }
@@ -17923,8 +17984,8 @@ class PixldocsRenderer {
17923
17984
  const onReadyOnce = () => {
17924
17985
  this.waitForCanvasScene(container, renderConfig, pageIndex).then(async () => {
17925
17986
  const fabricInstance = this.getFabricCanvasFromContainer(container);
17926
- const expectedImageCount = this.getExpectedImageCount(renderConfig, pageIndex);
17927
- await this.waitForCanvasImages(container, expectedImageCount);
17987
+ const expectedImageIds = this.getExpectedImageIds(renderConfig, pageIndex);
17988
+ await this.waitForCanvasImages(container, expectedImageIds);
17928
17989
  await this.waitForStableTextMetrics(container, renderConfig);
17929
17990
  await this.waitForCanvasScene(container, renderConfig, pageIndex);
17930
17991
  if (!fabricInstance) return settle();
@@ -17950,8 +18011,8 @@ class PixldocsRenderer {
17950
18011
  this.waitForCanvasScene(container, renderConfig, pageIndex).then(async () => {
17951
18012
  try {
17952
18013
  const fabricInstance = this.getFabricCanvasFromContainer(container);
17953
- const expectedImageCount = this.getExpectedImageCount(renderConfig, pageIndex);
17954
- await this.waitForCanvasImages(container, expectedImageCount);
18014
+ const expectedImageIds = this.getExpectedImageIds(renderConfig, pageIndex);
18015
+ await this.waitForCanvasImages(container, expectedImageIds);
17955
18016
  await this.waitForStableTextMetrics(container, renderConfig);
17956
18017
  await this.waitForCanvasScene(container, renderConfig, pageIndex);
17957
18018
  firstMountSettled = true;
@@ -18062,8 +18123,8 @@ class PixldocsRenderer {
18062
18123
  this.waitForCanvasScene(container, renderConfig, pageIndex).then(async () => {
18063
18124
  var _a, _b;
18064
18125
  try {
18065
- const expectedImageCount = this.getExpectedImageCount(renderConfig, pageIndex);
18066
- await this.waitForCanvasImages(container, expectedImageCount);
18126
+ const expectedImageIds = this.getExpectedImageIds(renderConfig, pageIndex);
18127
+ await this.waitForCanvasImages(container, expectedImageIds);
18067
18128
  await this.waitForStableTextMetrics(container, renderConfig);
18068
18129
  await this.waitForCanvasScene(container, renderConfig, pageIndex);
18069
18130
  const fabricInstance = this.getFabricCanvasFromContainer(container);
@@ -19702,7 +19763,7 @@ async function prepareLiveCanvasSvgForPdf(rawSvg, pageWidth, pageHeight, pageKey
19702
19763
  if (options == null ? void 0 : options.stripPageBackground) stripRootPageBackgroundFromSvg(svgToDraw);
19703
19764
  sanitizeSvgTreeForPdf(svgToDraw);
19704
19765
  try {
19705
- const { bakeTextAnchorPositionsFromLiveSvg, logTextMeasurementDiagnostic } = await Promise.resolve().then(() => require("./vectorPdfExport-O8vRHBlU.cjs"));
19766
+ const { bakeTextAnchorPositionsFromLiveSvg, logTextMeasurementDiagnostic } = await Promise.resolve().then(() => require("./vectorPdfExport-BHKMcbVb.cjs"));
19706
19767
  try {
19707
19768
  await logTextMeasurementDiagnostic(svgToDraw);
19708
19769
  } catch {
@@ -20099,4 +20160,4 @@ exports.setAutoShrinkDebug = setAutoShrinkDebug;
20099
20160
  exports.setBundledAssetPrefixes = setBundledAssetPrefixes;
20100
20161
  exports.warmResolvedTemplateForPreview = warmResolvedTemplateForPreview;
20101
20162
  exports.warmTemplateFromForm = warmTemplateFromForm;
20102
- //# sourceMappingURL=index-UIDDdWwb.cjs.map
20163
+ //# sourceMappingURL=index-uwKwubUL.cjs.map