@pixldocs/canvas-renderer 0.5.61 → 0.5.63
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 +108 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +108 -7
- package/dist/index.js.map +1 -1
- package/package.json +1 -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.63";
|
|
258
258
|
|
|
259
259
|
export declare interface PageSettings {
|
|
260
260
|
backgroundColor?: string;
|
|
@@ -443,6 +443,7 @@ export declare class PixldocsRenderer {
|
|
|
443
443
|
* using the global __fabricCanvasRegistry (set by PageCanvas).
|
|
444
444
|
*/
|
|
445
445
|
private getFabricCanvasFromContainer;
|
|
446
|
+
private resyncTextMetricsForSvgExport;
|
|
446
447
|
private waitForStableTextMetrics;
|
|
447
448
|
}
|
|
448
449
|
|
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.63";
|
|
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;
|
|
@@ -13269,28 +13270,74 @@ class PixldocsRenderer {
|
|
|
13269
13270
|
cleanup();
|
|
13270
13271
|
reject(new Error("SVG render timeout (30s)"));
|
|
13271
13272
|
}, 3e4);
|
|
13273
|
+
let root = null;
|
|
13274
|
+
let mountKey = 0;
|
|
13275
|
+
let didAutoShrinkParityRemount = false;
|
|
13272
13276
|
const cleanup = () => {
|
|
13273
13277
|
clearTimeout(timeout);
|
|
13274
13278
|
try {
|
|
13275
|
-
root.unmount();
|
|
13279
|
+
root == null ? void 0 : root.unmount();
|
|
13276
13280
|
} catch {
|
|
13277
13281
|
}
|
|
13278
13282
|
container.remove();
|
|
13279
13283
|
};
|
|
13284
|
+
const remountForAutoShrinkParity = async () => {
|
|
13285
|
+
didAutoShrinkParityRemount = true;
|
|
13286
|
+
mountKey += 1;
|
|
13287
|
+
try {
|
|
13288
|
+
clearMeasurementCache();
|
|
13289
|
+
} catch {
|
|
13290
|
+
}
|
|
13291
|
+
try {
|
|
13292
|
+
clearFabricCharCache();
|
|
13293
|
+
} catch {
|
|
13294
|
+
}
|
|
13295
|
+
try {
|
|
13296
|
+
root == null ? void 0 : root.unmount();
|
|
13297
|
+
} catch {
|
|
13298
|
+
}
|
|
13299
|
+
root = createRoot(container);
|
|
13300
|
+
await new Promise((settle) => {
|
|
13301
|
+
const onReadyOnce = () => {
|
|
13302
|
+
this.waitForCanvasScene(container, config, pageIndex).then(async () => {
|
|
13303
|
+
const expectedImageCount = this.getExpectedImageCount(config, pageIndex);
|
|
13304
|
+
await this.waitForCanvasImages(container, expectedImageCount);
|
|
13305
|
+
await this.waitForStableTextMetrics(container, config);
|
|
13306
|
+
await this.waitForCanvasScene(container, config, pageIndex);
|
|
13307
|
+
settle();
|
|
13308
|
+
}).catch(() => settle());
|
|
13309
|
+
};
|
|
13310
|
+
root.render(
|
|
13311
|
+
createElement(PreviewCanvas2, {
|
|
13312
|
+
key: `svg-auto-shrink-remount-${mountKey}`,
|
|
13313
|
+
config,
|
|
13314
|
+
pageIndex,
|
|
13315
|
+
zoom: 1,
|
|
13316
|
+
absoluteZoom: true,
|
|
13317
|
+
skipFontReadyWait: false,
|
|
13318
|
+
onReady: onReadyOnce
|
|
13319
|
+
})
|
|
13320
|
+
);
|
|
13321
|
+
});
|
|
13322
|
+
};
|
|
13280
13323
|
const onReady = () => {
|
|
13281
13324
|
this.waitForCanvasScene(container, config, pageIndex).then(async () => {
|
|
13282
13325
|
var _a, _b;
|
|
13283
13326
|
try {
|
|
13327
|
+
const expectedImageCount = this.getExpectedImageCount(config, pageIndex);
|
|
13328
|
+
await this.waitForCanvasImages(container, expectedImageCount);
|
|
13329
|
+
await this.waitForStableTextMetrics(container, config);
|
|
13330
|
+
await this.waitForCanvasScene(container, config, pageIndex);
|
|
13331
|
+
if (hasAutoShrink && !didAutoShrinkParityRemount) {
|
|
13332
|
+
console.log("[canvas-renderer][svg-parity] remounting auto-shrink text before PDF SVG capture");
|
|
13333
|
+
await remountForAutoShrinkParity();
|
|
13334
|
+
}
|
|
13284
13335
|
const fabricInstance = this.getFabricCanvasFromContainer(container);
|
|
13285
13336
|
if (!fabricInstance) {
|
|
13286
13337
|
cleanup();
|
|
13287
13338
|
reject(new Error("No Fabric canvas instance found for SVG capture"));
|
|
13288
13339
|
return;
|
|
13289
13340
|
}
|
|
13290
|
-
const expectedImageCount = this.getExpectedImageCount(config, pageIndex);
|
|
13291
|
-
await this.waitForCanvasImages(container, expectedImageCount);
|
|
13292
|
-
await this.waitForStableTextMetrics(container, config);
|
|
13293
|
-
await this.waitForCanvasScene(container, config, pageIndex);
|
|
13294
13341
|
const prevVPT = fabricInstance.viewportTransform ? [...fabricInstance.viewportTransform] : void 0;
|
|
13295
13342
|
const prevSvgVPT = fabricInstance.svgViewportTransformation;
|
|
13296
13343
|
const prevRetina = fabricInstance.enableRetinaScaling;
|
|
@@ -13303,6 +13350,7 @@ class PixldocsRenderer {
|
|
|
13303
13350
|
{ width: canvasWidth, height: canvasHeight },
|
|
13304
13351
|
{ cssOnly: false, backstoreOnly: false }
|
|
13305
13352
|
);
|
|
13353
|
+
this.resyncTextMetricsForSvgExport(fabricInstance);
|
|
13306
13354
|
const rawSvgString = fabricInstance.toSVG();
|
|
13307
13355
|
const svgString = this.normalizeSvgDimensions(
|
|
13308
13356
|
rawSvgString,
|
|
@@ -13333,7 +13381,7 @@ class PixldocsRenderer {
|
|
|
13333
13381
|
}
|
|
13334
13382
|
});
|
|
13335
13383
|
};
|
|
13336
|
-
|
|
13384
|
+
root = createRoot(container);
|
|
13337
13385
|
root.render(
|
|
13338
13386
|
createElement(PreviewCanvas2, {
|
|
13339
13387
|
config,
|
|
@@ -13413,6 +13461,59 @@ class PixldocsRenderer {
|
|
|
13413
13461
|
}
|
|
13414
13462
|
return null;
|
|
13415
13463
|
}
|
|
13464
|
+
resyncTextMetricsForSvgExport(fabricInstance) {
|
|
13465
|
+
if (typeof document === "undefined" || !(fabricInstance == null ? void 0 : fabricInstance.getObjects)) return;
|
|
13466
|
+
const ctx = document.createElement("canvas").getContext("2d");
|
|
13467
|
+
if (!ctx) return;
|
|
13468
|
+
const syncTextbox = (textbox) => {
|
|
13469
|
+
const tb = textbox;
|
|
13470
|
+
const rawLines = tb._textLines ?? textbox.textLines ?? [];
|
|
13471
|
+
if (!Array.isArray(rawLines) || rawLines.length === 0) return;
|
|
13472
|
+
const nextCharBounds = [];
|
|
13473
|
+
const nextLineWidths = [];
|
|
13474
|
+
rawLines.forEach((rawLine, lineIndex) => {
|
|
13475
|
+
const graphemes = Array.isArray(rawLine) ? rawLine.map((part) => String(part ?? "")) : Array.from(String(rawLine ?? ""));
|
|
13476
|
+
const bounds = [];
|
|
13477
|
+
let left = 0;
|
|
13478
|
+
graphemes.forEach((grapheme, charIndex) => {
|
|
13479
|
+
var _a, _b, _c, _d, _e, _f;
|
|
13480
|
+
const fontSize = Number(((_a = tb.getValueOfPropertyAt) == null ? void 0 : _a.call(tb, lineIndex, charIndex, "fontSize")) ?? textbox.fontSize ?? 16);
|
|
13481
|
+
const fontStyle = String(((_b = tb.getValueOfPropertyAt) == null ? void 0 : _b.call(tb, lineIndex, charIndex, "fontStyle")) ?? textbox.fontStyle ?? "normal");
|
|
13482
|
+
const fontWeight = String(((_c = tb.getValueOfPropertyAt) == null ? void 0 : _c.call(tb, lineIndex, charIndex, "fontWeight")) ?? textbox.fontWeight ?? "400");
|
|
13483
|
+
const fontFamily = String(((_d = tb.getValueOfPropertyAt) == null ? void 0 : _d.call(tb, lineIndex, charIndex, "fontFamily")) ?? textbox.fontFamily ?? "sans-serif");
|
|
13484
|
+
const charSpacing = Number(((_e = tb.getValueOfPropertyAt) == null ? void 0 : _e.call(tb, lineIndex, charIndex, "charSpacing")) ?? textbox.charSpacing ?? 0);
|
|
13485
|
+
const deltaY = Number(((_f = tb.getValueOfPropertyAt) == null ? void 0 : _f.call(tb, lineIndex, charIndex, "deltaY")) ?? 0);
|
|
13486
|
+
ctx.font = `${fontStyle} normal ${fontWeight} ${fontSize}px ${fontFamily}`;
|
|
13487
|
+
const charWidth = Math.max(0, ctx.measureText(grapheme).width);
|
|
13488
|
+
let kernedWidth = charWidth;
|
|
13489
|
+
const previous = charIndex > 0 ? graphemes[charIndex - 1] : "";
|
|
13490
|
+
if (previous) {
|
|
13491
|
+
const pairWidth = ctx.measureText(previous + grapheme).width;
|
|
13492
|
+
const previousWidth = ctx.measureText(previous).width;
|
|
13493
|
+
if (Number.isFinite(pairWidth) && Number.isFinite(previousWidth)) {
|
|
13494
|
+
kernedWidth = Math.max(0, pairWidth - previousWidth);
|
|
13495
|
+
}
|
|
13496
|
+
}
|
|
13497
|
+
if (charIndex < graphemes.length - 1 && charSpacing) {
|
|
13498
|
+
kernedWidth += charSpacing / 1e3 * fontSize;
|
|
13499
|
+
}
|
|
13500
|
+
bounds[charIndex] = { left, width: charWidth, kernedWidth, height: fontSize, deltaY };
|
|
13501
|
+
left += kernedWidth;
|
|
13502
|
+
});
|
|
13503
|
+
bounds[graphemes.length] = { left, width: 0, kernedWidth: 0, height: Number(textbox.fontSize ?? 16), deltaY: 0 };
|
|
13504
|
+
nextCharBounds[lineIndex] = bounds;
|
|
13505
|
+
nextLineWidths[lineIndex] = Math.max(0, left);
|
|
13506
|
+
});
|
|
13507
|
+
tb.__charBounds = nextCharBounds;
|
|
13508
|
+
tb.__lineWidths = nextLineWidths;
|
|
13509
|
+
textbox.dirty = true;
|
|
13510
|
+
};
|
|
13511
|
+
const visit = (obj) => {
|
|
13512
|
+
if (obj instanceof fabric.Textbox) syncTextbox(obj);
|
|
13513
|
+
else if (obj instanceof fabric.Group) obj.getObjects().forEach(visit);
|
|
13514
|
+
};
|
|
13515
|
+
fabricInstance.getObjects().forEach(visit);
|
|
13516
|
+
}
|
|
13416
13517
|
async waitForStableTextMetrics(container, config) {
|
|
13417
13518
|
var _a, _b, _c;
|
|
13418
13519
|
if (typeof document !== "undefined") {
|