@pixldocs/canvas-renderer 0.5.496 → 0.5.497
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-CiSoT2Lk.js → index-CKhnRi3S.js} +346 -66
- package/dist/index-CKhnRi3S.js.map +1 -0
- package/dist/{index-CZtvER5z.cjs → index-CZm1oVfa.cjs} +329 -49
- package/dist/index-CZm1oVfa.cjs.map +1 -0
- package/dist/index.cjs +2 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +31 -0
- package/dist/index.js +18 -17
- package/dist/{vectorPdfExport-E3x8GBto.js → vectorPdfExport-DV-TJwjP.js} +4 -4
- package/dist/{vectorPdfExport-E3x8GBto.js.map → vectorPdfExport-DV-TJwjP.js.map} +1 -1
- package/dist/{vectorPdfExport-B2KtFs76.cjs → vectorPdfExport-De8UFmDy.cjs} +4 -4
- package/dist/{vectorPdfExport-B2KtFs76.cjs.map → vectorPdfExport-De8UFmDy.cjs.map} +1 -1
- package/package.json +1 -1
- package/dist/canvasWatermark-B0ab38Ok.cjs +0 -123
- package/dist/canvasWatermark-B0ab38Ok.cjs.map +0 -1
- package/dist/canvasWatermark-pkhacGge.js +0 -123
- package/dist/canvasWatermark-pkhacGge.js.map +0 -1
- package/dist/index-CZtvER5z.cjs.map +0 -1
- package/dist/index-CiSoT2Lk.js.map +0 -1
|
@@ -94,6 +94,15 @@ const generateId = (prefix = "el") => {
|
|
|
94
94
|
return `${prefix}-${Date.now().toString(36)}-${Math.random().toString(36).substr(2, 9)}-${Math.random().toString(36).substr(2, 9)}`;
|
|
95
95
|
};
|
|
96
96
|
const createDefaultElement = (partial) => {
|
|
97
|
+
const loose = partial;
|
|
98
|
+
if (loose.type === "frame" || loose.type === "group") {
|
|
99
|
+
return createDefaultGroup({
|
|
100
|
+
layoutMode: loose.layout,
|
|
101
|
+
...partial,
|
|
102
|
+
type: "group",
|
|
103
|
+
children: Array.isArray(loose.children) ? loose.children : []
|
|
104
|
+
});
|
|
105
|
+
}
|
|
97
106
|
const isText = partial.type === "text";
|
|
98
107
|
const base = {
|
|
99
108
|
left: 48,
|
|
@@ -111,7 +120,7 @@ const createDefaultElement = (partial) => {
|
|
|
111
120
|
originY: "top",
|
|
112
121
|
opacity: 1,
|
|
113
122
|
fill: "#e2e8f0",
|
|
114
|
-
...isText ? {} : { stroke: "
|
|
123
|
+
...isText ? {} : { stroke: "transparent", strokeWidth: 0 },
|
|
115
124
|
visible: true,
|
|
116
125
|
selectable: true,
|
|
117
126
|
evented: true,
|
|
@@ -957,49 +966,15 @@ function worldPointToParentLocal(worldX, worldY, parent, pageChildren, resolveGr
|
|
|
957
966
|
);
|
|
958
967
|
return { left: local.x, top: local.y };
|
|
959
968
|
}
|
|
960
|
-
function unbakeChildrenToGroupLocal(group) {
|
|
961
|
-
const angle = getGroupAngleDeg(group);
|
|
962
|
-
if (Math.abs(angle) < 0.01) return group;
|
|
963
|
-
const { width, height } = getGroupFrameSize(group);
|
|
964
|
-
const cx = width / 2;
|
|
965
|
-
const cy = height / 2;
|
|
966
|
-
const inv = rotateAroundAffDeg(-angle, cx, cy);
|
|
967
|
-
const kids = (group.children ?? []).map((child) => {
|
|
968
|
-
const p = applyAff(inv, child.left ?? 0, child.top ?? 0);
|
|
969
|
-
const childAngle = typeof child.angle === "number" ? child.angle : 0;
|
|
970
|
-
const localAngle = normalizeAngleDeg(childAngle - angle);
|
|
971
|
-
if (isGroup(child)) {
|
|
972
|
-
const relocated = {
|
|
973
|
-
...child,
|
|
974
|
-
left: p.x,
|
|
975
|
-
top: p.y,
|
|
976
|
-
angle: localAngle
|
|
977
|
-
};
|
|
978
|
-
return Math.abs(getGroupAngleDeg(relocated)) > 0.01 ? unbakeChildrenToGroupLocal(relocated) : relocated;
|
|
979
|
-
}
|
|
980
|
-
return {
|
|
981
|
-
...child,
|
|
982
|
-
left: p.x,
|
|
983
|
-
top: p.y,
|
|
984
|
-
angle: localAngle
|
|
985
|
-
};
|
|
986
|
-
});
|
|
987
|
-
return { ...group, children: kids };
|
|
988
|
-
}
|
|
989
969
|
function migratePageTreeToGroupOwnedTransforms(nodes) {
|
|
990
970
|
return nodes.map((node) => {
|
|
991
971
|
if (!isGroup(node)) return node;
|
|
992
972
|
const g = node;
|
|
993
|
-
|
|
973
|
+
const next = {
|
|
994
974
|
...g,
|
|
995
975
|
children: migratePageTreeToGroupOwnedTransforms(g.children ?? [])
|
|
996
976
|
};
|
|
997
|
-
if (isRotatableGroup(next)
|
|
998
|
-
if (g.groupTransformModel !== "owned-v1") {
|
|
999
|
-
next = unbakeChildrenToGroupLocal(next);
|
|
1000
|
-
next.groupTransformModel = "owned-v1";
|
|
1001
|
-
}
|
|
1002
|
-
} else if (isRotatableGroup(next)) {
|
|
977
|
+
if (isRotatableGroup(next)) {
|
|
1003
978
|
next.groupTransformModel = "owned-v1";
|
|
1004
979
|
}
|
|
1005
980
|
return next;
|
|
@@ -6368,8 +6343,13 @@ async function loadImageAsync(element, placeholder, fc, fabricRef, syncLockedRef
|
|
|
6368
6343
|
});
|
|
6369
6344
|
const imgLoadOptions = url.startsWith("data:") || url.startsWith("blob:") ? {} : { crossOrigin: "anonymous" };
|
|
6370
6345
|
const img = await fabric.FabricImage.fromURL(url, imgLoadOptions);
|
|
6371
|
-
if (!fabricRef.current) return;
|
|
6346
|
+
if (fabricRef && !fabricRef.current) return;
|
|
6372
6347
|
await normalizeSvgImageDimensions(img, imageUrl, element.sourceFormat);
|
|
6348
|
+
const natW = img.width ?? 0;
|
|
6349
|
+
const natH = img.height ?? 0;
|
|
6350
|
+
if (natW <= 1 && natH <= 1 && Number(element.width) > 8 && Number(element.height) > 8) {
|
|
6351
|
+
throw new Error(`image decoded to ${natW}x${natH} — treating as failed load`);
|
|
6352
|
+
}
|
|
6373
6353
|
const isHidden = !element.visible;
|
|
6374
6354
|
img.set({
|
|
6375
6355
|
originX: "left",
|
|
@@ -6567,9 +6547,111 @@ async function loadImageAsync(element, placeholder, fc, fabricRef, syncLockedRef
|
|
|
6567
6547
|
proxiedUrl: getProxiedImageUrl(imageUrl).slice(0, 240),
|
|
6568
6548
|
error: error instanceof Error ? error.message : String(error)
|
|
6569
6549
|
});
|
|
6550
|
+
if (fc.__pixldocsEditMode === true) {
|
|
6551
|
+
try {
|
|
6552
|
+
markPlaceholderAsBrokenImage(placeholder);
|
|
6553
|
+
fc.requestRenderAll();
|
|
6554
|
+
} catch {
|
|
6555
|
+
}
|
|
6556
|
+
}
|
|
6570
6557
|
return;
|
|
6571
6558
|
}
|
|
6572
6559
|
}
|
|
6560
|
+
function markPlaceholderAsBrokenImage(placeholder) {
|
|
6561
|
+
if (!(placeholder instanceof fabric.Group)) return;
|
|
6562
|
+
const group = placeholder;
|
|
6563
|
+
if (group.__pixldocsBrokenImage) return;
|
|
6564
|
+
group.__pixldocsBrokenImage = true;
|
|
6565
|
+
const frameChild = group.getObjects().find(
|
|
6566
|
+
(o) => o.__isPlaceholderFrame
|
|
6567
|
+
);
|
|
6568
|
+
const w = Math.max(1, (frameChild == null ? void 0 : frameChild.width) ?? group.width ?? 1);
|
|
6569
|
+
const h = Math.max(1, (frameChild == null ? void 0 : frameChild.height) ?? group.height ?? 1);
|
|
6570
|
+
const center = group.getCenterPoint();
|
|
6571
|
+
const cx = center.x;
|
|
6572
|
+
const cy = center.y;
|
|
6573
|
+
const prevPose = { left: group.left, top: group.top, width: group.width, height: group.height };
|
|
6574
|
+
const bg = new fabric.Rect({
|
|
6575
|
+
originX: "center",
|
|
6576
|
+
originY: "center",
|
|
6577
|
+
left: cx,
|
|
6578
|
+
top: cy,
|
|
6579
|
+
width: w,
|
|
6580
|
+
height: h,
|
|
6581
|
+
fill: "rgba(148, 163, 184, 0.12)",
|
|
6582
|
+
stroke: "#94A3B8",
|
|
6583
|
+
strokeWidth: 1.5,
|
|
6584
|
+
strokeDashArray: [6, 4]
|
|
6585
|
+
});
|
|
6586
|
+
const s = Math.max(16, Math.min(w, h) * 0.28);
|
|
6587
|
+
const glyphStroke = { stroke: "#64748B", strokeWidth: Math.max(1.5, s / 12), fill: "transparent" };
|
|
6588
|
+
const iconFrame = new fabric.Rect({
|
|
6589
|
+
originX: "center",
|
|
6590
|
+
originY: "center",
|
|
6591
|
+
left: cx,
|
|
6592
|
+
top: cy,
|
|
6593
|
+
width: s,
|
|
6594
|
+
height: s * 0.8,
|
|
6595
|
+
rx: s * 0.08,
|
|
6596
|
+
ry: s * 0.08,
|
|
6597
|
+
...glyphStroke
|
|
6598
|
+
});
|
|
6599
|
+
const mountain = new fabric.Polyline(
|
|
6600
|
+
[
|
|
6601
|
+
{ x: -s * 0.38, y: s * 0.24 },
|
|
6602
|
+
{ x: -s * 0.1, y: -s * 0.08 },
|
|
6603
|
+
{ x: s * 0.08, y: s * 0.1 },
|
|
6604
|
+
{ x: s * 0.22, y: -s * 0.02 },
|
|
6605
|
+
{ x: s * 0.38, y: s * 0.24 }
|
|
6606
|
+
],
|
|
6607
|
+
{ originX: "center", originY: "center", left: cx, top: cy + s * 0.08, ...glyphStroke }
|
|
6608
|
+
);
|
|
6609
|
+
const slash = new fabric.Line([cx - s * 0.55, cy - s * 0.5, cx + s * 0.55, cy + s * 0.5], {
|
|
6610
|
+
...glyphStroke,
|
|
6611
|
+
originX: "center",
|
|
6612
|
+
originY: "center",
|
|
6613
|
+
left: cx,
|
|
6614
|
+
top: cy
|
|
6615
|
+
});
|
|
6616
|
+
for (const obj of [bg, iconFrame, mountain, slash]) {
|
|
6617
|
+
obj.set({ selectable: false, evented: false, excludeFromExport: true });
|
|
6618
|
+
obj.__pixldocsEditorChrome = true;
|
|
6619
|
+
group.add(obj);
|
|
6620
|
+
}
|
|
6621
|
+
group.set(prevPose);
|
|
6622
|
+
group.setCoords();
|
|
6623
|
+
group.dirty = true;
|
|
6624
|
+
}
|
|
6625
|
+
function hideEditorChromeForExport(fc) {
|
|
6626
|
+
const hidden = [];
|
|
6627
|
+
const walk = (objs) => {
|
|
6628
|
+
var _a2;
|
|
6629
|
+
for (const o of objs) {
|
|
6630
|
+
if (o.__pixldocsEditorChrome && o.visible !== false) {
|
|
6631
|
+
o.visible = false;
|
|
6632
|
+
hidden.push(o);
|
|
6633
|
+
}
|
|
6634
|
+
const kids = (_a2 = o.getObjects) == null ? void 0 : _a2.call(o);
|
|
6635
|
+
if (kids == null ? void 0 : kids.length) walk(kids);
|
|
6636
|
+
}
|
|
6637
|
+
};
|
|
6638
|
+
walk(fc.getObjects());
|
|
6639
|
+
if (hidden.length) {
|
|
6640
|
+
for (const o of hidden) {
|
|
6641
|
+
const g = o.group;
|
|
6642
|
+
if (g) g.dirty = true;
|
|
6643
|
+
}
|
|
6644
|
+
fc.renderAll();
|
|
6645
|
+
}
|
|
6646
|
+
return () => {
|
|
6647
|
+
for (const o of hidden) {
|
|
6648
|
+
o.visible = true;
|
|
6649
|
+
const g = o.group;
|
|
6650
|
+
if (g) g.dirty = true;
|
|
6651
|
+
}
|
|
6652
|
+
if (hidden.length) fc.requestRenderAll();
|
|
6653
|
+
};
|
|
6654
|
+
}
|
|
6573
6655
|
const canvasImageLoader = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
6574
6656
|
__proto__: null,
|
|
6575
6657
|
SVG_DECODE_HARD_CAP,
|
|
@@ -6579,12 +6661,14 @@ const canvasImageLoader = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.d
|
|
|
6579
6661
|
fetchSvgTextPublic,
|
|
6580
6662
|
getNormalizedSvgUrl,
|
|
6581
6663
|
getProxiedImageUrl,
|
|
6664
|
+
hideEditorChromeForExport,
|
|
6582
6665
|
isBundledAssetUrl,
|
|
6583
6666
|
isEmptyImagePlaceholderGroup,
|
|
6584
6667
|
isPrivateUrl,
|
|
6585
6668
|
isSvgImage,
|
|
6586
6669
|
loadImageAsync,
|
|
6587
6670
|
loadSvgDimensions,
|
|
6671
|
+
markPlaceholderAsBrokenImage,
|
|
6588
6672
|
normalizeSvgImageDimensions,
|
|
6589
6673
|
parseSvgDimensionsFromText,
|
|
6590
6674
|
preloadImage,
|
|
@@ -18096,6 +18180,7 @@ const PageCanvas = forwardRef(
|
|
|
18096
18180
|
// Transparent so underlay (page bg + group bgs) shows through
|
|
18097
18181
|
backgroundColor: "transparent"
|
|
18098
18182
|
});
|
|
18183
|
+
fabricCanvas.__pixldocsEditMode = isEditorMode && !isPreviewMode;
|
|
18099
18184
|
fabricCanvas.hoverCursor = "default";
|
|
18100
18185
|
fabricCanvas.moveCursor = "move";
|
|
18101
18186
|
const suppressTextEditForClick = (textbox) => {
|
|
@@ -25421,6 +25506,7 @@ const PageCanvas = forwardRef(
|
|
|
25421
25506
|
} else if (obj instanceof fabric.Textbox) {
|
|
25422
25507
|
const overflowPolicy = element.overflowPolicy || "grow-and-push";
|
|
25423
25508
|
let text = element.text != null && element.text !== "" ? element.text : " ";
|
|
25509
|
+
text = applyElementTextCase(text, element.textCase);
|
|
25424
25510
|
let parsedStyles = null;
|
|
25425
25511
|
if (element.formattingEnabled === true) {
|
|
25426
25512
|
const parsed = parseTextMarkdown(text);
|
|
@@ -26065,6 +26151,13 @@ const PageCanvas = forwardRef(
|
|
|
26065
26151
|
const img = await fabric.FabricImage.fromURL(url, { crossOrigin: "anonymous" });
|
|
26066
26152
|
if (!fabricRef.current || !isLatestRequest()) return;
|
|
26067
26153
|
await normalizeSvgImageDimensions(img, imageUrl, element.sourceFormat, svgDecodeTarget);
|
|
26154
|
+
{
|
|
26155
|
+
const natW = img.width ?? 0;
|
|
26156
|
+
const natH = img.height ?? 0;
|
|
26157
|
+
if (natW <= 1 && natH <= 1 && Number(element.width) > 8 && Number(element.height) > 8) {
|
|
26158
|
+
throw new Error(`image decoded to ${natW}x${natH} — treating as failed load`);
|
|
26159
|
+
}
|
|
26160
|
+
}
|
|
26068
26161
|
if (!isLatestRequest()) return;
|
|
26069
26162
|
const imageFitForFade = element.imageFit || ((_a2 = element.style) == null ? void 0 : _a2.imageFit) || "cover";
|
|
26070
26163
|
const clipShapeForFade = element.clipShape ?? ((_b2 = element.style) == null ? void 0 : _b2.imageFrameShape) ?? (isPreviewMode ? "rectangle" : "none");
|
|
@@ -26431,6 +26524,19 @@ const PageCanvas = forwardRef(
|
|
|
26431
26524
|
}
|
|
26432
26525
|
fc.requestRenderAll();
|
|
26433
26526
|
} catch (error) {
|
|
26527
|
+
console.error("[PageCanvas] image failed to load", {
|
|
26528
|
+
id: element.id,
|
|
26529
|
+
url: (element.src || element.imageUrl || "").slice(0, 200),
|
|
26530
|
+
error: error instanceof Error ? error.message : String(error)
|
|
26531
|
+
});
|
|
26532
|
+
const fcNow = fabricRef.current;
|
|
26533
|
+
if (fcNow && fcNow.__pixldocsEditMode === true) {
|
|
26534
|
+
try {
|
|
26535
|
+
markPlaceholderAsBrokenImage(placeholder);
|
|
26536
|
+
fcNow.requestRenderAll();
|
|
26537
|
+
} catch {
|
|
26538
|
+
}
|
|
26539
|
+
}
|
|
26434
26540
|
}
|
|
26435
26541
|
};
|
|
26436
26542
|
const handleCanvasClick = useCallback(
|
|
@@ -34101,6 +34207,14 @@ function captureFabricCanvasSvgForPdf(fabricInstance, canvasWidth, canvasHeight)
|
|
|
34101
34207
|
try {
|
|
34102
34208
|
const visit = (obj) => {
|
|
34103
34209
|
if (!obj) return;
|
|
34210
|
+
if (obj.__pixldocsEditorChrome) {
|
|
34211
|
+
const originalToSVG = typeof obj.toSVG === "function" ? obj.toSVG.bind(obj) : null;
|
|
34212
|
+
if (originalToSVG) {
|
|
34213
|
+
obj.toSVG = () => "";
|
|
34214
|
+
svgPatchRecords.push({ obj, originalToSVG });
|
|
34215
|
+
}
|
|
34216
|
+
return;
|
|
34217
|
+
}
|
|
34104
34218
|
const imageId = typeof obj.__docuforgeId === "string" && hasRenderableRasterCandidate(obj) ? obj.__docuforgeId : "";
|
|
34105
34219
|
const alphaGradient = objectNeedsAlphaGradientRaster(obj);
|
|
34106
34220
|
if ((isTextboxLike(obj) || imageId || alphaGradient) && typeof obj.toSVG === "function") {
|
|
@@ -34208,9 +34322,9 @@ function captureFabricCanvasSvgForPdf(fabricInstance, canvasWidth, canvasHeight)
|
|
|
34208
34322
|
}
|
|
34209
34323
|
return svgString;
|
|
34210
34324
|
}
|
|
34211
|
-
const resolvedPackageVersion = "0.5.
|
|
34325
|
+
const resolvedPackageVersion = "0.5.497";
|
|
34212
34326
|
const PACKAGE_VERSION = resolvedPackageVersion;
|
|
34213
|
-
const DEPLOYMENT_VERSION_MARKER = "__PIXLDOCS_CANVAS_RENDERER_VERSION__:0.5.
|
|
34327
|
+
const DEPLOYMENT_VERSION_MARKER = "__PIXLDOCS_CANVAS_RENDERER_VERSION__:0.5.497";
|
|
34214
34328
|
const roundParityValue = (value) => {
|
|
34215
34329
|
if (typeof value !== "number") return value;
|
|
34216
34330
|
return Number.isFinite(value) ? Number(value.toFixed(3)) : value;
|
|
@@ -34649,6 +34763,11 @@ class PixldocsRenderer {
|
|
|
34649
34763
|
* Mounts a hidden PreviewCanvas component and captures the Fabric canvas output.
|
|
34650
34764
|
*/
|
|
34651
34765
|
async render(templateConfig, options = {}) {
|
|
34766
|
+
if (options.watermark === true && !templateConfig.__pixldocsWatermarked) {
|
|
34767
|
+
const { injectWatermark: injectWatermark2 } = await Promise.resolve().then(() => canvasWatermark);
|
|
34768
|
+
templateConfig = injectWatermark2(templateConfig, options.watermarkOptions);
|
|
34769
|
+
templateConfig.__pixldocsWatermarked = true;
|
|
34770
|
+
}
|
|
34652
34771
|
const pageIndex = options.pageIndex ?? 0;
|
|
34653
34772
|
const format = options.format ?? "png";
|
|
34654
34773
|
const quality = options.quality ?? 0.92;
|
|
@@ -34664,6 +34783,7 @@ class PixldocsRenderer {
|
|
|
34664
34783
|
const hasAutoShrink = configHasAutoShrinkText(templateConfig);
|
|
34665
34784
|
const defaultWait = hasAutoShrink ? 4e3 : 1800;
|
|
34666
34785
|
await this.awaitFontsForConfig(templateConfig, options.waitForFontsMs ?? defaultWait);
|
|
34786
|
+
this.flushTextMeasurementCaches();
|
|
34667
34787
|
}
|
|
34668
34788
|
const { setPackageApiUrl: setPackageApiUrl2 } = await Promise.resolve().then(() => appApi);
|
|
34669
34789
|
setPackageApiUrl2(this.config.imageProxyUrl);
|
|
@@ -34691,6 +34811,7 @@ class PixldocsRenderer {
|
|
|
34691
34811
|
const hasAutoShrink = configHasAutoShrinkText(templateConfig);
|
|
34692
34812
|
const defaultWait = hasAutoShrink ? 4e3 : 1800;
|
|
34693
34813
|
await this.awaitFontsForConfig(templateConfig, options.waitForFontsMs ?? defaultWait);
|
|
34814
|
+
this.flushTextMeasurementCaches();
|
|
34694
34815
|
}
|
|
34695
34816
|
const results = [];
|
|
34696
34817
|
for (let i = 0; i < templateConfig.pages.length; i++) {
|
|
@@ -34717,8 +34838,8 @@ class PixldocsRenderer {
|
|
|
34717
34838
|
const shouldWatermark = watermark ?? resolved.price > 0;
|
|
34718
34839
|
let configToRender = resolved.config;
|
|
34719
34840
|
if (shouldWatermark) {
|
|
34720
|
-
const { injectWatermark } = await
|
|
34721
|
-
configToRender =
|
|
34841
|
+
const { injectWatermark: injectWatermark2 } = await Promise.resolve().then(() => canvasWatermark);
|
|
34842
|
+
configToRender = injectWatermark2(configToRender, watermarkOptions);
|
|
34722
34843
|
const { injectPreviewBlur: injectPreviewBlur2 } = await Promise.resolve().then(() => previewBlur);
|
|
34723
34844
|
configToRender = injectPreviewBlur2(configToRender);
|
|
34724
34845
|
}
|
|
@@ -34777,8 +34898,8 @@ class PixldocsRenderer {
|
|
|
34777
34898
|
const shouldWatermark = watermark ?? resolved.price > 0;
|
|
34778
34899
|
let configToRender = resolved.config;
|
|
34779
34900
|
if (shouldWatermark) {
|
|
34780
|
-
const { injectWatermark } = await
|
|
34781
|
-
configToRender =
|
|
34901
|
+
const { injectWatermark: injectWatermark2 } = await Promise.resolve().then(() => canvasWatermark);
|
|
34902
|
+
configToRender = injectWatermark2(configToRender, watermarkOptions);
|
|
34782
34903
|
const { injectPreviewBlur: injectPreviewBlur2 } = await Promise.resolve().then(() => previewBlur);
|
|
34783
34904
|
configToRender = injectPreviewBlur2(configToRender);
|
|
34784
34905
|
}
|
|
@@ -34798,6 +34919,10 @@ class PixldocsRenderer {
|
|
|
34798
34919
|
* exporter, which is what `renderPdfViaClientExport` does below.
|
|
34799
34920
|
*/
|
|
34800
34921
|
async renderPdf(templateConfig, options) {
|
|
34922
|
+
if ((options == null ? void 0 : options.watermark) === true) {
|
|
34923
|
+
const { injectWatermark: injectWatermark2 } = await Promise.resolve().then(() => canvasWatermark);
|
|
34924
|
+
templateConfig = injectWatermark2(templateConfig, options.watermarkOptions);
|
|
34925
|
+
}
|
|
34801
34926
|
return this.renderPdfViaClientExport(templateConfig, {
|
|
34802
34927
|
title: options == null ? void 0 : options.title,
|
|
34803
34928
|
textMode: options == null ? void 0 : options.textMode,
|
|
@@ -34826,8 +34951,8 @@ class PixldocsRenderer {
|
|
|
34826
34951
|
const shouldWatermark = watermark ?? resolved.price > 0;
|
|
34827
34952
|
let configToRender = resolved.config;
|
|
34828
34953
|
if (shouldWatermark) {
|
|
34829
|
-
const { injectWatermark } = await
|
|
34830
|
-
configToRender =
|
|
34954
|
+
const { injectWatermark: injectWatermark2 } = await Promise.resolve().then(() => canvasWatermark);
|
|
34955
|
+
configToRender = injectWatermark2(configToRender, watermarkOptions);
|
|
34831
34956
|
const { injectPreviewBlur: injectPreviewBlur2 } = await Promise.resolve().then(() => previewBlur);
|
|
34832
34957
|
configToRender = injectPreviewBlur2(configToRender);
|
|
34833
34958
|
}
|
|
@@ -35024,7 +35149,7 @@ class PixldocsRenderer {
|
|
|
35024
35149
|
await this.waitForCanvasScene(container, cloned, i);
|
|
35025
35150
|
}
|
|
35026
35151
|
console.log(`[canvas-renderer][pdf-unified] mounted ${cloned.pages.length} page(s), handing off to client exportMultiPagePdf`);
|
|
35027
|
-
const { exportMultiPagePdf, preparePagesForExport } = await import("./vectorPdfExport-
|
|
35152
|
+
const { exportMultiPagePdf, preparePagesForExport } = await import("./vectorPdfExport-DV-TJwjP.js");
|
|
35028
35153
|
const prepared = preparePagesForExport(
|
|
35029
35154
|
cloned.pages,
|
|
35030
35155
|
canvasWidth,
|
|
@@ -35302,6 +35427,37 @@ class PixldocsRenderer {
|
|
|
35302
35427
|
new Promise((r) => setTimeout(r, Math.min(500, maxWaitMs)))
|
|
35303
35428
|
]);
|
|
35304
35429
|
}
|
|
35430
|
+
/**
|
|
35431
|
+
* Flush BOTH process-global text-measurement caches after fonts are ready
|
|
35432
|
+
* and BEFORE the capture canvas mounts.
|
|
35433
|
+
*
|
|
35434
|
+
* Why: anything that measured text before the webfonts finished loading —
|
|
35435
|
+
* most notably `applyContentBoundsPagination` running inside
|
|
35436
|
+
* `resolveFromForm` on a cold page (the EC2/MCP flow: resolve + render in
|
|
35437
|
+
* one browser context) — populates the app measurement cache and Fabric's
|
|
35438
|
+
* global char-width cache with FALLBACK metrics. `createText` then places
|
|
35439
|
+
* center/right-aligned lines from those stale widths, so a right-aligned
|
|
35440
|
+
* grid cell on a continuation page drew shifted left by
|
|
35441
|
+
* (fallbackWidth − realWidth) px vs the editor (caught by
|
|
35442
|
+
* tests/parity `auto-paginate`, a 9px shift). The later
|
|
35443
|
+
* `waitForStableTextMetrics` pass re-primes glyph bounds but never moves
|
|
35444
|
+
* the already-positioned box, so the flush must happen pre-mount.
|
|
35445
|
+
*
|
|
35446
|
+
* Only called from the headless PNG paths (`render`/`renderAllPages`),
|
|
35447
|
+
* which already default to clearing the global char cache in
|
|
35448
|
+
* `waitForStableTextMetrics` — the live-preview-adjacent PDF path keeps
|
|
35449
|
+
* its `clearGlobalCharCache: false` behaviour untouched.
|
|
35450
|
+
*/
|
|
35451
|
+
flushTextMeasurementCaches() {
|
|
35452
|
+
try {
|
|
35453
|
+
clearMeasurementCache();
|
|
35454
|
+
} catch {
|
|
35455
|
+
}
|
|
35456
|
+
try {
|
|
35457
|
+
clearFabricCharCache();
|
|
35458
|
+
} catch {
|
|
35459
|
+
}
|
|
35460
|
+
}
|
|
35305
35461
|
getNormalizedGradientStops(gradient) {
|
|
35306
35462
|
const stops = Array.isArray(gradient == null ? void 0 : gradient.stops) ? gradient.stops.map((stop) => ({
|
|
35307
35463
|
offset: Math.max(0, Math.min(1, Number((stop == null ? void 0 : stop.offset) ?? 0))),
|
|
@@ -37344,7 +37500,7 @@ async function prepareLiveCanvasSvgForPdf(rawSvg, pageWidth, pageHeight, pageKey
|
|
|
37344
37500
|
if (options == null ? void 0 : options.stripPageBackground) stripRootPageBackgroundFromSvg(svgToDraw);
|
|
37345
37501
|
sanitizeSvgTreeForPdf(svgToDraw);
|
|
37346
37502
|
try {
|
|
37347
|
-
const { bakeTextAnchorPositionsFromLiveSvg, logTextMeasurementDiagnostic } = await import("./vectorPdfExport-
|
|
37503
|
+
const { bakeTextAnchorPositionsFromLiveSvg, logTextMeasurementDiagnostic } = await import("./vectorPdfExport-DV-TJwjP.js");
|
|
37348
37504
|
try {
|
|
37349
37505
|
await logTextMeasurementDiagnostic(svgToDraw);
|
|
37350
37506
|
} catch {
|
|
@@ -37592,13 +37748,136 @@ async function getPublishedTemplate(options) {
|
|
|
37592
37748
|
const rows = await res.json();
|
|
37593
37749
|
return rows[0] ?? null;
|
|
37594
37750
|
}
|
|
37751
|
+
const WATERMARK_ID_PREFIX = "__wm_";
|
|
37752
|
+
const DEFAULT_WATERMARK_OPACITY = 0.14;
|
|
37753
|
+
const DEFAULT_WATERMARK_FONT_SIZE = 18;
|
|
37754
|
+
const DEFAULT_WATERMARK_ANGLE = -30;
|
|
37755
|
+
function getWatermarkText() {
|
|
37756
|
+
try {
|
|
37757
|
+
const host = window.location.hostname;
|
|
37758
|
+
if (host.includes("biomaker")) return "biomaker.app";
|
|
37759
|
+
} catch {
|
|
37760
|
+
}
|
|
37761
|
+
return "pixldocs.com";
|
|
37762
|
+
}
|
|
37763
|
+
function getLuminance(color) {
|
|
37764
|
+
if (!color || color === "transparent" || color === "none") return 1;
|
|
37765
|
+
let r = 255, g = 255, b = 255;
|
|
37766
|
+
if (color.startsWith("#")) {
|
|
37767
|
+
const hex = color.slice(1);
|
|
37768
|
+
const full = hex.length === 3 ? hex.split("").map((c) => c + c).join("") : hex;
|
|
37769
|
+
const n = parseInt(full, 16);
|
|
37770
|
+
r = n >> 16 & 255;
|
|
37771
|
+
g = n >> 8 & 255;
|
|
37772
|
+
b = n & 255;
|
|
37773
|
+
} else {
|
|
37774
|
+
const m = color.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/);
|
|
37775
|
+
if (m) {
|
|
37776
|
+
r = +m[1];
|
|
37777
|
+
g = +m[2];
|
|
37778
|
+
b = +m[3];
|
|
37779
|
+
}
|
|
37780
|
+
}
|
|
37781
|
+
return (0.299 * r + 0.587 * g + 0.114 * b) / 255;
|
|
37782
|
+
}
|
|
37783
|
+
function getWatermarkColor(bgColor) {
|
|
37784
|
+
const lum = getLuminance(bgColor);
|
|
37785
|
+
return lum < 0.45 ? "#cccccc" : "#808080";
|
|
37786
|
+
}
|
|
37787
|
+
function getPageBgColor(page, canvasBg) {
|
|
37788
|
+
var _a2, _b2;
|
|
37789
|
+
const settingsBg = (_a2 = page.settings) == null ? void 0 : _a2.backgroundColor;
|
|
37790
|
+
if (settingsBg && settingsBg !== "transparent" && settingsBg !== "none") {
|
|
37791
|
+
return settingsBg;
|
|
37792
|
+
}
|
|
37793
|
+
const children = page.children || [];
|
|
37794
|
+
for (const child of children) {
|
|
37795
|
+
if (child.type === "shape" && child.fill && child.fill !== "transparent" && child.fill !== "none") {
|
|
37796
|
+
return child.fill;
|
|
37797
|
+
}
|
|
37798
|
+
if ((_b2 = child.children) == null ? void 0 : _b2.length) {
|
|
37799
|
+
for (const gc of child.children) {
|
|
37800
|
+
if (gc.type === "shape" && gc.fill && gc.fill !== "transparent" && gc.fill !== "none") {
|
|
37801
|
+
return gc.fill;
|
|
37802
|
+
}
|
|
37803
|
+
}
|
|
37804
|
+
}
|
|
37805
|
+
}
|
|
37806
|
+
return canvasBg;
|
|
37807
|
+
}
|
|
37808
|
+
function generateWatermarkElements(canvasWidth, canvasHeight, wmColor, options = {}) {
|
|
37809
|
+
const elements = [];
|
|
37810
|
+
const text = options.text ?? getWatermarkText();
|
|
37811
|
+
const fontSize = options.fontSize ?? DEFAULT_WATERMARK_FONT_SIZE;
|
|
37812
|
+
const angle = options.angle ?? DEFAULT_WATERMARK_ANGLE;
|
|
37813
|
+
const opacity = options.opacity ?? DEFAULT_WATERMARK_OPACITY;
|
|
37814
|
+
const estimatedTextWidth = text.length * fontSize * 0.55;
|
|
37815
|
+
const spacingX = Math.max(160, estimatedTextWidth + 30);
|
|
37816
|
+
const spacingY = 90;
|
|
37817
|
+
const startX = -canvasWidth * 0.3;
|
|
37818
|
+
const startY = -canvasHeight * 0.3;
|
|
37819
|
+
const endX = canvasWidth * 1.5;
|
|
37820
|
+
const endY = canvasHeight * 1.5;
|
|
37821
|
+
let idx = 0;
|
|
37822
|
+
for (let y = startY; y < endY; y += spacingY) {
|
|
37823
|
+
for (let x = startX; x < endX; x += spacingX) {
|
|
37824
|
+
elements.push({
|
|
37825
|
+
id: `${WATERMARK_ID_PREFIX}${idx++}`,
|
|
37826
|
+
type: "text",
|
|
37827
|
+
left: x,
|
|
37828
|
+
top: y,
|
|
37829
|
+
width: 200,
|
|
37830
|
+
height: 40,
|
|
37831
|
+
text,
|
|
37832
|
+
fontFamily: "Montserrat",
|
|
37833
|
+
fontSize,
|
|
37834
|
+
fontWeight: "600",
|
|
37835
|
+
fill: wmColor,
|
|
37836
|
+
angle,
|
|
37837
|
+
selectable: false,
|
|
37838
|
+
locked: true,
|
|
37839
|
+
visible: true,
|
|
37840
|
+
opacity,
|
|
37841
|
+
scaleX: 1,
|
|
37842
|
+
scaleY: 1,
|
|
37843
|
+
letterSpacing: 4
|
|
37844
|
+
});
|
|
37845
|
+
}
|
|
37846
|
+
}
|
|
37847
|
+
return elements;
|
|
37848
|
+
}
|
|
37849
|
+
function injectWatermark(config, options = {}) {
|
|
37850
|
+
var _a2, _b2, _c2;
|
|
37851
|
+
const canvasWidth = ((_a2 = config.canvas) == null ? void 0 : _a2.width) || 612;
|
|
37852
|
+
const canvasHeight = ((_b2 = config.canvas) == null ? void 0 : _b2.height) || 792;
|
|
37853
|
+
const canvasBg = (_c2 = config.canvas) == null ? void 0 : _c2.backgroundColor;
|
|
37854
|
+
return {
|
|
37855
|
+
...config,
|
|
37856
|
+
pages: config.pages.map((page) => {
|
|
37857
|
+
const pageBg = getPageBgColor(page, canvasBg);
|
|
37858
|
+
const wmColor = getWatermarkColor(pageBg);
|
|
37859
|
+
const watermarkElements = generateWatermarkElements(canvasWidth, canvasHeight, wmColor, options);
|
|
37860
|
+
return {
|
|
37861
|
+
...page,
|
|
37862
|
+
children: [
|
|
37863
|
+
...page.children || [],
|
|
37864
|
+
...watermarkElements
|
|
37865
|
+
]
|
|
37866
|
+
};
|
|
37867
|
+
})
|
|
37868
|
+
};
|
|
37869
|
+
}
|
|
37870
|
+
const canvasWatermark = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
37871
|
+
__proto__: null,
|
|
37872
|
+
injectWatermark
|
|
37873
|
+
}, Symbol.toStringTag, { value: "Module" }));
|
|
37595
37874
|
function setAutoShrinkDebug(enabled) {
|
|
37596
37875
|
if (typeof window !== "undefined") {
|
|
37597
37876
|
window.__pixldocsDebugAutoShrink = !!enabled;
|
|
37598
37877
|
}
|
|
37599
37878
|
}
|
|
37600
37879
|
export {
|
|
37601
|
-
|
|
37880
|
+
resolveBlurElementExactIdsFromFlatFormKeys as $,
|
|
37602
37881
|
API_URL as A,
|
|
37603
37882
|
collectFontDescriptorsFromConfig as B,
|
|
37604
37883
|
collectFontsFromConfig as C,
|
|
@@ -37619,23 +37898,24 @@ export {
|
|
|
37619
37898
|
hasAnyPreviewBlur as R,
|
|
37620
37899
|
injectPreviewBlur as S,
|
|
37621
37900
|
TRIANGLE_STROKE_MITER_LIMIT as T,
|
|
37622
|
-
|
|
37623
|
-
|
|
37624
|
-
|
|
37625
|
-
|
|
37626
|
-
|
|
37627
|
-
|
|
37628
|
-
|
|
37901
|
+
injectWatermark as U,
|
|
37902
|
+
isBundledAssetUrl as V,
|
|
37903
|
+
isFontAvailable as W,
|
|
37904
|
+
isPrivateUrl as X,
|
|
37905
|
+
listPublishedTemplates as Y,
|
|
37906
|
+
loadGoogleFontCSS as Z,
|
|
37907
|
+
normalizeFontFamily as _,
|
|
37629
37908
|
getAbsoluteBounds as a,
|
|
37630
|
-
|
|
37631
|
-
|
|
37632
|
-
|
|
37633
|
-
|
|
37634
|
-
|
|
37635
|
-
|
|
37636
|
-
|
|
37637
|
-
|
|
37638
|
-
|
|
37909
|
+
resolveFontWeight as a0,
|
|
37910
|
+
resolveForRender as a1,
|
|
37911
|
+
resolveFromForm as a2,
|
|
37912
|
+
resolveTemplateData as a3,
|
|
37913
|
+
rewriteSvgFontsForJsPDF as a4,
|
|
37914
|
+
setAutoShrinkDebug as a5,
|
|
37915
|
+
setBundledAssetPrefixes as a6,
|
|
37916
|
+
warmResolvedTemplateForPreview as a7,
|
|
37917
|
+
warmTemplateFromForm as a8,
|
|
37918
|
+
canvasImageLoader as a9,
|
|
37639
37919
|
getProxiedImageUrl as b,
|
|
37640
37920
|
captureFabricCanvasSvgForPdf as c,
|
|
37641
37921
|
getImageProxyFetchOptions as d,
|
|
@@ -37662,4 +37942,4 @@ export {
|
|
|
37662
37942
|
awaitFontsForConfig as y,
|
|
37663
37943
|
buildTeaserBlurFlatKeys as z
|
|
37664
37944
|
};
|
|
37665
|
-
//# sourceMappingURL=index-
|
|
37945
|
+
//# sourceMappingURL=index-CKhnRi3S.js.map
|