@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
|
@@ -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;
|
|
@@ -6386,8 +6361,13 @@ async function loadImageAsync(element, placeholder, fc, fabricRef, syncLockedRef
|
|
|
6386
6361
|
});
|
|
6387
6362
|
const imgLoadOptions = url.startsWith("data:") || url.startsWith("blob:") ? {} : { crossOrigin: "anonymous" };
|
|
6388
6363
|
const img = await fabric__namespace.FabricImage.fromURL(url, imgLoadOptions);
|
|
6389
|
-
if (!fabricRef.current) return;
|
|
6364
|
+
if (fabricRef && !fabricRef.current) return;
|
|
6390
6365
|
await normalizeSvgImageDimensions(img, imageUrl, element.sourceFormat);
|
|
6366
|
+
const natW = img.width ?? 0;
|
|
6367
|
+
const natH = img.height ?? 0;
|
|
6368
|
+
if (natW <= 1 && natH <= 1 && Number(element.width) > 8 && Number(element.height) > 8) {
|
|
6369
|
+
throw new Error(`image decoded to ${natW}x${natH} — treating as failed load`);
|
|
6370
|
+
}
|
|
6391
6371
|
const isHidden = !element.visible;
|
|
6392
6372
|
img.set({
|
|
6393
6373
|
originX: "left",
|
|
@@ -6585,9 +6565,111 @@ async function loadImageAsync(element, placeholder, fc, fabricRef, syncLockedRef
|
|
|
6585
6565
|
proxiedUrl: getProxiedImageUrl(imageUrl).slice(0, 240),
|
|
6586
6566
|
error: error instanceof Error ? error.message : String(error)
|
|
6587
6567
|
});
|
|
6568
|
+
if (fc.__pixldocsEditMode === true) {
|
|
6569
|
+
try {
|
|
6570
|
+
markPlaceholderAsBrokenImage(placeholder);
|
|
6571
|
+
fc.requestRenderAll();
|
|
6572
|
+
} catch {
|
|
6573
|
+
}
|
|
6574
|
+
}
|
|
6588
6575
|
return;
|
|
6589
6576
|
}
|
|
6590
6577
|
}
|
|
6578
|
+
function markPlaceholderAsBrokenImage(placeholder) {
|
|
6579
|
+
if (!(placeholder instanceof fabric__namespace.Group)) return;
|
|
6580
|
+
const group = placeholder;
|
|
6581
|
+
if (group.__pixldocsBrokenImage) return;
|
|
6582
|
+
group.__pixldocsBrokenImage = true;
|
|
6583
|
+
const frameChild = group.getObjects().find(
|
|
6584
|
+
(o) => o.__isPlaceholderFrame
|
|
6585
|
+
);
|
|
6586
|
+
const w = Math.max(1, (frameChild == null ? void 0 : frameChild.width) ?? group.width ?? 1);
|
|
6587
|
+
const h = Math.max(1, (frameChild == null ? void 0 : frameChild.height) ?? group.height ?? 1);
|
|
6588
|
+
const center = group.getCenterPoint();
|
|
6589
|
+
const cx = center.x;
|
|
6590
|
+
const cy = center.y;
|
|
6591
|
+
const prevPose = { left: group.left, top: group.top, width: group.width, height: group.height };
|
|
6592
|
+
const bg = new fabric__namespace.Rect({
|
|
6593
|
+
originX: "center",
|
|
6594
|
+
originY: "center",
|
|
6595
|
+
left: cx,
|
|
6596
|
+
top: cy,
|
|
6597
|
+
width: w,
|
|
6598
|
+
height: h,
|
|
6599
|
+
fill: "rgba(148, 163, 184, 0.12)",
|
|
6600
|
+
stroke: "#94A3B8",
|
|
6601
|
+
strokeWidth: 1.5,
|
|
6602
|
+
strokeDashArray: [6, 4]
|
|
6603
|
+
});
|
|
6604
|
+
const s = Math.max(16, Math.min(w, h) * 0.28);
|
|
6605
|
+
const glyphStroke = { stroke: "#64748B", strokeWidth: Math.max(1.5, s / 12), fill: "transparent" };
|
|
6606
|
+
const iconFrame = new fabric__namespace.Rect({
|
|
6607
|
+
originX: "center",
|
|
6608
|
+
originY: "center",
|
|
6609
|
+
left: cx,
|
|
6610
|
+
top: cy,
|
|
6611
|
+
width: s,
|
|
6612
|
+
height: s * 0.8,
|
|
6613
|
+
rx: s * 0.08,
|
|
6614
|
+
ry: s * 0.08,
|
|
6615
|
+
...glyphStroke
|
|
6616
|
+
});
|
|
6617
|
+
const mountain = new fabric__namespace.Polyline(
|
|
6618
|
+
[
|
|
6619
|
+
{ x: -s * 0.38, y: s * 0.24 },
|
|
6620
|
+
{ x: -s * 0.1, y: -s * 0.08 },
|
|
6621
|
+
{ x: s * 0.08, y: s * 0.1 },
|
|
6622
|
+
{ x: s * 0.22, y: -s * 0.02 },
|
|
6623
|
+
{ x: s * 0.38, y: s * 0.24 }
|
|
6624
|
+
],
|
|
6625
|
+
{ originX: "center", originY: "center", left: cx, top: cy + s * 0.08, ...glyphStroke }
|
|
6626
|
+
);
|
|
6627
|
+
const slash = new fabric__namespace.Line([cx - s * 0.55, cy - s * 0.5, cx + s * 0.55, cy + s * 0.5], {
|
|
6628
|
+
...glyphStroke,
|
|
6629
|
+
originX: "center",
|
|
6630
|
+
originY: "center",
|
|
6631
|
+
left: cx,
|
|
6632
|
+
top: cy
|
|
6633
|
+
});
|
|
6634
|
+
for (const obj of [bg, iconFrame, mountain, slash]) {
|
|
6635
|
+
obj.set({ selectable: false, evented: false, excludeFromExport: true });
|
|
6636
|
+
obj.__pixldocsEditorChrome = true;
|
|
6637
|
+
group.add(obj);
|
|
6638
|
+
}
|
|
6639
|
+
group.set(prevPose);
|
|
6640
|
+
group.setCoords();
|
|
6641
|
+
group.dirty = true;
|
|
6642
|
+
}
|
|
6643
|
+
function hideEditorChromeForExport(fc) {
|
|
6644
|
+
const hidden = [];
|
|
6645
|
+
const walk = (objs) => {
|
|
6646
|
+
var _a2;
|
|
6647
|
+
for (const o of objs) {
|
|
6648
|
+
if (o.__pixldocsEditorChrome && o.visible !== false) {
|
|
6649
|
+
o.visible = false;
|
|
6650
|
+
hidden.push(o);
|
|
6651
|
+
}
|
|
6652
|
+
const kids = (_a2 = o.getObjects) == null ? void 0 : _a2.call(o);
|
|
6653
|
+
if (kids == null ? void 0 : kids.length) walk(kids);
|
|
6654
|
+
}
|
|
6655
|
+
};
|
|
6656
|
+
walk(fc.getObjects());
|
|
6657
|
+
if (hidden.length) {
|
|
6658
|
+
for (const o of hidden) {
|
|
6659
|
+
const g = o.group;
|
|
6660
|
+
if (g) g.dirty = true;
|
|
6661
|
+
}
|
|
6662
|
+
fc.renderAll();
|
|
6663
|
+
}
|
|
6664
|
+
return () => {
|
|
6665
|
+
for (const o of hidden) {
|
|
6666
|
+
o.visible = true;
|
|
6667
|
+
const g = o.group;
|
|
6668
|
+
if (g) g.dirty = true;
|
|
6669
|
+
}
|
|
6670
|
+
if (hidden.length) fc.requestRenderAll();
|
|
6671
|
+
};
|
|
6672
|
+
}
|
|
6591
6673
|
const canvasImageLoader = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
6592
6674
|
__proto__: null,
|
|
6593
6675
|
SVG_DECODE_HARD_CAP,
|
|
@@ -6597,12 +6679,14 @@ const canvasImageLoader = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.d
|
|
|
6597
6679
|
fetchSvgTextPublic,
|
|
6598
6680
|
getNormalizedSvgUrl,
|
|
6599
6681
|
getProxiedImageUrl,
|
|
6682
|
+
hideEditorChromeForExport,
|
|
6600
6683
|
isBundledAssetUrl,
|
|
6601
6684
|
isEmptyImagePlaceholderGroup,
|
|
6602
6685
|
isPrivateUrl,
|
|
6603
6686
|
isSvgImage,
|
|
6604
6687
|
loadImageAsync,
|
|
6605
6688
|
loadSvgDimensions,
|
|
6689
|
+
markPlaceholderAsBrokenImage,
|
|
6606
6690
|
normalizeSvgImageDimensions,
|
|
6607
6691
|
parseSvgDimensionsFromText,
|
|
6608
6692
|
preloadImage,
|
|
@@ -18114,6 +18198,7 @@ const PageCanvas = react.forwardRef(
|
|
|
18114
18198
|
// Transparent so underlay (page bg + group bgs) shows through
|
|
18115
18199
|
backgroundColor: "transparent"
|
|
18116
18200
|
});
|
|
18201
|
+
fabricCanvas.__pixldocsEditMode = isEditorMode && !isPreviewMode;
|
|
18117
18202
|
fabricCanvas.hoverCursor = "default";
|
|
18118
18203
|
fabricCanvas.moveCursor = "move";
|
|
18119
18204
|
const suppressTextEditForClick = (textbox) => {
|
|
@@ -25439,6 +25524,7 @@ const PageCanvas = react.forwardRef(
|
|
|
25439
25524
|
} else if (obj instanceof fabric__namespace.Textbox) {
|
|
25440
25525
|
const overflowPolicy = element.overflowPolicy || "grow-and-push";
|
|
25441
25526
|
let text = element.text != null && element.text !== "" ? element.text : " ";
|
|
25527
|
+
text = applyElementTextCase(text, element.textCase);
|
|
25442
25528
|
let parsedStyles = null;
|
|
25443
25529
|
if (element.formattingEnabled === true) {
|
|
25444
25530
|
const parsed = parseTextMarkdown(text);
|
|
@@ -26083,6 +26169,13 @@ const PageCanvas = react.forwardRef(
|
|
|
26083
26169
|
const img = await fabric__namespace.FabricImage.fromURL(url, { crossOrigin: "anonymous" });
|
|
26084
26170
|
if (!fabricRef.current || !isLatestRequest()) return;
|
|
26085
26171
|
await normalizeSvgImageDimensions(img, imageUrl, element.sourceFormat, svgDecodeTarget);
|
|
26172
|
+
{
|
|
26173
|
+
const natW = img.width ?? 0;
|
|
26174
|
+
const natH = img.height ?? 0;
|
|
26175
|
+
if (natW <= 1 && natH <= 1 && Number(element.width) > 8 && Number(element.height) > 8) {
|
|
26176
|
+
throw new Error(`image decoded to ${natW}x${natH} — treating as failed load`);
|
|
26177
|
+
}
|
|
26178
|
+
}
|
|
26086
26179
|
if (!isLatestRequest()) return;
|
|
26087
26180
|
const imageFitForFade = element.imageFit || ((_a2 = element.style) == null ? void 0 : _a2.imageFit) || "cover";
|
|
26088
26181
|
const clipShapeForFade = element.clipShape ?? ((_b2 = element.style) == null ? void 0 : _b2.imageFrameShape) ?? (isPreviewMode ? "rectangle" : "none");
|
|
@@ -26449,6 +26542,19 @@ const PageCanvas = react.forwardRef(
|
|
|
26449
26542
|
}
|
|
26450
26543
|
fc.requestRenderAll();
|
|
26451
26544
|
} catch (error) {
|
|
26545
|
+
console.error("[PageCanvas] image failed to load", {
|
|
26546
|
+
id: element.id,
|
|
26547
|
+
url: (element.src || element.imageUrl || "").slice(0, 200),
|
|
26548
|
+
error: error instanceof Error ? error.message : String(error)
|
|
26549
|
+
});
|
|
26550
|
+
const fcNow = fabricRef.current;
|
|
26551
|
+
if (fcNow && fcNow.__pixldocsEditMode === true) {
|
|
26552
|
+
try {
|
|
26553
|
+
markPlaceholderAsBrokenImage(placeholder);
|
|
26554
|
+
fcNow.requestRenderAll();
|
|
26555
|
+
} catch {
|
|
26556
|
+
}
|
|
26557
|
+
}
|
|
26452
26558
|
}
|
|
26453
26559
|
};
|
|
26454
26560
|
const handleCanvasClick = react.useCallback(
|
|
@@ -34119,6 +34225,14 @@ function captureFabricCanvasSvgForPdf(fabricInstance, canvasWidth, canvasHeight)
|
|
|
34119
34225
|
try {
|
|
34120
34226
|
const visit = (obj) => {
|
|
34121
34227
|
if (!obj) return;
|
|
34228
|
+
if (obj.__pixldocsEditorChrome) {
|
|
34229
|
+
const originalToSVG = typeof obj.toSVG === "function" ? obj.toSVG.bind(obj) : null;
|
|
34230
|
+
if (originalToSVG) {
|
|
34231
|
+
obj.toSVG = () => "";
|
|
34232
|
+
svgPatchRecords.push({ obj, originalToSVG });
|
|
34233
|
+
}
|
|
34234
|
+
return;
|
|
34235
|
+
}
|
|
34122
34236
|
const imageId = typeof obj.__docuforgeId === "string" && hasRenderableRasterCandidate(obj) ? obj.__docuforgeId : "";
|
|
34123
34237
|
const alphaGradient = objectNeedsAlphaGradientRaster(obj);
|
|
34124
34238
|
if ((isTextboxLike(obj) || imageId || alphaGradient) && typeof obj.toSVG === "function") {
|
|
@@ -34226,9 +34340,9 @@ function captureFabricCanvasSvgForPdf(fabricInstance, canvasWidth, canvasHeight)
|
|
|
34226
34340
|
}
|
|
34227
34341
|
return svgString;
|
|
34228
34342
|
}
|
|
34229
|
-
const resolvedPackageVersion = "0.5.
|
|
34343
|
+
const resolvedPackageVersion = "0.5.497";
|
|
34230
34344
|
const PACKAGE_VERSION = resolvedPackageVersion;
|
|
34231
|
-
const DEPLOYMENT_VERSION_MARKER = "__PIXLDOCS_CANVAS_RENDERER_VERSION__:0.5.
|
|
34345
|
+
const DEPLOYMENT_VERSION_MARKER = "__PIXLDOCS_CANVAS_RENDERER_VERSION__:0.5.497";
|
|
34232
34346
|
const roundParityValue = (value) => {
|
|
34233
34347
|
if (typeof value !== "number") return value;
|
|
34234
34348
|
return Number.isFinite(value) ? Number(value.toFixed(3)) : value;
|
|
@@ -34667,6 +34781,11 @@ class PixldocsRenderer {
|
|
|
34667
34781
|
* Mounts a hidden PreviewCanvas component and captures the Fabric canvas output.
|
|
34668
34782
|
*/
|
|
34669
34783
|
async render(templateConfig, options = {}) {
|
|
34784
|
+
if (options.watermark === true && !templateConfig.__pixldocsWatermarked) {
|
|
34785
|
+
const { injectWatermark: injectWatermark2 } = await Promise.resolve().then(() => canvasWatermark);
|
|
34786
|
+
templateConfig = injectWatermark2(templateConfig, options.watermarkOptions);
|
|
34787
|
+
templateConfig.__pixldocsWatermarked = true;
|
|
34788
|
+
}
|
|
34670
34789
|
const pageIndex = options.pageIndex ?? 0;
|
|
34671
34790
|
const format = options.format ?? "png";
|
|
34672
34791
|
const quality = options.quality ?? 0.92;
|
|
@@ -34682,6 +34801,7 @@ class PixldocsRenderer {
|
|
|
34682
34801
|
const hasAutoShrink = configHasAutoShrinkText(templateConfig);
|
|
34683
34802
|
const defaultWait = hasAutoShrink ? 4e3 : 1800;
|
|
34684
34803
|
await this.awaitFontsForConfig(templateConfig, options.waitForFontsMs ?? defaultWait);
|
|
34804
|
+
this.flushTextMeasurementCaches();
|
|
34685
34805
|
}
|
|
34686
34806
|
const { setPackageApiUrl: setPackageApiUrl2 } = await Promise.resolve().then(() => appApi);
|
|
34687
34807
|
setPackageApiUrl2(this.config.imageProxyUrl);
|
|
@@ -34709,6 +34829,7 @@ class PixldocsRenderer {
|
|
|
34709
34829
|
const hasAutoShrink = configHasAutoShrinkText(templateConfig);
|
|
34710
34830
|
const defaultWait = hasAutoShrink ? 4e3 : 1800;
|
|
34711
34831
|
await this.awaitFontsForConfig(templateConfig, options.waitForFontsMs ?? defaultWait);
|
|
34832
|
+
this.flushTextMeasurementCaches();
|
|
34712
34833
|
}
|
|
34713
34834
|
const results = [];
|
|
34714
34835
|
for (let i = 0; i < templateConfig.pages.length; i++) {
|
|
@@ -34735,8 +34856,8 @@ class PixldocsRenderer {
|
|
|
34735
34856
|
const shouldWatermark = watermark ?? resolved.price > 0;
|
|
34736
34857
|
let configToRender = resolved.config;
|
|
34737
34858
|
if (shouldWatermark) {
|
|
34738
|
-
const { injectWatermark } = await Promise.resolve().then(() =>
|
|
34739
|
-
configToRender =
|
|
34859
|
+
const { injectWatermark: injectWatermark2 } = await Promise.resolve().then(() => canvasWatermark);
|
|
34860
|
+
configToRender = injectWatermark2(configToRender, watermarkOptions);
|
|
34740
34861
|
const { injectPreviewBlur: injectPreviewBlur2 } = await Promise.resolve().then(() => previewBlur);
|
|
34741
34862
|
configToRender = injectPreviewBlur2(configToRender);
|
|
34742
34863
|
}
|
|
@@ -34795,8 +34916,8 @@ class PixldocsRenderer {
|
|
|
34795
34916
|
const shouldWatermark = watermark ?? resolved.price > 0;
|
|
34796
34917
|
let configToRender = resolved.config;
|
|
34797
34918
|
if (shouldWatermark) {
|
|
34798
|
-
const { injectWatermark } = await Promise.resolve().then(() =>
|
|
34799
|
-
configToRender =
|
|
34919
|
+
const { injectWatermark: injectWatermark2 } = await Promise.resolve().then(() => canvasWatermark);
|
|
34920
|
+
configToRender = injectWatermark2(configToRender, watermarkOptions);
|
|
34800
34921
|
const { injectPreviewBlur: injectPreviewBlur2 } = await Promise.resolve().then(() => previewBlur);
|
|
34801
34922
|
configToRender = injectPreviewBlur2(configToRender);
|
|
34802
34923
|
}
|
|
@@ -34816,6 +34937,10 @@ class PixldocsRenderer {
|
|
|
34816
34937
|
* exporter, which is what `renderPdfViaClientExport` does below.
|
|
34817
34938
|
*/
|
|
34818
34939
|
async renderPdf(templateConfig, options) {
|
|
34940
|
+
if ((options == null ? void 0 : options.watermark) === true) {
|
|
34941
|
+
const { injectWatermark: injectWatermark2 } = await Promise.resolve().then(() => canvasWatermark);
|
|
34942
|
+
templateConfig = injectWatermark2(templateConfig, options.watermarkOptions);
|
|
34943
|
+
}
|
|
34819
34944
|
return this.renderPdfViaClientExport(templateConfig, {
|
|
34820
34945
|
title: options == null ? void 0 : options.title,
|
|
34821
34946
|
textMode: options == null ? void 0 : options.textMode,
|
|
@@ -34844,8 +34969,8 @@ class PixldocsRenderer {
|
|
|
34844
34969
|
const shouldWatermark = watermark ?? resolved.price > 0;
|
|
34845
34970
|
let configToRender = resolved.config;
|
|
34846
34971
|
if (shouldWatermark) {
|
|
34847
|
-
const { injectWatermark } = await Promise.resolve().then(() =>
|
|
34848
|
-
configToRender =
|
|
34972
|
+
const { injectWatermark: injectWatermark2 } = await Promise.resolve().then(() => canvasWatermark);
|
|
34973
|
+
configToRender = injectWatermark2(configToRender, watermarkOptions);
|
|
34849
34974
|
const { injectPreviewBlur: injectPreviewBlur2 } = await Promise.resolve().then(() => previewBlur);
|
|
34850
34975
|
configToRender = injectPreviewBlur2(configToRender);
|
|
34851
34976
|
}
|
|
@@ -35042,7 +35167,7 @@ class PixldocsRenderer {
|
|
|
35042
35167
|
await this.waitForCanvasScene(container, cloned, i);
|
|
35043
35168
|
}
|
|
35044
35169
|
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-
|
|
35170
|
+
const { exportMultiPagePdf, preparePagesForExport } = await Promise.resolve().then(() => require("./vectorPdfExport-De8UFmDy.cjs"));
|
|
35046
35171
|
const prepared = preparePagesForExport(
|
|
35047
35172
|
cloned.pages,
|
|
35048
35173
|
canvasWidth,
|
|
@@ -35320,6 +35445,37 @@ class PixldocsRenderer {
|
|
|
35320
35445
|
new Promise((r) => setTimeout(r, Math.min(500, maxWaitMs)))
|
|
35321
35446
|
]);
|
|
35322
35447
|
}
|
|
35448
|
+
/**
|
|
35449
|
+
* Flush BOTH process-global text-measurement caches after fonts are ready
|
|
35450
|
+
* and BEFORE the capture canvas mounts.
|
|
35451
|
+
*
|
|
35452
|
+
* Why: anything that measured text before the webfonts finished loading —
|
|
35453
|
+
* most notably `applyContentBoundsPagination` running inside
|
|
35454
|
+
* `resolveFromForm` on a cold page (the EC2/MCP flow: resolve + render in
|
|
35455
|
+
* one browser context) — populates the app measurement cache and Fabric's
|
|
35456
|
+
* global char-width cache with FALLBACK metrics. `createText` then places
|
|
35457
|
+
* center/right-aligned lines from those stale widths, so a right-aligned
|
|
35458
|
+
* grid cell on a continuation page drew shifted left by
|
|
35459
|
+
* (fallbackWidth − realWidth) px vs the editor (caught by
|
|
35460
|
+
* tests/parity `auto-paginate`, a 9px shift). The later
|
|
35461
|
+
* `waitForStableTextMetrics` pass re-primes glyph bounds but never moves
|
|
35462
|
+
* the already-positioned box, so the flush must happen pre-mount.
|
|
35463
|
+
*
|
|
35464
|
+
* Only called from the headless PNG paths (`render`/`renderAllPages`),
|
|
35465
|
+
* which already default to clearing the global char cache in
|
|
35466
|
+
* `waitForStableTextMetrics` — the live-preview-adjacent PDF path keeps
|
|
35467
|
+
* its `clearGlobalCharCache: false` behaviour untouched.
|
|
35468
|
+
*/
|
|
35469
|
+
flushTextMeasurementCaches() {
|
|
35470
|
+
try {
|
|
35471
|
+
clearMeasurementCache();
|
|
35472
|
+
} catch {
|
|
35473
|
+
}
|
|
35474
|
+
try {
|
|
35475
|
+
clearFabricCharCache();
|
|
35476
|
+
} catch {
|
|
35477
|
+
}
|
|
35478
|
+
}
|
|
35323
35479
|
getNormalizedGradientStops(gradient) {
|
|
35324
35480
|
const stops = Array.isArray(gradient == null ? void 0 : gradient.stops) ? gradient.stops.map((stop) => ({
|
|
35325
35481
|
offset: Math.max(0, Math.min(1, Number((stop == null ? void 0 : stop.offset) ?? 0))),
|
|
@@ -37362,7 +37518,7 @@ async function prepareLiveCanvasSvgForPdf(rawSvg, pageWidth, pageHeight, pageKey
|
|
|
37362
37518
|
if (options == null ? void 0 : options.stripPageBackground) stripRootPageBackgroundFromSvg(svgToDraw);
|
|
37363
37519
|
sanitizeSvgTreeForPdf(svgToDraw);
|
|
37364
37520
|
try {
|
|
37365
|
-
const { bakeTextAnchorPositionsFromLiveSvg, logTextMeasurementDiagnostic } = await Promise.resolve().then(() => require("./vectorPdfExport-
|
|
37521
|
+
const { bakeTextAnchorPositionsFromLiveSvg, logTextMeasurementDiagnostic } = await Promise.resolve().then(() => require("./vectorPdfExport-De8UFmDy.cjs"));
|
|
37366
37522
|
try {
|
|
37367
37523
|
await logTextMeasurementDiagnostic(svgToDraw);
|
|
37368
37524
|
} catch {
|
|
@@ -37610,6 +37766,129 @@ async function getPublishedTemplate(options) {
|
|
|
37610
37766
|
const rows = await res.json();
|
|
37611
37767
|
return rows[0] ?? null;
|
|
37612
37768
|
}
|
|
37769
|
+
const WATERMARK_ID_PREFIX = "__wm_";
|
|
37770
|
+
const DEFAULT_WATERMARK_OPACITY = 0.14;
|
|
37771
|
+
const DEFAULT_WATERMARK_FONT_SIZE = 18;
|
|
37772
|
+
const DEFAULT_WATERMARK_ANGLE = -30;
|
|
37773
|
+
function getWatermarkText() {
|
|
37774
|
+
try {
|
|
37775
|
+
const host = window.location.hostname;
|
|
37776
|
+
if (host.includes("biomaker")) return "biomaker.app";
|
|
37777
|
+
} catch {
|
|
37778
|
+
}
|
|
37779
|
+
return "pixldocs.com";
|
|
37780
|
+
}
|
|
37781
|
+
function getLuminance(color) {
|
|
37782
|
+
if (!color || color === "transparent" || color === "none") return 1;
|
|
37783
|
+
let r = 255, g = 255, b = 255;
|
|
37784
|
+
if (color.startsWith("#")) {
|
|
37785
|
+
const hex = color.slice(1);
|
|
37786
|
+
const full = hex.length === 3 ? hex.split("").map((c) => c + c).join("") : hex;
|
|
37787
|
+
const n = parseInt(full, 16);
|
|
37788
|
+
r = n >> 16 & 255;
|
|
37789
|
+
g = n >> 8 & 255;
|
|
37790
|
+
b = n & 255;
|
|
37791
|
+
} else {
|
|
37792
|
+
const m = color.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/);
|
|
37793
|
+
if (m) {
|
|
37794
|
+
r = +m[1];
|
|
37795
|
+
g = +m[2];
|
|
37796
|
+
b = +m[3];
|
|
37797
|
+
}
|
|
37798
|
+
}
|
|
37799
|
+
return (0.299 * r + 0.587 * g + 0.114 * b) / 255;
|
|
37800
|
+
}
|
|
37801
|
+
function getWatermarkColor(bgColor) {
|
|
37802
|
+
const lum = getLuminance(bgColor);
|
|
37803
|
+
return lum < 0.45 ? "#cccccc" : "#808080";
|
|
37804
|
+
}
|
|
37805
|
+
function getPageBgColor(page, canvasBg) {
|
|
37806
|
+
var _a2, _b2;
|
|
37807
|
+
const settingsBg = (_a2 = page.settings) == null ? void 0 : _a2.backgroundColor;
|
|
37808
|
+
if (settingsBg && settingsBg !== "transparent" && settingsBg !== "none") {
|
|
37809
|
+
return settingsBg;
|
|
37810
|
+
}
|
|
37811
|
+
const children = page.children || [];
|
|
37812
|
+
for (const child of children) {
|
|
37813
|
+
if (child.type === "shape" && child.fill && child.fill !== "transparent" && child.fill !== "none") {
|
|
37814
|
+
return child.fill;
|
|
37815
|
+
}
|
|
37816
|
+
if ((_b2 = child.children) == null ? void 0 : _b2.length) {
|
|
37817
|
+
for (const gc of child.children) {
|
|
37818
|
+
if (gc.type === "shape" && gc.fill && gc.fill !== "transparent" && gc.fill !== "none") {
|
|
37819
|
+
return gc.fill;
|
|
37820
|
+
}
|
|
37821
|
+
}
|
|
37822
|
+
}
|
|
37823
|
+
}
|
|
37824
|
+
return canvasBg;
|
|
37825
|
+
}
|
|
37826
|
+
function generateWatermarkElements(canvasWidth, canvasHeight, wmColor, options = {}) {
|
|
37827
|
+
const elements = [];
|
|
37828
|
+
const text = options.text ?? getWatermarkText();
|
|
37829
|
+
const fontSize = options.fontSize ?? DEFAULT_WATERMARK_FONT_SIZE;
|
|
37830
|
+
const angle = options.angle ?? DEFAULT_WATERMARK_ANGLE;
|
|
37831
|
+
const opacity = options.opacity ?? DEFAULT_WATERMARK_OPACITY;
|
|
37832
|
+
const estimatedTextWidth = text.length * fontSize * 0.55;
|
|
37833
|
+
const spacingX = Math.max(160, estimatedTextWidth + 30);
|
|
37834
|
+
const spacingY = 90;
|
|
37835
|
+
const startX = -canvasWidth * 0.3;
|
|
37836
|
+
const startY = -canvasHeight * 0.3;
|
|
37837
|
+
const endX = canvasWidth * 1.5;
|
|
37838
|
+
const endY = canvasHeight * 1.5;
|
|
37839
|
+
let idx = 0;
|
|
37840
|
+
for (let y = startY; y < endY; y += spacingY) {
|
|
37841
|
+
for (let x = startX; x < endX; x += spacingX) {
|
|
37842
|
+
elements.push({
|
|
37843
|
+
id: `${WATERMARK_ID_PREFIX}${idx++}`,
|
|
37844
|
+
type: "text",
|
|
37845
|
+
left: x,
|
|
37846
|
+
top: y,
|
|
37847
|
+
width: 200,
|
|
37848
|
+
height: 40,
|
|
37849
|
+
text,
|
|
37850
|
+
fontFamily: "Montserrat",
|
|
37851
|
+
fontSize,
|
|
37852
|
+
fontWeight: "600",
|
|
37853
|
+
fill: wmColor,
|
|
37854
|
+
angle,
|
|
37855
|
+
selectable: false,
|
|
37856
|
+
locked: true,
|
|
37857
|
+
visible: true,
|
|
37858
|
+
opacity,
|
|
37859
|
+
scaleX: 1,
|
|
37860
|
+
scaleY: 1,
|
|
37861
|
+
letterSpacing: 4
|
|
37862
|
+
});
|
|
37863
|
+
}
|
|
37864
|
+
}
|
|
37865
|
+
return elements;
|
|
37866
|
+
}
|
|
37867
|
+
function injectWatermark(config, options = {}) {
|
|
37868
|
+
var _a2, _b2, _c2;
|
|
37869
|
+
const canvasWidth = ((_a2 = config.canvas) == null ? void 0 : _a2.width) || 612;
|
|
37870
|
+
const canvasHeight = ((_b2 = config.canvas) == null ? void 0 : _b2.height) || 792;
|
|
37871
|
+
const canvasBg = (_c2 = config.canvas) == null ? void 0 : _c2.backgroundColor;
|
|
37872
|
+
return {
|
|
37873
|
+
...config,
|
|
37874
|
+
pages: config.pages.map((page) => {
|
|
37875
|
+
const pageBg = getPageBgColor(page, canvasBg);
|
|
37876
|
+
const wmColor = getWatermarkColor(pageBg);
|
|
37877
|
+
const watermarkElements = generateWatermarkElements(canvasWidth, canvasHeight, wmColor, options);
|
|
37878
|
+
return {
|
|
37879
|
+
...page,
|
|
37880
|
+
children: [
|
|
37881
|
+
...page.children || [],
|
|
37882
|
+
...watermarkElements
|
|
37883
|
+
]
|
|
37884
|
+
};
|
|
37885
|
+
})
|
|
37886
|
+
};
|
|
37887
|
+
}
|
|
37888
|
+
const canvasWatermark = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
37889
|
+
__proto__: null,
|
|
37890
|
+
injectWatermark
|
|
37891
|
+
}, Symbol.toStringTag, { value: "Module" }));
|
|
37613
37892
|
function setAutoShrinkDebug(enabled) {
|
|
37614
37893
|
if (typeof window !== "undefined") {
|
|
37615
37894
|
window.__pixldocsDebugAutoShrink = !!enabled;
|
|
@@ -37656,6 +37935,7 @@ exports.getWorldAngleDeg = getWorldAngleDeg$1;
|
|
|
37656
37935
|
exports.hasAnyPreviewBlur = hasAnyPreviewBlur;
|
|
37657
37936
|
exports.hasEdgeFade = hasEdgeFade;
|
|
37658
37937
|
exports.injectPreviewBlur = injectPreviewBlur;
|
|
37938
|
+
exports.injectWatermark = injectWatermark;
|
|
37659
37939
|
exports.isBundledAssetUrl = isBundledAssetUrl;
|
|
37660
37940
|
exports.isElement = isElement;
|
|
37661
37941
|
exports.isFontAvailable = isFontAvailable;
|
|
@@ -37677,4 +37957,4 @@ exports.setAutoShrinkDebug = setAutoShrinkDebug;
|
|
|
37677
37957
|
exports.setBundledAssetPrefixes = setBundledAssetPrefixes;
|
|
37678
37958
|
exports.warmResolvedTemplateForPreview = warmResolvedTemplateForPreview;
|
|
37679
37959
|
exports.warmTemplateFromForm = warmTemplateFromForm;
|
|
37680
|
-
//# sourceMappingURL=index-
|
|
37960
|
+
//# sourceMappingURL=index-CZm1oVfa.cjs.map
|