@pixldocs/canvas-renderer 0.5.496 → 0.5.498
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-CZtvER5z.cjs → index-CUZInOyk.cjs} +435 -74
- package/dist/index-CUZInOyk.cjs.map +1 -0
- package/dist/{index-CiSoT2Lk.js → index-lbU-Xs_t.js} +452 -91
- package/dist/index-lbU-Xs_t.js.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-B2KtFs76.cjs → vectorPdfExport-6Hi7Og4W.cjs} +4 -4
- package/dist/{vectorPdfExport-B2KtFs76.cjs.map → vectorPdfExport-6Hi7Og4W.cjs.map} +1 -1
- package/dist/{vectorPdfExport-E3x8GBto.js → vectorPdfExport-D8iQi9WT.js} +4 -4
- package/dist/{vectorPdfExport-E3x8GBto.js.map → vectorPdfExport-D8iQi9WT.js.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
|
@@ -112,6 +112,15 @@ const generateId = (prefix = "el") => {
|
|
|
112
112
|
return `${prefix}-${Date.now().toString(36)}-${Math.random().toString(36).substr(2, 9)}-${Math.random().toString(36).substr(2, 9)}`;
|
|
113
113
|
};
|
|
114
114
|
const createDefaultElement = (partial) => {
|
|
115
|
+
const loose = partial;
|
|
116
|
+
if (loose.type === "frame" || loose.type === "group") {
|
|
117
|
+
return createDefaultGroup({
|
|
118
|
+
layoutMode: loose.layout,
|
|
119
|
+
...partial,
|
|
120
|
+
type: "group",
|
|
121
|
+
children: Array.isArray(loose.children) ? loose.children : []
|
|
122
|
+
});
|
|
123
|
+
}
|
|
115
124
|
const isText = partial.type === "text";
|
|
116
125
|
const base = {
|
|
117
126
|
left: 48,
|
|
@@ -129,7 +138,7 @@ const createDefaultElement = (partial) => {
|
|
|
129
138
|
originY: "top",
|
|
130
139
|
opacity: 1,
|
|
131
140
|
fill: "#e2e8f0",
|
|
132
|
-
...isText ? {} : { stroke: "
|
|
141
|
+
...isText ? {} : { stroke: "transparent", strokeWidth: 0 },
|
|
133
142
|
visible: true,
|
|
134
143
|
selectable: true,
|
|
135
144
|
evented: true,
|
|
@@ -975,49 +984,15 @@ function worldPointToParentLocal(worldX, worldY, parent, pageChildren, resolveGr
|
|
|
975
984
|
);
|
|
976
985
|
return { left: local.x, top: local.y };
|
|
977
986
|
}
|
|
978
|
-
function unbakeChildrenToGroupLocal(group) {
|
|
979
|
-
const angle = getGroupAngleDeg(group);
|
|
980
|
-
if (Math.abs(angle) < 0.01) return group;
|
|
981
|
-
const { width, height } = getGroupFrameSize(group);
|
|
982
|
-
const cx = width / 2;
|
|
983
|
-
const cy = height / 2;
|
|
984
|
-
const inv = rotateAroundAffDeg(-angle, cx, cy);
|
|
985
|
-
const kids = (group.children ?? []).map((child) => {
|
|
986
|
-
const p = applyAff(inv, child.left ?? 0, child.top ?? 0);
|
|
987
|
-
const childAngle = typeof child.angle === "number" ? child.angle : 0;
|
|
988
|
-
const localAngle = normalizeAngleDeg(childAngle - angle);
|
|
989
|
-
if (isGroup(child)) {
|
|
990
|
-
const relocated = {
|
|
991
|
-
...child,
|
|
992
|
-
left: p.x,
|
|
993
|
-
top: p.y,
|
|
994
|
-
angle: localAngle
|
|
995
|
-
};
|
|
996
|
-
return Math.abs(getGroupAngleDeg(relocated)) > 0.01 ? unbakeChildrenToGroupLocal(relocated) : relocated;
|
|
997
|
-
}
|
|
998
|
-
return {
|
|
999
|
-
...child,
|
|
1000
|
-
left: p.x,
|
|
1001
|
-
top: p.y,
|
|
1002
|
-
angle: localAngle
|
|
1003
|
-
};
|
|
1004
|
-
});
|
|
1005
|
-
return { ...group, children: kids };
|
|
1006
|
-
}
|
|
1007
987
|
function migratePageTreeToGroupOwnedTransforms(nodes) {
|
|
1008
988
|
return nodes.map((node) => {
|
|
1009
989
|
if (!isGroup(node)) return node;
|
|
1010
990
|
const g = node;
|
|
1011
|
-
|
|
991
|
+
const next = {
|
|
1012
992
|
...g,
|
|
1013
993
|
children: migratePageTreeToGroupOwnedTransforms(g.children ?? [])
|
|
1014
994
|
};
|
|
1015
|
-
if (isRotatableGroup(next)
|
|
1016
|
-
if (g.groupTransformModel !== "owned-v1") {
|
|
1017
|
-
next = unbakeChildrenToGroupLocal(next);
|
|
1018
|
-
next.groupTransformModel = "owned-v1";
|
|
1019
|
-
}
|
|
1020
|
-
} else if (isRotatableGroup(next)) {
|
|
995
|
+
if (isRotatableGroup(next)) {
|
|
1021
996
|
next.groupTransformModel = "owned-v1";
|
|
1022
997
|
}
|
|
1023
998
|
return next;
|
|
@@ -2690,7 +2665,7 @@ let sizeBaseSnapshot = null;
|
|
|
2690
2665
|
const reflowPagesFromBase = (base, W, H) => {
|
|
2691
2666
|
const sx = base.width ? W / base.width : 1;
|
|
2692
2667
|
const sy = base.height ? H / base.height : 1;
|
|
2693
|
-
const fscale = Math.
|
|
2668
|
+
const fscale = Math.max(0.01, Math.min(sx, sy));
|
|
2694
2669
|
const adapt = layoutAdaptationFor(base.width, base.height, W, H);
|
|
2695
2670
|
const num = (v) => typeof v === "number" && Number.isFinite(v) ? v : 0;
|
|
2696
2671
|
const scaleNode = (node) => scaleNodeForReflow(node, sx, sy, fscale);
|
|
@@ -3239,7 +3214,7 @@ const useEditorStore = zustand.create((set, get) => ({
|
|
|
3239
3214
|
setCanvasSize: (width, height) => set((state) => {
|
|
3240
3215
|
const oldW = state.canvas.width || width, oldH = state.canvas.height || height;
|
|
3241
3216
|
const sx = oldW ? width / oldW : 1, sy = oldH ? height / oldH : 1;
|
|
3242
|
-
const fscale = Math.
|
|
3217
|
+
const fscale = Math.max(0.01, Math.min(sx, sy));
|
|
3243
3218
|
const n = (v) => typeof v === "number" && Number.isFinite(v) ? v : 0;
|
|
3244
3219
|
const scaleNode = (node) => {
|
|
3245
3220
|
const el = { ...node };
|
|
@@ -5895,6 +5870,26 @@ const setupFontLoadingListener = (canvas, afterRerender, options = {}) => {
|
|
|
5895
5870
|
}
|
|
5896
5871
|
};
|
|
5897
5872
|
};
|
|
5873
|
+
const GLOBAL_KEY = "__PIXLDOCS_IMAGE_FAILURES__";
|
|
5874
|
+
const MAX_RECORDED = 50;
|
|
5875
|
+
function host() {
|
|
5876
|
+
return typeof globalThis === "undefined" ? null : globalThis;
|
|
5877
|
+
}
|
|
5878
|
+
function recordImageLoadFailure(failure) {
|
|
5879
|
+
try {
|
|
5880
|
+
const g = host();
|
|
5881
|
+
if (!g) return;
|
|
5882
|
+
const list = g[GLOBAL_KEY] ?? [];
|
|
5883
|
+
if (list.length >= MAX_RECORDED) return;
|
|
5884
|
+
list.push({
|
|
5885
|
+
id: String(failure.id ?? ""),
|
|
5886
|
+
url: String(failure.url ?? "").slice(0, 500),
|
|
5887
|
+
reason: String(failure.reason ?? "").slice(0, 300)
|
|
5888
|
+
});
|
|
5889
|
+
g[GLOBAL_KEY] = list;
|
|
5890
|
+
} catch {
|
|
5891
|
+
}
|
|
5892
|
+
}
|
|
5898
5893
|
const EMPTY_IMAGE_PLACEHOLDER_DATA_URL = "data:image/png;base64,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";
|
|
5899
5894
|
const svgTextCache = /* @__PURE__ */ new Map();
|
|
5900
5895
|
const htmlImageCache = /* @__PURE__ */ new Map();
|
|
@@ -6386,8 +6381,13 @@ async function loadImageAsync(element, placeholder, fc, fabricRef, syncLockedRef
|
|
|
6386
6381
|
});
|
|
6387
6382
|
const imgLoadOptions = url.startsWith("data:") || url.startsWith("blob:") ? {} : { crossOrigin: "anonymous" };
|
|
6388
6383
|
const img = await fabric__namespace.FabricImage.fromURL(url, imgLoadOptions);
|
|
6389
|
-
if (!fabricRef.current) return;
|
|
6384
|
+
if (fabricRef && !fabricRef.current) return;
|
|
6390
6385
|
await normalizeSvgImageDimensions(img, imageUrl, element.sourceFormat);
|
|
6386
|
+
const natW = img.width ?? 0;
|
|
6387
|
+
const natH = img.height ?? 0;
|
|
6388
|
+
if (natW <= 1 && natH <= 1 && Number(element.width) > 8 && Number(element.height) > 8) {
|
|
6389
|
+
throw new Error(`image decoded to ${natW}x${natH} — treating as failed load`);
|
|
6390
|
+
}
|
|
6391
6391
|
const isHidden = !element.visible;
|
|
6392
6392
|
img.set({
|
|
6393
6393
|
originX: "left",
|
|
@@ -6585,9 +6585,116 @@ async function loadImageAsync(element, placeholder, fc, fabricRef, syncLockedRef
|
|
|
6585
6585
|
proxiedUrl: getProxiedImageUrl(imageUrl).slice(0, 240),
|
|
6586
6586
|
error: error instanceof Error ? error.message : String(error)
|
|
6587
6587
|
});
|
|
6588
|
+
recordImageLoadFailure({
|
|
6589
|
+
id: String(element.id ?? ""),
|
|
6590
|
+
url: imageUrl,
|
|
6591
|
+
reason: error instanceof Error ? error.message : String(error)
|
|
6592
|
+
});
|
|
6593
|
+
if (fc.__pixldocsEditMode === true) {
|
|
6594
|
+
try {
|
|
6595
|
+
markPlaceholderAsBrokenImage(placeholder);
|
|
6596
|
+
fc.requestRenderAll();
|
|
6597
|
+
} catch {
|
|
6598
|
+
}
|
|
6599
|
+
}
|
|
6588
6600
|
return;
|
|
6589
6601
|
}
|
|
6590
6602
|
}
|
|
6603
|
+
function markPlaceholderAsBrokenImage(placeholder) {
|
|
6604
|
+
if (!(placeholder instanceof fabric__namespace.Group)) return;
|
|
6605
|
+
const group = placeholder;
|
|
6606
|
+
if (group.__pixldocsBrokenImage) return;
|
|
6607
|
+
group.__pixldocsBrokenImage = true;
|
|
6608
|
+
const frameChild = group.getObjects().find(
|
|
6609
|
+
(o) => o.__isPlaceholderFrame
|
|
6610
|
+
);
|
|
6611
|
+
const w = Math.max(1, (frameChild == null ? void 0 : frameChild.width) ?? group.width ?? 1);
|
|
6612
|
+
const h = Math.max(1, (frameChild == null ? void 0 : frameChild.height) ?? group.height ?? 1);
|
|
6613
|
+
const center = group.getCenterPoint();
|
|
6614
|
+
const cx = center.x;
|
|
6615
|
+
const cy = center.y;
|
|
6616
|
+
const prevPose = { left: group.left, top: group.top, width: group.width, height: group.height };
|
|
6617
|
+
const bg = new fabric__namespace.Rect({
|
|
6618
|
+
originX: "center",
|
|
6619
|
+
originY: "center",
|
|
6620
|
+
left: cx,
|
|
6621
|
+
top: cy,
|
|
6622
|
+
width: w,
|
|
6623
|
+
height: h,
|
|
6624
|
+
fill: "rgba(148, 163, 184, 0.12)",
|
|
6625
|
+
stroke: "#94A3B8",
|
|
6626
|
+
strokeWidth: 1.5,
|
|
6627
|
+
strokeDashArray: [6, 4]
|
|
6628
|
+
});
|
|
6629
|
+
const s = Math.max(16, Math.min(w, h) * 0.28);
|
|
6630
|
+
const glyphStroke = { stroke: "#64748B", strokeWidth: Math.max(1.5, s / 12), fill: "transparent" };
|
|
6631
|
+
const iconFrame = new fabric__namespace.Rect({
|
|
6632
|
+
originX: "center",
|
|
6633
|
+
originY: "center",
|
|
6634
|
+
left: cx,
|
|
6635
|
+
top: cy,
|
|
6636
|
+
width: s,
|
|
6637
|
+
height: s * 0.8,
|
|
6638
|
+
rx: s * 0.08,
|
|
6639
|
+
ry: s * 0.08,
|
|
6640
|
+
...glyphStroke
|
|
6641
|
+
});
|
|
6642
|
+
const mountain = new fabric__namespace.Polyline(
|
|
6643
|
+
[
|
|
6644
|
+
{ x: -s * 0.38, y: s * 0.24 },
|
|
6645
|
+
{ x: -s * 0.1, y: -s * 0.08 },
|
|
6646
|
+
{ x: s * 0.08, y: s * 0.1 },
|
|
6647
|
+
{ x: s * 0.22, y: -s * 0.02 },
|
|
6648
|
+
{ x: s * 0.38, y: s * 0.24 }
|
|
6649
|
+
],
|
|
6650
|
+
{ originX: "center", originY: "center", left: cx, top: cy + s * 0.08, ...glyphStroke }
|
|
6651
|
+
);
|
|
6652
|
+
const slash = new fabric__namespace.Line([cx - s * 0.55, cy - s * 0.5, cx + s * 0.55, cy + s * 0.5], {
|
|
6653
|
+
...glyphStroke,
|
|
6654
|
+
originX: "center",
|
|
6655
|
+
originY: "center",
|
|
6656
|
+
left: cx,
|
|
6657
|
+
top: cy
|
|
6658
|
+
});
|
|
6659
|
+
for (const obj of [bg, iconFrame, mountain, slash]) {
|
|
6660
|
+
obj.set({ selectable: false, evented: false, excludeFromExport: true });
|
|
6661
|
+
obj.__pixldocsEditorChrome = true;
|
|
6662
|
+
group.add(obj);
|
|
6663
|
+
}
|
|
6664
|
+
group.set(prevPose);
|
|
6665
|
+
group.setCoords();
|
|
6666
|
+
group.dirty = true;
|
|
6667
|
+
}
|
|
6668
|
+
function hideEditorChromeForExport(fc) {
|
|
6669
|
+
const hidden = [];
|
|
6670
|
+
const walk = (objs) => {
|
|
6671
|
+
var _a2;
|
|
6672
|
+
for (const o of objs) {
|
|
6673
|
+
if (o.__pixldocsEditorChrome && o.visible !== false) {
|
|
6674
|
+
o.visible = false;
|
|
6675
|
+
hidden.push(o);
|
|
6676
|
+
}
|
|
6677
|
+
const kids = (_a2 = o.getObjects) == null ? void 0 : _a2.call(o);
|
|
6678
|
+
if (kids == null ? void 0 : kids.length) walk(kids);
|
|
6679
|
+
}
|
|
6680
|
+
};
|
|
6681
|
+
walk(fc.getObjects());
|
|
6682
|
+
if (hidden.length) {
|
|
6683
|
+
for (const o of hidden) {
|
|
6684
|
+
const g = o.group;
|
|
6685
|
+
if (g) g.dirty = true;
|
|
6686
|
+
}
|
|
6687
|
+
fc.renderAll();
|
|
6688
|
+
}
|
|
6689
|
+
return () => {
|
|
6690
|
+
for (const o of hidden) {
|
|
6691
|
+
o.visible = true;
|
|
6692
|
+
const g = o.group;
|
|
6693
|
+
if (g) g.dirty = true;
|
|
6694
|
+
}
|
|
6695
|
+
if (hidden.length) fc.requestRenderAll();
|
|
6696
|
+
};
|
|
6697
|
+
}
|
|
6591
6698
|
const canvasImageLoader = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
6592
6699
|
__proto__: null,
|
|
6593
6700
|
SVG_DECODE_HARD_CAP,
|
|
@@ -6597,12 +6704,14 @@ const canvasImageLoader = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.d
|
|
|
6597
6704
|
fetchSvgTextPublic,
|
|
6598
6705
|
getNormalizedSvgUrl,
|
|
6599
6706
|
getProxiedImageUrl,
|
|
6707
|
+
hideEditorChromeForExport,
|
|
6600
6708
|
isBundledAssetUrl,
|
|
6601
6709
|
isEmptyImagePlaceholderGroup,
|
|
6602
6710
|
isPrivateUrl,
|
|
6603
6711
|
isSvgImage,
|
|
6604
6712
|
loadImageAsync,
|
|
6605
6713
|
loadSvgDimensions,
|
|
6714
|
+
markPlaceholderAsBrokenImage,
|
|
6606
6715
|
normalizeSvgImageDimensions,
|
|
6607
6716
|
parseSvgDimensionsFromText,
|
|
6608
6717
|
preloadImage,
|
|
@@ -10328,10 +10437,10 @@ function textPathBoundsContainScenePoint(obj, point) {
|
|
|
10328
10437
|
}
|
|
10329
10438
|
function drawTextPathBounds(ctx, obj, bounds, hostCanvas) {
|
|
10330
10439
|
var _a2, _b2, _c2;
|
|
10331
|
-
const
|
|
10332
|
-
if (!
|
|
10333
|
-
const retina = ((_b2 =
|
|
10334
|
-
const matrix = fabric__namespace.util.multiplyTransformMatrices(
|
|
10440
|
+
const host2 = hostCanvas || obj.canvas || ((_a2 = obj.group) == null ? void 0 : _a2.canvas);
|
|
10441
|
+
if (!host2) return;
|
|
10442
|
+
const retina = ((_b2 = host2.getRetinaScaling) == null ? void 0 : _b2.call(host2)) || ((_c2 = obj.getCanvasRetinaScaling) == null ? void 0 : _c2.call(obj)) || 1;
|
|
10443
|
+
const matrix = fabric__namespace.util.multiplyTransformMatrices(host2.viewportTransform || [1, 0, 0, 1, 0, 0], obj.calcTransformMatrix());
|
|
10335
10444
|
const corners = [
|
|
10336
10445
|
new fabric__namespace.Point(bounds.minX, bounds.minY),
|
|
10337
10446
|
new fabric__namespace.Point(bounds.maxX, bounds.minY),
|
|
@@ -10582,11 +10691,11 @@ if (GroupProto && typeof GroupProto._renderControls === "function" && !GroupProt
|
|
|
10582
10691
|
GroupProto.__pixldocsOrigRenderControls = GroupProto._renderControls;
|
|
10583
10692
|
GroupProto._renderControls = function(ctx, styleOverride, childrenOverride) {
|
|
10584
10693
|
var _a2;
|
|
10585
|
-
const
|
|
10586
|
-
const active = (_a2 =
|
|
10587
|
-
const isActiveOrInActive = !!
|
|
10694
|
+
const host2 = this.canvas;
|
|
10695
|
+
const active = (_a2 = host2 == null ? void 0 : host2.getActiveObject) == null ? void 0 : _a2.call(host2);
|
|
10696
|
+
const isActiveOrInActive = !!host2 && (active === this || !!active && typeof active.contains === "function" && active.contains(this, true));
|
|
10588
10697
|
GroupProto.__pixldocsOrigRenderControls.call(this, ctx, styleOverride, childrenOverride);
|
|
10589
|
-
if (!
|
|
10698
|
+
if (!host2 || !isActiveOrInActive) return;
|
|
10590
10699
|
const drawForDescendants = (parent) => {
|
|
10591
10700
|
const kids = (parent == null ? void 0 : parent._objects) || [];
|
|
10592
10701
|
for (const child of kids) {
|
|
@@ -10595,7 +10704,7 @@ if (GroupProto && typeof GroupProto._renderControls === "function" && !GroupProt
|
|
|
10595
10704
|
}
|
|
10596
10705
|
if (child && child.textPath && child.textPath.preset && child.textPath.preset !== "none") {
|
|
10597
10706
|
const bounds = getTextPathHitBounds(child);
|
|
10598
|
-
if (bounds) drawTextPathBounds(ctx, child, bounds,
|
|
10707
|
+
if (bounds) drawTextPathBounds(ctx, child, bounds, host2);
|
|
10599
10708
|
}
|
|
10600
10709
|
}
|
|
10601
10710
|
};
|
|
@@ -18114,6 +18223,7 @@ const PageCanvas = react.forwardRef(
|
|
|
18114
18223
|
// Transparent so underlay (page bg + group bgs) shows through
|
|
18115
18224
|
backgroundColor: "transparent"
|
|
18116
18225
|
});
|
|
18226
|
+
fabricCanvas.__pixldocsEditMode = isEditorMode && !isPreviewMode;
|
|
18117
18227
|
fabricCanvas.hoverCursor = "default";
|
|
18118
18228
|
fabricCanvas.moveCursor = "move";
|
|
18119
18229
|
const suppressTextEditForClick = (textbox) => {
|
|
@@ -25439,6 +25549,7 @@ const PageCanvas = react.forwardRef(
|
|
|
25439
25549
|
} else if (obj instanceof fabric__namespace.Textbox) {
|
|
25440
25550
|
const overflowPolicy = element.overflowPolicy || "grow-and-push";
|
|
25441
25551
|
let text = element.text != null && element.text !== "" ? element.text : " ";
|
|
25552
|
+
text = applyElementTextCase(text, element.textCase);
|
|
25442
25553
|
let parsedStyles = null;
|
|
25443
25554
|
if (element.formattingEnabled === true) {
|
|
25444
25555
|
const parsed = parseTextMarkdown(text);
|
|
@@ -26083,6 +26194,13 @@ const PageCanvas = react.forwardRef(
|
|
|
26083
26194
|
const img = await fabric__namespace.FabricImage.fromURL(url, { crossOrigin: "anonymous" });
|
|
26084
26195
|
if (!fabricRef.current || !isLatestRequest()) return;
|
|
26085
26196
|
await normalizeSvgImageDimensions(img, imageUrl, element.sourceFormat, svgDecodeTarget);
|
|
26197
|
+
{
|
|
26198
|
+
const natW = img.width ?? 0;
|
|
26199
|
+
const natH = img.height ?? 0;
|
|
26200
|
+
if (natW <= 1 && natH <= 1 && Number(element.width) > 8 && Number(element.height) > 8) {
|
|
26201
|
+
throw new Error(`image decoded to ${natW}x${natH} — treating as failed load`);
|
|
26202
|
+
}
|
|
26203
|
+
}
|
|
26086
26204
|
if (!isLatestRequest()) return;
|
|
26087
26205
|
const imageFitForFade = element.imageFit || ((_a2 = element.style) == null ? void 0 : _a2.imageFit) || "cover";
|
|
26088
26206
|
const clipShapeForFade = element.clipShape ?? ((_b2 = element.style) == null ? void 0 : _b2.imageFrameShape) ?? (isPreviewMode ? "rectangle" : "none");
|
|
@@ -26449,6 +26567,24 @@ const PageCanvas = react.forwardRef(
|
|
|
26449
26567
|
}
|
|
26450
26568
|
fc.requestRenderAll();
|
|
26451
26569
|
} catch (error) {
|
|
26570
|
+
console.error("[PageCanvas] image failed to load", {
|
|
26571
|
+
id: element.id,
|
|
26572
|
+
url: (element.src || element.imageUrl || "").slice(0, 200),
|
|
26573
|
+
error: error instanceof Error ? error.message : String(error)
|
|
26574
|
+
});
|
|
26575
|
+
recordImageLoadFailure({
|
|
26576
|
+
id: String(element.id ?? ""),
|
|
26577
|
+
url: element.src || element.imageUrl || "",
|
|
26578
|
+
reason: error instanceof Error ? error.message : String(error)
|
|
26579
|
+
});
|
|
26580
|
+
const fcNow = fabricRef.current;
|
|
26581
|
+
if (fcNow && fcNow.__pixldocsEditMode === true) {
|
|
26582
|
+
try {
|
|
26583
|
+
markPlaceholderAsBrokenImage(placeholder);
|
|
26584
|
+
fcNow.requestRenderAll();
|
|
26585
|
+
} catch {
|
|
26586
|
+
}
|
|
26587
|
+
}
|
|
26452
26588
|
}
|
|
26453
26589
|
};
|
|
26454
26590
|
const handleCanvasClick = react.useCallback(
|
|
@@ -27772,6 +27908,7 @@ function PreviewCanvas({
|
|
|
27772
27908
|
const pageSettings = react.useMemo(() => {
|
|
27773
27909
|
var _a3, _b3;
|
|
27774
27910
|
return {
|
|
27911
|
+
// design-drift-ignore: artifact paper colour, not chrome
|
|
27775
27912
|
backgroundColor: ((_a3 = page == null ? void 0 : page.settings) == null ? void 0 : _a3.backgroundColor) || "#ffffff",
|
|
27776
27913
|
backgroundGradient: (_b3 = page == null ? void 0 : page.settings) == null ? void 0 : _b3.backgroundGradient
|
|
27777
27914
|
};
|
|
@@ -32394,11 +32531,31 @@ async function resolveTemplateData(options) {
|
|
|
32394
32531
|
...formData ?? {}
|
|
32395
32532
|
};
|
|
32396
32533
|
const dynamicFields = config.dynamicFields;
|
|
32397
|
-
|
|
32534
|
+
const hasBoundTable = (() => {
|
|
32535
|
+
let found = false;
|
|
32536
|
+
const walk = (nodes) => {
|
|
32537
|
+
var _a2, _b2;
|
|
32538
|
+
for (const n of nodes || []) {
|
|
32539
|
+
if (found) return;
|
|
32540
|
+
if ((n == null ? void 0 : n.type) === "table" && ((_b2 = (_a2 = n == null ? void 0 : n.tableData) == null ? void 0 : _a2.repeat) == null ? void 0 : _b2.from)) {
|
|
32541
|
+
found = true;
|
|
32542
|
+
return;
|
|
32543
|
+
}
|
|
32544
|
+
walk(n == null ? void 0 : n.children);
|
|
32545
|
+
}
|
|
32546
|
+
};
|
|
32547
|
+
for (const p of config.pages || []) walk(p.children);
|
|
32548
|
+
return found;
|
|
32549
|
+
})();
|
|
32550
|
+
const hasDynamicFields = Array.isArray(dynamicFields) && dynamicFields.length > 0;
|
|
32551
|
+
if (!hasDynamicFields && (hasBoundTable || repeatableSectionsInput.length > 0)) {
|
|
32552
|
+
console.log("[resolveTemplateData] no dynamicFields; binding via bound table / repeatable sections");
|
|
32553
|
+
}
|
|
32554
|
+
if (!hasDynamicFields && !hasBoundTable && repeatableSectionsInput.length === 0) {
|
|
32398
32555
|
return { config: applyThemeIfNeeded(config), templateName: template.name || "Untitled", templateId, price: template.price ?? 0 };
|
|
32399
32556
|
}
|
|
32400
32557
|
const mappings = [];
|
|
32401
|
-
for (const f of dynamicFields) {
|
|
32558
|
+
for (const f of dynamicFields || []) {
|
|
32402
32559
|
for (const m of f.mappings || []) {
|
|
32403
32560
|
mappings.push({
|
|
32404
32561
|
field_key: f.id,
|
|
@@ -34119,6 +34276,14 @@ function captureFabricCanvasSvgForPdf(fabricInstance, canvasWidth, canvasHeight)
|
|
|
34119
34276
|
try {
|
|
34120
34277
|
const visit = (obj) => {
|
|
34121
34278
|
if (!obj) return;
|
|
34279
|
+
if (obj.__pixldocsEditorChrome) {
|
|
34280
|
+
const originalToSVG = typeof obj.toSVG === "function" ? obj.toSVG.bind(obj) : null;
|
|
34281
|
+
if (originalToSVG) {
|
|
34282
|
+
obj.toSVG = () => "";
|
|
34283
|
+
svgPatchRecords.push({ obj, originalToSVG });
|
|
34284
|
+
}
|
|
34285
|
+
return;
|
|
34286
|
+
}
|
|
34122
34287
|
const imageId = typeof obj.__docuforgeId === "string" && hasRenderableRasterCandidate(obj) ? obj.__docuforgeId : "";
|
|
34123
34288
|
const alphaGradient = objectNeedsAlphaGradientRaster(obj);
|
|
34124
34289
|
if ((isTextboxLike(obj) || imageId || alphaGradient) && typeof obj.toSVG === "function") {
|
|
@@ -34226,9 +34391,22 @@ function captureFabricCanvasSvgForPdf(fabricInstance, canvasWidth, canvasHeight)
|
|
|
34226
34391
|
}
|
|
34227
34392
|
return svgString;
|
|
34228
34393
|
}
|
|
34229
|
-
const resolvedPackageVersion = "0.5.
|
|
34394
|
+
const resolvedPackageVersion = "0.5.498";
|
|
34230
34395
|
const PACKAGE_VERSION = resolvedPackageVersion;
|
|
34231
|
-
|
|
34396
|
+
async function crPhase(name, fn) {
|
|
34397
|
+
const now = () => typeof performance !== "undefined" ? performance.now() : Date.now();
|
|
34398
|
+
const t0 = now();
|
|
34399
|
+
try {
|
|
34400
|
+
return await fn();
|
|
34401
|
+
} finally {
|
|
34402
|
+
const g = globalThis;
|
|
34403
|
+
const bag = g.__CR_PHASES__ || (g.__CR_PHASES__ = {});
|
|
34404
|
+
const cur = bag[name] || (bag[name] = { count: 0, ms: 0 });
|
|
34405
|
+
cur.count += 1;
|
|
34406
|
+
cur.ms += Math.round(now() - t0);
|
|
34407
|
+
}
|
|
34408
|
+
}
|
|
34409
|
+
const DEPLOYMENT_VERSION_MARKER = "__PIXLDOCS_CANVAS_RENDERER_VERSION__:0.5.498";
|
|
34232
34410
|
const roundParityValue = (value) => {
|
|
34233
34411
|
if (typeof value !== "number") return value;
|
|
34234
34412
|
return Number.isFinite(value) ? Number(value.toFixed(3)) : value;
|
|
@@ -34667,6 +34845,11 @@ class PixldocsRenderer {
|
|
|
34667
34845
|
* Mounts a hidden PreviewCanvas component and captures the Fabric canvas output.
|
|
34668
34846
|
*/
|
|
34669
34847
|
async render(templateConfig, options = {}) {
|
|
34848
|
+
if (options.watermark === true && !templateConfig.__pixldocsWatermarked) {
|
|
34849
|
+
const { injectWatermark: injectWatermark2 } = await Promise.resolve().then(() => canvasWatermark);
|
|
34850
|
+
templateConfig = injectWatermark2(templateConfig, options.watermarkOptions);
|
|
34851
|
+
templateConfig.__pixldocsWatermarked = true;
|
|
34852
|
+
}
|
|
34670
34853
|
const pageIndex = options.pageIndex ?? 0;
|
|
34671
34854
|
const format = options.format ?? "png";
|
|
34672
34855
|
const quality = options.quality ?? 0.92;
|
|
@@ -34682,6 +34865,7 @@ class PixldocsRenderer {
|
|
|
34682
34865
|
const hasAutoShrink = configHasAutoShrinkText(templateConfig);
|
|
34683
34866
|
const defaultWait = hasAutoShrink ? 4e3 : 1800;
|
|
34684
34867
|
await this.awaitFontsForConfig(templateConfig, options.waitForFontsMs ?? defaultWait);
|
|
34868
|
+
this.flushTextMeasurementCaches();
|
|
34685
34869
|
}
|
|
34686
34870
|
const { setPackageApiUrl: setPackageApiUrl2 } = await Promise.resolve().then(() => appApi);
|
|
34687
34871
|
setPackageApiUrl2(this.config.imageProxyUrl);
|
|
@@ -34709,6 +34893,7 @@ class PixldocsRenderer {
|
|
|
34709
34893
|
const hasAutoShrink = configHasAutoShrinkText(templateConfig);
|
|
34710
34894
|
const defaultWait = hasAutoShrink ? 4e3 : 1800;
|
|
34711
34895
|
await this.awaitFontsForConfig(templateConfig, options.waitForFontsMs ?? defaultWait);
|
|
34896
|
+
this.flushTextMeasurementCaches();
|
|
34712
34897
|
}
|
|
34713
34898
|
const results = [];
|
|
34714
34899
|
for (let i = 0; i < templateConfig.pages.length; i++) {
|
|
@@ -34735,8 +34920,8 @@ class PixldocsRenderer {
|
|
|
34735
34920
|
const shouldWatermark = watermark ?? resolved.price > 0;
|
|
34736
34921
|
let configToRender = resolved.config;
|
|
34737
34922
|
if (shouldWatermark) {
|
|
34738
|
-
const { injectWatermark } = await Promise.resolve().then(() =>
|
|
34739
|
-
configToRender =
|
|
34923
|
+
const { injectWatermark: injectWatermark2 } = await Promise.resolve().then(() => canvasWatermark);
|
|
34924
|
+
configToRender = injectWatermark2(configToRender, watermarkOptions);
|
|
34740
34925
|
const { injectPreviewBlur: injectPreviewBlur2 } = await Promise.resolve().then(() => previewBlur);
|
|
34741
34926
|
configToRender = injectPreviewBlur2(configToRender);
|
|
34742
34927
|
}
|
|
@@ -34795,8 +34980,8 @@ class PixldocsRenderer {
|
|
|
34795
34980
|
const shouldWatermark = watermark ?? resolved.price > 0;
|
|
34796
34981
|
let configToRender = resolved.config;
|
|
34797
34982
|
if (shouldWatermark) {
|
|
34798
|
-
const { injectWatermark } = await Promise.resolve().then(() =>
|
|
34799
|
-
configToRender =
|
|
34983
|
+
const { injectWatermark: injectWatermark2 } = await Promise.resolve().then(() => canvasWatermark);
|
|
34984
|
+
configToRender = injectWatermark2(configToRender, watermarkOptions);
|
|
34800
34985
|
const { injectPreviewBlur: injectPreviewBlur2 } = await Promise.resolve().then(() => previewBlur);
|
|
34801
34986
|
configToRender = injectPreviewBlur2(configToRender);
|
|
34802
34987
|
}
|
|
@@ -34816,6 +35001,10 @@ class PixldocsRenderer {
|
|
|
34816
35001
|
* exporter, which is what `renderPdfViaClientExport` does below.
|
|
34817
35002
|
*/
|
|
34818
35003
|
async renderPdf(templateConfig, options) {
|
|
35004
|
+
if ((options == null ? void 0 : options.watermark) === true) {
|
|
35005
|
+
const { injectWatermark: injectWatermark2 } = await Promise.resolve().then(() => canvasWatermark);
|
|
35006
|
+
templateConfig = injectWatermark2(templateConfig, options.watermarkOptions);
|
|
35007
|
+
}
|
|
34819
35008
|
return this.renderPdfViaClientExport(templateConfig, {
|
|
34820
35009
|
title: options == null ? void 0 : options.title,
|
|
34821
35010
|
textMode: options == null ? void 0 : options.textMode,
|
|
@@ -34844,8 +35033,8 @@ class PixldocsRenderer {
|
|
|
34844
35033
|
const shouldWatermark = watermark ?? resolved.price > 0;
|
|
34845
35034
|
let configToRender = resolved.config;
|
|
34846
35035
|
if (shouldWatermark) {
|
|
34847
|
-
const { injectWatermark } = await Promise.resolve().then(() =>
|
|
34848
|
-
configToRender =
|
|
35036
|
+
const { injectWatermark: injectWatermark2 } = await Promise.resolve().then(() => canvasWatermark);
|
|
35037
|
+
configToRender = injectWatermark2(configToRender, watermarkOptions);
|
|
34849
35038
|
const { injectPreviewBlur: injectPreviewBlur2 } = await Promise.resolve().then(() => previewBlur);
|
|
34850
35039
|
configToRender = injectPreviewBlur2(configToRender);
|
|
34851
35040
|
}
|
|
@@ -35016,7 +35205,7 @@ class PixldocsRenderer {
|
|
|
35016
35205
|
containers.push(container);
|
|
35017
35206
|
const root = client.createRoot(container);
|
|
35018
35207
|
roots.push(root);
|
|
35019
|
-
await new Promise((resolve, reject) => {
|
|
35208
|
+
await crPhase("pdf_mount", () => new Promise((resolve, reject) => {
|
|
35020
35209
|
const timer = setTimeout(() => reject(new Error(`PreviewCanvas onReady timeout for page ${i}`)), 3e4);
|
|
35021
35210
|
root.render(
|
|
35022
35211
|
react.createElement(PreviewCanvas2, {
|
|
@@ -35034,15 +35223,15 @@ class PixldocsRenderer {
|
|
|
35034
35223
|
}
|
|
35035
35224
|
})
|
|
35036
35225
|
);
|
|
35037
|
-
});
|
|
35038
|
-
await this.waitForCanvasScene(container, cloned, i);
|
|
35226
|
+
}));
|
|
35227
|
+
await crPhase("pdf_scene1", () => this.waitForCanvasScene(container, cloned, i));
|
|
35039
35228
|
const expected = this.getExpectedImageIds(cloned, i);
|
|
35040
|
-
await this.waitForCanvasImages(container, expected);
|
|
35041
|
-
await this.waitForStableTextMetrics(container, cloned, { clearGlobalCharCache: false });
|
|
35042
|
-
await this.waitForCanvasScene(container, cloned, i);
|
|
35229
|
+
await crPhase("pdf_images", () => this.waitForCanvasImages(container, expected));
|
|
35230
|
+
await crPhase("pdf_text_metrics", () => this.waitForStableTextMetrics(container, cloned, { clearGlobalCharCache: false }));
|
|
35231
|
+
await crPhase("pdf_scene2", () => this.waitForCanvasScene(container, cloned, i));
|
|
35043
35232
|
}
|
|
35044
35233
|
console.log(`[canvas-renderer][pdf-unified] mounted ${cloned.pages.length} page(s), handing off to client exportMultiPagePdf`);
|
|
35045
|
-
const { exportMultiPagePdf, preparePagesForExport } = await Promise.resolve().then(() => require("./vectorPdfExport-
|
|
35234
|
+
const { exportMultiPagePdf, preparePagesForExport } = await Promise.resolve().then(() => require("./vectorPdfExport-6Hi7Og4W.cjs"));
|
|
35046
35235
|
const prepared = preparePagesForExport(
|
|
35047
35236
|
cloned.pages,
|
|
35048
35237
|
canvasWidth,
|
|
@@ -35220,8 +35409,14 @@ class PixldocsRenderer {
|
|
|
35220
35409
|
}
|
|
35221
35410
|
const sceneSettled = fabricReady && allDomLoaded && canvasReady && fabricObjects.length > 0;
|
|
35222
35411
|
const idleFor = Date.now() - lastProgressAt;
|
|
35223
|
-
|
|
35224
|
-
|
|
35412
|
+
const strictIdleMs = Math.max(earlyExitMs, 4e3);
|
|
35413
|
+
const stalled = strictById ? missingImageIds.length > 0 : actualImageCount < expectedImageCount;
|
|
35414
|
+
if (sceneSettled && stalled && idleFor >= (strictById ? strictIdleMs : earlyExitMs)) {
|
|
35415
|
+
if (strictById) {
|
|
35416
|
+
console.warn(
|
|
35417
|
+
`[canvas-renderer][asset-wait] early-exit after ${elapsed}ms with unresolved image id(s): ${missingImageIds.join(", ")} (idle=${idleFor}ms, ${summary})`
|
|
35418
|
+
);
|
|
35419
|
+
} else if (debug) {
|
|
35225
35420
|
console.log(
|
|
35226
35421
|
`[canvas-renderer][asset-wait] early-exit after ${elapsed}ms (idle=${idleFor}ms, ${summary})`
|
|
35227
35422
|
);
|
|
@@ -35320,6 +35515,37 @@ class PixldocsRenderer {
|
|
|
35320
35515
|
new Promise((r) => setTimeout(r, Math.min(500, maxWaitMs)))
|
|
35321
35516
|
]);
|
|
35322
35517
|
}
|
|
35518
|
+
/**
|
|
35519
|
+
* Flush BOTH process-global text-measurement caches after fonts are ready
|
|
35520
|
+
* and BEFORE the capture canvas mounts.
|
|
35521
|
+
*
|
|
35522
|
+
* Why: anything that measured text before the webfonts finished loading —
|
|
35523
|
+
* most notably `applyContentBoundsPagination` running inside
|
|
35524
|
+
* `resolveFromForm` on a cold page (the EC2/MCP flow: resolve + render in
|
|
35525
|
+
* one browser context) — populates the app measurement cache and Fabric's
|
|
35526
|
+
* global char-width cache with FALLBACK metrics. `createText` then places
|
|
35527
|
+
* center/right-aligned lines from those stale widths, so a right-aligned
|
|
35528
|
+
* grid cell on a continuation page drew shifted left by
|
|
35529
|
+
* (fallbackWidth − realWidth) px vs the editor (caught by
|
|
35530
|
+
* tests/parity `auto-paginate`, a 9px shift). The later
|
|
35531
|
+
* `waitForStableTextMetrics` pass re-primes glyph bounds but never moves
|
|
35532
|
+
* the already-positioned box, so the flush must happen pre-mount.
|
|
35533
|
+
*
|
|
35534
|
+
* Only called from the headless PNG paths (`render`/`renderAllPages`),
|
|
35535
|
+
* which already default to clearing the global char cache in
|
|
35536
|
+
* `waitForStableTextMetrics` — the live-preview-adjacent PDF path keeps
|
|
35537
|
+
* its `clearGlobalCharCache: false` behaviour untouched.
|
|
35538
|
+
*/
|
|
35539
|
+
flushTextMeasurementCaches() {
|
|
35540
|
+
try {
|
|
35541
|
+
clearMeasurementCache();
|
|
35542
|
+
} catch {
|
|
35543
|
+
}
|
|
35544
|
+
try {
|
|
35545
|
+
clearFabricCharCache();
|
|
35546
|
+
} catch {
|
|
35547
|
+
}
|
|
35548
|
+
}
|
|
35323
35549
|
getNormalizedGradientStops(gradient) {
|
|
35324
35550
|
const stops = Array.isArray(gradient == null ? void 0 : gradient.stops) ? gradient.stops.map((stop) => ({
|
|
35325
35551
|
offset: Math.max(0, Math.min(1, Number((stop == null ? void 0 : stop.offset) ?? 0))),
|
|
@@ -35409,6 +35635,8 @@ class PixldocsRenderer {
|
|
|
35409
35635
|
});
|
|
35410
35636
|
}
|
|
35411
35637
|
return new Promise((resolve, reject) => {
|
|
35638
|
+
const mountStartedAt = typeof performance !== "undefined" ? performance.now() : Date.now();
|
|
35639
|
+
let mountRecorded = false;
|
|
35412
35640
|
const container = document.createElement("div");
|
|
35413
35641
|
container.style.cssText = `
|
|
35414
35642
|
position: fixed; left: -99999px; top: -99999px;
|
|
@@ -35473,13 +35701,22 @@ class PixldocsRenderer {
|
|
|
35473
35701
|
});
|
|
35474
35702
|
};
|
|
35475
35703
|
const onReady = () => {
|
|
35476
|
-
|
|
35704
|
+
if (!mountRecorded) {
|
|
35705
|
+
mountRecorded = true;
|
|
35706
|
+
const now = typeof performance !== "undefined" ? performance.now() : Date.now();
|
|
35707
|
+
const g = globalThis;
|
|
35708
|
+
const bag = g.__CR_PHASES__ || (g.__CR_PHASES__ = {});
|
|
35709
|
+
const cur = bag.raster_mount || (bag.raster_mount = { count: 0, ms: 0 });
|
|
35710
|
+
cur.count += 1;
|
|
35711
|
+
cur.ms += Math.round(now - mountStartedAt);
|
|
35712
|
+
}
|
|
35713
|
+
crPhase("raster_scene1", () => this.waitForCanvasScene(container, renderConfig, pageIndex)).then(async () => {
|
|
35477
35714
|
try {
|
|
35478
35715
|
const fabricInstance = this.getFabricCanvasFromContainer(container);
|
|
35479
35716
|
const expectedImageIds = this.getExpectedImageIds(renderConfig, pageIndex);
|
|
35480
|
-
await this.waitForCanvasImages(container, expectedImageIds);
|
|
35481
|
-
await this.waitForStableTextMetrics(container, renderConfig);
|
|
35482
|
-
await this.waitForCanvasScene(container, renderConfig, pageIndex);
|
|
35717
|
+
await crPhase("raster_images", () => this.waitForCanvasImages(container, expectedImageIds));
|
|
35718
|
+
await crPhase("raster_text_metrics", () => this.waitForStableTextMetrics(container, renderConfig));
|
|
35719
|
+
await crPhase("raster_scene2", () => this.waitForCanvasScene(container, renderConfig, pageIndex));
|
|
35483
35720
|
firstMountSettled = true;
|
|
35484
35721
|
if (hasAutoShrink && lateFontSettleDetected) {
|
|
35485
35722
|
console.log("[canvas-renderer][parity] late font-settle detected — remounting for auto-shrink reflow");
|
|
@@ -37362,7 +37599,7 @@ async function prepareLiveCanvasSvgForPdf(rawSvg, pageWidth, pageHeight, pageKey
|
|
|
37362
37599
|
if (options == null ? void 0 : options.stripPageBackground) stripRootPageBackgroundFromSvg(svgToDraw);
|
|
37363
37600
|
sanitizeSvgTreeForPdf(svgToDraw);
|
|
37364
37601
|
try {
|
|
37365
|
-
const { bakeTextAnchorPositionsFromLiveSvg, logTextMeasurementDiagnostic } = await Promise.resolve().then(() => require("./vectorPdfExport-
|
|
37602
|
+
const { bakeTextAnchorPositionsFromLiveSvg, logTextMeasurementDiagnostic } = await Promise.resolve().then(() => require("./vectorPdfExport-6Hi7Og4W.cjs"));
|
|
37366
37603
|
try {
|
|
37367
37604
|
await logTextMeasurementDiagnostic(svgToDraw);
|
|
37368
37605
|
} catch {
|
|
@@ -37610,6 +37847,129 @@ async function getPublishedTemplate(options) {
|
|
|
37610
37847
|
const rows = await res.json();
|
|
37611
37848
|
return rows[0] ?? null;
|
|
37612
37849
|
}
|
|
37850
|
+
const WATERMARK_ID_PREFIX = "__wm_";
|
|
37851
|
+
const DEFAULT_WATERMARK_OPACITY = 0.14;
|
|
37852
|
+
const DEFAULT_WATERMARK_FONT_SIZE = 18;
|
|
37853
|
+
const DEFAULT_WATERMARK_ANGLE = -30;
|
|
37854
|
+
function getWatermarkText() {
|
|
37855
|
+
try {
|
|
37856
|
+
const host2 = window.location.hostname;
|
|
37857
|
+
if (host2.includes("biomaker")) return "biomaker.app";
|
|
37858
|
+
} catch {
|
|
37859
|
+
}
|
|
37860
|
+
return "pixldocs.com";
|
|
37861
|
+
}
|
|
37862
|
+
function getLuminance(color) {
|
|
37863
|
+
if (!color || color === "transparent" || color === "none") return 1;
|
|
37864
|
+
let r = 255, g = 255, b = 255;
|
|
37865
|
+
if (color.startsWith("#")) {
|
|
37866
|
+
const hex = color.slice(1);
|
|
37867
|
+
const full = hex.length === 3 ? hex.split("").map((c) => c + c).join("") : hex;
|
|
37868
|
+
const n = parseInt(full, 16);
|
|
37869
|
+
r = n >> 16 & 255;
|
|
37870
|
+
g = n >> 8 & 255;
|
|
37871
|
+
b = n & 255;
|
|
37872
|
+
} else {
|
|
37873
|
+
const m = color.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/);
|
|
37874
|
+
if (m) {
|
|
37875
|
+
r = +m[1];
|
|
37876
|
+
g = +m[2];
|
|
37877
|
+
b = +m[3];
|
|
37878
|
+
}
|
|
37879
|
+
}
|
|
37880
|
+
return (0.299 * r + 0.587 * g + 0.114 * b) / 255;
|
|
37881
|
+
}
|
|
37882
|
+
function getWatermarkColor(bgColor) {
|
|
37883
|
+
const lum = getLuminance(bgColor);
|
|
37884
|
+
return lum < 0.45 ? "#cccccc" : "#808080";
|
|
37885
|
+
}
|
|
37886
|
+
function getPageBgColor(page, canvasBg) {
|
|
37887
|
+
var _a2, _b2;
|
|
37888
|
+
const settingsBg = (_a2 = page.settings) == null ? void 0 : _a2.backgroundColor;
|
|
37889
|
+
if (settingsBg && settingsBg !== "transparent" && settingsBg !== "none") {
|
|
37890
|
+
return settingsBg;
|
|
37891
|
+
}
|
|
37892
|
+
const children = page.children || [];
|
|
37893
|
+
for (const child of children) {
|
|
37894
|
+
if (child.type === "shape" && child.fill && child.fill !== "transparent" && child.fill !== "none") {
|
|
37895
|
+
return child.fill;
|
|
37896
|
+
}
|
|
37897
|
+
if ((_b2 = child.children) == null ? void 0 : _b2.length) {
|
|
37898
|
+
for (const gc of child.children) {
|
|
37899
|
+
if (gc.type === "shape" && gc.fill && gc.fill !== "transparent" && gc.fill !== "none") {
|
|
37900
|
+
return gc.fill;
|
|
37901
|
+
}
|
|
37902
|
+
}
|
|
37903
|
+
}
|
|
37904
|
+
}
|
|
37905
|
+
return canvasBg;
|
|
37906
|
+
}
|
|
37907
|
+
function generateWatermarkElements(canvasWidth, canvasHeight, wmColor, options = {}) {
|
|
37908
|
+
const elements = [];
|
|
37909
|
+
const text = options.text ?? getWatermarkText();
|
|
37910
|
+
const fontSize = options.fontSize ?? DEFAULT_WATERMARK_FONT_SIZE;
|
|
37911
|
+
const angle = options.angle ?? DEFAULT_WATERMARK_ANGLE;
|
|
37912
|
+
const opacity = options.opacity ?? DEFAULT_WATERMARK_OPACITY;
|
|
37913
|
+
const estimatedTextWidth = text.length * fontSize * 0.55;
|
|
37914
|
+
const spacingX = Math.max(160, estimatedTextWidth + 30);
|
|
37915
|
+
const spacingY = 90;
|
|
37916
|
+
const startX = -canvasWidth * 0.3;
|
|
37917
|
+
const startY = -canvasHeight * 0.3;
|
|
37918
|
+
const endX = canvasWidth * 1.5;
|
|
37919
|
+
const endY = canvasHeight * 1.5;
|
|
37920
|
+
let idx = 0;
|
|
37921
|
+
for (let y = startY; y < endY; y += spacingY) {
|
|
37922
|
+
for (let x = startX; x < endX; x += spacingX) {
|
|
37923
|
+
elements.push({
|
|
37924
|
+
id: `${WATERMARK_ID_PREFIX}${idx++}`,
|
|
37925
|
+
type: "text",
|
|
37926
|
+
left: x,
|
|
37927
|
+
top: y,
|
|
37928
|
+
width: 200,
|
|
37929
|
+
height: 40,
|
|
37930
|
+
text,
|
|
37931
|
+
fontFamily: "Montserrat",
|
|
37932
|
+
fontSize,
|
|
37933
|
+
fontWeight: "600",
|
|
37934
|
+
fill: wmColor,
|
|
37935
|
+
angle,
|
|
37936
|
+
selectable: false,
|
|
37937
|
+
locked: true,
|
|
37938
|
+
visible: true,
|
|
37939
|
+
opacity,
|
|
37940
|
+
scaleX: 1,
|
|
37941
|
+
scaleY: 1,
|
|
37942
|
+
letterSpacing: 4
|
|
37943
|
+
});
|
|
37944
|
+
}
|
|
37945
|
+
}
|
|
37946
|
+
return elements;
|
|
37947
|
+
}
|
|
37948
|
+
function injectWatermark(config, options = {}) {
|
|
37949
|
+
var _a2, _b2, _c2;
|
|
37950
|
+
const canvasWidth = ((_a2 = config.canvas) == null ? void 0 : _a2.width) || 612;
|
|
37951
|
+
const canvasHeight = ((_b2 = config.canvas) == null ? void 0 : _b2.height) || 792;
|
|
37952
|
+
const canvasBg = (_c2 = config.canvas) == null ? void 0 : _c2.backgroundColor;
|
|
37953
|
+
return {
|
|
37954
|
+
...config,
|
|
37955
|
+
pages: config.pages.map((page) => {
|
|
37956
|
+
const pageBg = getPageBgColor(page, canvasBg);
|
|
37957
|
+
const wmColor = getWatermarkColor(pageBg);
|
|
37958
|
+
const watermarkElements = generateWatermarkElements(canvasWidth, canvasHeight, wmColor, options);
|
|
37959
|
+
return {
|
|
37960
|
+
...page,
|
|
37961
|
+
children: [
|
|
37962
|
+
...page.children || [],
|
|
37963
|
+
...watermarkElements
|
|
37964
|
+
]
|
|
37965
|
+
};
|
|
37966
|
+
})
|
|
37967
|
+
};
|
|
37968
|
+
}
|
|
37969
|
+
const canvasWatermark = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
37970
|
+
__proto__: null,
|
|
37971
|
+
injectWatermark
|
|
37972
|
+
}, Symbol.toStringTag, { value: "Module" }));
|
|
37613
37973
|
function setAutoShrinkDebug(enabled) {
|
|
37614
37974
|
if (typeof window !== "undefined") {
|
|
37615
37975
|
window.__pixldocsDebugAutoShrink = !!enabled;
|
|
@@ -37656,6 +38016,7 @@ exports.getWorldAngleDeg = getWorldAngleDeg$1;
|
|
|
37656
38016
|
exports.hasAnyPreviewBlur = hasAnyPreviewBlur;
|
|
37657
38017
|
exports.hasEdgeFade = hasEdgeFade;
|
|
37658
38018
|
exports.injectPreviewBlur = injectPreviewBlur;
|
|
38019
|
+
exports.injectWatermark = injectWatermark;
|
|
37659
38020
|
exports.isBundledAssetUrl = isBundledAssetUrl;
|
|
37660
38021
|
exports.isElement = isElement;
|
|
37661
38022
|
exports.isFontAvailable = isFontAvailable;
|
|
@@ -37677,4 +38038,4 @@ exports.setAutoShrinkDebug = setAutoShrinkDebug;
|
|
|
37677
38038
|
exports.setBundledAssetPrefixes = setBundledAssetPrefixes;
|
|
37678
38039
|
exports.warmResolvedTemplateForPreview = warmResolvedTemplateForPreview;
|
|
37679
38040
|
exports.warmTemplateFromForm = warmTemplateFromForm;
|
|
37680
|
-
//# sourceMappingURL=index-
|
|
38041
|
+
//# sourceMappingURL=index-CUZInOyk.cjs.map
|