@pixldocs/canvas-renderer 0.5.191 → 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.
- package/README.md +11 -0
- package/dist/{index-C3kuDISv.js → index-CDoyeKa8.js} +107 -26
- package/dist/{index-C3kuDISv.js.map → index-CDoyeKa8.js.map} +1 -1
- package/dist/{index-BJR7zaam.cjs → index-uwKwubUL.cjs} +107 -26
- package/dist/{index-BJR7zaam.cjs.map → index-uwKwubUL.cjs.map} +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +7 -15
- package/dist/index.js +1 -1
- package/dist/{vectorPdfExport-D_2mdcwO.cjs → vectorPdfExport-BHKMcbVb.cjs} +65 -6
- package/dist/vectorPdfExport-BHKMcbVb.cjs.map +1 -0
- package/dist/{vectorPdfExport-CrTGqxx6.js → vectorPdfExport-Cd--tBky.js} +65 -6
- package/dist/vectorPdfExport-Cd--tBky.js.map +1 -0
- package/package.json +1 -1
- package/dist/vectorPdfExport-CrTGqxx6.js.map +0 -1
- package/dist/vectorPdfExport-D_2mdcwO.cjs.map +0 -1
|
@@ -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, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
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
|
|
16836
|
+
const svgPatchRecords = [];
|
|
16820
16837
|
try {
|
|
16821
16838
|
const visit = (obj) => {
|
|
16822
16839
|
if (!obj) return;
|
|
16823
|
-
|
|
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) =>
|
|
16826
|
-
|
|
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
|
|
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.
|
|
16940
|
+
const resolvedPackageVersion = "0.5.193";
|
|
16911
16941
|
const PACKAGE_VERSION = resolvedPackageVersion;
|
|
16912
|
-
const DEPLOYMENT_VERSION_MARKER = "__PIXLDOCS_CANVAS_RENDERER_VERSION__:0.5.
|
|
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.
|
|
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-
|
|
17569
|
+
const { exportMultiPagePdf, preparePagesForExport } = await Promise.resolve().then(() => require("./vectorPdfExport-BHKMcbVb.cjs"));
|
|
17540
17570
|
const prepared = preparePagesForExport(
|
|
17541
17571
|
cloned.pages,
|
|
17542
17572
|
canvasWidth,
|
|
@@ -17547,7 +17577,27 @@ class PixldocsRenderer {
|
|
|
17547
17577
|
watermark: !!options.watermark,
|
|
17548
17578
|
returnBlob: true,
|
|
17549
17579
|
pdfTextMode: options.textMode ?? (cloned == null ? void 0 : cloned.pdfTextMode) ?? ((_a = cloned.canvas) == null ? void 0 : _a.n) ?? "auto",
|
|
17550
|
-
|
|
17580
|
+
// IMPORTANT: We intentionally do NOT skip the live-canvas SVG fast path
|
|
17581
|
+
// here, even when `shouldForcePerElement` is true via auto-detection.
|
|
17582
|
+
//
|
|
17583
|
+
// Reason: skipping the fast path forces the config-space export, which
|
|
17584
|
+
// computes positions from stored values rather than the live Fabric
|
|
17585
|
+
// layout (post auto-shrink, post text-init, post crop-group bake).
|
|
17586
|
+
// That drift causes severe text overlap / mis-positioning in the PDF
|
|
17587
|
+
// while the on-screen preview (which uses the live canvas) still looks
|
|
17588
|
+
// correct. v0.5.191 shipped with this skip enabled and produced exactly
|
|
17589
|
+
// that regression.
|
|
17590
|
+
//
|
|
17591
|
+
// The Safari/iOS "missing photo" issue is solved end-to-end by the
|
|
17592
|
+
// `downscaleConfigRasterImages()` pre-pass above, which shrinks large
|
|
17593
|
+
// `data:image/*` JPEGs to a safe edge length before the canvas mounts.
|
|
17594
|
+
// That alone keeps Safari's SVG capture reliable without altering the
|
|
17595
|
+
// layout pipeline.
|
|
17596
|
+
//
|
|
17597
|
+
// We still honor an explicit `forcePerElementPdf: true` from the host
|
|
17598
|
+
// app (advanced opt-in for niche cases), but the auto path no longer
|
|
17599
|
+
// toggles this flag.
|
|
17600
|
+
skipLiveCanvasSvgFastPath: forceMode === true
|
|
17551
17601
|
});
|
|
17552
17602
|
if (!result || typeof result === "undefined") {
|
|
17553
17603
|
throw new Error("exportMultiPagePdf returned no blob (returnBlob path failed)");
|
|
@@ -17588,17 +17638,21 @@ class PixldocsRenderer {
|
|
|
17588
17638
|
walk(page.children);
|
|
17589
17639
|
return ids;
|
|
17590
17640
|
}
|
|
17591
|
-
waitForCanvasImages(container,
|
|
17641
|
+
waitForCanvasImages(container, expectedImages, maxWaitMs, pollMs = 120) {
|
|
17592
17642
|
const timeout = Math.max(500, maxWaitMs ?? this.config.assetWaitTimeoutMs ?? 15e3);
|
|
17593
17643
|
const earlyExitMs = Math.max(250, this.config.assetWaitEarlyExitMs ?? 1500);
|
|
17594
17644
|
const debug = !!this.config.debug;
|
|
17595
|
-
|
|
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) => {
|
|
17596
17649
|
const start = Date.now();
|
|
17597
17650
|
let stableFrames = 0;
|
|
17598
17651
|
let lastSummary = "";
|
|
17599
|
-
let
|
|
17652
|
+
let lastProgressKey = "";
|
|
17600
17653
|
let lastProgressAt = Date.now();
|
|
17601
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;
|
|
17602
17656
|
const collectRenderableImages = (obj, seen) => {
|
|
17603
17657
|
if (!obj || typeof obj !== "object") return;
|
|
17604
17658
|
const candidates = [obj._element, obj._originalElement, obj._filteredEl, obj._cacheCanvasEl];
|
|
@@ -17615,6 +17669,25 @@ class PixldocsRenderer {
|
|
|
17615
17669
|
}
|
|
17616
17670
|
return true;
|
|
17617
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
|
+
};
|
|
17618
17691
|
const getFabricCanvas = () => {
|
|
17619
17692
|
const registry2 = window.__fabricCanvasRegistry;
|
|
17620
17693
|
if (registry2 instanceof Map) {
|
|
@@ -17654,17 +17727,21 @@ class PixldocsRenderer {
|
|
|
17654
17727
|
const fabricObjects = fabricCanvas && typeof fabricCanvas.getObjects === "function" ? fabricCanvas.getObjects() : [];
|
|
17655
17728
|
const renderableImages = /* @__PURE__ */ new Set();
|
|
17656
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)) : [];
|
|
17657
17733
|
const actualImageCount = Math.max(domImages.length, renderableImages.size);
|
|
17658
17734
|
const canvasReady = !!fabricCanvas && !!(fabricCanvas.lowerCanvasEl || fabricCanvas.upperCanvasEl);
|
|
17659
|
-
const hasExpectedAssets = expectedImageCount === 0 ? true : actualImageCount >= expectedImageCount;
|
|
17735
|
+
const hasExpectedAssets = strictById ? missingImageIds.length === 0 : expectedImageCount === 0 ? true : actualImageCount >= expectedImageCount;
|
|
17660
17736
|
const ready = allDomLoaded && fabricReady && hasExpectedAssets;
|
|
17661
|
-
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(",")}` : ""}`;
|
|
17662
17738
|
if (summary !== lastSummary) {
|
|
17663
17739
|
lastSummary = summary;
|
|
17664
17740
|
if (debug) console.log(`[canvas-renderer][asset-wait] ${summary}`);
|
|
17665
17741
|
}
|
|
17666
|
-
|
|
17667
|
-
|
|
17742
|
+
const progressKey = strictById ? expectedImageIds.filter((id) => renderableImageIds.has(id)).join("|") : String(actualImageCount);
|
|
17743
|
+
if (progressKey !== lastProgressKey) {
|
|
17744
|
+
lastProgressKey = progressKey;
|
|
17668
17745
|
lastProgressAt = Date.now();
|
|
17669
17746
|
}
|
|
17670
17747
|
if (ready) {
|
|
@@ -17679,7 +17756,7 @@ class PixldocsRenderer {
|
|
|
17679
17756
|
}
|
|
17680
17757
|
const sceneSettled = fabricReady && allDomLoaded && canvasReady && fabricObjects.length > 0;
|
|
17681
17758
|
const idleFor = Date.now() - lastProgressAt;
|
|
17682
|
-
if (sceneSettled && actualImageCount < expectedImageCount && idleFor >= earlyExitMs) {
|
|
17759
|
+
if (!strictById && sceneSettled && actualImageCount < expectedImageCount && idleFor >= earlyExitMs) {
|
|
17683
17760
|
if (debug) {
|
|
17684
17761
|
console.log(
|
|
17685
17762
|
`[canvas-renderer][asset-wait] early-exit after ${elapsed}ms (idle=${idleFor}ms, ${summary})`
|
|
@@ -17703,6 +17780,10 @@ class PixldocsRenderer {
|
|
|
17703
17780
|
console.warn(`[canvas-renderer][asset-wait-timeout] elapsed=${elapsed}ms ${summary}`);
|
|
17704
17781
|
console.warn("[canvas-renderer][asset-wait-timeout][dom-images]", domImageDebug);
|
|
17705
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
|
+
}
|
|
17706
17787
|
settle();
|
|
17707
17788
|
return;
|
|
17708
17789
|
}
|
|
@@ -17903,8 +17984,8 @@ class PixldocsRenderer {
|
|
|
17903
17984
|
const onReadyOnce = () => {
|
|
17904
17985
|
this.waitForCanvasScene(container, renderConfig, pageIndex).then(async () => {
|
|
17905
17986
|
const fabricInstance = this.getFabricCanvasFromContainer(container);
|
|
17906
|
-
const
|
|
17907
|
-
await this.waitForCanvasImages(container,
|
|
17987
|
+
const expectedImageIds = this.getExpectedImageIds(renderConfig, pageIndex);
|
|
17988
|
+
await this.waitForCanvasImages(container, expectedImageIds);
|
|
17908
17989
|
await this.waitForStableTextMetrics(container, renderConfig);
|
|
17909
17990
|
await this.waitForCanvasScene(container, renderConfig, pageIndex);
|
|
17910
17991
|
if (!fabricInstance) return settle();
|
|
@@ -17930,8 +18011,8 @@ class PixldocsRenderer {
|
|
|
17930
18011
|
this.waitForCanvasScene(container, renderConfig, pageIndex).then(async () => {
|
|
17931
18012
|
try {
|
|
17932
18013
|
const fabricInstance = this.getFabricCanvasFromContainer(container);
|
|
17933
|
-
const
|
|
17934
|
-
await this.waitForCanvasImages(container,
|
|
18014
|
+
const expectedImageIds = this.getExpectedImageIds(renderConfig, pageIndex);
|
|
18015
|
+
await this.waitForCanvasImages(container, expectedImageIds);
|
|
17935
18016
|
await this.waitForStableTextMetrics(container, renderConfig);
|
|
17936
18017
|
await this.waitForCanvasScene(container, renderConfig, pageIndex);
|
|
17937
18018
|
firstMountSettled = true;
|
|
@@ -18042,8 +18123,8 @@ class PixldocsRenderer {
|
|
|
18042
18123
|
this.waitForCanvasScene(container, renderConfig, pageIndex).then(async () => {
|
|
18043
18124
|
var _a, _b;
|
|
18044
18125
|
try {
|
|
18045
|
-
const
|
|
18046
|
-
await this.waitForCanvasImages(container,
|
|
18126
|
+
const expectedImageIds = this.getExpectedImageIds(renderConfig, pageIndex);
|
|
18127
|
+
await this.waitForCanvasImages(container, expectedImageIds);
|
|
18047
18128
|
await this.waitForStableTextMetrics(container, renderConfig);
|
|
18048
18129
|
await this.waitForCanvasScene(container, renderConfig, pageIndex);
|
|
18049
18130
|
const fabricInstance = this.getFabricCanvasFromContainer(container);
|
|
@@ -19682,7 +19763,7 @@ async function prepareLiveCanvasSvgForPdf(rawSvg, pageWidth, pageHeight, pageKey
|
|
|
19682
19763
|
if (options == null ? void 0 : options.stripPageBackground) stripRootPageBackgroundFromSvg(svgToDraw);
|
|
19683
19764
|
sanitizeSvgTreeForPdf(svgToDraw);
|
|
19684
19765
|
try {
|
|
19685
|
-
const { bakeTextAnchorPositionsFromLiveSvg, logTextMeasurementDiagnostic } = await Promise.resolve().then(() => require("./vectorPdfExport-
|
|
19766
|
+
const { bakeTextAnchorPositionsFromLiveSvg, logTextMeasurementDiagnostic } = await Promise.resolve().then(() => require("./vectorPdfExport-BHKMcbVb.cjs"));
|
|
19686
19767
|
try {
|
|
19687
19768
|
await logTextMeasurementDiagnostic(svgToDraw);
|
|
19688
19769
|
} catch {
|
|
@@ -20079,4 +20160,4 @@ exports.setAutoShrinkDebug = setAutoShrinkDebug;
|
|
|
20079
20160
|
exports.setBundledAssetPrefixes = setBundledAssetPrefixes;
|
|
20080
20161
|
exports.warmResolvedTemplateForPreview = warmResolvedTemplateForPreview;
|
|
20081
20162
|
exports.warmTemplateFromForm = warmTemplateFromForm;
|
|
20082
|
-
//# sourceMappingURL=index-
|
|
20163
|
+
//# sourceMappingURL=index-uwKwubUL.cjs.map
|