@pixldocs/canvas-renderer 0.5.25 → 0.5.27
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 +227 -197
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.js +227 -197
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -9632,6 +9632,10 @@ function PreviewCanvas({
|
|
|
9632
9632
|
}
|
|
9633
9633
|
);
|
|
9634
9634
|
}
|
|
9635
|
+
const PreviewCanvas$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
9636
|
+
__proto__: null,
|
|
9637
|
+
PreviewCanvas
|
|
9638
|
+
}, Symbol.toStringTag, { value: "Module" }));
|
|
9635
9639
|
function applyThemeToConfig(config, themeOverrides) {
|
|
9636
9640
|
var _a, _b, _c;
|
|
9637
9641
|
if (!themeOverrides || Object.keys(themeOverrides).length === 0) return config;
|
|
@@ -11848,74 +11852,17 @@ async function ensureFontsForResolvedConfig(config) {
|
|
|
11848
11852
|
if (typeof document === "undefined") return;
|
|
11849
11853
|
const descriptors = collectFontDescriptorsFromConfig(config);
|
|
11850
11854
|
const families = new Set(descriptors.map((d) => d.family));
|
|
11851
|
-
|
|
11855
|
+
void withTimeout(Promise.all([...families].map((f) => loadGoogleFontCSS(f))), 2500);
|
|
11852
11856
|
if (document.fonts) {
|
|
11853
|
-
|
|
11857
|
+
descriptors.forEach((d) => {
|
|
11854
11858
|
const stylePrefix = d.style === "italic" ? "italic " : "";
|
|
11855
11859
|
const weightStr = String(d.weight);
|
|
11856
11860
|
const spec = `${stylePrefix}${weightStr} 16px "${d.family}"`;
|
|
11857
|
-
|
|
11861
|
+
document.fonts.load(spec).catch(() => {
|
|
11858
11862
|
});
|
|
11859
|
-
})
|
|
11860
|
-
await withTimeout(document.fonts.ready, 6e3);
|
|
11863
|
+
});
|
|
11861
11864
|
}
|
|
11862
11865
|
}
|
|
11863
|
-
const TEXT_TYPES = /* @__PURE__ */ new Set(["textbox", "text", "i-text"]);
|
|
11864
|
-
function getFabricCanvasFromContainer(container) {
|
|
11865
|
-
const registry2 = window.__fabricCanvasRegistry;
|
|
11866
|
-
if (registry2 instanceof Map) {
|
|
11867
|
-
for (const entry of registry2.values()) {
|
|
11868
|
-
const canvas = (entry == null ? void 0 : entry.canvas) || entry;
|
|
11869
|
-
if (!canvas || typeof canvas.toSVG !== "function") continue;
|
|
11870
|
-
const el = canvas.lowerCanvasEl || canvas.upperCanvasEl;
|
|
11871
|
-
if (el && container.contains(el)) return canvas;
|
|
11872
|
-
}
|
|
11873
|
-
}
|
|
11874
|
-
return null;
|
|
11875
|
-
}
|
|
11876
|
-
function stabilizeFabricTextObjects(fabricInstance) {
|
|
11877
|
-
var _a, _b, _c;
|
|
11878
|
-
if (!(fabricInstance == null ? void 0 : fabricInstance.getObjects)) return;
|
|
11879
|
-
clearFabricCharCache();
|
|
11880
|
-
clearMeasurementCache();
|
|
11881
|
-
const walk = (obj) => {
|
|
11882
|
-
var _a2, _b2, _c2, _d;
|
|
11883
|
-
if (!obj) return;
|
|
11884
|
-
const children = Array.isArray(obj._objects) ? obj._objects : Array.isArray(obj.objects) ? obj.objects : [];
|
|
11885
|
-
if (children.length) children.forEach(walk);
|
|
11886
|
-
const isTextObject = typeof obj.text === "string" && typeof obj.initDimensions === "function" && (TEXT_TYPES.has(obj.type) || obj.isEditing !== void 0);
|
|
11887
|
-
if (!isTextObject) return;
|
|
11888
|
-
const saved = { width: obj.width, scaleX: obj.scaleX, scaleY: obj.scaleY };
|
|
11889
|
-
const reset = () => {
|
|
11890
|
-
var _a3;
|
|
11891
|
-
(_a3 = obj._clearCache) == null ? void 0 : _a3.call(obj);
|
|
11892
|
-
obj.__charBounds = [];
|
|
11893
|
-
obj.__lineWidths = [];
|
|
11894
|
-
obj.__lineHeights = [];
|
|
11895
|
-
obj.__graphemeLines = [];
|
|
11896
|
-
obj._textLines = [];
|
|
11897
|
-
obj.textLines = [];
|
|
11898
|
-
obj._styleMap = null;
|
|
11899
|
-
obj.styleMap = null;
|
|
11900
|
-
obj.dirty = true;
|
|
11901
|
-
};
|
|
11902
|
-
reset();
|
|
11903
|
-
obj.initDimensions();
|
|
11904
|
-
if (saved.width != null) {
|
|
11905
|
-
(_a2 = obj.set) == null ? void 0 : _a2.call(obj, { width: saved.width, scaleX: saved.scaleX, scaleY: saved.scaleY });
|
|
11906
|
-
reset();
|
|
11907
|
-
obj.initDimensions();
|
|
11908
|
-
(_b2 = obj.set) == null ? void 0 : _b2.call(obj, { width: saved.width, scaleX: saved.scaleX, scaleY: saved.scaleY });
|
|
11909
|
-
}
|
|
11910
|
-
obj.dirty = true;
|
|
11911
|
-
(_c2 = obj._clearCache) == null ? void 0 : _c2.call(obj);
|
|
11912
|
-
(_d = obj.setCoords) == null ? void 0 : _d.call(obj);
|
|
11913
|
-
};
|
|
11914
|
-
fabricInstance.getObjects().forEach(walk);
|
|
11915
|
-
(_a = fabricInstance.calcOffset) == null ? void 0 : _a.call(fabricInstance);
|
|
11916
|
-
(_b = fabricInstance.renderAll) == null ? void 0 : _b.call(fabricInstance);
|
|
11917
|
-
(_c = fabricInstance.requestRenderAll) == null ? void 0 : _c.call(fabricInstance);
|
|
11918
|
-
}
|
|
11919
11866
|
function PixldocsPreview(props) {
|
|
11920
11867
|
const {
|
|
11921
11868
|
pageIndex = 0,
|
|
@@ -11926,7 +11873,8 @@ function PixldocsPreview(props) {
|
|
|
11926
11873
|
style,
|
|
11927
11874
|
onDynamicFieldClick,
|
|
11928
11875
|
onReady,
|
|
11929
|
-
onError
|
|
11876
|
+
onError,
|
|
11877
|
+
skipFontReadyWait = true
|
|
11930
11878
|
} = props;
|
|
11931
11879
|
react.useEffect(() => {
|
|
11932
11880
|
setPackageApiUrl(imageProxyUrl);
|
|
@@ -11999,6 +11947,7 @@ function PixldocsPreview(props) {
|
|
|
11999
11947
|
const bump = () => {
|
|
12000
11948
|
if (cancelled) return;
|
|
12001
11949
|
clearMeasurementCache();
|
|
11950
|
+
clearFabricCharCache();
|
|
12002
11951
|
setFontsReadyVersion((v) => v + 1);
|
|
12003
11952
|
};
|
|
12004
11953
|
(_b = (_a = document.fonts) == null ? void 0 : _a.ready) == null ? void 0 : _b.then(bump);
|
|
@@ -12012,13 +11961,6 @@ function PixldocsPreview(props) {
|
|
|
12012
11961
|
() => `${pageIndex}-${fontsReadyVersion}-${stabilizationPass}`,
|
|
12013
11962
|
[pageIndex, fontsReadyVersion, stabilizationPass]
|
|
12014
11963
|
);
|
|
12015
|
-
const previewWrapRef = react.useCallback((node) => {
|
|
12016
|
-
if (!node || !config) return;
|
|
12017
|
-
requestAnimationFrame(() => {
|
|
12018
|
-
const fabricCanvas = getFabricCanvasFromContainer(node);
|
|
12019
|
-
if (fabricCanvas) stabilizeFabricTextObjects(fabricCanvas);
|
|
12020
|
-
});
|
|
12021
|
-
}, [config, previewKey]);
|
|
12022
11964
|
react.useEffect(() => {
|
|
12023
11965
|
if (isResolveMode) return;
|
|
12024
11966
|
if (!config) {
|
|
@@ -12049,13 +11991,14 @@ function PixldocsPreview(props) {
|
|
|
12049
11991
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className, style: { ...style, display: "flex", alignItems: "center", justifyContent: "center", minHeight: 200 }, children: /* @__PURE__ */ jsxRuntime.jsx("div", { style: { color: "#888", fontSize: 14 }, children: "Loading preview..." }) });
|
|
12050
11992
|
}
|
|
12051
11993
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, style: { ...style, position: "relative" }, children: [
|
|
12052
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", {
|
|
11994
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { visibility: canvasSettled ? "visible" : "hidden" }, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
12053
11995
|
PreviewCanvas,
|
|
12054
11996
|
{
|
|
12055
11997
|
config,
|
|
12056
11998
|
pageIndex,
|
|
12057
11999
|
zoom,
|
|
12058
12000
|
absoluteZoom,
|
|
12001
|
+
skipFontReadyWait,
|
|
12059
12002
|
onDynamicFieldClick,
|
|
12060
12003
|
onReady: handleCanvasReady
|
|
12061
12004
|
},
|
|
@@ -12064,70 +12007,6 @@ function PixldocsPreview(props) {
|
|
|
12064
12007
|
!canvasSettled && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { position: "absolute", inset: 0, display: "flex", alignItems: "center", justifyContent: "center", minHeight: 200 }, children: /* @__PURE__ */ jsxRuntime.jsx("div", { style: { color: "#888", fontSize: 14 }, children: "Loading preview..." }) })
|
|
12065
12008
|
] });
|
|
12066
12009
|
}
|
|
12067
|
-
const PixldocsPreview$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
12068
|
-
__proto__: null,
|
|
12069
|
-
PixldocsPreview
|
|
12070
|
-
}, Symbol.toStringTag, { value: "Module" }));
|
|
12071
|
-
const inlinedAssetCache = /* @__PURE__ */ new Map();
|
|
12072
|
-
function shouldInlineImageUrl(url) {
|
|
12073
|
-
if (!url || url.startsWith("data:")) return false;
|
|
12074
|
-
if (url.startsWith("blob:")) return true;
|
|
12075
|
-
if (url.startsWith("/") && !url.startsWith("//")) return true;
|
|
12076
|
-
try {
|
|
12077
|
-
const parsed = new URL(url, window.location.href);
|
|
12078
|
-
const current = new URL(window.location.href);
|
|
12079
|
-
const host = parsed.hostname.toLowerCase();
|
|
12080
|
-
return parsed.origin === current.origin || host === "localhost" || host === "127.0.0.1" || host === "0.0.0.0" || host.endsWith(".local") || /^(10\.|192\.168\.|169\.254\.)/.test(host);
|
|
12081
|
-
} catch {
|
|
12082
|
-
return false;
|
|
12083
|
-
}
|
|
12084
|
-
}
|
|
12085
|
-
async function imageUrlToDataUrl(url) {
|
|
12086
|
-
if (inlinedAssetCache.has(url)) return inlinedAssetCache.get(url) ?? null;
|
|
12087
|
-
try {
|
|
12088
|
-
const response = await fetch(url);
|
|
12089
|
-
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
|
12090
|
-
const blob = await response.blob();
|
|
12091
|
-
if (blob.type.includes("text/html")) throw new Error("Expected image but got text/html");
|
|
12092
|
-
const dataUrl = await new Promise((resolve, reject) => {
|
|
12093
|
-
const reader = new FileReader();
|
|
12094
|
-
reader.onloadend = () => resolve(String(reader.result || ""));
|
|
12095
|
-
reader.onerror = reject;
|
|
12096
|
-
reader.readAsDataURL(blob);
|
|
12097
|
-
});
|
|
12098
|
-
inlinedAssetCache.set(url, dataUrl);
|
|
12099
|
-
return dataUrl;
|
|
12100
|
-
} catch (error) {
|
|
12101
|
-
console.warn("[@pixldocs/canvas-renderer] Failed to inline image asset:", url, error);
|
|
12102
|
-
inlinedAssetCache.set(url, null);
|
|
12103
|
-
return null;
|
|
12104
|
-
}
|
|
12105
|
-
}
|
|
12106
|
-
async function inlineNodeAssets(node) {
|
|
12107
|
-
if (node.type === "image") {
|
|
12108
|
-
const url = typeof node.src === "string" && node.src.trim() ? node.src.trim() : typeof node.imageUrl === "string" ? node.imageUrl.trim() : "";
|
|
12109
|
-
if (shouldInlineImageUrl(url)) {
|
|
12110
|
-
const dataUrl = await imageUrlToDataUrl(url);
|
|
12111
|
-
if (dataUrl) {
|
|
12112
|
-
node.src = dataUrl;
|
|
12113
|
-
node.imageUrl = dataUrl;
|
|
12114
|
-
}
|
|
12115
|
-
}
|
|
12116
|
-
}
|
|
12117
|
-
if (Array.isArray(node.children)) {
|
|
12118
|
-
await Promise.all(node.children.map(inlineNodeAssets));
|
|
12119
|
-
}
|
|
12120
|
-
}
|
|
12121
|
-
async function inlineBrowserReachableImageAssets(config) {
|
|
12122
|
-
if (typeof window === "undefined" || typeof fetch === "undefined" || typeof FileReader === "undefined") {
|
|
12123
|
-
return config;
|
|
12124
|
-
}
|
|
12125
|
-
const cloned = JSON.parse(JSON.stringify(config));
|
|
12126
|
-
await Promise.all(
|
|
12127
|
-
(cloned.pages || []).flatMap((page) => (page.children || []).map(inlineNodeAssets))
|
|
12128
|
-
);
|
|
12129
|
-
return cloned;
|
|
12130
|
-
}
|
|
12131
12010
|
class PixldocsRenderer {
|
|
12132
12011
|
constructor(config) {
|
|
12133
12012
|
__publicField(this, "config");
|
|
@@ -12138,22 +12017,21 @@ class PixldocsRenderer {
|
|
|
12138
12017
|
* Mounts a hidden PreviewCanvas component and captures the Fabric canvas output.
|
|
12139
12018
|
*/
|
|
12140
12019
|
async render(templateConfig, options = {}) {
|
|
12141
|
-
const renderConfig = await inlineBrowserReachableImageAssets(templateConfig);
|
|
12142
12020
|
const pageIndex = options.pageIndex ?? 0;
|
|
12143
12021
|
const format = options.format ?? "png";
|
|
12144
12022
|
const quality = options.quality ?? 0.92;
|
|
12145
12023
|
const pixelRatio = options.pixelRatio ?? this.config.pixelRatio ?? 2;
|
|
12146
|
-
const canvasWidth =
|
|
12147
|
-
const canvasHeight =
|
|
12148
|
-
const page =
|
|
12024
|
+
const canvasWidth = templateConfig.canvas.width;
|
|
12025
|
+
const canvasHeight = templateConfig.canvas.height;
|
|
12026
|
+
const page = templateConfig.pages[pageIndex];
|
|
12149
12027
|
if (!page) {
|
|
12150
|
-
throw new Error(`Page index ${pageIndex} not found (template has ${
|
|
12028
|
+
throw new Error(`Page index ${pageIndex} not found (template has ${templateConfig.pages.length} pages)`);
|
|
12151
12029
|
}
|
|
12152
|
-
await ensureFontsForResolvedConfig(
|
|
12030
|
+
await ensureFontsForResolvedConfig(templateConfig);
|
|
12153
12031
|
const { setPackageApiUrl: setPackageApiUrl2 } = await Promise.resolve().then(() => appApi);
|
|
12154
12032
|
setPackageApiUrl2(this.config.imageProxyUrl);
|
|
12155
12033
|
const dataUrl = await this.renderPageViaPreviewCanvas(
|
|
12156
|
-
|
|
12034
|
+
templateConfig,
|
|
12157
12035
|
pageIndex,
|
|
12158
12036
|
pixelRatio,
|
|
12159
12037
|
format,
|
|
@@ -12205,17 +12083,16 @@ class PixldocsRenderer {
|
|
|
12205
12083
|
* This is the key building block for client-side vector PDF export.
|
|
12206
12084
|
*/
|
|
12207
12085
|
async renderPageSvg(templateConfig, pageIndex = 0) {
|
|
12208
|
-
const
|
|
12209
|
-
const page = renderConfig.pages[pageIndex];
|
|
12086
|
+
const page = templateConfig.pages[pageIndex];
|
|
12210
12087
|
if (!page) {
|
|
12211
|
-
throw new Error(`Page index ${pageIndex} not found (template has ${
|
|
12088
|
+
throw new Error(`Page index ${pageIndex} not found (template has ${templateConfig.pages.length} pages)`);
|
|
12212
12089
|
}
|
|
12213
|
-
await ensureFontsForResolvedConfig(
|
|
12090
|
+
await ensureFontsForResolvedConfig(templateConfig);
|
|
12214
12091
|
const { setPackageApiUrl: setPackageApiUrl2 } = await Promise.resolve().then(() => appApi);
|
|
12215
12092
|
setPackageApiUrl2(this.config.imageProxyUrl);
|
|
12216
|
-
const canvasWidth =
|
|
12217
|
-
const canvasHeight =
|
|
12218
|
-
return this.captureSvgViaPreviewCanvas(
|
|
12093
|
+
const canvasWidth = templateConfig.canvas.width;
|
|
12094
|
+
const canvasHeight = templateConfig.canvas.height;
|
|
12095
|
+
return this.captureSvgViaPreviewCanvas(templateConfig, pageIndex, canvasWidth, canvasHeight);
|
|
12219
12096
|
}
|
|
12220
12097
|
/**
|
|
12221
12098
|
* Render all pages and return SVG strings for each.
|
|
@@ -12548,7 +12425,7 @@ class PixldocsRenderer {
|
|
|
12548
12425
|
}
|
|
12549
12426
|
}
|
|
12550
12427
|
async renderPageViaPreviewCanvas(config, pageIndex, pixelRatio, format, quality) {
|
|
12551
|
-
const {
|
|
12428
|
+
const { PreviewCanvas: PreviewCanvas2 } = await Promise.resolve().then(() => PreviewCanvas$1);
|
|
12552
12429
|
const canvasWidth = config.canvas.width;
|
|
12553
12430
|
const canvasHeight = config.canvas.height;
|
|
12554
12431
|
return new Promise((resolve, reject) => {
|
|
@@ -12556,14 +12433,13 @@ class PixldocsRenderer {
|
|
|
12556
12433
|
container.style.cssText = `
|
|
12557
12434
|
position: fixed; left: -99999px; top: -99999px;
|
|
12558
12435
|
width: ${canvasWidth}px; height: ${canvasHeight}px;
|
|
12559
|
-
overflow: hidden; pointer-events: none;
|
|
12436
|
+
overflow: hidden; pointer-events: none; opacity: 0;
|
|
12560
12437
|
`;
|
|
12561
12438
|
document.body.appendChild(container);
|
|
12562
12439
|
const timeout = setTimeout(() => {
|
|
12563
12440
|
cleanup();
|
|
12564
12441
|
reject(new Error("Render timeout (30s)"));
|
|
12565
12442
|
}, 3e4);
|
|
12566
|
-
let finished = false;
|
|
12567
12443
|
const cleanup = () => {
|
|
12568
12444
|
clearTimeout(timeout);
|
|
12569
12445
|
try {
|
|
@@ -12573,12 +12449,8 @@ class PixldocsRenderer {
|
|
|
12573
12449
|
container.remove();
|
|
12574
12450
|
};
|
|
12575
12451
|
const onReady = () => {
|
|
12576
|
-
if (finished) return;
|
|
12577
|
-
finished = true;
|
|
12578
12452
|
this.waitForCanvasScene(container, config, pageIndex).then(async () => {
|
|
12579
12453
|
try {
|
|
12580
|
-
await this.waitForStableTextMetrics(container, config, true);
|
|
12581
|
-
await this.waitForCanvasScene(container, config, pageIndex, 2500, 50);
|
|
12582
12454
|
const fabricInstance = this.getFabricCanvasFromContainer(container);
|
|
12583
12455
|
const expectedImageCount = this.getExpectedImageCount(config, pageIndex);
|
|
12584
12456
|
await this.waitForCanvasImages(container, expectedImageCount);
|
|
@@ -12590,8 +12462,8 @@ class PixldocsRenderer {
|
|
|
12590
12462
|
return;
|
|
12591
12463
|
}
|
|
12592
12464
|
const exportCanvas = document.createElement("canvas");
|
|
12593
|
-
exportCanvas.width =
|
|
12594
|
-
exportCanvas.height =
|
|
12465
|
+
exportCanvas.width = sourceCanvas.width;
|
|
12466
|
+
exportCanvas.height = sourceCanvas.height;
|
|
12595
12467
|
const exportCtx = exportCanvas.getContext("2d");
|
|
12596
12468
|
if (!exportCtx) {
|
|
12597
12469
|
cleanup();
|
|
@@ -12599,10 +12471,10 @@ class PixldocsRenderer {
|
|
|
12599
12471
|
return;
|
|
12600
12472
|
}
|
|
12601
12473
|
exportCtx.save();
|
|
12602
|
-
exportCtx.scale(
|
|
12474
|
+
exportCtx.scale(sourceCanvas.width / canvasWidth, sourceCanvas.height / canvasHeight);
|
|
12603
12475
|
this.paintPageBackground(exportCtx, config.pages[pageIndex], canvasWidth, canvasHeight);
|
|
12604
12476
|
exportCtx.restore();
|
|
12605
|
-
exportCtx.drawImage(sourceCanvas, 0, 0
|
|
12477
|
+
exportCtx.drawImage(sourceCanvas, 0, 0);
|
|
12606
12478
|
const mimeType = format === "jpeg" ? "image/jpeg" : format === "webp" ? "image/webp" : "image/png";
|
|
12607
12479
|
const dataUrl = exportCanvas.toDataURL(mimeType, quality);
|
|
12608
12480
|
cleanup();
|
|
@@ -12615,11 +12487,12 @@ class PixldocsRenderer {
|
|
|
12615
12487
|
};
|
|
12616
12488
|
const root = client.createRoot(container);
|
|
12617
12489
|
root.render(
|
|
12618
|
-
react.createElement(
|
|
12490
|
+
react.createElement(PreviewCanvas2, {
|
|
12619
12491
|
config,
|
|
12620
12492
|
pageIndex,
|
|
12621
|
-
zoom:
|
|
12493
|
+
zoom: pixelRatio,
|
|
12622
12494
|
absoluteZoom: true,
|
|
12495
|
+
skipFontReadyWait: true,
|
|
12623
12496
|
onReady
|
|
12624
12497
|
})
|
|
12625
12498
|
);
|
|
@@ -12636,19 +12509,18 @@ class PixldocsRenderer {
|
|
|
12636
12509
|
// document space (e.g. 612x792) instead of inflated pixel space.
|
|
12637
12510
|
captureSvgViaPreviewCanvas(config, pageIndex, canvasWidth, canvasHeight) {
|
|
12638
12511
|
return new Promise(async (resolve, reject) => {
|
|
12639
|
-
const {
|
|
12512
|
+
const { PreviewCanvas: PreviewCanvas2 } = await Promise.resolve().then(() => PreviewCanvas$1);
|
|
12640
12513
|
const container = document.createElement("div");
|
|
12641
12514
|
container.style.cssText = `
|
|
12642
12515
|
position: fixed; left: -99999px; top: -99999px;
|
|
12643
12516
|
width: ${canvasWidth}px; height: ${canvasHeight}px;
|
|
12644
|
-
overflow: hidden; pointer-events: none;
|
|
12517
|
+
overflow: hidden; pointer-events: none; opacity: 0;
|
|
12645
12518
|
`;
|
|
12646
12519
|
document.body.appendChild(container);
|
|
12647
12520
|
const timeout = setTimeout(() => {
|
|
12648
12521
|
cleanup();
|
|
12649
12522
|
reject(new Error("SVG render timeout (30s)"));
|
|
12650
12523
|
}, 3e4);
|
|
12651
|
-
let finished = false;
|
|
12652
12524
|
const cleanup = () => {
|
|
12653
12525
|
clearTimeout(timeout);
|
|
12654
12526
|
try {
|
|
@@ -12658,13 +12530,9 @@ class PixldocsRenderer {
|
|
|
12658
12530
|
container.remove();
|
|
12659
12531
|
};
|
|
12660
12532
|
const onReady = () => {
|
|
12661
|
-
if (finished) return;
|
|
12662
|
-
finished = true;
|
|
12663
12533
|
this.waitForCanvasScene(container, config, pageIndex).then(async () => {
|
|
12664
12534
|
var _a, _b;
|
|
12665
12535
|
try {
|
|
12666
|
-
await this.waitForStableTextMetrics(container, config, true);
|
|
12667
|
-
await this.waitForCanvasScene(container, config, pageIndex, 2500, 50);
|
|
12668
12536
|
const fabricInstance = this.getFabricCanvasFromContainer(container);
|
|
12669
12537
|
if (!fabricInstance) {
|
|
12670
12538
|
cleanup();
|
|
@@ -12717,12 +12585,13 @@ class PixldocsRenderer {
|
|
|
12717
12585
|
};
|
|
12718
12586
|
const root = client.createRoot(container);
|
|
12719
12587
|
root.render(
|
|
12720
|
-
react.createElement(
|
|
12588
|
+
react.createElement(PreviewCanvas2, {
|
|
12721
12589
|
config,
|
|
12722
12590
|
pageIndex,
|
|
12723
12591
|
zoom: 1,
|
|
12724
12592
|
// 1:1 — no UI scaling for SVG capture
|
|
12725
12593
|
absoluteZoom: true,
|
|
12594
|
+
skipFontReadyWait: true,
|
|
12726
12595
|
onReady
|
|
12727
12596
|
})
|
|
12728
12597
|
);
|
|
@@ -12783,12 +12652,21 @@ class PixldocsRenderer {
|
|
|
12783
12652
|
* using the global __fabricCanvasRegistry (set by PageCanvas).
|
|
12784
12653
|
*/
|
|
12785
12654
|
getFabricCanvasFromContainer(container) {
|
|
12786
|
-
|
|
12655
|
+
const registry2 = window.__fabricCanvasRegistry;
|
|
12656
|
+
if (registry2 instanceof Map) {
|
|
12657
|
+
for (const entry of registry2.values()) {
|
|
12658
|
+
const canvas = (entry == null ? void 0 : entry.canvas) || entry;
|
|
12659
|
+
if (!canvas || typeof canvas.toSVG !== "function") continue;
|
|
12660
|
+
const el = canvas.lowerCanvasEl || canvas.upperCanvasEl;
|
|
12661
|
+
if (el && container.contains(el)) return canvas;
|
|
12662
|
+
}
|
|
12663
|
+
}
|
|
12664
|
+
return null;
|
|
12787
12665
|
}
|
|
12788
|
-
async waitForStableTextMetrics(container, config
|
|
12666
|
+
async waitForStableTextMetrics(container, config) {
|
|
12789
12667
|
if (typeof document !== "undefined") {
|
|
12790
|
-
|
|
12791
|
-
await this.waitForRelevantFonts(config
|
|
12668
|
+
void ensureFontsForResolvedConfig(config);
|
|
12669
|
+
await this.waitForRelevantFonts(config);
|
|
12792
12670
|
}
|
|
12793
12671
|
const fabricInstance = this.getFabricCanvasFromContainer(container);
|
|
12794
12672
|
if (!(fabricInstance == null ? void 0 : fabricInstance.getObjects)) return;
|
|
@@ -12797,7 +12675,59 @@ class PixldocsRenderer {
|
|
|
12797
12675
|
clearFabricCharCache();
|
|
12798
12676
|
clearMeasurementCache();
|
|
12799
12677
|
};
|
|
12800
|
-
const reflowTextboxes = () =>
|
|
12678
|
+
const reflowTextboxes = () => {
|
|
12679
|
+
var _a, _b, _c;
|
|
12680
|
+
const walk = (obj) => {
|
|
12681
|
+
var _a2, _b2, _c2, _d;
|
|
12682
|
+
if (!obj) return;
|
|
12683
|
+
const children = Array.isArray(obj._objects) ? obj._objects : Array.isArray(obj.objects) ? obj.objects : [];
|
|
12684
|
+
if (children.length) children.forEach(walk);
|
|
12685
|
+
const isTextObject = typeof obj.text === "string" && typeof obj.initDimensions === "function" && (obj.type === "textbox" || obj.type === "text" || obj.type === "i-text" || obj.isEditing !== void 0);
|
|
12686
|
+
if (isTextObject) {
|
|
12687
|
+
const saved = {
|
|
12688
|
+
width: obj.width,
|
|
12689
|
+
scaleX: obj.scaleX,
|
|
12690
|
+
scaleY: obj.scaleY
|
|
12691
|
+
};
|
|
12692
|
+
const resetTextboxLayoutInternals = () => {
|
|
12693
|
+
var _a3;
|
|
12694
|
+
(_a3 = obj._clearCache) == null ? void 0 : _a3.call(obj);
|
|
12695
|
+
obj.__charBounds = [];
|
|
12696
|
+
obj.__lineWidths = [];
|
|
12697
|
+
obj.__lineHeights = [];
|
|
12698
|
+
obj.__graphemeLines = [];
|
|
12699
|
+
obj._textLines = [];
|
|
12700
|
+
obj.textLines = [];
|
|
12701
|
+
obj._styleMap = null;
|
|
12702
|
+
obj.styleMap = null;
|
|
12703
|
+
obj.dirty = true;
|
|
12704
|
+
};
|
|
12705
|
+
resetTextboxLayoutInternals();
|
|
12706
|
+
obj.initDimensions();
|
|
12707
|
+
if (saved.width != null) {
|
|
12708
|
+
(_a2 = obj.set) == null ? void 0 : _a2.call(obj, {
|
|
12709
|
+
width: saved.width,
|
|
12710
|
+
scaleX: saved.scaleX,
|
|
12711
|
+
scaleY: saved.scaleY
|
|
12712
|
+
});
|
|
12713
|
+
resetTextboxLayoutInternals();
|
|
12714
|
+
obj.initDimensions();
|
|
12715
|
+
}
|
|
12716
|
+
(_b2 = obj.set) == null ? void 0 : _b2.call(obj, {
|
|
12717
|
+
width: saved.width,
|
|
12718
|
+
scaleX: saved.scaleX,
|
|
12719
|
+
scaleY: saved.scaleY,
|
|
12720
|
+
dirty: true
|
|
12721
|
+
});
|
|
12722
|
+
(_c2 = obj._clearCache) == null ? void 0 : _c2.call(obj);
|
|
12723
|
+
(_d = obj.setCoords) == null ? void 0 : _d.call(obj);
|
|
12724
|
+
}
|
|
12725
|
+
};
|
|
12726
|
+
fabricInstance.getObjects().forEach(walk);
|
|
12727
|
+
(_a = fabricInstance.calcOffset) == null ? void 0 : _a.call(fabricInstance);
|
|
12728
|
+
(_b = fabricInstance.renderAll) == null ? void 0 : _b.call(fabricInstance);
|
|
12729
|
+
(_c = fabricInstance.requestRenderAll) == null ? void 0 : _c.call(fabricInstance);
|
|
12730
|
+
};
|
|
12801
12731
|
clearTextMetricCaches();
|
|
12802
12732
|
await waitForPaint();
|
|
12803
12733
|
reflowTextboxes();
|
|
@@ -13531,6 +13461,9 @@ function rewriteSvgFontsForJsPDF(svgStr) {
|
|
|
13531
13461
|
const resolved = resolveFontWeight(weight);
|
|
13532
13462
|
const isItalic = /italic|oblique/i.test(styleRaw);
|
|
13533
13463
|
const jsPdfName = getEmbeddedJsPDFFontName(clean, resolved, isItalic);
|
|
13464
|
+
el.setAttribute("data-source-font-family", clean);
|
|
13465
|
+
el.setAttribute("data-source-font-weight", String(resolved));
|
|
13466
|
+
el.setAttribute("data-source-font-style", isItalic ? "italic" : "normal");
|
|
13534
13467
|
const directText = Array.from(el.childNodes).filter((n) => n.nodeType === 3).map((n) => n.textContent || "").join("");
|
|
13535
13468
|
const hasDevanagari = containsDevanagari(directText);
|
|
13536
13469
|
if (hasDevanagari && directText.length > 0) {
|
|
@@ -14512,24 +14445,89 @@ async function svg2pdfWithDomMount(svg, pdf, opts) {
|
|
|
14512
14445
|
if (wrap.parentNode) document.body.removeChild(wrap);
|
|
14513
14446
|
}
|
|
14514
14447
|
}
|
|
14515
|
-
function convertTextDecorationsToLines(svg) {
|
|
14448
|
+
async function convertTextDecorationsToLines(svg) {
|
|
14516
14449
|
const doc = svg.ownerDocument;
|
|
14517
14450
|
if (!doc) return;
|
|
14518
|
-
|
|
14451
|
+
const resolveInheritedSvgValue = (el, attr, styleProp = attr) => {
|
|
14452
|
+
var _a, _b;
|
|
14453
|
+
let current = el;
|
|
14454
|
+
while (current) {
|
|
14455
|
+
const attrValue = (_a = current.getAttribute(attr)) == null ? void 0 : _a.trim();
|
|
14456
|
+
if (attrValue) return attrValue;
|
|
14457
|
+
const styleValue = (_b = getInlineStyleValue(current, styleProp)) == null ? void 0 : _b.trim();
|
|
14458
|
+
if (styleValue) return styleValue;
|
|
14459
|
+
current = current.parentElement;
|
|
14460
|
+
}
|
|
14461
|
+
return null;
|
|
14462
|
+
};
|
|
14463
|
+
if (typeof document !== "undefined" && document.fonts) {
|
|
14464
|
+
const fontFamilies = /* @__PURE__ */ new Set();
|
|
14465
|
+
for (const textEl of svg.querySelectorAll("text")) {
|
|
14466
|
+
const ff = textEl.getAttribute("data-source-font-family") || textEl.getAttribute("font-family");
|
|
14467
|
+
if (ff) fontFamilies.add(ff.replace(/'/g, ""));
|
|
14468
|
+
for (const tspan of textEl.querySelectorAll("tspan")) {
|
|
14469
|
+
const tff = tspan.getAttribute("data-source-font-family") || tspan.getAttribute("font-family");
|
|
14470
|
+
if (tff) fontFamilies.add(tff.replace(/'/g, ""));
|
|
14471
|
+
}
|
|
14472
|
+
}
|
|
14473
|
+
await Promise.all(Array.from(fontFamilies).flatMap((ff) => [
|
|
14474
|
+
document.fonts.load(`16px "${ff}"`).then(() => {
|
|
14475
|
+
}).catch(() => {
|
|
14476
|
+
}),
|
|
14477
|
+
document.fonts.load(`bold 16px "${ff}"`).then(() => {
|
|
14478
|
+
}).catch(() => {
|
|
14479
|
+
})
|
|
14480
|
+
]));
|
|
14481
|
+
await document.fonts.ready;
|
|
14482
|
+
}
|
|
14483
|
+
let tempContainer = null;
|
|
14484
|
+
let liveSvg = null;
|
|
14485
|
+
try {
|
|
14486
|
+
if (typeof document !== "undefined") {
|
|
14487
|
+
tempContainer = document.createElement("div");
|
|
14488
|
+
tempContainer.style.cssText = "position:fixed;left:-9999px;top:-9999px;visibility:hidden;pointer-events:none;";
|
|
14489
|
+
document.body.appendChild(tempContainer);
|
|
14490
|
+
const clone = svg.cloneNode(true);
|
|
14491
|
+
for (const textNode of clone.querySelectorAll("text, tspan, textPath")) {
|
|
14492
|
+
const sourceFamily = textNode.getAttribute("data-source-font-family");
|
|
14493
|
+
const sourceWeight = textNode.getAttribute("data-source-font-weight");
|
|
14494
|
+
const sourceStyle = textNode.getAttribute("data-source-font-style");
|
|
14495
|
+
if (sourceFamily) textNode.setAttribute("font-family", sourceFamily);
|
|
14496
|
+
if (sourceWeight) textNode.setAttribute("font-weight", sourceWeight);
|
|
14497
|
+
if (sourceStyle) textNode.setAttribute("font-style", sourceStyle);
|
|
14498
|
+
const inlineStyle = textNode.getAttribute("style") || "";
|
|
14499
|
+
const stylePairs = inlineStyle.split(";").map((part) => part.trim()).filter(Boolean).filter((part) => !/^font-family\s*:/i.test(part) && !/^font-weight\s*:/i.test(part) && !/^font-style\s*:/i.test(part));
|
|
14500
|
+
if (sourceFamily) stylePairs.push(`font-family: ${sourceFamily}`);
|
|
14501
|
+
if (sourceWeight) stylePairs.push(`font-weight: ${sourceWeight}`);
|
|
14502
|
+
if (sourceStyle) stylePairs.push(`font-style: ${sourceStyle}`);
|
|
14503
|
+
if (stylePairs.length > 0) textNode.setAttribute("style", stylePairs.join("; "));
|
|
14504
|
+
}
|
|
14505
|
+
tempContainer.appendChild(clone);
|
|
14506
|
+
liveSvg = clone;
|
|
14507
|
+
}
|
|
14508
|
+
} catch {
|
|
14509
|
+
}
|
|
14519
14510
|
let ctx = null;
|
|
14520
14511
|
try {
|
|
14521
|
-
|
|
14512
|
+
const realDoc = typeof document !== "undefined" ? document : doc;
|
|
14513
|
+
const measureCanvas = realDoc.createElement("canvas");
|
|
14522
14514
|
ctx = measureCanvas.getContext("2d");
|
|
14523
14515
|
} catch {
|
|
14524
14516
|
}
|
|
14525
14517
|
const textEls = Array.from(svg.querySelectorAll("text"));
|
|
14526
|
-
|
|
14518
|
+
const liveTextEls = liveSvg ? Array.from(liveSvg.querySelectorAll("text")) : null;
|
|
14519
|
+
for (let ti = 0; ti < textEls.length; ti++) {
|
|
14520
|
+
const textEl = textEls[ti];
|
|
14521
|
+
const liveTextEl = liveTextEls == null ? void 0 : liveTextEls[ti];
|
|
14527
14522
|
const tspans = Array.from(textEl.querySelectorAll("tspan"));
|
|
14528
14523
|
if (tspans.length === 0) continue;
|
|
14524
|
+
const liveTspans = liveTextEl ? Array.from(liveTextEl.querySelectorAll("tspan")) : null;
|
|
14529
14525
|
const textDecOnText = (textEl.getAttribute("text-decoration") || "").toLowerCase();
|
|
14530
14526
|
const textStyleDec = (getInlineStyleValue(textEl, "text-decoration") || "").toLowerCase();
|
|
14531
14527
|
const textHasUnderline = textDecOnText.includes("underline") || textStyleDec.includes("underline");
|
|
14532
|
-
for (
|
|
14528
|
+
for (let si = 0; si < tspans.length; si++) {
|
|
14529
|
+
const tspan = tspans[si];
|
|
14530
|
+
const liveTspan = liveTspans == null ? void 0 : liveTspans[si];
|
|
14533
14531
|
const tspanDec = (tspan.getAttribute("text-decoration") || "").toLowerCase();
|
|
14534
14532
|
const tspanStyleDec = (getInlineStyleValue(tspan, "text-decoration") || "").toLowerCase();
|
|
14535
14533
|
const hasUnderline = tspanDec.includes("underline") || tspanStyleDec.includes("underline") || textHasUnderline;
|
|
@@ -14543,41 +14541,73 @@ function convertTextDecorationsToLines(svg) {
|
|
|
14543
14541
|
const fontSize = parseFloat(
|
|
14544
14542
|
tspan.getAttribute("font-size") || textEl.getAttribute("font-size") || "16"
|
|
14545
14543
|
);
|
|
14546
|
-
const fontFamily = tspan.getAttribute("font-family") || textEl.getAttribute("font-family") || "sans-serif";
|
|
14547
|
-
const fontWeight = tspan.getAttribute("font-weight") || textEl.getAttribute("font-weight") || "normal";
|
|
14544
|
+
const fontFamily = tspan.getAttribute("data-source-font-family") || textEl.getAttribute("data-source-font-family") || resolveInheritedSvgValue(tspan, "font-family") || "sans-serif";
|
|
14545
|
+
const fontWeight = tspan.getAttribute("data-source-font-weight") || textEl.getAttribute("data-source-font-weight") || resolveInheritedSvgValue(tspan, "font-weight") || "normal";
|
|
14546
|
+
const fontStyle = tspan.getAttribute("data-source-font-style") || textEl.getAttribute("data-source-font-style") || resolveInheritedSvgValue(tspan, "font-style") || "normal";
|
|
14548
14547
|
const fill = tspan.getAttribute("fill") || textEl.getAttribute("fill") || "#000000";
|
|
14549
|
-
let textWidth = 0;
|
|
14550
|
-
if (
|
|
14548
|
+
let textWidth = content.length * fontSize * 0.6;
|
|
14549
|
+
if (ctx) {
|
|
14550
|
+
ctx.font = `${fontStyle} ${fontWeight} ${fontSize}px ${fontFamily.replace(/'/g, "")}`;
|
|
14551
|
+
textWidth = ctx.measureText(content).width;
|
|
14552
|
+
}
|
|
14553
|
+
const textAnchorRaw = (resolveInheritedSvgValue(tspan, "text-anchor") || "start").toLowerCase();
|
|
14554
|
+
const textAnchor = textAnchorRaw === "middle" || textAnchorRaw === "end" ? textAnchorRaw : "start";
|
|
14555
|
+
let lineStartX = x - (textAnchor === "middle" ? textWidth / 2 : textAnchor === "end" ? textWidth : 0);
|
|
14556
|
+
let lineEndX = lineStartX + textWidth;
|
|
14557
|
+
let baselineY = y;
|
|
14558
|
+
if (liveTspan) {
|
|
14551
14559
|
try {
|
|
14552
|
-
|
|
14560
|
+
const liveCharCount = liveTspan.getNumberOfChars();
|
|
14561
|
+
const svgWidth = liveTspan.getComputedTextLength();
|
|
14562
|
+
if (Number.isFinite(svgWidth) && svgWidth > 0) {
|
|
14563
|
+
textWidth = Math.max(textWidth, svgWidth);
|
|
14564
|
+
}
|
|
14565
|
+
if (liveCharCount > 0) {
|
|
14566
|
+
const start = liveTspan.getStartPositionOfChar(0);
|
|
14567
|
+
const end = liveTspan.getEndPositionOfChar(liveCharCount - 1);
|
|
14568
|
+
if (Number.isFinite(start.x)) lineStartX = start.x;
|
|
14569
|
+
if (Number.isFinite(start.y)) baselineY = start.y;
|
|
14570
|
+
if (Number.isFinite(end.x)) lineEndX = Math.max(end.x, lineStartX + textWidth);
|
|
14571
|
+
if (Number.isFinite(end.y) && !Number.isFinite(baselineY)) baselineY = end.y;
|
|
14572
|
+
} else {
|
|
14573
|
+
lineEndX = lineStartX + textWidth;
|
|
14574
|
+
}
|
|
14575
|
+
const bbox = liveTspan.getBBox();
|
|
14576
|
+
if (Number.isFinite(bbox.x) && Number.isFinite(bbox.width)) {
|
|
14577
|
+
lineStartX = Math.min(lineStartX, bbox.x);
|
|
14578
|
+
lineEndX = Math.max(lineEndX, bbox.x + bbox.width);
|
|
14579
|
+
}
|
|
14553
14580
|
} catch {
|
|
14554
14581
|
}
|
|
14555
14582
|
}
|
|
14556
|
-
if (!
|
|
14557
|
-
|
|
14558
|
-
|
|
14559
|
-
textWidth = ctx.measureText(content).width;
|
|
14560
|
-
} else {
|
|
14561
|
-
textWidth = content.length * fontSize * 0.6;
|
|
14562
|
-
}
|
|
14583
|
+
if (!(lineEndX > lineStartX)) {
|
|
14584
|
+
lineStartX = x - (textAnchor === "middle" ? textWidth / 2 : textAnchor === "end" ? textWidth : 0);
|
|
14585
|
+
lineEndX = lineStartX + textWidth;
|
|
14563
14586
|
}
|
|
14564
|
-
const underlineY =
|
|
14587
|
+
const underlineY = baselineY + fontSize * 0.15;
|
|
14565
14588
|
const thickness = Math.max(0.5, fontSize * 0.066667);
|
|
14566
14589
|
const line = doc.createElementNS("http://www.w3.org/2000/svg", "line");
|
|
14567
|
-
line.setAttribute("x1", String(
|
|
14590
|
+
line.setAttribute("x1", String(lineStartX));
|
|
14568
14591
|
line.setAttribute("y1", String(underlineY));
|
|
14569
|
-
line.setAttribute("x2", String(
|
|
14592
|
+
line.setAttribute("x2", String(lineEndX));
|
|
14570
14593
|
line.setAttribute("y2", String(underlineY));
|
|
14571
14594
|
line.setAttribute("stroke", fill.startsWith("url(") ? "#000000" : fill);
|
|
14572
14595
|
line.setAttribute("stroke-width", String(thickness));
|
|
14596
|
+
line.setAttribute("stroke-linecap", "butt");
|
|
14573
14597
|
line.setAttribute("fill", "none");
|
|
14574
14598
|
if (textEl.parentElement) {
|
|
14575
14599
|
textEl.parentElement.insertBefore(line, textEl.nextSibling);
|
|
14576
14600
|
}
|
|
14577
14601
|
}
|
|
14578
14602
|
}
|
|
14603
|
+
if (tempContainer) {
|
|
14604
|
+
try {
|
|
14605
|
+
document.body.removeChild(tempContainer);
|
|
14606
|
+
} catch {
|
|
14607
|
+
}
|
|
14608
|
+
}
|
|
14579
14609
|
}
|
|
14580
|
-
function prepareLiveCanvasSvgForPdf(rawSvg, pageWidth, pageHeight, pageKey, options) {
|
|
14610
|
+
async function prepareLiveCanvasSvgForPdf(rawSvg, pageWidth, pageHeight, pageKey, options) {
|
|
14581
14611
|
try {
|
|
14582
14612
|
const parser = new DOMParser();
|
|
14583
14613
|
const processedSvg = inlineNestedSvgImageDataUris(rawSvg, parser);
|
|
@@ -14606,7 +14636,6 @@ function prepareLiveCanvasSvgForPdf(rawSvg, pageWidth, pageHeight, pageKey, opti
|
|
|
14606
14636
|
stripSuspiciousFullPageOverlayNodes(svgToDraw);
|
|
14607
14637
|
if (options == null ? void 0 : options.stripPageBackground) stripRootPageBackgroundFromSvg(svgToDraw);
|
|
14608
14638
|
sanitizeSvgTreeForPdf(svgToDraw);
|
|
14609
|
-
convertTextDecorationsToLines(svgToDraw);
|
|
14610
14639
|
return svgToDraw;
|
|
14611
14640
|
} catch {
|
|
14612
14641
|
return null;
|
|
@@ -14709,7 +14738,7 @@ async function assemblePdfFromSvgs(svgResults, options = {}) {
|
|
|
14709
14738
|
const hasGradient = !!((_b = (_a = page.backgroundGradient) == null ? void 0 : _a.stops) == null ? void 0 : _b.length);
|
|
14710
14739
|
drawPageBackground(pdf, i, page.width, page.height, page.backgroundColor, page.backgroundGradient);
|
|
14711
14740
|
const shouldStripBg = stripPageBackground ?? hasGradient;
|
|
14712
|
-
let processedSvg = prepareLiveCanvasSvgForPdf(page.svg, page.width, page.height, `page-${i + 1}`, {
|
|
14741
|
+
let processedSvg = await prepareLiveCanvasSvgForPdf(page.svg, page.width, page.height, `page-${i + 1}`, {
|
|
14713
14742
|
stripPageBackground: shouldStripBg
|
|
14714
14743
|
});
|
|
14715
14744
|
if (processedSvg) {
|
|
@@ -14718,6 +14747,7 @@ async function assemblePdfFromSvgs(svgResults, options = {}) {
|
|
|
14718
14747
|
const reParser = new DOMParser();
|
|
14719
14748
|
const reDoc = reParser.parseFromString(rewrittenSvg, "image/svg+xml");
|
|
14720
14749
|
processedSvg = reDoc.documentElement;
|
|
14750
|
+
await convertTextDecorationsToLines(processedSvg);
|
|
14721
14751
|
}
|
|
14722
14752
|
if (processedSvg) {
|
|
14723
14753
|
pdf.setFillColor(0, 0, 0);
|