@pixldocs/canvas-renderer 0.5.81 → 0.5.83
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.cjs +209 -53
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +13 -0
- package/dist/index.js +209 -53
- package/dist/index.js.map +1 -1
- package/dist/{svgTextToPath-BTHnqJpM.cjs → svgTextToPath-CBcIgtk1.cjs} +74 -4
- package/dist/svgTextToPath-CBcIgtk1.cjs.map +1 -0
- package/dist/{svgTextToPath-BP0Kppla.js → svgTextToPath-CShDi4Ky.js} +56 -3
- package/dist/svgTextToPath-CShDi4Ky.js.map +1 -0
- package/package.json +1 -1
- package/dist/svgTextToPath-BP0Kppla.js.map +0 -1
- package/dist/svgTextToPath-BTHnqJpM.cjs.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -494,29 +494,39 @@ function resolveStackGroupEffectivePositions(group, pageChildren, options) {
|
|
|
494
494
|
const mode = group.layoutMode ?? "absolute";
|
|
495
495
|
if (!isStackLayoutMode(mode)) return /* @__PURE__ */ new Map();
|
|
496
496
|
const gap = group.stackSpacing ?? 8;
|
|
497
|
+
const padTop = group.paddingTop ?? 0;
|
|
498
|
+
const padLeft = group.paddingLeft ?? 0;
|
|
497
499
|
const kids = group.children ?? [];
|
|
498
500
|
const out = /* @__PURE__ */ new Map();
|
|
499
501
|
if (isVerticalStackLayoutMode(mode)) {
|
|
500
|
-
let prevBottom =
|
|
502
|
+
let prevBottom = padTop;
|
|
503
|
+
let firstSeen = false;
|
|
501
504
|
for (let i = 0; i < kids.length; i++) {
|
|
502
505
|
const child = kids[i];
|
|
503
506
|
const storedTop = getNodeTop(child);
|
|
504
507
|
const storedLeft = getNodeLeft(child);
|
|
505
|
-
const
|
|
506
|
-
|
|
508
|
+
const mTop = child.marginTop ?? 0;
|
|
509
|
+
const mLeft = child.marginLeft ?? 0;
|
|
510
|
+
const effectiveTop = !firstSeen ? padTop + storedTop + mTop : prevBottom + gap + storedTop + mTop;
|
|
511
|
+
firstSeen = true;
|
|
512
|
+
out.set(child.id, { top: effectiveTop, left: padLeft + storedLeft + mLeft });
|
|
507
513
|
const h = getNodeBounds(child, pageChildren).height;
|
|
508
|
-
prevBottom = effectiveTop + h;
|
|
514
|
+
prevBottom = effectiveTop + h + (child.marginBottom ?? 0);
|
|
509
515
|
}
|
|
510
516
|
} else {
|
|
511
|
-
let prevRight =
|
|
517
|
+
let prevRight = padLeft;
|
|
518
|
+
let firstSeen = false;
|
|
512
519
|
for (let i = 0; i < kids.length; i++) {
|
|
513
520
|
const child = kids[i];
|
|
514
521
|
const storedLeft = getNodeLeft(child);
|
|
515
522
|
const storedTop = getNodeTop(child);
|
|
516
|
-
const
|
|
517
|
-
|
|
523
|
+
const mTop = child.marginTop ?? 0;
|
|
524
|
+
const mLeft = child.marginLeft ?? 0;
|
|
525
|
+
const effectiveLeft = !firstSeen ? padLeft + storedLeft + mLeft : prevRight + gap + storedLeft + mLeft;
|
|
526
|
+
firstSeen = true;
|
|
527
|
+
out.set(child.id, { top: padTop + storedTop + mTop, left: effectiveLeft });
|
|
518
528
|
const w = getNodeBounds(child, pageChildren).width;
|
|
519
|
-
prevRight = effectiveLeft + w;
|
|
529
|
+
prevRight = effectiveLeft + w + (child.marginRight ?? 0);
|
|
520
530
|
}
|
|
521
531
|
}
|
|
522
532
|
return out;
|
|
@@ -541,6 +551,14 @@ function groupBoundsFromChildren(group, pageChildren, options) {
|
|
|
541
551
|
maxX = Math.max(maxX, cl + b.width);
|
|
542
552
|
maxY = Math.max(maxY, ct + b.height);
|
|
543
553
|
}
|
|
554
|
+
if (isStack) {
|
|
555
|
+
const padRight = group.paddingRight ?? 0;
|
|
556
|
+
const padBottom = group.paddingBottom ?? 0;
|
|
557
|
+
return {
|
|
558
|
+
width: Math.max(1, maxX + padRight),
|
|
559
|
+
height: Math.max(1, maxY + padBottom)
|
|
560
|
+
};
|
|
561
|
+
}
|
|
544
562
|
return {
|
|
545
563
|
width: Math.max(1, maxX - minX),
|
|
546
564
|
height: Math.max(1, maxY - minY)
|
|
@@ -603,7 +621,7 @@ function absoluteToStorePosition(absoluteLeft, absoluteTop, nodeId, pageChildren
|
|
|
603
621
|
const prev = kids[idx - 1];
|
|
604
622
|
const prevResolved = resolved.get(prev.id);
|
|
605
623
|
const prevHeight = getNodeBounds(prev, pageChildren).height;
|
|
606
|
-
const prevBottom = prevResolved ? prevResolved.top + prevHeight : 0;
|
|
624
|
+
const prevBottom = prevResolved ? prevResolved.top + prevHeight + (prev.marginBottom ?? 0) : 0;
|
|
607
625
|
const storeTop = inParentTop - prevBottom - gap;
|
|
608
626
|
return { left: storeLeft, top: Math.max(0, storeTop) };
|
|
609
627
|
}
|
|
@@ -625,7 +643,7 @@ function reflowStackGroup(group, pageChildren, spacing) {
|
|
|
625
643
|
const b = getNodeBounds(child, pageChildren);
|
|
626
644
|
const currentTop = getNodeTop(child);
|
|
627
645
|
const effectiveTop = i === 0 ? currentTop : prevBottom + gap;
|
|
628
|
-
prevBottom = effectiveTop + b.height;
|
|
646
|
+
prevBottom = effectiveTop + b.height + (child.marginBottom ?? 0);
|
|
629
647
|
if (i > 0) updates.set(child.id, { top: 0, left: firstLeft });
|
|
630
648
|
}
|
|
631
649
|
} else {
|
|
@@ -636,7 +654,7 @@ function reflowStackGroup(group, pageChildren, spacing) {
|
|
|
636
654
|
const b = getNodeBounds(child, pageChildren);
|
|
637
655
|
const currentLeft = getNodeLeft(child);
|
|
638
656
|
const effectiveLeft = i === 0 ? currentLeft : prevRight + gap;
|
|
639
|
-
prevRight = effectiveLeft + b.width;
|
|
657
|
+
prevRight = effectiveLeft + b.width + (child.marginRight ?? 0);
|
|
640
658
|
if (i > 0) updates.set(child.id, { left: 0, top: firstTop });
|
|
641
659
|
}
|
|
642
660
|
}
|
|
@@ -788,7 +806,8 @@ const cloneCanvas = (canvas) => ({
|
|
|
788
806
|
themeConfig: canvas.themeConfig ? {
|
|
789
807
|
properties: canvas.themeConfig.properties.map((p) => ({ ...p })),
|
|
790
808
|
variants: canvas.themeConfig.variants.map((v) => ({ ...v, values: { ...v.values } }))
|
|
791
|
-
} : void 0
|
|
809
|
+
} : void 0,
|
|
810
|
+
pdfTextMode: canvas.pdfTextMode
|
|
792
811
|
});
|
|
793
812
|
const sameIdSet = (a, b) => {
|
|
794
813
|
if (a.length !== b.length) return false;
|
|
@@ -1268,6 +1287,12 @@ const useEditorStore = zustand.create((set, get) => ({
|
|
|
1268
1287
|
const committed = commitFromState(state, nextCanvas);
|
|
1269
1288
|
return { canvas: nextCanvas, ...committed };
|
|
1270
1289
|
}),
|
|
1290
|
+
setPdfTextMode: (mode) => set((state) => {
|
|
1291
|
+
if (state.canvas.pdfTextMode === mode) return {};
|
|
1292
|
+
const nextCanvas = { ...state.canvas, pdfTextMode: mode };
|
|
1293
|
+
const committed = commitFromState(state, nextCanvas);
|
|
1294
|
+
return { canvas: nextCanvas, ...committed };
|
|
1295
|
+
}),
|
|
1271
1296
|
setZoom: (zoom) => set((state) => ({
|
|
1272
1297
|
canvas: { ...state.canvas, zoom: Math.max(0.1, Math.min(10, zoom)) }
|
|
1273
1298
|
})),
|
|
@@ -2455,7 +2480,8 @@ const useEditorStore = zustand.create((set, get) => ({
|
|
|
2455
2480
|
formBindingMode: config.formBindingMode,
|
|
2456
2481
|
boundFormDefId: config.boundFormDefId,
|
|
2457
2482
|
boundFormDefName: config.boundFormDefName,
|
|
2458
|
-
themeConfig: config.themeConfig ?? void 0
|
|
2483
|
+
themeConfig: config.themeConfig ?? void 0,
|
|
2484
|
+
pdfTextMode: config.pdfTextMode ?? "selectable"
|
|
2459
2485
|
};
|
|
2460
2486
|
const committed = commitFromState(state, nextCanvas);
|
|
2461
2487
|
const out = {
|
|
@@ -4922,7 +4948,9 @@ function extractTextBgConfig(element) {
|
|
|
4922
4948
|
if (!Number.isFinite(n)) return void 0;
|
|
4923
4949
|
return Math.max(0, Math.min(1, n));
|
|
4924
4950
|
})(),
|
|
4925
|
-
shadowAffectsBg: element.textShadowAffectsBg !== false
|
|
4951
|
+
shadowAffectsBg: element.textShadowAffectsBg !== false,
|
|
4952
|
+
shadowAffectsText: element.textShadowAffectsText !== false,
|
|
4953
|
+
fitToText: element.textBgFitToText === true
|
|
4926
4954
|
};
|
|
4927
4955
|
}
|
|
4928
4956
|
function hasTextBackground(cfg) {
|
|
@@ -4978,10 +5006,6 @@ function applyTextBackground(obj, cfg) {
|
|
|
4978
5006
|
const pR = Math.max(0, Number(bg.padRight ?? 0));
|
|
4979
5007
|
const pB = Math.max(0, Number(bg.padBottom ?? 0));
|
|
4980
5008
|
const pL = Math.max(0, Number(bg.padLeft ?? 0));
|
|
4981
|
-
const x = -w / 2 - pL;
|
|
4982
|
-
const y = -h / 2 - pT;
|
|
4983
|
-
const bgW = w + pL + pR;
|
|
4984
|
-
const bgH = h + pT + pB;
|
|
4985
5009
|
ctx.save();
|
|
4986
5010
|
const suppressShadowOnBg = bg.shadowAffectsBg === false;
|
|
4987
5011
|
if (suppressShadowOnBg) {
|
|
@@ -4990,24 +5014,38 @@ function applyTextBackground(obj, cfg) {
|
|
|
4990
5014
|
ctx.shadowOffsetX = 0;
|
|
4991
5015
|
ctx.shadowOffsetY = 0;
|
|
4992
5016
|
}
|
|
4993
|
-
buildRoundedRectPath2D(
|
|
4994
|
-
ctx,
|
|
4995
|
-
x,
|
|
4996
|
-
y,
|
|
4997
|
-
bgW,
|
|
4998
|
-
bgH,
|
|
4999
|
-
bg.rxTL ?? 0,
|
|
5000
|
-
bg.rxTR ?? 0,
|
|
5001
|
-
bg.rxBR ?? 0,
|
|
5002
|
-
bg.rxBL ?? 0
|
|
5003
|
-
);
|
|
5004
5017
|
const op = typeof bg.opacity === "number" ? Math.max(0, Math.min(1, bg.opacity)) : 1;
|
|
5005
5018
|
if (op < 1) ctx.globalAlpha = (ctx.globalAlpha ?? 1) * op;
|
|
5006
5019
|
ctx.fillStyle = bg.color;
|
|
5007
|
-
|
|
5020
|
+
const rects = computeBgRects(this, w, h, pT, pR, pB, pL, !!bg.fitToText);
|
|
5021
|
+
for (const r of rects) {
|
|
5022
|
+
buildRoundedRectPath2D(
|
|
5023
|
+
ctx,
|
|
5024
|
+
r.x,
|
|
5025
|
+
r.y,
|
|
5026
|
+
r.w,
|
|
5027
|
+
r.h,
|
|
5028
|
+
bg.rxTL ?? 0,
|
|
5029
|
+
bg.rxTR ?? 0,
|
|
5030
|
+
bg.rxBR ?? 0,
|
|
5031
|
+
bg.rxBL ?? 0
|
|
5032
|
+
);
|
|
5033
|
+
ctx.fill();
|
|
5034
|
+
}
|
|
5008
5035
|
ctx.restore();
|
|
5009
5036
|
}
|
|
5010
|
-
|
|
5037
|
+
const suppressShadowOnText = bg && bg.shadowAffectsText === false;
|
|
5038
|
+
if (suppressShadowOnText) {
|
|
5039
|
+
ctx.save();
|
|
5040
|
+
ctx.shadowColor = "transparent";
|
|
5041
|
+
ctx.shadowBlur = 0;
|
|
5042
|
+
ctx.shadowOffsetX = 0;
|
|
5043
|
+
ctx.shadowOffsetY = 0;
|
|
5044
|
+
originalRender(ctx);
|
|
5045
|
+
ctx.restore();
|
|
5046
|
+
} else {
|
|
5047
|
+
originalRender(ctx);
|
|
5048
|
+
}
|
|
5011
5049
|
};
|
|
5012
5050
|
const originalToObject = obj.toObject.bind(obj);
|
|
5013
5051
|
obj.toObject = function(propertiesToInclude) {
|
|
@@ -5033,20 +5071,18 @@ function applyTextBackground(obj, cfg) {
|
|
|
5033
5071
|
const pR = Math.max(0, Number((bg == null ? void 0 : bg.padRight) ?? 0));
|
|
5034
5072
|
const pB = Math.max(0, Number((bg == null ? void 0 : bg.padBottom) ?? 0));
|
|
5035
5073
|
const pL = Math.max(0, Number((bg == null ? void 0 : bg.padLeft) ?? 0));
|
|
5036
|
-
const
|
|
5037
|
-
const
|
|
5038
|
-
const
|
|
5039
|
-
|
|
5040
|
-
|
|
5041
|
-
|
|
5042
|
-
|
|
5043
|
-
bgW,
|
|
5044
|
-
bgH,
|
|
5074
|
+
const fit = !!(bg == null ? void 0 : bg.fitToText);
|
|
5075
|
+
const rects = computeBgRects(this, w, h, pT, pR, pB, pL, fit);
|
|
5076
|
+
const bgD = rects.map((r) => buildRoundedRectPathD(
|
|
5077
|
+
r.x,
|
|
5078
|
+
r.y,
|
|
5079
|
+
r.w,
|
|
5080
|
+
r.h,
|
|
5045
5081
|
(bg == null ? void 0 : bg.rxTL) ?? 0,
|
|
5046
5082
|
(bg == null ? void 0 : bg.rxTR) ?? 0,
|
|
5047
5083
|
(bg == null ? void 0 : bg.rxBR) ?? 0,
|
|
5048
5084
|
(bg == null ? void 0 : bg.rxBL) ?? 0
|
|
5049
|
-
);
|
|
5085
|
+
)).join(" ");
|
|
5050
5086
|
const bgFill = (bg == null ? void 0 : bg.color) || "";
|
|
5051
5087
|
const bgOpacity = typeof (bg == null ? void 0 : bg.opacity) === "number" ? Math.max(0, Math.min(1, bg.opacity)) : 1;
|
|
5052
5088
|
const bgOpacityAttr = bgOpacity < 1 ? ` fill-opacity="${bgOpacity}"` : "";
|
|
@@ -5071,9 +5107,11 @@ function applyTextBackground(obj, cfg) {
|
|
|
5071
5107
|
const shadowBgPath = `<path d="${bgD}" fill="${escapeXmlAttr(shadowColor)}" />`;
|
|
5072
5108
|
bgShadowMarker = wrapShadow(shadowBgPath);
|
|
5073
5109
|
}
|
|
5074
|
-
|
|
5075
|
-
|
|
5076
|
-
|
|
5110
|
+
if ((bg == null ? void 0 : bg.shadowAffectsText) !== false) {
|
|
5111
|
+
const inner = extractGInnerMarkup(svg);
|
|
5112
|
+
const recoloredText = recolorSvgFills(inner, shadowColor);
|
|
5113
|
+
if (recoloredText) textShadowMarker = wrapShadow(recoloredText);
|
|
5114
|
+
}
|
|
5077
5115
|
}
|
|
5078
5116
|
const openTagMatch = svg.match(/^\s*<g\b[^>]*>/);
|
|
5079
5117
|
const inserted = bgShadowMarker + bgPath + textShadowMarker;
|
|
@@ -5124,6 +5162,74 @@ function buildRoundedRectPathD(x, y, w, h, rTL, rTR, rBR, rBL) {
|
|
|
5124
5162
|
parts.push("Z");
|
|
5125
5163
|
return parts.join(" ");
|
|
5126
5164
|
}
|
|
5165
|
+
function computeBgRects(obj, w, h, pT, pR, pB, pL, fit) {
|
|
5166
|
+
var _a;
|
|
5167
|
+
if (!fit) {
|
|
5168
|
+
return [{
|
|
5169
|
+
x: -w / 2 - pL,
|
|
5170
|
+
y: -h / 2 - pT,
|
|
5171
|
+
w: w + pL + pR,
|
|
5172
|
+
h: h + pT + pB
|
|
5173
|
+
}];
|
|
5174
|
+
}
|
|
5175
|
+
const lines = (obj == null ? void 0 : obj._textLines) ?? [];
|
|
5176
|
+
if (!lines || lines.length === 0) {
|
|
5177
|
+
return [{
|
|
5178
|
+
x: -w / 2 - pL,
|
|
5179
|
+
y: -h / 2 - pT,
|
|
5180
|
+
w: w + pL + pR,
|
|
5181
|
+
h: h + pT + pB
|
|
5182
|
+
}];
|
|
5183
|
+
}
|
|
5184
|
+
const rects = [];
|
|
5185
|
+
const halfW = w / 2;
|
|
5186
|
+
const halfH = h / 2;
|
|
5187
|
+
const lineHeightRatio = Math.max(0.01, Number((obj == null ? void 0 : obj.lineHeight) ?? 1) || 1);
|
|
5188
|
+
let cursorY = -halfH;
|
|
5189
|
+
for (let i = 0; i < lines.length; i++) {
|
|
5190
|
+
let lineW = 0;
|
|
5191
|
+
let lineLeft = 0;
|
|
5192
|
+
let lineH = 0;
|
|
5193
|
+
try {
|
|
5194
|
+
lineW = obj.getLineWidth(i) || 0;
|
|
5195
|
+
} catch {
|
|
5196
|
+
lineW = 0;
|
|
5197
|
+
}
|
|
5198
|
+
try {
|
|
5199
|
+
lineLeft = ((_a = obj._getLineLeftOffset) == null ? void 0 : _a.call(obj, i)) ?? 0;
|
|
5200
|
+
} catch {
|
|
5201
|
+
lineLeft = 0;
|
|
5202
|
+
}
|
|
5203
|
+
try {
|
|
5204
|
+
lineH = obj.getHeightOfLine(i) || 0;
|
|
5205
|
+
} catch {
|
|
5206
|
+
lineH = 0;
|
|
5207
|
+
}
|
|
5208
|
+
const rawSlotH = i === lines.length - 1 ? lineH / lineHeightRatio : lineH;
|
|
5209
|
+
const usedH = cursorY + halfH;
|
|
5210
|
+
const slotH = Math.max(0, Math.min(rawSlotH, h - usedH));
|
|
5211
|
+
if (lineW <= 0 || slotH <= 0) {
|
|
5212
|
+
cursorY += slotH;
|
|
5213
|
+
continue;
|
|
5214
|
+
}
|
|
5215
|
+
rects.push({
|
|
5216
|
+
x: -halfW + lineLeft - pL,
|
|
5217
|
+
y: cursorY - pT,
|
|
5218
|
+
w: lineW + pL + pR,
|
|
5219
|
+
h: slotH + pT + pB
|
|
5220
|
+
});
|
|
5221
|
+
cursorY += slotH;
|
|
5222
|
+
}
|
|
5223
|
+
if (rects.length === 0) {
|
|
5224
|
+
return [{
|
|
5225
|
+
x: -w / 2 - pL,
|
|
5226
|
+
y: -h / 2 - pT,
|
|
5227
|
+
w: w + pL + pR,
|
|
5228
|
+
h: h + pT + pB
|
|
5229
|
+
}];
|
|
5230
|
+
}
|
|
5231
|
+
return rects;
|
|
5232
|
+
}
|
|
5127
5233
|
function escapeXmlAttr(s) {
|
|
5128
5234
|
return String(s).replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
5129
5235
|
}
|
|
@@ -8143,10 +8249,14 @@ const PageCanvas = react.forwardRef(
|
|
|
8143
8249
|
tr: element.textBgRxTR ?? 0,
|
|
8144
8250
|
br: element.textBgRxBR ?? 0,
|
|
8145
8251
|
bl: element.textBgRxBL ?? 0,
|
|
8252
|
+
ft: element.textBgFitToText === true,
|
|
8253
|
+
bo: element.textBgOpacity ?? 1,
|
|
8146
8254
|
sc: element.textShadowColor ?? null,
|
|
8147
8255
|
sb: element.textShadowBlur ?? 0,
|
|
8148
8256
|
sx: element.textShadowOffsetX ?? 0,
|
|
8149
|
-
sy: element.textShadowOffsetY ?? 0
|
|
8257
|
+
sy: element.textShadowOffsetY ?? 0,
|
|
8258
|
+
st: element.textShadowAffectsText !== false,
|
|
8259
|
+
sa: element.textShadowAffectsBg !== false
|
|
8150
8260
|
}) !== (existingObj.__lastTextBgShadowJson ?? "") || // CRITICAL: Detect gradient fill/stroke changes — serialise to JSON for deep comparison
|
|
8151
8261
|
JSON.stringify(element.fillGradient || null) !== (existingObj.__lastFillGradientJson ?? "null") || JSON.stringify(element.strokeGradient || null) !== (existingObj.__lastStrokeGradientJson ?? "null");
|
|
8152
8262
|
const forceApplyFromPanel = syncTriggeredByPanelRef.current;
|
|
@@ -9060,10 +9170,14 @@ const PageCanvas = react.forwardRef(
|
|
|
9060
9170
|
tr: element.textBgRxTR ?? 0,
|
|
9061
9171
|
br: element.textBgRxBR ?? 0,
|
|
9062
9172
|
bl: element.textBgRxBL ?? 0,
|
|
9173
|
+
ft: element.textBgFitToText === true,
|
|
9174
|
+
bo: element.textBgOpacity ?? 1,
|
|
9063
9175
|
sc: element.textShadowColor ?? null,
|
|
9064
9176
|
sb: element.textShadowBlur ?? 0,
|
|
9065
9177
|
sx: element.textShadowOffsetX ?? 0,
|
|
9066
|
-
sy: element.textShadowOffsetY ?? 0
|
|
9178
|
+
sy: element.textShadowOffsetY ?? 0,
|
|
9179
|
+
st: element.textShadowAffectsText !== false,
|
|
9180
|
+
sa: element.textShadowAffectsBg !== false
|
|
9067
9181
|
});
|
|
9068
9182
|
obj.dirty = true;
|
|
9069
9183
|
} catch (err) {
|
|
@@ -12884,7 +12998,7 @@ class PixldocsRenderer {
|
|
|
12884
12998
|
async renderPdf(templateConfig, options) {
|
|
12885
12999
|
const svgs = await this.renderAllPageSvgs(templateConfig);
|
|
12886
13000
|
const { assemblePdfFromSvgs: assemblePdfFromSvgs2 } = await Promise.resolve().then(() => pdfExport);
|
|
12887
|
-
return assemblePdfFromSvgs2(svgs, { title: options == null ? void 0 : options.title, fontBaseUrl: options == null ? void 0 : options.fontBaseUrl });
|
|
13001
|
+
return assemblePdfFromSvgs2(svgs, { title: options == null ? void 0 : options.title, fontBaseUrl: options == null ? void 0 : options.fontBaseUrl, textMode: (options == null ? void 0 : options.textMode) ?? templateConfig.pdfTextMode ?? "selectable" });
|
|
12888
13002
|
}
|
|
12889
13003
|
/**
|
|
12890
13004
|
* Resolve from V2 sectionState and render a vector PDF.
|
|
@@ -12909,7 +13023,7 @@ class PixldocsRenderer {
|
|
|
12909
13023
|
}
|
|
12910
13024
|
const svgs = await this.renderAllPageSvgs(configToRender);
|
|
12911
13025
|
const { assemblePdfFromSvgs: assemblePdfFromSvgs2 } = await Promise.resolve().then(() => pdfExport);
|
|
12912
|
-
return assemblePdfFromSvgs2(svgs, { title: title ?? resolved.config.name, fontBaseUrl });
|
|
13026
|
+
return assemblePdfFromSvgs2(svgs, { title: title ?? resolved.config.name, fontBaseUrl, textMode: options.textMode ?? configToRender.pdfTextMode ?? "selectable" });
|
|
12913
13027
|
}
|
|
12914
13028
|
async renderById(templateId, formData, options) {
|
|
12915
13029
|
const resolved = await resolveTemplateData({
|
|
@@ -14115,6 +14229,7 @@ async function fetchTTFAsBase64(url) {
|
|
|
14115
14229
|
if (!res.ok) return null;
|
|
14116
14230
|
const buf = await res.arrayBuffer();
|
|
14117
14231
|
const bytes = new Uint8Array(buf);
|
|
14232
|
+
if (!isJsPdfEmbeddableTrueType(bytes)) return null;
|
|
14118
14233
|
let binary = "";
|
|
14119
14234
|
for (let i = 0; i < bytes.length; i++) {
|
|
14120
14235
|
binary += String.fromCharCode(bytes[i]);
|
|
@@ -14126,6 +14241,33 @@ async function fetchTTFAsBase64(url) {
|
|
|
14126
14241
|
return null;
|
|
14127
14242
|
}
|
|
14128
14243
|
}
|
|
14244
|
+
function isJsPdfEmbeddableTrueType(bytes) {
|
|
14245
|
+
if (bytes.length < 12) return false;
|
|
14246
|
+
const signature = String.fromCharCode(bytes[0], bytes[1], bytes[2], bytes[3]);
|
|
14247
|
+
if (signature !== "\0\0\0" && signature !== "true") return false;
|
|
14248
|
+
const u16 = (offset) => bytes[offset] << 8 | bytes[offset + 1];
|
|
14249
|
+
const u32 = (offset) => (bytes[offset] << 24 | bytes[offset + 1] << 16 | bytes[offset + 2] << 8 | bytes[offset + 3]) >>> 0;
|
|
14250
|
+
const tableCount = u16(4);
|
|
14251
|
+
for (let i = 0; i < tableCount; i++) {
|
|
14252
|
+
const recordOffset = 12 + i * 16;
|
|
14253
|
+
if (recordOffset + 16 > bytes.length) return false;
|
|
14254
|
+
const tag = String.fromCharCode(bytes[recordOffset], bytes[recordOffset + 1], bytes[recordOffset + 2], bytes[recordOffset + 3]);
|
|
14255
|
+
if (tag !== "cmap") continue;
|
|
14256
|
+
const cmapOffset = u32(recordOffset + 8);
|
|
14257
|
+
const cmapLength = u32(recordOffset + 12);
|
|
14258
|
+
if (cmapOffset + Math.min(cmapLength, 4) > bytes.length) return false;
|
|
14259
|
+
const subtables = u16(cmapOffset + 2);
|
|
14260
|
+
for (let j = 0; j < subtables; j++) {
|
|
14261
|
+
const encOffset = cmapOffset + 4 + j * 8;
|
|
14262
|
+
if (encOffset + 8 > bytes.length) return false;
|
|
14263
|
+
const platform = u16(encOffset);
|
|
14264
|
+
const encoding = u16(encOffset + 2);
|
|
14265
|
+
if (platform === 0 || platform === 3 && (encoding === 1 || encoding === 10)) return true;
|
|
14266
|
+
}
|
|
14267
|
+
return false;
|
|
14268
|
+
}
|
|
14269
|
+
return false;
|
|
14270
|
+
}
|
|
14129
14271
|
async function embedFont(pdf, fontName, weight, fontBaseUrl, isItalic = false) {
|
|
14130
14272
|
const fontFiles = FONT_FILES[fontName];
|
|
14131
14273
|
if (!fontFiles) return false;
|
|
@@ -14159,10 +14301,22 @@ async function embedFont(pdf, fontName, weight, fontBaseUrl, isItalic = false) {
|
|
|
14159
14301
|
async function embedFontsForConfig(pdf, config, fontBaseUrl) {
|
|
14160
14302
|
const fontKeys = /* @__PURE__ */ new Set();
|
|
14161
14303
|
const SEP = "";
|
|
14304
|
+
const normalizeWeight = (raw) => {
|
|
14305
|
+
if (raw == null) return 400;
|
|
14306
|
+
if (typeof raw === "number" && Number.isFinite(raw)) return resolveFontWeight(raw);
|
|
14307
|
+
const str = String(raw).trim().toLowerCase();
|
|
14308
|
+
const parsed = Number.parseInt(str, 10);
|
|
14309
|
+
if (Number.isFinite(parsed)) return resolveFontWeight(parsed);
|
|
14310
|
+
if (str === "bold" || str === "bolder") return 700;
|
|
14311
|
+
if (str === "semibold" || str === "demibold") return 600;
|
|
14312
|
+
if (str === "medium") return 500;
|
|
14313
|
+
if (str === "light" || str === "lighter" || str === "thin") return 300;
|
|
14314
|
+
return 400;
|
|
14315
|
+
};
|
|
14162
14316
|
const walkElements = (elements) => {
|
|
14163
14317
|
for (const el of elements) {
|
|
14164
14318
|
if (el.fontFamily) {
|
|
14165
|
-
const w =
|
|
14319
|
+
const w = normalizeWeight(el.fontWeight);
|
|
14166
14320
|
fontKeys.add(`${el.fontFamily}${SEP}${w}`);
|
|
14167
14321
|
}
|
|
14168
14322
|
if (el.styles && typeof el.styles === "object") {
|
|
@@ -14172,7 +14326,7 @@ async function embedFontsForConfig(pdf, config, fontBaseUrl) {
|
|
|
14172
14326
|
for (const charKey of Object.keys(lineStyles)) {
|
|
14173
14327
|
const s = lineStyles[charKey];
|
|
14174
14328
|
if (s == null ? void 0 : s.fontFamily) {
|
|
14175
|
-
const w =
|
|
14329
|
+
const w = normalizeWeight(s.fontWeight);
|
|
14176
14330
|
fontKeys.add(`${s.fontFamily}${SEP}${w}`);
|
|
14177
14331
|
}
|
|
14178
14332
|
}
|
|
@@ -15807,7 +15961,9 @@ async function assemblePdfFromSvgs(svgResults, options = {}) {
|
|
|
15807
15961
|
const hasGradient = !!((_b = (_a = page.backgroundGradient) == null ? void 0 : _a.stops) == null ? void 0 : _b.length);
|
|
15808
15962
|
drawPageBackground(pdf, i, page.width, page.height, page.backgroundColor, page.backgroundGradient);
|
|
15809
15963
|
const shouldStripBg = stripPageBackground ?? hasGradient;
|
|
15810
|
-
const
|
|
15964
|
+
const textMode = options.textMode ?? (options.outlineText ? "pixel-perfect" : "selectable");
|
|
15965
|
+
const shouldOutlineText = textMode === "pixel-perfect" || textMode === "auto";
|
|
15966
|
+
const outlineSubMode = textMode === "auto" ? "complex-only" : "all";
|
|
15811
15967
|
let pageSvg = page.svg;
|
|
15812
15968
|
try {
|
|
15813
15969
|
pageSvg = await convertSvgTextDecorationsToLinesString(pageSvg);
|
|
@@ -15819,8 +15975,8 @@ async function assemblePdfFromSvgs(svgResults, options = {}) {
|
|
|
15819
15975
|
}
|
|
15820
15976
|
if (shouldOutlineText) {
|
|
15821
15977
|
try {
|
|
15822
|
-
const { convertAllTextToPath } = await Promise.resolve().then(() => require("./svgTextToPath-
|
|
15823
|
-
pageSvg = await convertAllTextToPath(pageSvg, fontBaseUrl);
|
|
15978
|
+
const { convertAllTextToPath } = await Promise.resolve().then(() => require("./svgTextToPath-CBcIgtk1.cjs"));
|
|
15979
|
+
pageSvg = await convertAllTextToPath(pageSvg, fontBaseUrl, { mode: outlineSubMode });
|
|
15824
15980
|
try {
|
|
15825
15981
|
dumpSvgTextDiagnostics(pageSvg, i, PARITY_TAG, "STAGE-1b-after-text-to-path-raw");
|
|
15826
15982
|
} catch {
|