@pixldocs/canvas-renderer 0.5.39 → 0.5.41
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/{canvasWatermark-DAZIQ_IR.cjs → canvasWatermark-B0ab38Ok.cjs} +12 -8
- package/dist/canvasWatermark-B0ab38Ok.cjs.map +1 -0
- package/dist/{canvasWatermark-CM85x4k7.js → canvasWatermark-pkhacGge.js} +12 -8
- package/dist/canvasWatermark-pkhacGge.js.map +1 -0
- package/dist/index.cjs +34 -20
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +13 -1
- package/dist/index.js +34 -20
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/canvasWatermark-CM85x4k7.js.map +0 -1
- package/dist/canvasWatermark-DAZIQ_IR.cjs.map +0 -1
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
3
|
const WATERMARK_ID_PREFIX = "__wm_";
|
|
4
|
+
const DEFAULT_WATERMARK_OPACITY = 0.14;
|
|
5
|
+
const DEFAULT_WATERMARK_FONT_SIZE = 18;
|
|
6
|
+
const DEFAULT_WATERMARK_ANGLE = -30;
|
|
4
7
|
function getWatermarkText() {
|
|
5
8
|
try {
|
|
6
9
|
const host = window.location.hostname;
|
|
@@ -54,11 +57,12 @@ function getPageBgColor(page, canvasBg) {
|
|
|
54
57
|
}
|
|
55
58
|
return canvasBg;
|
|
56
59
|
}
|
|
57
|
-
function generateWatermarkElements(canvasWidth, canvasHeight, wmColor) {
|
|
60
|
+
function generateWatermarkElements(canvasWidth, canvasHeight, wmColor, options = {}) {
|
|
58
61
|
const elements = [];
|
|
59
|
-
const text = getWatermarkText();
|
|
60
|
-
const fontSize =
|
|
61
|
-
const angle =
|
|
62
|
+
const text = options.text ?? getWatermarkText();
|
|
63
|
+
const fontSize = options.fontSize ?? DEFAULT_WATERMARK_FONT_SIZE;
|
|
64
|
+
const angle = options.angle ?? DEFAULT_WATERMARK_ANGLE;
|
|
65
|
+
const opacity = options.opacity ?? DEFAULT_WATERMARK_OPACITY;
|
|
62
66
|
const estimatedTextWidth = text.length * fontSize * 0.55;
|
|
63
67
|
const spacingX = Math.max(160, estimatedTextWidth + 30);
|
|
64
68
|
const spacingY = 90;
|
|
@@ -85,7 +89,7 @@ function generateWatermarkElements(canvasWidth, canvasHeight, wmColor) {
|
|
|
85
89
|
selectable: false,
|
|
86
90
|
locked: true,
|
|
87
91
|
visible: true,
|
|
88
|
-
opacity
|
|
92
|
+
opacity,
|
|
89
93
|
scaleX: 1,
|
|
90
94
|
scaleY: 1,
|
|
91
95
|
letterSpacing: 4
|
|
@@ -94,7 +98,7 @@ function generateWatermarkElements(canvasWidth, canvasHeight, wmColor) {
|
|
|
94
98
|
}
|
|
95
99
|
return elements;
|
|
96
100
|
}
|
|
97
|
-
function injectWatermark(config) {
|
|
101
|
+
function injectWatermark(config, options = {}) {
|
|
98
102
|
var _a, _b, _c;
|
|
99
103
|
const canvasWidth = ((_a = config.canvas) == null ? void 0 : _a.width) || 612;
|
|
100
104
|
const canvasHeight = ((_b = config.canvas) == null ? void 0 : _b.height) || 792;
|
|
@@ -104,7 +108,7 @@ function injectWatermark(config) {
|
|
|
104
108
|
pages: config.pages.map((page) => {
|
|
105
109
|
const pageBg = getPageBgColor(page, canvasBg);
|
|
106
110
|
const wmColor = getWatermarkColor(pageBg);
|
|
107
|
-
const watermarkElements = generateWatermarkElements(canvasWidth, canvasHeight, wmColor);
|
|
111
|
+
const watermarkElements = generateWatermarkElements(canvasWidth, canvasHeight, wmColor, options);
|
|
108
112
|
return {
|
|
109
113
|
...page,
|
|
110
114
|
children: [
|
|
@@ -116,4 +120,4 @@ function injectWatermark(config) {
|
|
|
116
120
|
};
|
|
117
121
|
}
|
|
118
122
|
exports.injectWatermark = injectWatermark;
|
|
119
|
-
//# sourceMappingURL=canvasWatermark-
|
|
123
|
+
//# sourceMappingURL=canvasWatermark-B0ab38Ok.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"canvasWatermark-B0ab38Ok.cjs","sources":["../../../src/lib/canvasWatermark.ts"],"sourcesContent":["/**\n * Injects diagonal \"PixlDocs\" watermark text elements into a TemplateConfig's pages.\n * The watermark elements are rendered as actual canvas text objects,\n * making them impossible to remove via browser inspect.\n */\n\nimport type { TemplateConfig, CanvasElement } from '@/types/editor';\n\nconst WATERMARK_ID_PREFIX = '__wm_';\n\n/** Optional overrides for watermark appearance. */\nexport interface WatermarkOptions {\n /** Override the watermark text. Defaults to domain-based ('pixldocs.com' / 'biomaker.app'). */\n text?: string;\n /** Opacity 0–1. Default: 0.14 */\n opacity?: number;\n /** Font size in px. Default: 18 */\n fontSize?: number;\n /** Rotation angle in degrees. Default: -30 */\n angle?: number;\n}\n\nconst DEFAULT_WATERMARK_OPACITY = 0.14;\nconst DEFAULT_WATERMARK_FONT_SIZE = 18;\nconst DEFAULT_WATERMARK_ANGLE = -30;\n\n/** Determine watermark text based on current domain */\nfunction getWatermarkText(): string {\n try {\n const host = window.location.hostname;\n if (host.includes('biomaker')) return 'biomaker.app';\n } catch {}\n return 'pixldocs.com';\n}\n\n/** Parse a hex/rgb color to luminance (0=black, 1=white) */\nfunction getLuminance(color: string | undefined): number {\n if (!color || color === 'transparent' || color === 'none') return 1; // assume light\n let r = 255, g = 255, b = 255;\n if (color.startsWith('#')) {\n const hex = color.slice(1);\n const full = hex.length === 3 ? hex.split('').map(c => c + c).join('') : hex;\n const n = parseInt(full, 16);\n r = (n >> 16) & 255;\n g = (n >> 8) & 255;\n b = n & 255;\n } else {\n const m = color.match(/rgba?\\((\\d+),\\s*(\\d+),\\s*(\\d+)/);\n if (m) { r = +m[1]; g = +m[2]; b = +m[3]; }\n }\n return (0.299 * r + 0.587 * g + 0.114 * b) / 255;\n}\n\n/** Pick watermark color that contrasts with page background */\nfunction getWatermarkColor(bgColor: string | undefined): string {\n const lum = getLuminance(bgColor);\n // Dark bg → light watermark, Light bg → dark watermark\n return lum < 0.45 ? '#cccccc' : '#808080';\n}\n\n/** Find the dominant background color of a page */\nfunction getPageBgColor(page: { children?: any[]; settings?: { backgroundColor?: string } }, canvasBg?: string): string | undefined {\n // 1. Check page-level settings (theme-applied bg lives here)\n const settingsBg = page.settings?.backgroundColor;\n if (settingsBg && settingsBg !== 'transparent' && settingsBg !== 'none') {\n return settingsBg;\n }\n // 2. Check first background shape fill\n const children = page.children || [];\n for (const child of children) {\n if (child.type === 'shape' && child.fill && child.fill !== 'transparent' && child.fill !== 'none') {\n return child.fill;\n }\n // Check inside groups (background groups)\n if (child.children?.length) {\n for (const gc of child.children) {\n if (gc.type === 'shape' && gc.fill && gc.fill !== 'transparent' && gc.fill !== 'none') {\n return gc.fill;\n }\n }\n }\n }\n return canvasBg;\n}\n\n/** Generate watermark text elements for a given canvas size */\nfunction generateWatermarkElements(\n canvasWidth: number,\n canvasHeight: number,\n wmColor: string,\n options: WatermarkOptions = {},\n): CanvasElement[] {\n const elements: CanvasElement[] = [];\n const text = options.text ?? getWatermarkText();\n const fontSize = options.fontSize ?? DEFAULT_WATERMARK_FONT_SIZE;\n const angle = options.angle ?? DEFAULT_WATERMARK_ANGLE;\n const opacity = options.opacity ?? DEFAULT_WATERMARK_OPACITY;\n // Adjust spacing based on text length to prevent overlap\n const estimatedTextWidth = text.length * fontSize * 0.55;\n const spacingX = Math.max(160, estimatedTextWidth + 30);\n const spacingY = 90;\n\n const startX = -canvasWidth * 0.3;\n const startY = -canvasHeight * 0.3;\n const endX = canvasWidth * 1.5;\n const endY = canvasHeight * 1.5;\n\n let idx = 0;\n for (let y = startY; y < endY; y += spacingY) {\n for (let x = startX; x < endX; x += spacingX) {\n elements.push({\n id: `${WATERMARK_ID_PREFIX}${idx++}`,\n type: 'text',\n left: x,\n top: y,\n width: 200,\n height: 40,\n text,\n fontFamily: 'Montserrat',\n fontSize,\n fontWeight: '600',\n fill: wmColor,\n angle,\n selectable: false,\n locked: true,\n visible: true,\n opacity,\n scaleX: 1,\n scaleY: 1,\n letterSpacing: 4,\n } as CanvasElement);\n }\n }\n return elements;\n}\n\n/**\n * Returns a new config with watermark elements injected into every page.\n * The original config is NOT mutated.\n */\nexport function injectWatermark(\n config: TemplateConfig,\n options: WatermarkOptions = {},\n): TemplateConfig {\n const canvasWidth = config.canvas?.width || 612;\n const canvasHeight = config.canvas?.height || 792;\n const canvasBg = (config.canvas as any)?.backgroundColor;\n\n return {\n ...config,\n pages: config.pages.map((page) => {\n const pageBg = getPageBgColor(page as any, canvasBg);\n const wmColor = getWatermarkColor(pageBg);\n const watermarkElements = generateWatermarkElements(canvasWidth, canvasHeight, wmColor, options);\n return {\n ...page,\n children: [\n ...(page.children || []),\n ...watermarkElements,\n ],\n };\n }),\n };\n}\n\n/** Check if an element ID is a watermark element */\nexport function isWatermarkElement(id: string): boolean {\n return id.startsWith(WATERMARK_ID_PREFIX);\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
const WATERMARK_ID_PREFIX = "__wm_";
|
|
2
|
+
const DEFAULT_WATERMARK_OPACITY = 0.14;
|
|
3
|
+
const DEFAULT_WATERMARK_FONT_SIZE = 18;
|
|
4
|
+
const DEFAULT_WATERMARK_ANGLE = -30;
|
|
2
5
|
function getWatermarkText() {
|
|
3
6
|
try {
|
|
4
7
|
const host = window.location.hostname;
|
|
@@ -52,11 +55,12 @@ function getPageBgColor(page, canvasBg) {
|
|
|
52
55
|
}
|
|
53
56
|
return canvasBg;
|
|
54
57
|
}
|
|
55
|
-
function generateWatermarkElements(canvasWidth, canvasHeight, wmColor) {
|
|
58
|
+
function generateWatermarkElements(canvasWidth, canvasHeight, wmColor, options = {}) {
|
|
56
59
|
const elements = [];
|
|
57
|
-
const text = getWatermarkText();
|
|
58
|
-
const fontSize =
|
|
59
|
-
const angle =
|
|
60
|
+
const text = options.text ?? getWatermarkText();
|
|
61
|
+
const fontSize = options.fontSize ?? DEFAULT_WATERMARK_FONT_SIZE;
|
|
62
|
+
const angle = options.angle ?? DEFAULT_WATERMARK_ANGLE;
|
|
63
|
+
const opacity = options.opacity ?? DEFAULT_WATERMARK_OPACITY;
|
|
60
64
|
const estimatedTextWidth = text.length * fontSize * 0.55;
|
|
61
65
|
const spacingX = Math.max(160, estimatedTextWidth + 30);
|
|
62
66
|
const spacingY = 90;
|
|
@@ -83,7 +87,7 @@ function generateWatermarkElements(canvasWidth, canvasHeight, wmColor) {
|
|
|
83
87
|
selectable: false,
|
|
84
88
|
locked: true,
|
|
85
89
|
visible: true,
|
|
86
|
-
opacity
|
|
90
|
+
opacity,
|
|
87
91
|
scaleX: 1,
|
|
88
92
|
scaleY: 1,
|
|
89
93
|
letterSpacing: 4
|
|
@@ -92,7 +96,7 @@ function generateWatermarkElements(canvasWidth, canvasHeight, wmColor) {
|
|
|
92
96
|
}
|
|
93
97
|
return elements;
|
|
94
98
|
}
|
|
95
|
-
function injectWatermark(config) {
|
|
99
|
+
function injectWatermark(config, options = {}) {
|
|
96
100
|
var _a, _b, _c;
|
|
97
101
|
const canvasWidth = ((_a = config.canvas) == null ? void 0 : _a.width) || 612;
|
|
98
102
|
const canvasHeight = ((_b = config.canvas) == null ? void 0 : _b.height) || 792;
|
|
@@ -102,7 +106,7 @@ function injectWatermark(config) {
|
|
|
102
106
|
pages: config.pages.map((page) => {
|
|
103
107
|
const pageBg = getPageBgColor(page, canvasBg);
|
|
104
108
|
const wmColor = getWatermarkColor(pageBg);
|
|
105
|
-
const watermarkElements = generateWatermarkElements(canvasWidth, canvasHeight, wmColor);
|
|
109
|
+
const watermarkElements = generateWatermarkElements(canvasWidth, canvasHeight, wmColor, options);
|
|
106
110
|
return {
|
|
107
111
|
...page,
|
|
108
112
|
children: [
|
|
@@ -116,4 +120,4 @@ function injectWatermark(config) {
|
|
|
116
120
|
export {
|
|
117
121
|
injectWatermark
|
|
118
122
|
};
|
|
119
|
-
//# sourceMappingURL=canvasWatermark-
|
|
123
|
+
//# sourceMappingURL=canvasWatermark-pkhacGge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"canvasWatermark-pkhacGge.js","sources":["../../../src/lib/canvasWatermark.ts"],"sourcesContent":["/**\n * Injects diagonal \"PixlDocs\" watermark text elements into a TemplateConfig's pages.\n * The watermark elements are rendered as actual canvas text objects,\n * making them impossible to remove via browser inspect.\n */\n\nimport type { TemplateConfig, CanvasElement } from '@/types/editor';\n\nconst WATERMARK_ID_PREFIX = '__wm_';\n\n/** Optional overrides for watermark appearance. */\nexport interface WatermarkOptions {\n /** Override the watermark text. Defaults to domain-based ('pixldocs.com' / 'biomaker.app'). */\n text?: string;\n /** Opacity 0–1. Default: 0.14 */\n opacity?: number;\n /** Font size in px. Default: 18 */\n fontSize?: number;\n /** Rotation angle in degrees. Default: -30 */\n angle?: number;\n}\n\nconst DEFAULT_WATERMARK_OPACITY = 0.14;\nconst DEFAULT_WATERMARK_FONT_SIZE = 18;\nconst DEFAULT_WATERMARK_ANGLE = -30;\n\n/** Determine watermark text based on current domain */\nfunction getWatermarkText(): string {\n try {\n const host = window.location.hostname;\n if (host.includes('biomaker')) return 'biomaker.app';\n } catch {}\n return 'pixldocs.com';\n}\n\n/** Parse a hex/rgb color to luminance (0=black, 1=white) */\nfunction getLuminance(color: string | undefined): number {\n if (!color || color === 'transparent' || color === 'none') return 1; // assume light\n let r = 255, g = 255, b = 255;\n if (color.startsWith('#')) {\n const hex = color.slice(1);\n const full = hex.length === 3 ? hex.split('').map(c => c + c).join('') : hex;\n const n = parseInt(full, 16);\n r = (n >> 16) & 255;\n g = (n >> 8) & 255;\n b = n & 255;\n } else {\n const m = color.match(/rgba?\\((\\d+),\\s*(\\d+),\\s*(\\d+)/);\n if (m) { r = +m[1]; g = +m[2]; b = +m[3]; }\n }\n return (0.299 * r + 0.587 * g + 0.114 * b) / 255;\n}\n\n/** Pick watermark color that contrasts with page background */\nfunction getWatermarkColor(bgColor: string | undefined): string {\n const lum = getLuminance(bgColor);\n // Dark bg → light watermark, Light bg → dark watermark\n return lum < 0.45 ? '#cccccc' : '#808080';\n}\n\n/** Find the dominant background color of a page */\nfunction getPageBgColor(page: { children?: any[]; settings?: { backgroundColor?: string } }, canvasBg?: string): string | undefined {\n // 1. Check page-level settings (theme-applied bg lives here)\n const settingsBg = page.settings?.backgroundColor;\n if (settingsBg && settingsBg !== 'transparent' && settingsBg !== 'none') {\n return settingsBg;\n }\n // 2. Check first background shape fill\n const children = page.children || [];\n for (const child of children) {\n if (child.type === 'shape' && child.fill && child.fill !== 'transparent' && child.fill !== 'none') {\n return child.fill;\n }\n // Check inside groups (background groups)\n if (child.children?.length) {\n for (const gc of child.children) {\n if (gc.type === 'shape' && gc.fill && gc.fill !== 'transparent' && gc.fill !== 'none') {\n return gc.fill;\n }\n }\n }\n }\n return canvasBg;\n}\n\n/** Generate watermark text elements for a given canvas size */\nfunction generateWatermarkElements(\n canvasWidth: number,\n canvasHeight: number,\n wmColor: string,\n options: WatermarkOptions = {},\n): CanvasElement[] {\n const elements: CanvasElement[] = [];\n const text = options.text ?? getWatermarkText();\n const fontSize = options.fontSize ?? DEFAULT_WATERMARK_FONT_SIZE;\n const angle = options.angle ?? DEFAULT_WATERMARK_ANGLE;\n const opacity = options.opacity ?? DEFAULT_WATERMARK_OPACITY;\n // Adjust spacing based on text length to prevent overlap\n const estimatedTextWidth = text.length * fontSize * 0.55;\n const spacingX = Math.max(160, estimatedTextWidth + 30);\n const spacingY = 90;\n\n const startX = -canvasWidth * 0.3;\n const startY = -canvasHeight * 0.3;\n const endX = canvasWidth * 1.5;\n const endY = canvasHeight * 1.5;\n\n let idx = 0;\n for (let y = startY; y < endY; y += spacingY) {\n for (let x = startX; x < endX; x += spacingX) {\n elements.push({\n id: `${WATERMARK_ID_PREFIX}${idx++}`,\n type: 'text',\n left: x,\n top: y,\n width: 200,\n height: 40,\n text,\n fontFamily: 'Montserrat',\n fontSize,\n fontWeight: '600',\n fill: wmColor,\n angle,\n selectable: false,\n locked: true,\n visible: true,\n opacity,\n scaleX: 1,\n scaleY: 1,\n letterSpacing: 4,\n } as CanvasElement);\n }\n }\n return elements;\n}\n\n/**\n * Returns a new config with watermark elements injected into every page.\n * The original config is NOT mutated.\n */\nexport function injectWatermark(\n config: TemplateConfig,\n options: WatermarkOptions = {},\n): TemplateConfig {\n const canvasWidth = config.canvas?.width || 612;\n const canvasHeight = config.canvas?.height || 792;\n const canvasBg = (config.canvas as any)?.backgroundColor;\n\n return {\n ...config,\n pages: config.pages.map((page) => {\n const pageBg = getPageBgColor(page as any, canvasBg);\n const wmColor = getWatermarkColor(pageBg);\n const watermarkElements = generateWatermarkElements(canvasWidth, canvasHeight, wmColor, options);\n return {\n ...page,\n children: [\n ...(page.children || []),\n ...watermarkElements,\n ],\n };\n }),\n };\n}\n\n/** Check if an element ID is a watermark element */\nexport function isWatermarkElement(id: string): boolean {\n return id.startsWith(WATERMARK_ID_PREFIX);\n}\n"],"names":[],"mappings":"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"}
|
package/dist/index.cjs
CHANGED
|
@@ -12072,7 +12072,7 @@ function PixldocsPreview(props) {
|
|
|
12072
12072
|
!canvasSettled && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { position: "absolute", inset: 0, display: "flex", alignItems: "center", justifyContent: "center", minHeight: 200 }, children: /* @__PURE__ */ jsxRuntime.jsx("div", { style: { color: "#888", fontSize: 14 }, children: "Loading preview..." }) })
|
|
12073
12073
|
] });
|
|
12074
12074
|
}
|
|
12075
|
-
const PACKAGE_VERSION = "0.5.
|
|
12075
|
+
const PACKAGE_VERSION = "0.5.40";
|
|
12076
12076
|
let __underlineFixInstalled = false;
|
|
12077
12077
|
function installUnderlineFix(fab) {
|
|
12078
12078
|
var _a;
|
|
@@ -12080,6 +12080,24 @@ function installUnderlineFix(fab) {
|
|
|
12080
12080
|
const TextProto = (_a = fab.Text) == null ? void 0 : _a.prototype;
|
|
12081
12081
|
if (!TextProto || typeof TextProto._renderTextDecoration !== "function") return;
|
|
12082
12082
|
const original = TextProto._renderTextDecoration;
|
|
12083
|
+
const measureLineTextWidth = (obj, ctx, lineIndex) => {
|
|
12084
|
+
var _a2, _b, _c, _d, _e, _f;
|
|
12085
|
+
const rawLine = (_a2 = obj._textLines) == null ? void 0 : _a2[lineIndex];
|
|
12086
|
+
const lineText = Array.isArray(rawLine) ? rawLine.join("") : String(rawLine ?? "");
|
|
12087
|
+
if (!lineText) return 0;
|
|
12088
|
+
const fontSize = Number(((_b = obj.getValueOfPropertyAt) == null ? void 0 : _b.call(obj, lineIndex, 0, "fontSize")) ?? obj.fontSize ?? 0);
|
|
12089
|
+
const fontStyle = String(((_c = obj.getValueOfPropertyAt) == null ? void 0 : _c.call(obj, lineIndex, 0, "fontStyle")) ?? obj.fontStyle ?? "normal");
|
|
12090
|
+
const fontWeight = String(((_d = obj.getValueOfPropertyAt) == null ? void 0 : _d.call(obj, lineIndex, 0, "fontWeight")) ?? obj.fontWeight ?? "400");
|
|
12091
|
+
const fontFamily = String(((_e = obj.getValueOfPropertyAt) == null ? void 0 : _e.call(obj, lineIndex, 0, "fontFamily")) ?? obj.fontFamily ?? "sans-serif");
|
|
12092
|
+
const charSpacing = Number(((_f = obj.getValueOfPropertyAt) == null ? void 0 : _f.call(obj, lineIndex, 0, "charSpacing")) ?? obj.charSpacing ?? 0);
|
|
12093
|
+
ctx.save();
|
|
12094
|
+
ctx.font = `${fontStyle} normal ${fontWeight} ${fontSize}px ${fontFamily}`;
|
|
12095
|
+
const measured = ctx.measureText(lineText).width;
|
|
12096
|
+
ctx.restore();
|
|
12097
|
+
const graphemeCount = Array.from(lineText).length;
|
|
12098
|
+
const spacingWidth = graphemeCount > 1 ? charSpacing / 1e3 * fontSize * (graphemeCount - 1) : 0;
|
|
12099
|
+
return Math.max(0, measured + spacingWidth);
|
|
12100
|
+
};
|
|
12083
12101
|
TextProto._renderTextDecoration = function patchedRenderTextDecoration(ctx, type) {
|
|
12084
12102
|
try {
|
|
12085
12103
|
const hasOwn = !!this[type];
|
|
@@ -12110,20 +12128,16 @@ function installUnderlineFix(fab) {
|
|
|
12110
12128
|
topOffset += heightOfLine;
|
|
12111
12129
|
continue;
|
|
12112
12130
|
}
|
|
12113
|
-
|
|
12114
|
-
this.__lineWidths[i] = void 0;
|
|
12115
|
-
}
|
|
12116
|
-
let lineWidth = 0;
|
|
12117
|
-
try {
|
|
12118
|
-
lineWidth = this.getLineWidth(i);
|
|
12119
|
-
} catch {
|
|
12120
|
-
lineWidth = 0;
|
|
12121
|
-
}
|
|
12131
|
+
const lineWidth = measureLineTextWidth(this, ctx, i);
|
|
12122
12132
|
if (!lineWidth) {
|
|
12123
12133
|
topOffset += heightOfLine;
|
|
12124
12134
|
continue;
|
|
12125
12135
|
}
|
|
12126
|
-
const
|
|
12136
|
+
const availableWidth = Number(this.width ?? lineWidth);
|
|
12137
|
+
let lineLeftOffset = 0;
|
|
12138
|
+
const align = String(this.textAlign ?? "left");
|
|
12139
|
+
if (align === "center") lineLeftOffset = (availableWidth - lineWidth) / 2;
|
|
12140
|
+
else if (align === "right" || align === "end") lineLeftOffset = availableWidth - lineWidth;
|
|
12127
12141
|
let drawStart = leftOffset + lineLeftOffset;
|
|
12128
12142
|
if (this.direction === "rtl") {
|
|
12129
12143
|
drawStart = this.width - drawStart - lineWidth;
|
|
@@ -12213,7 +12227,7 @@ class PixldocsRenderer {
|
|
|
12213
12227
|
* This is the primary external API for the package.
|
|
12214
12228
|
*/
|
|
12215
12229
|
async renderFromForm(options) {
|
|
12216
|
-
const { templateId, formSchemaId, sectionState, themeId, watermark, prefetched, ...renderOpts } = options;
|
|
12230
|
+
const { templateId, formSchemaId, sectionState, themeId, watermark, watermarkOptions, prefetched, ...renderOpts } = options;
|
|
12217
12231
|
const resolved = await resolveFromForm({
|
|
12218
12232
|
templateId,
|
|
12219
12233
|
formSchemaId,
|
|
@@ -12226,8 +12240,8 @@ class PixldocsRenderer {
|
|
|
12226
12240
|
const shouldWatermark = watermark ?? resolved.price > 0;
|
|
12227
12241
|
let configToRender = resolved.config;
|
|
12228
12242
|
if (shouldWatermark) {
|
|
12229
|
-
const { injectWatermark } = await Promise.resolve().then(() => require("./canvasWatermark-
|
|
12230
|
-
configToRender = injectWatermark(configToRender);
|
|
12243
|
+
const { injectWatermark } = await Promise.resolve().then(() => require("./canvasWatermark-B0ab38Ok.cjs"));
|
|
12244
|
+
configToRender = injectWatermark(configToRender, watermarkOptions);
|
|
12231
12245
|
}
|
|
12232
12246
|
return this.renderAllPages(configToRender, renderOpts);
|
|
12233
12247
|
}
|
|
@@ -12266,7 +12280,7 @@ class PixldocsRenderer {
|
|
|
12266
12280
|
* Resolve from V2 sectionState and return SVGs for all pages (for server vector PDF).
|
|
12267
12281
|
*/
|
|
12268
12282
|
async renderSvgsFromForm(options) {
|
|
12269
|
-
const { templateId, formSchemaId, sectionState, themeId, watermark, prefetched } = options;
|
|
12283
|
+
const { templateId, formSchemaId, sectionState, themeId, watermark, watermarkOptions, prefetched } = options;
|
|
12270
12284
|
const resolved = await resolveFromForm({
|
|
12271
12285
|
templateId,
|
|
12272
12286
|
formSchemaId,
|
|
@@ -12279,8 +12293,8 @@ class PixldocsRenderer {
|
|
|
12279
12293
|
const shouldWatermark = watermark ?? resolved.price > 0;
|
|
12280
12294
|
let configToRender = resolved.config;
|
|
12281
12295
|
if (shouldWatermark) {
|
|
12282
|
-
const { injectWatermark } = await Promise.resolve().then(() => require("./canvasWatermark-
|
|
12283
|
-
configToRender = injectWatermark(configToRender);
|
|
12296
|
+
const { injectWatermark } = await Promise.resolve().then(() => require("./canvasWatermark-B0ab38Ok.cjs"));
|
|
12297
|
+
configToRender = injectWatermark(configToRender, watermarkOptions);
|
|
12284
12298
|
}
|
|
12285
12299
|
return this.renderAllPageSvgs(configToRender);
|
|
12286
12300
|
}
|
|
@@ -12298,7 +12312,7 @@ class PixldocsRenderer {
|
|
|
12298
12312
|
* This is the primary PDF export API — mirrors renderFromForm() but returns a PDF.
|
|
12299
12313
|
*/
|
|
12300
12314
|
async renderPdfFromForm(options) {
|
|
12301
|
-
const { templateId, formSchemaId, sectionState, themeId, watermark, prefetched, title, fontBaseUrl } = options;
|
|
12315
|
+
const { templateId, formSchemaId, sectionState, themeId, watermark, watermarkOptions, prefetched, title, fontBaseUrl } = options;
|
|
12302
12316
|
const resolved = await resolveFromForm({
|
|
12303
12317
|
templateId,
|
|
12304
12318
|
formSchemaId,
|
|
@@ -12311,8 +12325,8 @@ class PixldocsRenderer {
|
|
|
12311
12325
|
const shouldWatermark = watermark ?? resolved.price > 0;
|
|
12312
12326
|
let configToRender = resolved.config;
|
|
12313
12327
|
if (shouldWatermark) {
|
|
12314
|
-
const { injectWatermark } = await Promise.resolve().then(() => require("./canvasWatermark-
|
|
12315
|
-
configToRender = injectWatermark(configToRender);
|
|
12328
|
+
const { injectWatermark } = await Promise.resolve().then(() => require("./canvasWatermark-B0ab38Ok.cjs"));
|
|
12329
|
+
configToRender = injectWatermark(configToRender, watermarkOptions);
|
|
12316
12330
|
}
|
|
12317
12331
|
const svgs = await this.renderAllPageSvgs(configToRender);
|
|
12318
12332
|
const { assemblePdfFromSvgs: assemblePdfFromSvgs2 } = await Promise.resolve().then(() => pdfExport);
|