@pixldocs/canvas-renderer 0.5.64 → 0.5.66
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 +81 -17
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +81 -17
- package/dist/index.js.map +1 -1
- package/dist/svgTextToPath-BP0Kppla.js +1083 -0
- package/dist/svgTextToPath-BP0Kppla.js.map +1 -0
- package/dist/svgTextToPath-BTHnqJpM.cjs +1105 -0
- package/dist/svgTextToPath-BTHnqJpM.cjs.map +1 -0
- package/package.json +3 -1
package/dist/index.d.ts
CHANGED
|
@@ -254,7 +254,7 @@ export declare function normalizeFontFamily(fontStack: string): string;
|
|
|
254
254
|
* Package version banner. Bump alongside package.json so we can confirm
|
|
255
255
|
* (via browser:log) that the deployed bundle matches the expected build.
|
|
256
256
|
*/
|
|
257
|
-
export declare const PACKAGE_VERSION = "0.5.
|
|
257
|
+
export declare const PACKAGE_VERSION = "0.5.66";
|
|
258
258
|
|
|
259
259
|
export declare interface PageSettings {
|
|
260
260
|
backgroundColor?: string;
|
|
@@ -272,6 +272,8 @@ export declare interface PdfAssemblyOptions {
|
|
|
272
272
|
stripPageBackground?: boolean;
|
|
273
273
|
/** Base URL for TTF font files (e.g. 'https://pixldocs.com/fonts/' or '/fonts/'). Required for correct font rendering. */
|
|
274
274
|
fontBaseUrl?: string;
|
|
275
|
+
/** Convert SVG text to paths before svg2pdf for preview/PDF font metric parity. Default: true. */
|
|
276
|
+
outlineText?: boolean;
|
|
275
277
|
}
|
|
276
278
|
|
|
277
279
|
/** Options for PDF rendering */
|
package/dist/index.js
CHANGED
|
@@ -12542,7 +12542,7 @@ function PixldocsPreview(props) {
|
|
|
12542
12542
|
!canvasSettled && /* @__PURE__ */ jsx("div", { style: { position: "absolute", inset: 0, display: "flex", alignItems: "center", justifyContent: "center", minHeight: 200 }, children: /* @__PURE__ */ jsx("div", { style: { color: "#888", fontSize: 14 }, children: "Loading preview..." }) })
|
|
12543
12543
|
] });
|
|
12544
12544
|
}
|
|
12545
|
-
const PACKAGE_VERSION = "0.5.
|
|
12545
|
+
const PACKAGE_VERSION = "0.5.66";
|
|
12546
12546
|
let __underlineFixInstalled = false;
|
|
12547
12547
|
function installUnderlineFix(fab) {
|
|
12548
12548
|
var _a;
|
|
@@ -13258,6 +13258,7 @@ class PixldocsRenderer {
|
|
|
13258
13258
|
captureSvgViaPreviewCanvas(config, pageIndex, canvasWidth, canvasHeight) {
|
|
13259
13259
|
return new Promise(async (resolve, reject) => {
|
|
13260
13260
|
const { PreviewCanvas: PreviewCanvas2 } = await Promise.resolve().then(() => PreviewCanvas$1);
|
|
13261
|
+
const hasAutoShrink = configHasAutoShrinkText(config);
|
|
13261
13262
|
const container = document.createElement("div");
|
|
13262
13263
|
container.style.cssText = `
|
|
13263
13264
|
position: fixed; left: -99999px; top: -99999px;
|
|
@@ -13270,6 +13271,8 @@ class PixldocsRenderer {
|
|
|
13270
13271
|
reject(new Error("SVG render timeout (30s)"));
|
|
13271
13272
|
}, 3e4);
|
|
13272
13273
|
let root = null;
|
|
13274
|
+
let mountKey = 0;
|
|
13275
|
+
let didPreviewParityRemount = false;
|
|
13273
13276
|
const cleanup = () => {
|
|
13274
13277
|
clearTimeout(timeout);
|
|
13275
13278
|
try {
|
|
@@ -13278,6 +13281,48 @@ class PixldocsRenderer {
|
|
|
13278
13281
|
}
|
|
13279
13282
|
container.remove();
|
|
13280
13283
|
};
|
|
13284
|
+
const mountPreview = (readyHandler) => {
|
|
13285
|
+
root = createRoot(container);
|
|
13286
|
+
root.render(
|
|
13287
|
+
createElement(PreviewCanvas2, {
|
|
13288
|
+
key: `svg-capture-${mountKey}`,
|
|
13289
|
+
config,
|
|
13290
|
+
pageIndex,
|
|
13291
|
+
zoom: 1,
|
|
13292
|
+
absoluteZoom: true,
|
|
13293
|
+
skipFontReadyWait: false,
|
|
13294
|
+
onReady: readyHandler
|
|
13295
|
+
})
|
|
13296
|
+
);
|
|
13297
|
+
};
|
|
13298
|
+
const remountForPreviewParity = async () => {
|
|
13299
|
+
if (didPreviewParityRemount) return;
|
|
13300
|
+
didPreviewParityRemount = true;
|
|
13301
|
+
mountKey += 1;
|
|
13302
|
+
try {
|
|
13303
|
+
clearMeasurementCache();
|
|
13304
|
+
} catch {
|
|
13305
|
+
}
|
|
13306
|
+
try {
|
|
13307
|
+
clearFabricCharCache();
|
|
13308
|
+
} catch {
|
|
13309
|
+
}
|
|
13310
|
+
try {
|
|
13311
|
+
root == null ? void 0 : root.unmount();
|
|
13312
|
+
} catch {
|
|
13313
|
+
}
|
|
13314
|
+
await new Promise((settle) => {
|
|
13315
|
+
mountPreview(() => {
|
|
13316
|
+
this.waitForCanvasScene(container, config, pageIndex).then(async () => {
|
|
13317
|
+
const expectedImageCount = this.getExpectedImageCount(config, pageIndex);
|
|
13318
|
+
await this.waitForCanvasImages(container, expectedImageCount);
|
|
13319
|
+
await this.waitForStableTextMetrics(container, config);
|
|
13320
|
+
await this.waitForCanvasScene(container, config, pageIndex);
|
|
13321
|
+
settle();
|
|
13322
|
+
}).catch(() => settle());
|
|
13323
|
+
});
|
|
13324
|
+
});
|
|
13325
|
+
};
|
|
13281
13326
|
const onReady = () => {
|
|
13282
13327
|
this.waitForCanvasScene(container, config, pageIndex).then(async () => {
|
|
13283
13328
|
var _a, _b;
|
|
@@ -13286,6 +13331,10 @@ class PixldocsRenderer {
|
|
|
13286
13331
|
await this.waitForCanvasImages(container, expectedImageCount);
|
|
13287
13332
|
await this.waitForStableTextMetrics(container, config);
|
|
13288
13333
|
await this.waitForCanvasScene(container, config, pageIndex);
|
|
13334
|
+
if (hasAutoShrink && !didPreviewParityRemount) {
|
|
13335
|
+
console.log("[canvas-renderer][svg-parity] remounting once to match PixldocsPreview auto-shrink stabilization");
|
|
13336
|
+
await remountForPreviewParity();
|
|
13337
|
+
}
|
|
13289
13338
|
const fabricInstance = this.getFabricCanvasFromContainer(container);
|
|
13290
13339
|
if (!fabricInstance) {
|
|
13291
13340
|
cleanup();
|
|
@@ -13334,18 +13383,7 @@ class PixldocsRenderer {
|
|
|
13334
13383
|
}
|
|
13335
13384
|
});
|
|
13336
13385
|
};
|
|
13337
|
-
|
|
13338
|
-
root.render(
|
|
13339
|
-
createElement(PreviewCanvas2, {
|
|
13340
|
-
config,
|
|
13341
|
-
pageIndex,
|
|
13342
|
-
zoom: 1,
|
|
13343
|
-
// 1:1 — no UI scaling for SVG capture
|
|
13344
|
-
absoluteZoom: true,
|
|
13345
|
-
skipFontReadyWait: false,
|
|
13346
|
-
onReady
|
|
13347
|
-
})
|
|
13348
|
-
);
|
|
13386
|
+
mountPreview(onReady);
|
|
13349
13387
|
});
|
|
13350
13388
|
}
|
|
13351
13389
|
/**
|
|
@@ -15160,6 +15198,14 @@ async function svg2pdfWithDomMount(svg, pdf, opts) {
|
|
|
15160
15198
|
async function convertTextDecorationsToLines(svg) {
|
|
15161
15199
|
const doc = svg.ownerDocument;
|
|
15162
15200
|
if (!doc) return;
|
|
15201
|
+
const stripTextDecoration = (el) => {
|
|
15202
|
+
el.removeAttribute("text-decoration");
|
|
15203
|
+
const style = el.getAttribute("style") || "";
|
|
15204
|
+
if (!style) return;
|
|
15205
|
+
const kept = style.split(";").map((part) => part.trim()).filter(Boolean).filter((part) => !/^text-decoration\s*:/i.test(part));
|
|
15206
|
+
if (kept.length > 0) el.setAttribute("style", kept.join("; "));
|
|
15207
|
+
else el.removeAttribute("style");
|
|
15208
|
+
};
|
|
15163
15209
|
const resolveInheritedSvgValue = (el, attr, styleProp = attr) => {
|
|
15164
15210
|
var _a, _b;
|
|
15165
15211
|
let current = el;
|
|
@@ -15310,6 +15356,8 @@ async function convertTextDecorationsToLines(svg) {
|
|
|
15310
15356
|
if (textEl.parentElement) {
|
|
15311
15357
|
textEl.parentElement.insertBefore(line, textEl.nextSibling);
|
|
15312
15358
|
}
|
|
15359
|
+
stripTextDecoration(tspan);
|
|
15360
|
+
if (textHasUnderline) stripTextDecoration(textEl);
|
|
15313
15361
|
}
|
|
15314
15362
|
}
|
|
15315
15363
|
if (tempContainer) {
|
|
@@ -15548,7 +15596,7 @@ function drawPageBackground(pdf, pageIndex, pageWidth, pageHeight, backgroundCol
|
|
|
15548
15596
|
}
|
|
15549
15597
|
}
|
|
15550
15598
|
async function assemblePdfFromSvgs(svgResults, options = {}) {
|
|
15551
|
-
var _a, _b;
|
|
15599
|
+
var _a, _b, _c;
|
|
15552
15600
|
if (svgResults.length === 0) throw new Error("No pages to export");
|
|
15553
15601
|
const { title, stripPageBackground } = options;
|
|
15554
15602
|
const firstPage = svgResults[0];
|
|
@@ -15576,17 +15624,33 @@ async function assemblePdfFromSvgs(svgResults, options = {}) {
|
|
|
15576
15624
|
const hasGradient = !!((_b = (_a = page.backgroundGradient) == null ? void 0 : _a.stops) == null ? void 0 : _b.length);
|
|
15577
15625
|
drawPageBackground(pdf, i, page.width, page.height, page.backgroundColor, page.backgroundGradient);
|
|
15578
15626
|
const shouldStripBg = stripPageBackground ?? hasGradient;
|
|
15627
|
+
const shouldOutlineText = options.outlineText ?? true;
|
|
15579
15628
|
const pageSvg = page.svg;
|
|
15580
15629
|
let processedSvg = await prepareLiveCanvasSvgForPdf(pageSvg, page.width, page.height, `page-${i + 1}`, {
|
|
15581
15630
|
stripPageBackground: shouldStripBg
|
|
15582
15631
|
});
|
|
15583
15632
|
if (processedSvg) {
|
|
15584
|
-
|
|
15585
|
-
|
|
15633
|
+
await convertTextDecorationsToLines(processedSvg);
|
|
15634
|
+
if (shouldOutlineText) {
|
|
15635
|
+
try {
|
|
15636
|
+
const { convertAllTextToPath } = await import("./svgTextToPath-BP0Kppla.js");
|
|
15637
|
+
const outlinedSvg = await convertAllTextToPath(
|
|
15638
|
+
new XMLSerializer().serializeToString(processedSvg),
|
|
15639
|
+
fontBaseUrl
|
|
15640
|
+
);
|
|
15641
|
+
const outlineDoc = new DOMParser().parseFromString(outlinedSvg, "image/svg+xml");
|
|
15642
|
+
const outlinedRoot = outlineDoc.documentElement;
|
|
15643
|
+
if (outlinedRoot && ((_c = outlinedRoot.tagName) == null ? void 0 : _c.toLowerCase()) === "svg" && !outlineDoc.querySelector("parsererror")) {
|
|
15644
|
+
processedSvg = outlinedRoot;
|
|
15645
|
+
}
|
|
15646
|
+
} catch (outlineErr) {
|
|
15647
|
+
console.warn("[canvas-renderer][pdf] text outlining unavailable, falling back to embedded SVG text:", outlineErr);
|
|
15648
|
+
}
|
|
15649
|
+
}
|
|
15650
|
+
const rewrittenSvg = rewriteSvgFontsForJsPDF(new XMLSerializer().serializeToString(processedSvg));
|
|
15586
15651
|
const reParser = new DOMParser();
|
|
15587
15652
|
const reDoc = reParser.parseFromString(rewrittenSvg, "image/svg+xml");
|
|
15588
15653
|
processedSvg = reDoc.documentElement;
|
|
15589
|
-
await convertTextDecorationsToLines(processedSvg);
|
|
15590
15654
|
}
|
|
15591
15655
|
if (processedSvg) {
|
|
15592
15656
|
pdf.setFillColor(0, 0, 0);
|