@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
|
@@ -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;
|
|
@@ -2672,7 +2647,7 @@ let sizeBaseSnapshot = null;
|
|
|
2672
2647
|
const reflowPagesFromBase = (base, W, H) => {
|
|
2673
2648
|
const sx = base.width ? W / base.width : 1;
|
|
2674
2649
|
const sy = base.height ? H / base.height : 1;
|
|
2675
|
-
const fscale = Math.
|
|
2650
|
+
const fscale = Math.max(0.01, Math.min(sx, sy));
|
|
2676
2651
|
const adapt = layoutAdaptationFor(base.width, base.height, W, H);
|
|
2677
2652
|
const num = (v) => typeof v === "number" && Number.isFinite(v) ? v : 0;
|
|
2678
2653
|
const scaleNode = (node) => scaleNodeForReflow(node, sx, sy, fscale);
|
|
@@ -3221,7 +3196,7 @@ const useEditorStore = create((set, get) => ({
|
|
|
3221
3196
|
setCanvasSize: (width, height) => set((state) => {
|
|
3222
3197
|
const oldW = state.canvas.width || width, oldH = state.canvas.height || height;
|
|
3223
3198
|
const sx = oldW ? width / oldW : 1, sy = oldH ? height / oldH : 1;
|
|
3224
|
-
const fscale = Math.
|
|
3199
|
+
const fscale = Math.max(0.01, Math.min(sx, sy));
|
|
3225
3200
|
const n = (v) => typeof v === "number" && Number.isFinite(v) ? v : 0;
|
|
3226
3201
|
const scaleNode = (node) => {
|
|
3227
3202
|
const el = { ...node };
|
|
@@ -5877,6 +5852,26 @@ const setupFontLoadingListener = (canvas, afterRerender, options = {}) => {
|
|
|
5877
5852
|
}
|
|
5878
5853
|
};
|
|
5879
5854
|
};
|
|
5855
|
+
const GLOBAL_KEY = "__PIXLDOCS_IMAGE_FAILURES__";
|
|
5856
|
+
const MAX_RECORDED = 50;
|
|
5857
|
+
function host() {
|
|
5858
|
+
return typeof globalThis === "undefined" ? null : globalThis;
|
|
5859
|
+
}
|
|
5860
|
+
function recordImageLoadFailure(failure) {
|
|
5861
|
+
try {
|
|
5862
|
+
const g = host();
|
|
5863
|
+
if (!g) return;
|
|
5864
|
+
const list = g[GLOBAL_KEY] ?? [];
|
|
5865
|
+
if (list.length >= MAX_RECORDED) return;
|
|
5866
|
+
list.push({
|
|
5867
|
+
id: String(failure.id ?? ""),
|
|
5868
|
+
url: String(failure.url ?? "").slice(0, 500),
|
|
5869
|
+
reason: String(failure.reason ?? "").slice(0, 300)
|
|
5870
|
+
});
|
|
5871
|
+
g[GLOBAL_KEY] = list;
|
|
5872
|
+
} catch {
|
|
5873
|
+
}
|
|
5874
|
+
}
|
|
5880
5875
|
const EMPTY_IMAGE_PLACEHOLDER_DATA_URL = "data:image/png;base64,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";
|
|
5881
5876
|
const svgTextCache = /* @__PURE__ */ new Map();
|
|
5882
5877
|
const htmlImageCache = /* @__PURE__ */ new Map();
|
|
@@ -6368,8 +6363,13 @@ async function loadImageAsync(element, placeholder, fc, fabricRef, syncLockedRef
|
|
|
6368
6363
|
});
|
|
6369
6364
|
const imgLoadOptions = url.startsWith("data:") || url.startsWith("blob:") ? {} : { crossOrigin: "anonymous" };
|
|
6370
6365
|
const img = await fabric.FabricImage.fromURL(url, imgLoadOptions);
|
|
6371
|
-
if (!fabricRef.current) return;
|
|
6366
|
+
if (fabricRef && !fabricRef.current) return;
|
|
6372
6367
|
await normalizeSvgImageDimensions(img, imageUrl, element.sourceFormat);
|
|
6368
|
+
const natW = img.width ?? 0;
|
|
6369
|
+
const natH = img.height ?? 0;
|
|
6370
|
+
if (natW <= 1 && natH <= 1 && Number(element.width) > 8 && Number(element.height) > 8) {
|
|
6371
|
+
throw new Error(`image decoded to ${natW}x${natH} — treating as failed load`);
|
|
6372
|
+
}
|
|
6373
6373
|
const isHidden = !element.visible;
|
|
6374
6374
|
img.set({
|
|
6375
6375
|
originX: "left",
|
|
@@ -6567,9 +6567,116 @@ async function loadImageAsync(element, placeholder, fc, fabricRef, syncLockedRef
|
|
|
6567
6567
|
proxiedUrl: getProxiedImageUrl(imageUrl).slice(0, 240),
|
|
6568
6568
|
error: error instanceof Error ? error.message : String(error)
|
|
6569
6569
|
});
|
|
6570
|
+
recordImageLoadFailure({
|
|
6571
|
+
id: String(element.id ?? ""),
|
|
6572
|
+
url: imageUrl,
|
|
6573
|
+
reason: error instanceof Error ? error.message : String(error)
|
|
6574
|
+
});
|
|
6575
|
+
if (fc.__pixldocsEditMode === true) {
|
|
6576
|
+
try {
|
|
6577
|
+
markPlaceholderAsBrokenImage(placeholder);
|
|
6578
|
+
fc.requestRenderAll();
|
|
6579
|
+
} catch {
|
|
6580
|
+
}
|
|
6581
|
+
}
|
|
6570
6582
|
return;
|
|
6571
6583
|
}
|
|
6572
6584
|
}
|
|
6585
|
+
function markPlaceholderAsBrokenImage(placeholder) {
|
|
6586
|
+
if (!(placeholder instanceof fabric.Group)) return;
|
|
6587
|
+
const group = placeholder;
|
|
6588
|
+
if (group.__pixldocsBrokenImage) return;
|
|
6589
|
+
group.__pixldocsBrokenImage = true;
|
|
6590
|
+
const frameChild = group.getObjects().find(
|
|
6591
|
+
(o) => o.__isPlaceholderFrame
|
|
6592
|
+
);
|
|
6593
|
+
const w = Math.max(1, (frameChild == null ? void 0 : frameChild.width) ?? group.width ?? 1);
|
|
6594
|
+
const h = Math.max(1, (frameChild == null ? void 0 : frameChild.height) ?? group.height ?? 1);
|
|
6595
|
+
const center = group.getCenterPoint();
|
|
6596
|
+
const cx = center.x;
|
|
6597
|
+
const cy = center.y;
|
|
6598
|
+
const prevPose = { left: group.left, top: group.top, width: group.width, height: group.height };
|
|
6599
|
+
const bg = new fabric.Rect({
|
|
6600
|
+
originX: "center",
|
|
6601
|
+
originY: "center",
|
|
6602
|
+
left: cx,
|
|
6603
|
+
top: cy,
|
|
6604
|
+
width: w,
|
|
6605
|
+
height: h,
|
|
6606
|
+
fill: "rgba(148, 163, 184, 0.12)",
|
|
6607
|
+
stroke: "#94A3B8",
|
|
6608
|
+
strokeWidth: 1.5,
|
|
6609
|
+
strokeDashArray: [6, 4]
|
|
6610
|
+
});
|
|
6611
|
+
const s = Math.max(16, Math.min(w, h) * 0.28);
|
|
6612
|
+
const glyphStroke = { stroke: "#64748B", strokeWidth: Math.max(1.5, s / 12), fill: "transparent" };
|
|
6613
|
+
const iconFrame = new fabric.Rect({
|
|
6614
|
+
originX: "center",
|
|
6615
|
+
originY: "center",
|
|
6616
|
+
left: cx,
|
|
6617
|
+
top: cy,
|
|
6618
|
+
width: s,
|
|
6619
|
+
height: s * 0.8,
|
|
6620
|
+
rx: s * 0.08,
|
|
6621
|
+
ry: s * 0.08,
|
|
6622
|
+
...glyphStroke
|
|
6623
|
+
});
|
|
6624
|
+
const mountain = new fabric.Polyline(
|
|
6625
|
+
[
|
|
6626
|
+
{ x: -s * 0.38, y: s * 0.24 },
|
|
6627
|
+
{ x: -s * 0.1, y: -s * 0.08 },
|
|
6628
|
+
{ x: s * 0.08, y: s * 0.1 },
|
|
6629
|
+
{ x: s * 0.22, y: -s * 0.02 },
|
|
6630
|
+
{ x: s * 0.38, y: s * 0.24 }
|
|
6631
|
+
],
|
|
6632
|
+
{ originX: "center", originY: "center", left: cx, top: cy + s * 0.08, ...glyphStroke }
|
|
6633
|
+
);
|
|
6634
|
+
const slash = new fabric.Line([cx - s * 0.55, cy - s * 0.5, cx + s * 0.55, cy + s * 0.5], {
|
|
6635
|
+
...glyphStroke,
|
|
6636
|
+
originX: "center",
|
|
6637
|
+
originY: "center",
|
|
6638
|
+
left: cx,
|
|
6639
|
+
top: cy
|
|
6640
|
+
});
|
|
6641
|
+
for (const obj of [bg, iconFrame, mountain, slash]) {
|
|
6642
|
+
obj.set({ selectable: false, evented: false, excludeFromExport: true });
|
|
6643
|
+
obj.__pixldocsEditorChrome = true;
|
|
6644
|
+
group.add(obj);
|
|
6645
|
+
}
|
|
6646
|
+
group.set(prevPose);
|
|
6647
|
+
group.setCoords();
|
|
6648
|
+
group.dirty = true;
|
|
6649
|
+
}
|
|
6650
|
+
function hideEditorChromeForExport(fc) {
|
|
6651
|
+
const hidden = [];
|
|
6652
|
+
const walk = (objs) => {
|
|
6653
|
+
var _a2;
|
|
6654
|
+
for (const o of objs) {
|
|
6655
|
+
if (o.__pixldocsEditorChrome && o.visible !== false) {
|
|
6656
|
+
o.visible = false;
|
|
6657
|
+
hidden.push(o);
|
|
6658
|
+
}
|
|
6659
|
+
const kids = (_a2 = o.getObjects) == null ? void 0 : _a2.call(o);
|
|
6660
|
+
if (kids == null ? void 0 : kids.length) walk(kids);
|
|
6661
|
+
}
|
|
6662
|
+
};
|
|
6663
|
+
walk(fc.getObjects());
|
|
6664
|
+
if (hidden.length) {
|
|
6665
|
+
for (const o of hidden) {
|
|
6666
|
+
const g = o.group;
|
|
6667
|
+
if (g) g.dirty = true;
|
|
6668
|
+
}
|
|
6669
|
+
fc.renderAll();
|
|
6670
|
+
}
|
|
6671
|
+
return () => {
|
|
6672
|
+
for (const o of hidden) {
|
|
6673
|
+
o.visible = true;
|
|
6674
|
+
const g = o.group;
|
|
6675
|
+
if (g) g.dirty = true;
|
|
6676
|
+
}
|
|
6677
|
+
if (hidden.length) fc.requestRenderAll();
|
|
6678
|
+
};
|
|
6679
|
+
}
|
|
6573
6680
|
const canvasImageLoader = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
6574
6681
|
__proto__: null,
|
|
6575
6682
|
SVG_DECODE_HARD_CAP,
|
|
@@ -6579,12 +6686,14 @@ const canvasImageLoader = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.d
|
|
|
6579
6686
|
fetchSvgTextPublic,
|
|
6580
6687
|
getNormalizedSvgUrl,
|
|
6581
6688
|
getProxiedImageUrl,
|
|
6689
|
+
hideEditorChromeForExport,
|
|
6582
6690
|
isBundledAssetUrl,
|
|
6583
6691
|
isEmptyImagePlaceholderGroup,
|
|
6584
6692
|
isPrivateUrl,
|
|
6585
6693
|
isSvgImage,
|
|
6586
6694
|
loadImageAsync,
|
|
6587
6695
|
loadSvgDimensions,
|
|
6696
|
+
markPlaceholderAsBrokenImage,
|
|
6588
6697
|
normalizeSvgImageDimensions,
|
|
6589
6698
|
parseSvgDimensionsFromText,
|
|
6590
6699
|
preloadImage,
|
|
@@ -10310,10 +10419,10 @@ function textPathBoundsContainScenePoint(obj, point) {
|
|
|
10310
10419
|
}
|
|
10311
10420
|
function drawTextPathBounds(ctx, obj, bounds, hostCanvas) {
|
|
10312
10421
|
var _a2, _b2, _c2;
|
|
10313
|
-
const
|
|
10314
|
-
if (!
|
|
10315
|
-
const retina = ((_b2 =
|
|
10316
|
-
const matrix = fabric.util.multiplyTransformMatrices(
|
|
10422
|
+
const host2 = hostCanvas || obj.canvas || ((_a2 = obj.group) == null ? void 0 : _a2.canvas);
|
|
10423
|
+
if (!host2) return;
|
|
10424
|
+
const retina = ((_b2 = host2.getRetinaScaling) == null ? void 0 : _b2.call(host2)) || ((_c2 = obj.getCanvasRetinaScaling) == null ? void 0 : _c2.call(obj)) || 1;
|
|
10425
|
+
const matrix = fabric.util.multiplyTransformMatrices(host2.viewportTransform || [1, 0, 0, 1, 0, 0], obj.calcTransformMatrix());
|
|
10317
10426
|
const corners = [
|
|
10318
10427
|
new fabric.Point(bounds.minX, bounds.minY),
|
|
10319
10428
|
new fabric.Point(bounds.maxX, bounds.minY),
|
|
@@ -10564,11 +10673,11 @@ if (GroupProto && typeof GroupProto._renderControls === "function" && !GroupProt
|
|
|
10564
10673
|
GroupProto.__pixldocsOrigRenderControls = GroupProto._renderControls;
|
|
10565
10674
|
GroupProto._renderControls = function(ctx, styleOverride, childrenOverride) {
|
|
10566
10675
|
var _a2;
|
|
10567
|
-
const
|
|
10568
|
-
const active = (_a2 =
|
|
10569
|
-
const isActiveOrInActive = !!
|
|
10676
|
+
const host2 = this.canvas;
|
|
10677
|
+
const active = (_a2 = host2 == null ? void 0 : host2.getActiveObject) == null ? void 0 : _a2.call(host2);
|
|
10678
|
+
const isActiveOrInActive = !!host2 && (active === this || !!active && typeof active.contains === "function" && active.contains(this, true));
|
|
10570
10679
|
GroupProto.__pixldocsOrigRenderControls.call(this, ctx, styleOverride, childrenOverride);
|
|
10571
|
-
if (!
|
|
10680
|
+
if (!host2 || !isActiveOrInActive) return;
|
|
10572
10681
|
const drawForDescendants = (parent) => {
|
|
10573
10682
|
const kids = (parent == null ? void 0 : parent._objects) || [];
|
|
10574
10683
|
for (const child of kids) {
|
|
@@ -10577,7 +10686,7 @@ if (GroupProto && typeof GroupProto._renderControls === "function" && !GroupProt
|
|
|
10577
10686
|
}
|
|
10578
10687
|
if (child && child.textPath && child.textPath.preset && child.textPath.preset !== "none") {
|
|
10579
10688
|
const bounds = getTextPathHitBounds(child);
|
|
10580
|
-
if (bounds) drawTextPathBounds(ctx, child, bounds,
|
|
10689
|
+
if (bounds) drawTextPathBounds(ctx, child, bounds, host2);
|
|
10581
10690
|
}
|
|
10582
10691
|
}
|
|
10583
10692
|
};
|
|
@@ -18096,6 +18205,7 @@ const PageCanvas = forwardRef(
|
|
|
18096
18205
|
// Transparent so underlay (page bg + group bgs) shows through
|
|
18097
18206
|
backgroundColor: "transparent"
|
|
18098
18207
|
});
|
|
18208
|
+
fabricCanvas.__pixldocsEditMode = isEditorMode && !isPreviewMode;
|
|
18099
18209
|
fabricCanvas.hoverCursor = "default";
|
|
18100
18210
|
fabricCanvas.moveCursor = "move";
|
|
18101
18211
|
const suppressTextEditForClick = (textbox) => {
|
|
@@ -25421,6 +25531,7 @@ const PageCanvas = forwardRef(
|
|
|
25421
25531
|
} else if (obj instanceof fabric.Textbox) {
|
|
25422
25532
|
const overflowPolicy = element.overflowPolicy || "grow-and-push";
|
|
25423
25533
|
let text = element.text != null && element.text !== "" ? element.text : " ";
|
|
25534
|
+
text = applyElementTextCase(text, element.textCase);
|
|
25424
25535
|
let parsedStyles = null;
|
|
25425
25536
|
if (element.formattingEnabled === true) {
|
|
25426
25537
|
const parsed = parseTextMarkdown(text);
|
|
@@ -26065,6 +26176,13 @@ const PageCanvas = forwardRef(
|
|
|
26065
26176
|
const img = await fabric.FabricImage.fromURL(url, { crossOrigin: "anonymous" });
|
|
26066
26177
|
if (!fabricRef.current || !isLatestRequest()) return;
|
|
26067
26178
|
await normalizeSvgImageDimensions(img, imageUrl, element.sourceFormat, svgDecodeTarget);
|
|
26179
|
+
{
|
|
26180
|
+
const natW = img.width ?? 0;
|
|
26181
|
+
const natH = img.height ?? 0;
|
|
26182
|
+
if (natW <= 1 && natH <= 1 && Number(element.width) > 8 && Number(element.height) > 8) {
|
|
26183
|
+
throw new Error(`image decoded to ${natW}x${natH} — treating as failed load`);
|
|
26184
|
+
}
|
|
26185
|
+
}
|
|
26068
26186
|
if (!isLatestRequest()) return;
|
|
26069
26187
|
const imageFitForFade = element.imageFit || ((_a2 = element.style) == null ? void 0 : _a2.imageFit) || "cover";
|
|
26070
26188
|
const clipShapeForFade = element.clipShape ?? ((_b2 = element.style) == null ? void 0 : _b2.imageFrameShape) ?? (isPreviewMode ? "rectangle" : "none");
|
|
@@ -26431,6 +26549,24 @@ const PageCanvas = forwardRef(
|
|
|
26431
26549
|
}
|
|
26432
26550
|
fc.requestRenderAll();
|
|
26433
26551
|
} catch (error) {
|
|
26552
|
+
console.error("[PageCanvas] image failed to load", {
|
|
26553
|
+
id: element.id,
|
|
26554
|
+
url: (element.src || element.imageUrl || "").slice(0, 200),
|
|
26555
|
+
error: error instanceof Error ? error.message : String(error)
|
|
26556
|
+
});
|
|
26557
|
+
recordImageLoadFailure({
|
|
26558
|
+
id: String(element.id ?? ""),
|
|
26559
|
+
url: element.src || element.imageUrl || "",
|
|
26560
|
+
reason: error instanceof Error ? error.message : String(error)
|
|
26561
|
+
});
|
|
26562
|
+
const fcNow = fabricRef.current;
|
|
26563
|
+
if (fcNow && fcNow.__pixldocsEditMode === true) {
|
|
26564
|
+
try {
|
|
26565
|
+
markPlaceholderAsBrokenImage(placeholder);
|
|
26566
|
+
fcNow.requestRenderAll();
|
|
26567
|
+
} catch {
|
|
26568
|
+
}
|
|
26569
|
+
}
|
|
26434
26570
|
}
|
|
26435
26571
|
};
|
|
26436
26572
|
const handleCanvasClick = useCallback(
|
|
@@ -27754,6 +27890,7 @@ function PreviewCanvas({
|
|
|
27754
27890
|
const pageSettings = useMemo(() => {
|
|
27755
27891
|
var _a3, _b3;
|
|
27756
27892
|
return {
|
|
27893
|
+
// design-drift-ignore: artifact paper colour, not chrome
|
|
27757
27894
|
backgroundColor: ((_a3 = page == null ? void 0 : page.settings) == null ? void 0 : _a3.backgroundColor) || "#ffffff",
|
|
27758
27895
|
backgroundGradient: (_b3 = page == null ? void 0 : page.settings) == null ? void 0 : _b3.backgroundGradient
|
|
27759
27896
|
};
|
|
@@ -32376,11 +32513,31 @@ async function resolveTemplateData(options) {
|
|
|
32376
32513
|
...formData ?? {}
|
|
32377
32514
|
};
|
|
32378
32515
|
const dynamicFields = config.dynamicFields;
|
|
32379
|
-
|
|
32516
|
+
const hasBoundTable = (() => {
|
|
32517
|
+
let found = false;
|
|
32518
|
+
const walk = (nodes) => {
|
|
32519
|
+
var _a2, _b2;
|
|
32520
|
+
for (const n of nodes || []) {
|
|
32521
|
+
if (found) return;
|
|
32522
|
+
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)) {
|
|
32523
|
+
found = true;
|
|
32524
|
+
return;
|
|
32525
|
+
}
|
|
32526
|
+
walk(n == null ? void 0 : n.children);
|
|
32527
|
+
}
|
|
32528
|
+
};
|
|
32529
|
+
for (const p of config.pages || []) walk(p.children);
|
|
32530
|
+
return found;
|
|
32531
|
+
})();
|
|
32532
|
+
const hasDynamicFields = Array.isArray(dynamicFields) && dynamicFields.length > 0;
|
|
32533
|
+
if (!hasDynamicFields && (hasBoundTable || repeatableSectionsInput.length > 0)) {
|
|
32534
|
+
console.log("[resolveTemplateData] no dynamicFields; binding via bound table / repeatable sections");
|
|
32535
|
+
}
|
|
32536
|
+
if (!hasDynamicFields && !hasBoundTable && repeatableSectionsInput.length === 0) {
|
|
32380
32537
|
return { config: applyThemeIfNeeded(config), templateName: template.name || "Untitled", templateId, price: template.price ?? 0 };
|
|
32381
32538
|
}
|
|
32382
32539
|
const mappings = [];
|
|
32383
|
-
for (const f of dynamicFields) {
|
|
32540
|
+
for (const f of dynamicFields || []) {
|
|
32384
32541
|
for (const m of f.mappings || []) {
|
|
32385
32542
|
mappings.push({
|
|
32386
32543
|
field_key: f.id,
|
|
@@ -34101,6 +34258,14 @@ function captureFabricCanvasSvgForPdf(fabricInstance, canvasWidth, canvasHeight)
|
|
|
34101
34258
|
try {
|
|
34102
34259
|
const visit = (obj) => {
|
|
34103
34260
|
if (!obj) return;
|
|
34261
|
+
if (obj.__pixldocsEditorChrome) {
|
|
34262
|
+
const originalToSVG = typeof obj.toSVG === "function" ? obj.toSVG.bind(obj) : null;
|
|
34263
|
+
if (originalToSVG) {
|
|
34264
|
+
obj.toSVG = () => "";
|
|
34265
|
+
svgPatchRecords.push({ obj, originalToSVG });
|
|
34266
|
+
}
|
|
34267
|
+
return;
|
|
34268
|
+
}
|
|
34104
34269
|
const imageId = typeof obj.__docuforgeId === "string" && hasRenderableRasterCandidate(obj) ? obj.__docuforgeId : "";
|
|
34105
34270
|
const alphaGradient = objectNeedsAlphaGradientRaster(obj);
|
|
34106
34271
|
if ((isTextboxLike(obj) || imageId || alphaGradient) && typeof obj.toSVG === "function") {
|
|
@@ -34208,9 +34373,22 @@ function captureFabricCanvasSvgForPdf(fabricInstance, canvasWidth, canvasHeight)
|
|
|
34208
34373
|
}
|
|
34209
34374
|
return svgString;
|
|
34210
34375
|
}
|
|
34211
|
-
const resolvedPackageVersion = "0.5.
|
|
34376
|
+
const resolvedPackageVersion = "0.5.498";
|
|
34212
34377
|
const PACKAGE_VERSION = resolvedPackageVersion;
|
|
34213
|
-
|
|
34378
|
+
async function crPhase(name, fn) {
|
|
34379
|
+
const now = () => typeof performance !== "undefined" ? performance.now() : Date.now();
|
|
34380
|
+
const t0 = now();
|
|
34381
|
+
try {
|
|
34382
|
+
return await fn();
|
|
34383
|
+
} finally {
|
|
34384
|
+
const g = globalThis;
|
|
34385
|
+
const bag = g.__CR_PHASES__ || (g.__CR_PHASES__ = {});
|
|
34386
|
+
const cur = bag[name] || (bag[name] = { count: 0, ms: 0 });
|
|
34387
|
+
cur.count += 1;
|
|
34388
|
+
cur.ms += Math.round(now() - t0);
|
|
34389
|
+
}
|
|
34390
|
+
}
|
|
34391
|
+
const DEPLOYMENT_VERSION_MARKER = "__PIXLDOCS_CANVAS_RENDERER_VERSION__:0.5.498";
|
|
34214
34392
|
const roundParityValue = (value) => {
|
|
34215
34393
|
if (typeof value !== "number") return value;
|
|
34216
34394
|
return Number.isFinite(value) ? Number(value.toFixed(3)) : value;
|
|
@@ -34649,6 +34827,11 @@ class PixldocsRenderer {
|
|
|
34649
34827
|
* Mounts a hidden PreviewCanvas component and captures the Fabric canvas output.
|
|
34650
34828
|
*/
|
|
34651
34829
|
async render(templateConfig, options = {}) {
|
|
34830
|
+
if (options.watermark === true && !templateConfig.__pixldocsWatermarked) {
|
|
34831
|
+
const { injectWatermark: injectWatermark2 } = await Promise.resolve().then(() => canvasWatermark);
|
|
34832
|
+
templateConfig = injectWatermark2(templateConfig, options.watermarkOptions);
|
|
34833
|
+
templateConfig.__pixldocsWatermarked = true;
|
|
34834
|
+
}
|
|
34652
34835
|
const pageIndex = options.pageIndex ?? 0;
|
|
34653
34836
|
const format = options.format ?? "png";
|
|
34654
34837
|
const quality = options.quality ?? 0.92;
|
|
@@ -34664,6 +34847,7 @@ class PixldocsRenderer {
|
|
|
34664
34847
|
const hasAutoShrink = configHasAutoShrinkText(templateConfig);
|
|
34665
34848
|
const defaultWait = hasAutoShrink ? 4e3 : 1800;
|
|
34666
34849
|
await this.awaitFontsForConfig(templateConfig, options.waitForFontsMs ?? defaultWait);
|
|
34850
|
+
this.flushTextMeasurementCaches();
|
|
34667
34851
|
}
|
|
34668
34852
|
const { setPackageApiUrl: setPackageApiUrl2 } = await Promise.resolve().then(() => appApi);
|
|
34669
34853
|
setPackageApiUrl2(this.config.imageProxyUrl);
|
|
@@ -34691,6 +34875,7 @@ class PixldocsRenderer {
|
|
|
34691
34875
|
const hasAutoShrink = configHasAutoShrinkText(templateConfig);
|
|
34692
34876
|
const defaultWait = hasAutoShrink ? 4e3 : 1800;
|
|
34693
34877
|
await this.awaitFontsForConfig(templateConfig, options.waitForFontsMs ?? defaultWait);
|
|
34878
|
+
this.flushTextMeasurementCaches();
|
|
34694
34879
|
}
|
|
34695
34880
|
const results = [];
|
|
34696
34881
|
for (let i = 0; i < templateConfig.pages.length; i++) {
|
|
@@ -34717,8 +34902,8 @@ class PixldocsRenderer {
|
|
|
34717
34902
|
const shouldWatermark = watermark ?? resolved.price > 0;
|
|
34718
34903
|
let configToRender = resolved.config;
|
|
34719
34904
|
if (shouldWatermark) {
|
|
34720
|
-
const { injectWatermark } = await
|
|
34721
|
-
configToRender =
|
|
34905
|
+
const { injectWatermark: injectWatermark2 } = await Promise.resolve().then(() => canvasWatermark);
|
|
34906
|
+
configToRender = injectWatermark2(configToRender, watermarkOptions);
|
|
34722
34907
|
const { injectPreviewBlur: injectPreviewBlur2 } = await Promise.resolve().then(() => previewBlur);
|
|
34723
34908
|
configToRender = injectPreviewBlur2(configToRender);
|
|
34724
34909
|
}
|
|
@@ -34777,8 +34962,8 @@ class PixldocsRenderer {
|
|
|
34777
34962
|
const shouldWatermark = watermark ?? resolved.price > 0;
|
|
34778
34963
|
let configToRender = resolved.config;
|
|
34779
34964
|
if (shouldWatermark) {
|
|
34780
|
-
const { injectWatermark } = await
|
|
34781
|
-
configToRender =
|
|
34965
|
+
const { injectWatermark: injectWatermark2 } = await Promise.resolve().then(() => canvasWatermark);
|
|
34966
|
+
configToRender = injectWatermark2(configToRender, watermarkOptions);
|
|
34782
34967
|
const { injectPreviewBlur: injectPreviewBlur2 } = await Promise.resolve().then(() => previewBlur);
|
|
34783
34968
|
configToRender = injectPreviewBlur2(configToRender);
|
|
34784
34969
|
}
|
|
@@ -34798,6 +34983,10 @@ class PixldocsRenderer {
|
|
|
34798
34983
|
* exporter, which is what `renderPdfViaClientExport` does below.
|
|
34799
34984
|
*/
|
|
34800
34985
|
async renderPdf(templateConfig, options) {
|
|
34986
|
+
if ((options == null ? void 0 : options.watermark) === true) {
|
|
34987
|
+
const { injectWatermark: injectWatermark2 } = await Promise.resolve().then(() => canvasWatermark);
|
|
34988
|
+
templateConfig = injectWatermark2(templateConfig, options.watermarkOptions);
|
|
34989
|
+
}
|
|
34801
34990
|
return this.renderPdfViaClientExport(templateConfig, {
|
|
34802
34991
|
title: options == null ? void 0 : options.title,
|
|
34803
34992
|
textMode: options == null ? void 0 : options.textMode,
|
|
@@ -34826,8 +35015,8 @@ class PixldocsRenderer {
|
|
|
34826
35015
|
const shouldWatermark = watermark ?? resolved.price > 0;
|
|
34827
35016
|
let configToRender = resolved.config;
|
|
34828
35017
|
if (shouldWatermark) {
|
|
34829
|
-
const { injectWatermark } = await
|
|
34830
|
-
configToRender =
|
|
35018
|
+
const { injectWatermark: injectWatermark2 } = await Promise.resolve().then(() => canvasWatermark);
|
|
35019
|
+
configToRender = injectWatermark2(configToRender, watermarkOptions);
|
|
34831
35020
|
const { injectPreviewBlur: injectPreviewBlur2 } = await Promise.resolve().then(() => previewBlur);
|
|
34832
35021
|
configToRender = injectPreviewBlur2(configToRender);
|
|
34833
35022
|
}
|
|
@@ -34998,7 +35187,7 @@ class PixldocsRenderer {
|
|
|
34998
35187
|
containers.push(container);
|
|
34999
35188
|
const root = createRoot(container);
|
|
35000
35189
|
roots.push(root);
|
|
35001
|
-
await new Promise((resolve, reject) => {
|
|
35190
|
+
await crPhase("pdf_mount", () => new Promise((resolve, reject) => {
|
|
35002
35191
|
const timer = setTimeout(() => reject(new Error(`PreviewCanvas onReady timeout for page ${i}`)), 3e4);
|
|
35003
35192
|
root.render(
|
|
35004
35193
|
createElement(PreviewCanvas2, {
|
|
@@ -35016,15 +35205,15 @@ class PixldocsRenderer {
|
|
|
35016
35205
|
}
|
|
35017
35206
|
})
|
|
35018
35207
|
);
|
|
35019
|
-
});
|
|
35020
|
-
await this.waitForCanvasScene(container, cloned, i);
|
|
35208
|
+
}));
|
|
35209
|
+
await crPhase("pdf_scene1", () => this.waitForCanvasScene(container, cloned, i));
|
|
35021
35210
|
const expected = this.getExpectedImageIds(cloned, i);
|
|
35022
|
-
await this.waitForCanvasImages(container, expected);
|
|
35023
|
-
await this.waitForStableTextMetrics(container, cloned, { clearGlobalCharCache: false });
|
|
35024
|
-
await this.waitForCanvasScene(container, cloned, i);
|
|
35211
|
+
await crPhase("pdf_images", () => this.waitForCanvasImages(container, expected));
|
|
35212
|
+
await crPhase("pdf_text_metrics", () => this.waitForStableTextMetrics(container, cloned, { clearGlobalCharCache: false }));
|
|
35213
|
+
await crPhase("pdf_scene2", () => this.waitForCanvasScene(container, cloned, i));
|
|
35025
35214
|
}
|
|
35026
35215
|
console.log(`[canvas-renderer][pdf-unified] mounted ${cloned.pages.length} page(s), handing off to client exportMultiPagePdf`);
|
|
35027
|
-
const { exportMultiPagePdf, preparePagesForExport } = await import("./vectorPdfExport-
|
|
35216
|
+
const { exportMultiPagePdf, preparePagesForExport } = await import("./vectorPdfExport-D8iQi9WT.js");
|
|
35028
35217
|
const prepared = preparePagesForExport(
|
|
35029
35218
|
cloned.pages,
|
|
35030
35219
|
canvasWidth,
|
|
@@ -35202,8 +35391,14 @@ class PixldocsRenderer {
|
|
|
35202
35391
|
}
|
|
35203
35392
|
const sceneSettled = fabricReady && allDomLoaded && canvasReady && fabricObjects.length > 0;
|
|
35204
35393
|
const idleFor = Date.now() - lastProgressAt;
|
|
35205
|
-
|
|
35206
|
-
|
|
35394
|
+
const strictIdleMs = Math.max(earlyExitMs, 4e3);
|
|
35395
|
+
const stalled = strictById ? missingImageIds.length > 0 : actualImageCount < expectedImageCount;
|
|
35396
|
+
if (sceneSettled && stalled && idleFor >= (strictById ? strictIdleMs : earlyExitMs)) {
|
|
35397
|
+
if (strictById) {
|
|
35398
|
+
console.warn(
|
|
35399
|
+
`[canvas-renderer][asset-wait] early-exit after ${elapsed}ms with unresolved image id(s): ${missingImageIds.join(", ")} (idle=${idleFor}ms, ${summary})`
|
|
35400
|
+
);
|
|
35401
|
+
} else if (debug) {
|
|
35207
35402
|
console.log(
|
|
35208
35403
|
`[canvas-renderer][asset-wait] early-exit after ${elapsed}ms (idle=${idleFor}ms, ${summary})`
|
|
35209
35404
|
);
|
|
@@ -35302,6 +35497,37 @@ class PixldocsRenderer {
|
|
|
35302
35497
|
new Promise((r) => setTimeout(r, Math.min(500, maxWaitMs)))
|
|
35303
35498
|
]);
|
|
35304
35499
|
}
|
|
35500
|
+
/**
|
|
35501
|
+
* Flush BOTH process-global text-measurement caches after fonts are ready
|
|
35502
|
+
* and BEFORE the capture canvas mounts.
|
|
35503
|
+
*
|
|
35504
|
+
* Why: anything that measured text before the webfonts finished loading —
|
|
35505
|
+
* most notably `applyContentBoundsPagination` running inside
|
|
35506
|
+
* `resolveFromForm` on a cold page (the EC2/MCP flow: resolve + render in
|
|
35507
|
+
* one browser context) — populates the app measurement cache and Fabric's
|
|
35508
|
+
* global char-width cache with FALLBACK metrics. `createText` then places
|
|
35509
|
+
* center/right-aligned lines from those stale widths, so a right-aligned
|
|
35510
|
+
* grid cell on a continuation page drew shifted left by
|
|
35511
|
+
* (fallbackWidth − realWidth) px vs the editor (caught by
|
|
35512
|
+
* tests/parity `auto-paginate`, a 9px shift). The later
|
|
35513
|
+
* `waitForStableTextMetrics` pass re-primes glyph bounds but never moves
|
|
35514
|
+
* the already-positioned box, so the flush must happen pre-mount.
|
|
35515
|
+
*
|
|
35516
|
+
* Only called from the headless PNG paths (`render`/`renderAllPages`),
|
|
35517
|
+
* which already default to clearing the global char cache in
|
|
35518
|
+
* `waitForStableTextMetrics` — the live-preview-adjacent PDF path keeps
|
|
35519
|
+
* its `clearGlobalCharCache: false` behaviour untouched.
|
|
35520
|
+
*/
|
|
35521
|
+
flushTextMeasurementCaches() {
|
|
35522
|
+
try {
|
|
35523
|
+
clearMeasurementCache();
|
|
35524
|
+
} catch {
|
|
35525
|
+
}
|
|
35526
|
+
try {
|
|
35527
|
+
clearFabricCharCache();
|
|
35528
|
+
} catch {
|
|
35529
|
+
}
|
|
35530
|
+
}
|
|
35305
35531
|
getNormalizedGradientStops(gradient) {
|
|
35306
35532
|
const stops = Array.isArray(gradient == null ? void 0 : gradient.stops) ? gradient.stops.map((stop) => ({
|
|
35307
35533
|
offset: Math.max(0, Math.min(1, Number((stop == null ? void 0 : stop.offset) ?? 0))),
|
|
@@ -35391,6 +35617,8 @@ class PixldocsRenderer {
|
|
|
35391
35617
|
});
|
|
35392
35618
|
}
|
|
35393
35619
|
return new Promise((resolve, reject) => {
|
|
35620
|
+
const mountStartedAt = typeof performance !== "undefined" ? performance.now() : Date.now();
|
|
35621
|
+
let mountRecorded = false;
|
|
35394
35622
|
const container = document.createElement("div");
|
|
35395
35623
|
container.style.cssText = `
|
|
35396
35624
|
position: fixed; left: -99999px; top: -99999px;
|
|
@@ -35455,13 +35683,22 @@ class PixldocsRenderer {
|
|
|
35455
35683
|
});
|
|
35456
35684
|
};
|
|
35457
35685
|
const onReady = () => {
|
|
35458
|
-
|
|
35686
|
+
if (!mountRecorded) {
|
|
35687
|
+
mountRecorded = true;
|
|
35688
|
+
const now = typeof performance !== "undefined" ? performance.now() : Date.now();
|
|
35689
|
+
const g = globalThis;
|
|
35690
|
+
const bag = g.__CR_PHASES__ || (g.__CR_PHASES__ = {});
|
|
35691
|
+
const cur = bag.raster_mount || (bag.raster_mount = { count: 0, ms: 0 });
|
|
35692
|
+
cur.count += 1;
|
|
35693
|
+
cur.ms += Math.round(now - mountStartedAt);
|
|
35694
|
+
}
|
|
35695
|
+
crPhase("raster_scene1", () => this.waitForCanvasScene(container, renderConfig, pageIndex)).then(async () => {
|
|
35459
35696
|
try {
|
|
35460
35697
|
const fabricInstance = this.getFabricCanvasFromContainer(container);
|
|
35461
35698
|
const expectedImageIds = this.getExpectedImageIds(renderConfig, pageIndex);
|
|
35462
|
-
await this.waitForCanvasImages(container, expectedImageIds);
|
|
35463
|
-
await this.waitForStableTextMetrics(container, renderConfig);
|
|
35464
|
-
await this.waitForCanvasScene(container, renderConfig, pageIndex);
|
|
35699
|
+
await crPhase("raster_images", () => this.waitForCanvasImages(container, expectedImageIds));
|
|
35700
|
+
await crPhase("raster_text_metrics", () => this.waitForStableTextMetrics(container, renderConfig));
|
|
35701
|
+
await crPhase("raster_scene2", () => this.waitForCanvasScene(container, renderConfig, pageIndex));
|
|
35465
35702
|
firstMountSettled = true;
|
|
35466
35703
|
if (hasAutoShrink && lateFontSettleDetected) {
|
|
35467
35704
|
console.log("[canvas-renderer][parity] late font-settle detected — remounting for auto-shrink reflow");
|
|
@@ -37344,7 +37581,7 @@ async function prepareLiveCanvasSvgForPdf(rawSvg, pageWidth, pageHeight, pageKey
|
|
|
37344
37581
|
if (options == null ? void 0 : options.stripPageBackground) stripRootPageBackgroundFromSvg(svgToDraw);
|
|
37345
37582
|
sanitizeSvgTreeForPdf(svgToDraw);
|
|
37346
37583
|
try {
|
|
37347
|
-
const { bakeTextAnchorPositionsFromLiveSvg, logTextMeasurementDiagnostic } = await import("./vectorPdfExport-
|
|
37584
|
+
const { bakeTextAnchorPositionsFromLiveSvg, logTextMeasurementDiagnostic } = await import("./vectorPdfExport-D8iQi9WT.js");
|
|
37348
37585
|
try {
|
|
37349
37586
|
await logTextMeasurementDiagnostic(svgToDraw);
|
|
37350
37587
|
} catch {
|
|
@@ -37592,13 +37829,136 @@ async function getPublishedTemplate(options) {
|
|
|
37592
37829
|
const rows = await res.json();
|
|
37593
37830
|
return rows[0] ?? null;
|
|
37594
37831
|
}
|
|
37832
|
+
const WATERMARK_ID_PREFIX = "__wm_";
|
|
37833
|
+
const DEFAULT_WATERMARK_OPACITY = 0.14;
|
|
37834
|
+
const DEFAULT_WATERMARK_FONT_SIZE = 18;
|
|
37835
|
+
const DEFAULT_WATERMARK_ANGLE = -30;
|
|
37836
|
+
function getWatermarkText() {
|
|
37837
|
+
try {
|
|
37838
|
+
const host2 = window.location.hostname;
|
|
37839
|
+
if (host2.includes("biomaker")) return "biomaker.app";
|
|
37840
|
+
} catch {
|
|
37841
|
+
}
|
|
37842
|
+
return "pixldocs.com";
|
|
37843
|
+
}
|
|
37844
|
+
function getLuminance(color) {
|
|
37845
|
+
if (!color || color === "transparent" || color === "none") return 1;
|
|
37846
|
+
let r = 255, g = 255, b = 255;
|
|
37847
|
+
if (color.startsWith("#")) {
|
|
37848
|
+
const hex = color.slice(1);
|
|
37849
|
+
const full = hex.length === 3 ? hex.split("").map((c) => c + c).join("") : hex;
|
|
37850
|
+
const n = parseInt(full, 16);
|
|
37851
|
+
r = n >> 16 & 255;
|
|
37852
|
+
g = n >> 8 & 255;
|
|
37853
|
+
b = n & 255;
|
|
37854
|
+
} else {
|
|
37855
|
+
const m = color.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/);
|
|
37856
|
+
if (m) {
|
|
37857
|
+
r = +m[1];
|
|
37858
|
+
g = +m[2];
|
|
37859
|
+
b = +m[3];
|
|
37860
|
+
}
|
|
37861
|
+
}
|
|
37862
|
+
return (0.299 * r + 0.587 * g + 0.114 * b) / 255;
|
|
37863
|
+
}
|
|
37864
|
+
function getWatermarkColor(bgColor) {
|
|
37865
|
+
const lum = getLuminance(bgColor);
|
|
37866
|
+
return lum < 0.45 ? "#cccccc" : "#808080";
|
|
37867
|
+
}
|
|
37868
|
+
function getPageBgColor(page, canvasBg) {
|
|
37869
|
+
var _a2, _b2;
|
|
37870
|
+
const settingsBg = (_a2 = page.settings) == null ? void 0 : _a2.backgroundColor;
|
|
37871
|
+
if (settingsBg && settingsBg !== "transparent" && settingsBg !== "none") {
|
|
37872
|
+
return settingsBg;
|
|
37873
|
+
}
|
|
37874
|
+
const children = page.children || [];
|
|
37875
|
+
for (const child of children) {
|
|
37876
|
+
if (child.type === "shape" && child.fill && child.fill !== "transparent" && child.fill !== "none") {
|
|
37877
|
+
return child.fill;
|
|
37878
|
+
}
|
|
37879
|
+
if ((_b2 = child.children) == null ? void 0 : _b2.length) {
|
|
37880
|
+
for (const gc of child.children) {
|
|
37881
|
+
if (gc.type === "shape" && gc.fill && gc.fill !== "transparent" && gc.fill !== "none") {
|
|
37882
|
+
return gc.fill;
|
|
37883
|
+
}
|
|
37884
|
+
}
|
|
37885
|
+
}
|
|
37886
|
+
}
|
|
37887
|
+
return canvasBg;
|
|
37888
|
+
}
|
|
37889
|
+
function generateWatermarkElements(canvasWidth, canvasHeight, wmColor, options = {}) {
|
|
37890
|
+
const elements = [];
|
|
37891
|
+
const text = options.text ?? getWatermarkText();
|
|
37892
|
+
const fontSize = options.fontSize ?? DEFAULT_WATERMARK_FONT_SIZE;
|
|
37893
|
+
const angle = options.angle ?? DEFAULT_WATERMARK_ANGLE;
|
|
37894
|
+
const opacity = options.opacity ?? DEFAULT_WATERMARK_OPACITY;
|
|
37895
|
+
const estimatedTextWidth = text.length * fontSize * 0.55;
|
|
37896
|
+
const spacingX = Math.max(160, estimatedTextWidth + 30);
|
|
37897
|
+
const spacingY = 90;
|
|
37898
|
+
const startX = -canvasWidth * 0.3;
|
|
37899
|
+
const startY = -canvasHeight * 0.3;
|
|
37900
|
+
const endX = canvasWidth * 1.5;
|
|
37901
|
+
const endY = canvasHeight * 1.5;
|
|
37902
|
+
let idx = 0;
|
|
37903
|
+
for (let y = startY; y < endY; y += spacingY) {
|
|
37904
|
+
for (let x = startX; x < endX; x += spacingX) {
|
|
37905
|
+
elements.push({
|
|
37906
|
+
id: `${WATERMARK_ID_PREFIX}${idx++}`,
|
|
37907
|
+
type: "text",
|
|
37908
|
+
left: x,
|
|
37909
|
+
top: y,
|
|
37910
|
+
width: 200,
|
|
37911
|
+
height: 40,
|
|
37912
|
+
text,
|
|
37913
|
+
fontFamily: "Montserrat",
|
|
37914
|
+
fontSize,
|
|
37915
|
+
fontWeight: "600",
|
|
37916
|
+
fill: wmColor,
|
|
37917
|
+
angle,
|
|
37918
|
+
selectable: false,
|
|
37919
|
+
locked: true,
|
|
37920
|
+
visible: true,
|
|
37921
|
+
opacity,
|
|
37922
|
+
scaleX: 1,
|
|
37923
|
+
scaleY: 1,
|
|
37924
|
+
letterSpacing: 4
|
|
37925
|
+
});
|
|
37926
|
+
}
|
|
37927
|
+
}
|
|
37928
|
+
return elements;
|
|
37929
|
+
}
|
|
37930
|
+
function injectWatermark(config, options = {}) {
|
|
37931
|
+
var _a2, _b2, _c2;
|
|
37932
|
+
const canvasWidth = ((_a2 = config.canvas) == null ? void 0 : _a2.width) || 612;
|
|
37933
|
+
const canvasHeight = ((_b2 = config.canvas) == null ? void 0 : _b2.height) || 792;
|
|
37934
|
+
const canvasBg = (_c2 = config.canvas) == null ? void 0 : _c2.backgroundColor;
|
|
37935
|
+
return {
|
|
37936
|
+
...config,
|
|
37937
|
+
pages: config.pages.map((page) => {
|
|
37938
|
+
const pageBg = getPageBgColor(page, canvasBg);
|
|
37939
|
+
const wmColor = getWatermarkColor(pageBg);
|
|
37940
|
+
const watermarkElements = generateWatermarkElements(canvasWidth, canvasHeight, wmColor, options);
|
|
37941
|
+
return {
|
|
37942
|
+
...page,
|
|
37943
|
+
children: [
|
|
37944
|
+
...page.children || [],
|
|
37945
|
+
...watermarkElements
|
|
37946
|
+
]
|
|
37947
|
+
};
|
|
37948
|
+
})
|
|
37949
|
+
};
|
|
37950
|
+
}
|
|
37951
|
+
const canvasWatermark = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
37952
|
+
__proto__: null,
|
|
37953
|
+
injectWatermark
|
|
37954
|
+
}, Symbol.toStringTag, { value: "Module" }));
|
|
37595
37955
|
function setAutoShrinkDebug(enabled) {
|
|
37596
37956
|
if (typeof window !== "undefined") {
|
|
37597
37957
|
window.__pixldocsDebugAutoShrink = !!enabled;
|
|
37598
37958
|
}
|
|
37599
37959
|
}
|
|
37600
37960
|
export {
|
|
37601
|
-
|
|
37961
|
+
resolveBlurElementExactIdsFromFlatFormKeys as $,
|
|
37602
37962
|
API_URL as A,
|
|
37603
37963
|
collectFontDescriptorsFromConfig as B,
|
|
37604
37964
|
collectFontsFromConfig as C,
|
|
@@ -37619,23 +37979,24 @@ export {
|
|
|
37619
37979
|
hasAnyPreviewBlur as R,
|
|
37620
37980
|
injectPreviewBlur as S,
|
|
37621
37981
|
TRIANGLE_STROKE_MITER_LIMIT as T,
|
|
37622
|
-
|
|
37623
|
-
|
|
37624
|
-
|
|
37625
|
-
|
|
37626
|
-
|
|
37627
|
-
|
|
37628
|
-
|
|
37982
|
+
injectWatermark as U,
|
|
37983
|
+
isBundledAssetUrl as V,
|
|
37984
|
+
isFontAvailable as W,
|
|
37985
|
+
isPrivateUrl as X,
|
|
37986
|
+
listPublishedTemplates as Y,
|
|
37987
|
+
loadGoogleFontCSS as Z,
|
|
37988
|
+
normalizeFontFamily as _,
|
|
37629
37989
|
getAbsoluteBounds as a,
|
|
37630
|
-
|
|
37631
|
-
|
|
37632
|
-
|
|
37633
|
-
|
|
37634
|
-
|
|
37635
|
-
|
|
37636
|
-
|
|
37637
|
-
|
|
37638
|
-
|
|
37990
|
+
resolveFontWeight as a0,
|
|
37991
|
+
resolveForRender as a1,
|
|
37992
|
+
resolveFromForm as a2,
|
|
37993
|
+
resolveTemplateData as a3,
|
|
37994
|
+
rewriteSvgFontsForJsPDF as a4,
|
|
37995
|
+
setAutoShrinkDebug as a5,
|
|
37996
|
+
setBundledAssetPrefixes as a6,
|
|
37997
|
+
warmResolvedTemplateForPreview as a7,
|
|
37998
|
+
warmTemplateFromForm as a8,
|
|
37999
|
+
canvasImageLoader as a9,
|
|
37639
38000
|
getProxiedImageUrl as b,
|
|
37640
38001
|
captureFabricCanvasSvgForPdf as c,
|
|
37641
38002
|
getImageProxyFetchOptions as d,
|
|
@@ -37662,4 +38023,4 @@ export {
|
|
|
37662
38023
|
awaitFontsForConfig as y,
|
|
37663
38024
|
buildTeaserBlurFlatKeys as z
|
|
37664
38025
|
};
|
|
37665
|
-
//# sourceMappingURL=index-
|
|
38026
|
+
//# sourceMappingURL=index-lbU-Xs_t.js.map
|