av6-pdf-engine 1.2.0 → 3.0.0
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/README.md +686 -88
- package/dist/index.d.mts +277 -23
- package/dist/index.d.ts +277 -23
- package/dist/index.js +1562 -801
- package/dist/index.mjs +1527 -800
- package/package.json +6 -1
- package/.prettierignore +0 -4
- package/.prettierrc +0 -6
package/dist/index.js
CHANGED
|
@@ -34,10 +34,44 @@ __export(index_exports, {
|
|
|
34
34
|
PdfEngineError: () => PdfEngineError,
|
|
35
35
|
PdfEngineErrorCode: () => PdfEngineErrorCode,
|
|
36
36
|
QR_ERROR_LEVEL: () => QR_ERROR_LEVEL,
|
|
37
|
+
computeColumnPixelWidths: () => computeColumnPixelWidths,
|
|
38
|
+
contentEnv: () => contentEnv,
|
|
39
|
+
createBlockRenderer: () => createBlockRenderer,
|
|
40
|
+
createBottomLimitForContent: () => createBottomLimitForContent,
|
|
41
|
+
createEnsureSpaceFor: () => createEnsureSpaceFor,
|
|
42
|
+
createInitialContext: () => createInitialContext,
|
|
43
|
+
createMeasureBlockHeight: () => createMeasureBlockHeight,
|
|
44
|
+
createProcessSignatureBlock: () => createProcessSignatureBlock,
|
|
45
|
+
createStartNewPageLayout: () => createStartNewPageLayout,
|
|
46
|
+
drawFooter: () => drawFooter,
|
|
47
|
+
drawHeader: () => drawHeader,
|
|
48
|
+
drawPageBackground: () => drawPageBackground,
|
|
49
|
+
drawSignatureBlock: () => drawSignatureBlock,
|
|
50
|
+
drawStyledText: () => drawStyledText,
|
|
51
|
+
drawWatermarkForPage: () => drawWatermarkForPage,
|
|
52
|
+
finishPage: () => finishPage,
|
|
53
|
+
generateBarcodeBuffer: () => generateBarcodeBuffer,
|
|
54
|
+
generateQrBuffer: () => generateQrBuffer,
|
|
55
|
+
getBottomLimitForContent: () => getBottomLimitForContent,
|
|
56
|
+
getFontNameForText: () => getFontNameForText,
|
|
57
|
+
hasPadding: () => hasPadding,
|
|
58
|
+
images: () => images,
|
|
37
59
|
isPdfEngineError: () => isPdfEngineError,
|
|
60
|
+
mapBarcodeTypeToBcid: () => mapBarcodeTypeToBcid,
|
|
61
|
+
materializeImagesInBlocks: () => materializeImagesInBlocks,
|
|
62
|
+
materializeQrAndBarcodesInBlocks: () => materializeQrAndBarcodesInBlocks,
|
|
63
|
+
mergeStyleDefs: () => mergeStyleDefs,
|
|
64
|
+
normalizeImageSrc: () => normalizeImageSrc,
|
|
38
65
|
renderCustomPdf: () => renderCustomPdf,
|
|
39
66
|
renderCustomPdfToBuffer: () => renderCustomPdfToBuffer,
|
|
40
|
-
|
|
67
|
+
resolveBlockPadding: () => resolveBlockPadding,
|
|
68
|
+
resolveFooterPadding: () => resolveFooterPadding,
|
|
69
|
+
resolveHeaderPadding: () => resolveHeaderPadding,
|
|
70
|
+
resolveSpacing: () => resolveSpacing,
|
|
71
|
+
resolveTableCell: () => resolveTableCell,
|
|
72
|
+
resolveTextBlock: () => resolveTextBlock,
|
|
73
|
+
toPdfEngineError: () => toPdfEngineError,
|
|
74
|
+
watermarkUsesLast: () => watermarkUsesLast
|
|
41
75
|
});
|
|
42
76
|
module.exports = __toCommonJS(index_exports);
|
|
43
77
|
|
|
@@ -73,6 +107,11 @@ function toPdfEngineError(cause, fallback) {
|
|
|
73
107
|
});
|
|
74
108
|
}
|
|
75
109
|
|
|
110
|
+
// src/images/index.ts
|
|
111
|
+
var images = {
|
|
112
|
+
default: "data:image/png;base64,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"
|
|
113
|
+
};
|
|
114
|
+
|
|
76
115
|
// src/renderer-engine/index.ts
|
|
77
116
|
var import_fs = __toESM(require("fs"));
|
|
78
117
|
var import_pdfkit = __toESM(require("pdfkit"));
|
|
@@ -251,7 +290,7 @@ var drawRotatedImage = (doc, src, x, y, width, height, rotationDeg) => {
|
|
|
251
290
|
doc.image(src, x, y, { width, height });
|
|
252
291
|
doc.restore();
|
|
253
292
|
};
|
|
254
|
-
var processImageBlock = (doc, ctx, block, y, env, ensureSpaceFor) => {
|
|
293
|
+
var processImageBlock = (doc, ctx, block, y, env, ensureSpaceFor, defaultImage) => {
|
|
255
294
|
const imgSource = block.src;
|
|
256
295
|
const imgWidth = block.width ?? 80;
|
|
257
296
|
const imgHeight = block.height ?? 50;
|
|
@@ -261,12 +300,11 @@ var processImageBlock = (doc, ctx, block, y, env, ensureSpaceFor) => {
|
|
|
261
300
|
const availableWidth = Math.max(env.innerWidth - localLeft - localRight, 1);
|
|
262
301
|
const mt = block.marginTop ?? 0;
|
|
263
302
|
const mb = block.marginBottom ?? 0;
|
|
264
|
-
const baseY = y ?? ctx.currentY;
|
|
265
|
-
const startY = baseY + mt;
|
|
266
303
|
const heightNeeded = mt + imgHeight + mb;
|
|
267
304
|
if (y === null) {
|
|
268
305
|
ensureSpaceFor(heightNeeded, env);
|
|
269
306
|
}
|
|
307
|
+
const startY = (y ?? ctx.currentY) + mt;
|
|
270
308
|
let x = baseLeft;
|
|
271
309
|
if (block.align === "center") {
|
|
272
310
|
x = baseLeft + (availableWidth - imgWidth) / 2;
|
|
@@ -279,7 +317,18 @@ var processImageBlock = (doc, ctx, block, y, env, ensureSpaceFor) => {
|
|
|
279
317
|
height: imgHeight
|
|
280
318
|
});
|
|
281
319
|
} catch (e) {
|
|
282
|
-
|
|
320
|
+
if (defaultImage !== void 0) {
|
|
321
|
+
try {
|
|
322
|
+
doc.image(defaultImage, x, startY, {
|
|
323
|
+
width: imgWidth,
|
|
324
|
+
height: imgHeight
|
|
325
|
+
});
|
|
326
|
+
} catch {
|
|
327
|
+
console.warn("Failed to render default image fallback:", e);
|
|
328
|
+
}
|
|
329
|
+
} else {
|
|
330
|
+
console.warn("Failed to load image:", e);
|
|
331
|
+
}
|
|
283
332
|
}
|
|
284
333
|
const newY = startY + imgHeight + mb;
|
|
285
334
|
if (y === null) ctx.currentY = newY;
|
|
@@ -331,7 +380,7 @@ var processKeyValueGridBlock = (doc, ctx, styles, block, y, env, computeColumnPi
|
|
|
331
380
|
...base,
|
|
332
381
|
style: styleNames
|
|
333
382
|
});
|
|
334
|
-
const
|
|
383
|
+
const measureTextHeight2 = (tb, width) => {
|
|
335
384
|
const fontName = getFontNameForText(tb);
|
|
336
385
|
doc.font(fontName);
|
|
337
386
|
doc.fontSize(tb.fontSize ?? 10);
|
|
@@ -364,10 +413,10 @@ var processKeyValueGridBlock = (doc, ctx, styles, block, y, env, computeColumnPi
|
|
|
364
413
|
const valueStyleNames = item.valueStyle ?? block.valueStyle ?? void 0;
|
|
365
414
|
const keyBase = buildKeyBlock(item);
|
|
366
415
|
const keyResolved = resolveStyled(keyBase, keyStyleNames);
|
|
367
|
-
const keyHeight =
|
|
416
|
+
const keyHeight = measureTextHeight2(keyResolved, colWidth);
|
|
368
417
|
const valueBase = buildValueBlock(item);
|
|
369
418
|
const valueResolved = resolveStyled(valueBase, valueStyleNames);
|
|
370
|
-
const valueHeight =
|
|
419
|
+
const valueHeight = measureTextHeight2(valueResolved, colWidth);
|
|
371
420
|
const rowHeight = keyHeight + keyValueGap + valueHeight;
|
|
372
421
|
colHeight += rowHeight + rowGap;
|
|
373
422
|
}
|
|
@@ -387,12 +436,12 @@ var processKeyValueGridBlock = (doc, ctx, styles, block, y, env, computeColumnPi
|
|
|
387
436
|
const valueStyleNames = item.valueStyle ?? block.valueStyle ?? void 0;
|
|
388
437
|
const keyBase = buildKeyBlock(item);
|
|
389
438
|
const keyResolved = resolveStyled(keyBase, keyStyleNames);
|
|
390
|
-
const keyHeight =
|
|
439
|
+
const keyHeight = measureTextHeight2(keyResolved, keyWidthPx);
|
|
391
440
|
const valueBase = buildValueBlock(item);
|
|
392
441
|
const valueResolved = resolveStyled(valueBase, valueStyleNames);
|
|
393
442
|
const valueXInsideCol = keyWidthPx + (separatorText ? sepBoxWidth + 4 : 4);
|
|
394
443
|
const valueWidth = Math.max(colWidth - valueXInsideCol, 1);
|
|
395
|
-
const valueHeight =
|
|
444
|
+
const valueHeight = measureTextHeight2(valueResolved, valueWidth);
|
|
396
445
|
const cellHeight = Math.max(keyHeight, valueHeight);
|
|
397
446
|
if (cellHeight > rowHeight) rowHeight = cellHeight;
|
|
398
447
|
}
|
|
@@ -420,12 +469,12 @@ var processKeyValueGridBlock = (doc, ctx, styles, block, y, env, computeColumnPi
|
|
|
420
469
|
const valueStyleNames = item.valueStyle ?? block.valueStyle ?? void 0;
|
|
421
470
|
const keyBlock = buildKeyBlock(item);
|
|
422
471
|
const keyResolved = resolveStyled(keyBlock, keyStyleNames);
|
|
423
|
-
const keyHeight =
|
|
472
|
+
const keyHeight = measureTextHeight2(keyResolved, colWidth);
|
|
424
473
|
drawStyledText(doc, keyResolved, colX, colY, colWidth);
|
|
425
474
|
colY += keyHeight + keyValueGap;
|
|
426
475
|
const valueBlock = buildValueBlock(item);
|
|
427
476
|
const valueResolved = resolveStyled(valueBlock, valueStyleNames);
|
|
428
|
-
const valueHeight =
|
|
477
|
+
const valueHeight = measureTextHeight2(valueResolved, colWidth);
|
|
429
478
|
drawStyledText(doc, valueResolved, colX, colY, colWidth);
|
|
430
479
|
colY += valueHeight + rowGap;
|
|
431
480
|
}
|
|
@@ -445,12 +494,12 @@ var processKeyValueGridBlock = (doc, ctx, styles, block, y, env, computeColumnPi
|
|
|
445
494
|
const valueStyleNames = item.valueStyle ?? block.valueStyle ?? void 0;
|
|
446
495
|
const keyBase = buildKeyBlock(item);
|
|
447
496
|
const keyResolved = resolveStyled(keyBase, keyStyleNames);
|
|
448
|
-
const keyHeight =
|
|
497
|
+
const keyHeight = measureTextHeight2(keyResolved, keyWidthPx);
|
|
449
498
|
const valueBase = buildValueBlock(item);
|
|
450
499
|
const valueResolved = resolveStyled(valueBase, valueStyleNames);
|
|
451
500
|
const valueXInsideCol = keyWidthPx + (separatorText ? sepBoxWidth + 4 : 4);
|
|
452
501
|
const valueWidth = Math.max(colWidth - valueXInsideCol, 1);
|
|
453
|
-
const valueHeight =
|
|
502
|
+
const valueHeight = measureTextHeight2(valueResolved, valueWidth);
|
|
454
503
|
const cellHeight = Math.max(keyHeight, valueHeight);
|
|
455
504
|
if (cellHeight > rowHeight) rowHeight = cellHeight;
|
|
456
505
|
}
|
|
@@ -491,6 +540,149 @@ var processKeyValueGridBlock = (doc, ctx, styles, block, y, env, computeColumnPi
|
|
|
491
540
|
return endY;
|
|
492
541
|
};
|
|
493
542
|
|
|
543
|
+
// src/renderer-engine/blocks/list.ts
|
|
544
|
+
var DEFAULT_BULLET = "\u2022";
|
|
545
|
+
var DEFAULT_MARKER_GAP = 6;
|
|
546
|
+
var DEFAULT_ITEM_GAP = 4;
|
|
547
|
+
var MARKER_PADDING = 2;
|
|
548
|
+
var normalizeListItem = (item) => typeof item === "string" ? { text: item } : item;
|
|
549
|
+
var buildTextBlock = (list, item) => ({
|
|
550
|
+
type: "text",
|
|
551
|
+
text: item.text ?? "",
|
|
552
|
+
fontSize: item.fontSize ?? list.fontSize,
|
|
553
|
+
lineGap: item.lineGap ?? list.lineGap,
|
|
554
|
+
color: item.color ?? list.color,
|
|
555
|
+
bold: item.bold,
|
|
556
|
+
italic: item.italic,
|
|
557
|
+
underline: item.underline,
|
|
558
|
+
strike: item.strike,
|
|
559
|
+
link: item.link,
|
|
560
|
+
font: item.font,
|
|
561
|
+
style: item.style ?? list.style
|
|
562
|
+
});
|
|
563
|
+
var getMarker = (list, index) => {
|
|
564
|
+
if ((list.listStyle ?? "bullet") === "number") {
|
|
565
|
+
const start = list.start ?? 1;
|
|
566
|
+
return `${start + index}.`;
|
|
567
|
+
}
|
|
568
|
+
return list.bullet ?? DEFAULT_BULLET;
|
|
569
|
+
};
|
|
570
|
+
var applyTextOptions = (doc, tb) => {
|
|
571
|
+
doc.fontSize(tb.fontSize ?? 10);
|
|
572
|
+
doc.font(getFontNameForText(tb));
|
|
573
|
+
if (tb.color) doc.fillColor(tb.color);
|
|
574
|
+
else doc.fillColor("black");
|
|
575
|
+
};
|
|
576
|
+
var measureTextHeight = (doc, tb, width) => {
|
|
577
|
+
applyTextOptions(doc, tb);
|
|
578
|
+
const lineGap = tb.lineGap ?? 4;
|
|
579
|
+
return doc.heightOfString(tb.text ?? "", { width, lineGap });
|
|
580
|
+
};
|
|
581
|
+
var measureMarkerWidth = (doc, marker, tb) => {
|
|
582
|
+
applyTextOptions(doc, tb);
|
|
583
|
+
return doc.widthOfString(marker) + MARKER_PADDING;
|
|
584
|
+
};
|
|
585
|
+
var computeMarkerWidth = (doc, list, items, tbSample) => {
|
|
586
|
+
if (list.markerWidth !== void 0) return list.markerWidth;
|
|
587
|
+
let maxW = 0;
|
|
588
|
+
for (let i = 0; i < items.length; i++) {
|
|
589
|
+
const marker = getMarker(list, i);
|
|
590
|
+
const w = measureMarkerWidth(doc, marker, tbSample);
|
|
591
|
+
if (w > maxW) maxW = w;
|
|
592
|
+
}
|
|
593
|
+
return maxW;
|
|
594
|
+
};
|
|
595
|
+
var measureItemHeight = (doc, list, item, index, markerWidth, textWidth, styles) => {
|
|
596
|
+
const tb = resolveTextBlock(styles, buildTextBlock(list, item));
|
|
597
|
+
const marker = getMarker(list, index);
|
|
598
|
+
const markerTb = { ...tb, text: marker, underline: false, strike: false, link: void 0 };
|
|
599
|
+
const markerH = measureTextHeight(doc, markerTb, markerWidth);
|
|
600
|
+
const textH = measureTextHeight(doc, tb, textWidth);
|
|
601
|
+
const lineGap = tb.lineGap ?? 4;
|
|
602
|
+
return Math.max(markerH, textH) + lineGap;
|
|
603
|
+
};
|
|
604
|
+
var measureListHeight = (doc, styles, block, env) => {
|
|
605
|
+
const items = (block.items ?? []).map(normalizeListItem);
|
|
606
|
+
const mt = block.marginTop ?? 0;
|
|
607
|
+
const mb = block.marginBottom ?? 0;
|
|
608
|
+
const itemGap = block.itemGap ?? DEFAULT_ITEM_GAP;
|
|
609
|
+
const markerGap = block.markerGap ?? DEFAULT_MARKER_GAP;
|
|
610
|
+
if (!items.length) return mt + mb;
|
|
611
|
+
const localLeft = block.marginLeft ?? 0;
|
|
612
|
+
const localRight = block.marginRight ?? 0;
|
|
613
|
+
const innerWidth = Math.max(env.innerWidth - localLeft - localRight, 1);
|
|
614
|
+
const firstResolved = resolveTextBlock(styles, buildTextBlock(block, items[0]));
|
|
615
|
+
const markerWidth = computeMarkerWidth(doc, block, items, firstResolved);
|
|
616
|
+
const textWidth = Math.max(innerWidth - markerWidth - markerGap, 1);
|
|
617
|
+
let total = mt;
|
|
618
|
+
for (let i = 0; i < items.length; i++) {
|
|
619
|
+
total += measureItemHeight(doc, block, items[i], i, markerWidth, textWidth, styles);
|
|
620
|
+
if (i < items.length - 1) total += itemGap;
|
|
621
|
+
}
|
|
622
|
+
return total + mb;
|
|
623
|
+
};
|
|
624
|
+
var drawListText = (doc, tb, x, y, width) => {
|
|
625
|
+
applyTextOptions(doc, tb);
|
|
626
|
+
const lineGap = tb.lineGap ?? 4;
|
|
627
|
+
doc.text(tb.text ?? "", x, y, {
|
|
628
|
+
width,
|
|
629
|
+
align: tb.align ?? "left",
|
|
630
|
+
underline: !!tb.underline,
|
|
631
|
+
strike: !!tb.strike,
|
|
632
|
+
link: tb.link,
|
|
633
|
+
lineGap
|
|
634
|
+
});
|
|
635
|
+
};
|
|
636
|
+
var processListBlock = (doc, ctx, styles, block, y, env, ensureSpaceFor) => {
|
|
637
|
+
const items = (block.items ?? []).map(normalizeListItem);
|
|
638
|
+
const mt = block.marginTop ?? 0;
|
|
639
|
+
const mb = block.marginBottom ?? 0;
|
|
640
|
+
const itemGap = block.itemGap ?? DEFAULT_ITEM_GAP;
|
|
641
|
+
const markerGap = block.markerGap ?? DEFAULT_MARKER_GAP;
|
|
642
|
+
const localLeft = block.marginLeft ?? 0;
|
|
643
|
+
const localRight = block.marginRight ?? 0;
|
|
644
|
+
const xLeft = env.marginLeft + localLeft;
|
|
645
|
+
const innerWidth = Math.max(env.innerWidth - localLeft - localRight, 1);
|
|
646
|
+
if (!items.length) {
|
|
647
|
+
const endY2 = (y ?? ctx.currentY) + mt + mb;
|
|
648
|
+
if (y === null) ctx.currentY = endY2;
|
|
649
|
+
return endY2;
|
|
650
|
+
}
|
|
651
|
+
const firstResolved = resolveTextBlock(styles, buildTextBlock(block, items[0]));
|
|
652
|
+
const markerWidth = computeMarkerWidth(doc, block, items, firstResolved);
|
|
653
|
+
const textX = xLeft + markerWidth + markerGap;
|
|
654
|
+
const textWidth = Math.max(innerWidth - markerWidth - markerGap, 1);
|
|
655
|
+
if (y !== null) {
|
|
656
|
+
let drawY = y + mt;
|
|
657
|
+
for (let i = 0; i < items.length; i++) {
|
|
658
|
+
if (i > 0) drawY += itemGap;
|
|
659
|
+
const tb = resolveTextBlock(styles, buildTextBlock(block, items[i]));
|
|
660
|
+
const marker = getMarker(block, i);
|
|
661
|
+
const markerTb = { ...tb, text: marker, underline: false, strike: false, link: void 0 };
|
|
662
|
+
const itemHeight = measureItemHeight(doc, block, items[i], i, markerWidth, textWidth, styles);
|
|
663
|
+
drawListText(doc, markerTb, xLeft, drawY, markerWidth);
|
|
664
|
+
drawListText(doc, tb, textX, drawY, textWidth);
|
|
665
|
+
drawY += itemHeight;
|
|
666
|
+
}
|
|
667
|
+
return drawY + mb;
|
|
668
|
+
}
|
|
669
|
+
for (let i = 0; i < items.length; i++) {
|
|
670
|
+
const leading = i === 0 ? mt : itemGap;
|
|
671
|
+
const itemHeight = measureItemHeight(doc, block, items[i], i, markerWidth, textWidth, styles);
|
|
672
|
+
ensureSpaceFor(leading + itemHeight, env);
|
|
673
|
+
const drawY = ctx.currentY + leading;
|
|
674
|
+
const tb = resolveTextBlock(styles, buildTextBlock(block, items[i]));
|
|
675
|
+
const marker = getMarker(block, i);
|
|
676
|
+
const markerTb = { ...tb, text: marker, underline: false, strike: false, link: void 0 };
|
|
677
|
+
drawListText(doc, markerTb, xLeft, drawY, markerWidth);
|
|
678
|
+
drawListText(doc, tb, textX, drawY, textWidth);
|
|
679
|
+
ctx.currentY = drawY + itemHeight;
|
|
680
|
+
}
|
|
681
|
+
const endY = ctx.currentY + mb;
|
|
682
|
+
ctx.currentY = endY;
|
|
683
|
+
return endY;
|
|
684
|
+
};
|
|
685
|
+
|
|
494
686
|
// src/renderer-engine/blocks/line.ts
|
|
495
687
|
var processLineBlock = (doc, ctx, block, y, env, ensureSpaceFor) => {
|
|
496
688
|
const localLeft = block.marginLeft ?? 0;
|
|
@@ -499,13 +691,12 @@ var processLineBlock = (doc, ctx, block, y, env, ensureSpaceFor) => {
|
|
|
499
691
|
const width = Math.max(env.innerWidth - localLeft - localRight, 1);
|
|
500
692
|
const mt = block.marginTop ?? 0;
|
|
501
693
|
const mb = block.marginBottom ?? 0;
|
|
502
|
-
const baseY = y ?? ctx.currentY;
|
|
503
|
-
const startY = baseY + mt;
|
|
504
694
|
const lineWidth = block.lineWidth ?? 1;
|
|
505
695
|
const heightNeeded = mt + lineWidth + mb;
|
|
506
696
|
if (y === null) {
|
|
507
697
|
ensureSpaceFor(heightNeeded, env);
|
|
508
698
|
}
|
|
699
|
+
const startY = (y ?? ctx.currentY) + mt;
|
|
509
700
|
doc.save();
|
|
510
701
|
if (block.color) {
|
|
511
702
|
doc.strokeColor(block.color);
|
|
@@ -518,7 +709,99 @@ var processLineBlock = (doc, ctx, block, y, env, ensureSpaceFor) => {
|
|
|
518
709
|
return newY;
|
|
519
710
|
};
|
|
520
711
|
|
|
712
|
+
// src/renderer-engine/blocks/shape.ts
|
|
713
|
+
var processShapeBlock = (doc, ctx, block, y, env, ensureSpaceFor) => {
|
|
714
|
+
const mt = block.marginTop ?? 0;
|
|
715
|
+
const mb = block.marginBottom ?? 0;
|
|
716
|
+
const ml = block.marginLeft ?? 0;
|
|
717
|
+
const mr = block.marginRight ?? 0;
|
|
718
|
+
const lineWidth = block.lineWidth ?? 1;
|
|
719
|
+
const width = block.width ?? Math.max(env.innerWidth - ml - mr, 1);
|
|
720
|
+
const height = block.height ?? lineWidth;
|
|
721
|
+
const heightNeeded = mt + height + mb;
|
|
722
|
+
if (y === null) {
|
|
723
|
+
ensureSpaceFor(heightNeeded, env);
|
|
724
|
+
}
|
|
725
|
+
const startY = (y ?? ctx.currentY) + mt;
|
|
726
|
+
const availableWidth = Math.max(env.innerWidth - ml - mr, 1);
|
|
727
|
+
let x = env.marginLeft + ml;
|
|
728
|
+
if (block.align === "center") {
|
|
729
|
+
x = env.marginLeft + ml + (availableWidth - width) / 2;
|
|
730
|
+
} else if (block.align === "right") {
|
|
731
|
+
x = env.marginLeft + ml + availableWidth - width;
|
|
732
|
+
}
|
|
733
|
+
const drawY = startY;
|
|
734
|
+
doc.save();
|
|
735
|
+
if (typeof block.opacity === "number") {
|
|
736
|
+
doc.opacity(block.opacity);
|
|
737
|
+
}
|
|
738
|
+
doc.lineWidth(lineWidth);
|
|
739
|
+
if (block.strokeColor) {
|
|
740
|
+
doc.strokeColor(block.strokeColor);
|
|
741
|
+
}
|
|
742
|
+
if (block.fillColor) {
|
|
743
|
+
doc.fillColor(block.fillColor);
|
|
744
|
+
}
|
|
745
|
+
switch (block.shape) {
|
|
746
|
+
case "rect":
|
|
747
|
+
doc.rect(x, drawY, width, height);
|
|
748
|
+
break;
|
|
749
|
+
case "roundedRect":
|
|
750
|
+
doc.roundedRect(x, drawY, width, height, block.radius ?? 6);
|
|
751
|
+
break;
|
|
752
|
+
case "circle": {
|
|
753
|
+
const radius = block.radius ?? Math.min(width, height) / 2;
|
|
754
|
+
doc.circle(x + radius, drawY + radius, radius);
|
|
755
|
+
break;
|
|
756
|
+
}
|
|
757
|
+
case "ellipse":
|
|
758
|
+
doc.ellipse(x + width / 2, drawY + height / 2, width / 2, height / 2);
|
|
759
|
+
break;
|
|
760
|
+
case "line":
|
|
761
|
+
doc.moveTo(x, drawY).lineTo(x + width, drawY);
|
|
762
|
+
break;
|
|
763
|
+
case "polygon":
|
|
764
|
+
if (block.points?.length) {
|
|
765
|
+
const [first, ...rest] = block.points;
|
|
766
|
+
doc.moveTo(x + first.x, drawY + first.y);
|
|
767
|
+
rest.forEach((point) => {
|
|
768
|
+
doc.lineTo(x + point.x, drawY + point.y);
|
|
769
|
+
});
|
|
770
|
+
doc.closePath();
|
|
771
|
+
}
|
|
772
|
+
break;
|
|
773
|
+
case "path":
|
|
774
|
+
if (block.path) {
|
|
775
|
+
const safePath = block.path.trim().replace(/[\n\r\t]+/g, " ").replace(/\s+/g, " ");
|
|
776
|
+
if (safePath.includes("undefined") || safePath.includes("NaN")) {
|
|
777
|
+
throw new Error(`Invalid shape path: ${safePath}`);
|
|
778
|
+
}
|
|
779
|
+
doc.translate(x, drawY);
|
|
780
|
+
doc.path(safePath);
|
|
781
|
+
}
|
|
782
|
+
break;
|
|
783
|
+
}
|
|
784
|
+
if (block.fillColor && block.strokeColor) {
|
|
785
|
+
doc.fillAndStroke(block.fillColor, block.strokeColor);
|
|
786
|
+
} else if (block.fillColor) {
|
|
787
|
+
doc.fill(block.fillColor);
|
|
788
|
+
} else {
|
|
789
|
+
doc.stroke();
|
|
790
|
+
}
|
|
791
|
+
doc.restore();
|
|
792
|
+
const newY = startY + height + mb;
|
|
793
|
+
if (y === null) {
|
|
794
|
+
ctx.currentY = newY;
|
|
795
|
+
}
|
|
796
|
+
return newY;
|
|
797
|
+
};
|
|
798
|
+
|
|
521
799
|
// src/renderer-engine/blocks/table.ts
|
|
800
|
+
var shouldSkipHeaderOnlyTable = (table, rows) => {
|
|
801
|
+
const headerRows = table.headerRows ?? 0;
|
|
802
|
+
if (headerRows <= 0) return false;
|
|
803
|
+
return rows.length <= headerRows;
|
|
804
|
+
};
|
|
522
805
|
var normalizeSpan = (value) => {
|
|
523
806
|
if (!value || value < 1) return 1;
|
|
524
807
|
return Math.floor(value);
|
|
@@ -589,6 +872,7 @@ var toTableCell = (rawBlock) => {
|
|
|
589
872
|
const tableCellInput = isTableCellInput(rawBlock) ? rawBlock : void 0;
|
|
590
873
|
return {
|
|
591
874
|
text: rawBlock.text,
|
|
875
|
+
blocks: tableCellInput?.blocks,
|
|
592
876
|
italic: rawBlock.italic,
|
|
593
877
|
underline: rawBlock.underline,
|
|
594
878
|
link: rawBlock.link,
|
|
@@ -605,7 +889,8 @@ var toTableCell = (rawBlock) => {
|
|
|
605
889
|
paddingTop: tableCellInput?.paddingTop,
|
|
606
890
|
paddingRight: tableCellInput?.paddingRight,
|
|
607
891
|
paddingBottom: tableCellInput?.paddingBottom,
|
|
608
|
-
paddingLeft: tableCellInput?.paddingLeft
|
|
892
|
+
paddingLeft: tableCellInput?.paddingLeft,
|
|
893
|
+
border: tableCellInput?.border
|
|
609
894
|
};
|
|
610
895
|
};
|
|
611
896
|
var resolvePathValue = (obj, dottedPath) => {
|
|
@@ -628,7 +913,7 @@ var interpolateCellText = (text, item, rowIndex) => {
|
|
|
628
913
|
};
|
|
629
914
|
var applyIterableData = (cell, item, rowIndex) => ({
|
|
630
915
|
...cell,
|
|
631
|
-
text: interpolateCellText(cell.text, item, rowIndex)
|
|
916
|
+
text: cell.text !== void 0 ? interpolateCellText(cell.text, item, rowIndex) : void 0
|
|
632
917
|
});
|
|
633
918
|
var expandIterableRow = (table, bodyDef) => {
|
|
634
919
|
const templateRow = bodyDef.content.map(toTableCell).filter((cell) => cell !== null);
|
|
@@ -658,11 +943,22 @@ var normalizeTableRows = (table) => {
|
|
|
658
943
|
}
|
|
659
944
|
return rows;
|
|
660
945
|
};
|
|
661
|
-
var
|
|
946
|
+
var measureCellHeight = (doc, cell, textWidth, paddingTop, paddingBottom, measureBlockHeightFn) => {
|
|
947
|
+
if (cell.blocks?.length && measureBlockHeightFn) {
|
|
948
|
+
const cellEnv = { marginLeft: 0, innerWidth: textWidth, allowPageBreak: false };
|
|
949
|
+
const contentH = cell.blocks.filter((b) => b.visible !== false).reduce((acc, b) => acc + measureBlockHeightFn(b, cellEnv), 0);
|
|
950
|
+
return contentH + paddingTop + paddingBottom;
|
|
951
|
+
}
|
|
952
|
+
return doc.heightOfString(cell.text ?? "", { width: textWidth }) + paddingTop + paddingBottom;
|
|
953
|
+
};
|
|
954
|
+
var measureTableHeight = (doc, table, env, styles, computeColumnPixelWidths2, measureBlockHeightFn) => {
|
|
662
955
|
const localLeft = table.marginLeft ?? 0;
|
|
663
956
|
const localRight = table.marginRight ?? 0;
|
|
664
957
|
const width = Math.max(env.innerWidth - localLeft - localRight, 1);
|
|
665
958
|
const rows = normalizeTableRows(table);
|
|
959
|
+
if (shouldSkipHeaderOnlyTable(table, rows)) {
|
|
960
|
+
return 0;
|
|
961
|
+
}
|
|
666
962
|
const totalCols = table.widths.length;
|
|
667
963
|
const colWidths = computeColumnPixelWidths2(table.widths, width);
|
|
668
964
|
const rowHeights = [];
|
|
@@ -681,9 +977,11 @@ var measureTableHeight = (doc, table, env, styles, computeColumnPixelWidths2) =>
|
|
|
681
977
|
const paddingBottom = cell.paddingBottom ?? 2;
|
|
682
978
|
const colW = getPlacedCellWidth(colWidths, startCol, colSpan);
|
|
683
979
|
const textWidth = Math.max(colW - paddingLeft - paddingRight, 1);
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
980
|
+
if (!cell.blocks?.length) {
|
|
981
|
+
doc.font(getCellFontName(cell));
|
|
982
|
+
doc.fontSize(cell.fontSize ?? 10);
|
|
983
|
+
}
|
|
984
|
+
const h = measureCellHeight(doc, cell, textWidth, paddingTop, paddingBottom, measureBlockHeightFn);
|
|
687
985
|
rowHeight = Math.max(rowHeight, h);
|
|
688
986
|
});
|
|
689
987
|
rowHeights.push(rowHeight);
|
|
@@ -700,9 +998,11 @@ var measureTableHeight = (doc, table, env, styles, computeColumnPixelWidths2) =>
|
|
|
700
998
|
const paddingBottom = cell.paddingBottom ?? 2;
|
|
701
999
|
const colW = getPlacedCellWidth(colWidths, startCol, colSpan);
|
|
702
1000
|
const textWidth = Math.max(colW - paddingLeft - paddingRight, 1);
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
1001
|
+
if (!cell.blocks?.length) {
|
|
1002
|
+
doc.font(getCellFontName(cell));
|
|
1003
|
+
doc.fontSize(cell.fontSize ?? 10);
|
|
1004
|
+
}
|
|
1005
|
+
const neededHeight = measureCellHeight(doc, cell, textWidth, paddingTop, paddingBottom, measureBlockHeightFn);
|
|
706
1006
|
const currentGroupHeight = getRowSpanGroupHeight(rowHeights, rowIndex, rowSpan);
|
|
707
1007
|
if (neededHeight > currentGroupHeight) {
|
|
708
1008
|
const deficit = neededHeight - currentGroupHeight;
|
|
@@ -717,7 +1017,7 @@ var measureTableHeight = (doc, table, env, styles, computeColumnPixelWidths2) =>
|
|
|
717
1017
|
totalHeight += table.marginBottom ?? 0;
|
|
718
1018
|
return totalHeight;
|
|
719
1019
|
};
|
|
720
|
-
var processTableBlock = (doc, ctx, styles, table, y, env, computeColumnPixelWidths2, bottomLimitForContent, finishPage2) => {
|
|
1020
|
+
var processTableBlock = (doc, ctx, styles, table, y, env, computeColumnPixelWidths2, bottomLimitForContent, finishPage2, renderBlockFn, measureBlockHeightFn) => {
|
|
721
1021
|
const localLeft = table.marginLeft ?? 0;
|
|
722
1022
|
const localRight = table.marginRight ?? 0;
|
|
723
1023
|
const baseLeft = env.marginLeft + localLeft;
|
|
@@ -733,9 +1033,11 @@ var processTableBlock = (doc, ctx, styles, table, y, env, computeColumnPixelWidt
|
|
|
733
1033
|
hLineColor: "#ccc",
|
|
734
1034
|
vLineColor: "#ccc"
|
|
735
1035
|
};
|
|
736
|
-
const borderAll = layout.border !== "none";
|
|
737
1036
|
const headerRows = table.headerRows ?? 0;
|
|
738
1037
|
const rows = normalizeTableRows(table);
|
|
1038
|
+
if (shouldSkipHeaderOnlyTable(table, rows)) {
|
|
1039
|
+
return baseY;
|
|
1040
|
+
}
|
|
739
1041
|
const buildPlacementAndHeights = (rows2) => {
|
|
740
1042
|
const placedRows = [];
|
|
741
1043
|
const rowHeights = [];
|
|
@@ -753,9 +1055,11 @@ var processTableBlock = (doc, ctx, styles, table, y, env, computeColumnPixelWidt
|
|
|
753
1055
|
const paddingBottom = cell.paddingBottom ?? 2;
|
|
754
1056
|
const colW = getPlacedCellWidth(colWidths, startCol, colSpan);
|
|
755
1057
|
const textWidth = Math.max(colW - paddingLeft - paddingRight, 1);
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
1058
|
+
if (!cell.blocks?.length) {
|
|
1059
|
+
doc.font(getCellFontName(cell));
|
|
1060
|
+
doc.fontSize(cell.fontSize ?? 10);
|
|
1061
|
+
}
|
|
1062
|
+
const h = measureCellHeight(doc, cell, textWidth, paddingTop, paddingBottom, measureBlockHeightFn);
|
|
759
1063
|
rowHeight = Math.max(rowHeight, h);
|
|
760
1064
|
});
|
|
761
1065
|
rowHeights.push(rowHeight);
|
|
@@ -772,9 +1076,11 @@ var processTableBlock = (doc, ctx, styles, table, y, env, computeColumnPixelWidt
|
|
|
772
1076
|
const paddingBottom = cell.paddingBottom ?? 2;
|
|
773
1077
|
const colW = getPlacedCellWidth(colWidths, startCol, colSpan);
|
|
774
1078
|
const textWidth = Math.max(colW - paddingLeft - paddingRight, 1);
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
1079
|
+
if (!cell.blocks?.length) {
|
|
1080
|
+
doc.font(getCellFontName(cell));
|
|
1081
|
+
doc.fontSize(cell.fontSize ?? 10);
|
|
1082
|
+
}
|
|
1083
|
+
const neededHeight = measureCellHeight(doc, cell, textWidth, paddingTop, paddingBottom, measureBlockHeightFn);
|
|
778
1084
|
const currentGroupHeight = getRowSpanGroupHeight(rowHeights, rowIndex, rowSpan);
|
|
779
1085
|
if (neededHeight > currentGroupHeight) {
|
|
780
1086
|
const deficit = neededHeight - currentGroupHeight;
|
|
@@ -797,47 +1103,60 @@ var processTableBlock = (doc, ctx, styles, table, y, env, computeColumnPixelWidt
|
|
|
797
1103
|
const paddingTop = cell.paddingTop ?? 2;
|
|
798
1104
|
const paddingBottom = cell.paddingBottom ?? 2;
|
|
799
1105
|
doc.save();
|
|
800
|
-
|
|
801
|
-
|
|
1106
|
+
const columnStyle = table.layout?.columnStyles?.[startCol];
|
|
1107
|
+
const rowStyle = table.layout?.rowStyles?.[rowIndex];
|
|
1108
|
+
const fillColor = cell.fillColor ?? rowStyle?.fillColor ?? columnStyle?.fillColor;
|
|
1109
|
+
if (fillColor) {
|
|
1110
|
+
doc.rect(x, rowTop2, colW, drawHeight).fillOpacity(1).fill(fillColor);
|
|
802
1111
|
doc.fillOpacity(1);
|
|
803
1112
|
}
|
|
804
|
-
doc.font(getCellFontName(cell));
|
|
805
|
-
doc.fontSize(fontSize);
|
|
806
|
-
doc.fillColor(cell.color ?? "black");
|
|
807
|
-
const align = cell.align ?? "left";
|
|
808
1113
|
const textWidth = Math.max(colW - paddingLeft - paddingRight, 1);
|
|
809
|
-
const
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
1114
|
+
const textY = rowTop2 + paddingTop;
|
|
1115
|
+
if (cell.blocks?.length && renderBlockFn) {
|
|
1116
|
+
const cellEnv = {
|
|
1117
|
+
marginLeft: x + paddingLeft,
|
|
1118
|
+
innerWidth: textWidth,
|
|
1119
|
+
allowPageBreak: false
|
|
1120
|
+
};
|
|
1121
|
+
const savedY = ctx.currentY;
|
|
1122
|
+
let contentY = textY;
|
|
1123
|
+
for (const block of cell.blocks) {
|
|
1124
|
+
if (!block || block.visible === false) continue;
|
|
1125
|
+
if (block.type === "signature" || block.type === "pageBreak") continue;
|
|
1126
|
+
contentY = renderBlockFn(block, contentY, cellEnv);
|
|
1127
|
+
}
|
|
1128
|
+
ctx.currentY = savedY;
|
|
1129
|
+
} else {
|
|
1130
|
+
doc.font(getCellFontName(cell));
|
|
1131
|
+
doc.fontSize(fontSize);
|
|
1132
|
+
doc.fillColor(cell.color ?? "black");
|
|
1133
|
+
const align = cell.align ?? "left";
|
|
1134
|
+
const textHeight = doc.heightOfString(cell.text ?? "", { width: textWidth });
|
|
1135
|
+
let paintY = textY;
|
|
1136
|
+
if (isHeaderRow) {
|
|
1137
|
+
const available = Math.max(drawHeight - paddingTop - paddingBottom, 0);
|
|
1138
|
+
const offset = Math.max((available - textHeight) / 2, 0);
|
|
1139
|
+
paintY = rowTop2 + paddingTop + offset;
|
|
1140
|
+
}
|
|
1141
|
+
doc.text(cell.text ?? "", x + paddingLeft, paintY, {
|
|
1142
|
+
width: textWidth,
|
|
1143
|
+
align,
|
|
1144
|
+
underline: !!cell.underline,
|
|
1145
|
+
strike: !!cell.strike,
|
|
1146
|
+
link: cell.link
|
|
1147
|
+
});
|
|
815
1148
|
}
|
|
816
|
-
doc.text(cell.text, x + paddingLeft, textY, {
|
|
817
|
-
width: textWidth,
|
|
818
|
-
align,
|
|
819
|
-
underline: !!cell.underline,
|
|
820
|
-
strike: !!cell.strike,
|
|
821
|
-
link: cell.link
|
|
822
|
-
});
|
|
823
1149
|
doc.restore();
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
doc.moveTo(x, bottomY).lineTo(x + colW, bottomY).stroke();
|
|
833
|
-
doc.restore();
|
|
834
|
-
doc.save();
|
|
835
|
-
doc.lineWidth(0.5);
|
|
836
|
-
doc.strokeColor(layout.vLineColor ?? "#ccc");
|
|
837
|
-
doc.moveTo(x, rowTop2).lineTo(x, bottomY).stroke();
|
|
838
|
-
doc.moveTo(x + colW, rowTop2).lineTo(x + colW, bottomY).stroke();
|
|
839
|
-
doc.restore();
|
|
1150
|
+
const effectiveBorder = getEffectiveCellBorder({
|
|
1151
|
+
table,
|
|
1152
|
+
cell,
|
|
1153
|
+
rowIndex,
|
|
1154
|
+
startCol
|
|
1155
|
+
});
|
|
1156
|
+
if (!drawTopBorder) {
|
|
1157
|
+
effectiveBorder.top.visible = false;
|
|
840
1158
|
}
|
|
1159
|
+
drawCellBorder(doc, effectiveBorder, x, rowTop2, colW, drawHeight);
|
|
841
1160
|
});
|
|
842
1161
|
return rowTop2 + rowHeight;
|
|
843
1162
|
};
|
|
@@ -877,16 +1196,133 @@ var processTableBlock = (doc, ctx, styles, table, y, env, computeColumnPixelWidt
|
|
|
877
1196
|
if (y === null) ctx.currentY = newY;
|
|
878
1197
|
return newY;
|
|
879
1198
|
};
|
|
1199
|
+
var SIDES = ["top", "right", "bottom", "left"];
|
|
1200
|
+
var DEFAULT_BORDER_COLOR = "#ccc";
|
|
1201
|
+
var DEFAULT_BORDER_WIDTH = 0.5;
|
|
1202
|
+
var isBorderStyleObject = (value) => {
|
|
1203
|
+
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
1204
|
+
};
|
|
1205
|
+
var normalizeOneSideBorder = (value, fallback) => {
|
|
1206
|
+
if (value === void 0) return fallback;
|
|
1207
|
+
if (typeof value === "boolean") {
|
|
1208
|
+
return {
|
|
1209
|
+
...fallback,
|
|
1210
|
+
visible: value
|
|
1211
|
+
};
|
|
1212
|
+
}
|
|
1213
|
+
return {
|
|
1214
|
+
visible: value.visible ?? fallback.visible,
|
|
1215
|
+
color: value.color ?? fallback.color,
|
|
1216
|
+
width: value.width ?? fallback.width,
|
|
1217
|
+
dash: value.dash ?? fallback.dash
|
|
1218
|
+
};
|
|
1219
|
+
};
|
|
1220
|
+
var normalizeCellBorder = (input, fallback) => {
|
|
1221
|
+
if (input === void 0) return fallback;
|
|
1222
|
+
if (typeof input === "boolean") {
|
|
1223
|
+
return SIDES.reduce((acc, side) => {
|
|
1224
|
+
acc[side] = {
|
|
1225
|
+
...fallback[side],
|
|
1226
|
+
visible: input
|
|
1227
|
+
};
|
|
1228
|
+
return acc;
|
|
1229
|
+
}, {});
|
|
1230
|
+
}
|
|
1231
|
+
if (isBorderStyleObject(input) && ("visible" in input || "color" in input || "width" in input || "dash" in input)) {
|
|
1232
|
+
return SIDES.reduce((acc, side) => {
|
|
1233
|
+
acc[side] = normalizeOneSideBorder(input, fallback[side]);
|
|
1234
|
+
return acc;
|
|
1235
|
+
}, {});
|
|
1236
|
+
}
|
|
1237
|
+
const sideInput = input;
|
|
1238
|
+
return SIDES.reduce((acc, side) => {
|
|
1239
|
+
acc[side] = normalizeOneSideBorder(sideInput[side], fallback[side]);
|
|
1240
|
+
return acc;
|
|
1241
|
+
}, {});
|
|
1242
|
+
};
|
|
1243
|
+
var createDefaultTableBorder = (layout) => {
|
|
1244
|
+
const visible = layout?.border !== "none";
|
|
1245
|
+
const hColor = layout?.hLineColor ?? layout?.borderColor ?? DEFAULT_BORDER_COLOR;
|
|
1246
|
+
const vColor = layout?.vLineColor ?? layout?.borderColor ?? DEFAULT_BORDER_COLOR;
|
|
1247
|
+
const width = layout?.borderWidth ?? DEFAULT_BORDER_WIDTH;
|
|
1248
|
+
return {
|
|
1249
|
+
top: {
|
|
1250
|
+
visible,
|
|
1251
|
+
color: hColor,
|
|
1252
|
+
width,
|
|
1253
|
+
dash: layout?.borderDash
|
|
1254
|
+
},
|
|
1255
|
+
bottom: {
|
|
1256
|
+
visible,
|
|
1257
|
+
color: hColor,
|
|
1258
|
+
width,
|
|
1259
|
+
dash: layout?.borderDash
|
|
1260
|
+
},
|
|
1261
|
+
left: {
|
|
1262
|
+
visible,
|
|
1263
|
+
color: vColor,
|
|
1264
|
+
width,
|
|
1265
|
+
dash: layout?.borderDash
|
|
1266
|
+
},
|
|
1267
|
+
right: {
|
|
1268
|
+
visible,
|
|
1269
|
+
color: vColor,
|
|
1270
|
+
width,
|
|
1271
|
+
dash: layout?.borderDash
|
|
1272
|
+
}
|
|
1273
|
+
};
|
|
1274
|
+
};
|
|
1275
|
+
var getEffectiveCellBorder = (args) => {
|
|
1276
|
+
const { table, cell, rowIndex, startCol } = args;
|
|
1277
|
+
const tableBorder = createDefaultTableBorder(table.layout);
|
|
1278
|
+
const columnBorder = normalizeCellBorder(table.layout?.columnStyles?.[startCol]?.border, tableBorder);
|
|
1279
|
+
const rowBorder = normalizeCellBorder(table.layout?.rowStyles?.[rowIndex]?.border, columnBorder);
|
|
1280
|
+
return normalizeCellBorder(cell.border, rowBorder);
|
|
1281
|
+
};
|
|
1282
|
+
var drawBorderSide = (doc, side, border, x, y, width, height) => {
|
|
1283
|
+
if (!border.visible || border.width <= 0) return;
|
|
1284
|
+
doc.save();
|
|
1285
|
+
doc.lineWidth(border.width);
|
|
1286
|
+
doc.strokeColor(border.color);
|
|
1287
|
+
if (border.dash?.length) {
|
|
1288
|
+
doc.dash(border.dash[0], {
|
|
1289
|
+
space: border.dash[1] ?? border.dash[0]
|
|
1290
|
+
});
|
|
1291
|
+
} else {
|
|
1292
|
+
doc.undash();
|
|
1293
|
+
}
|
|
1294
|
+
switch (side) {
|
|
1295
|
+
case "top":
|
|
1296
|
+
doc.moveTo(x, y).lineTo(x + width, y).stroke();
|
|
1297
|
+
break;
|
|
1298
|
+
case "right":
|
|
1299
|
+
doc.moveTo(x + width, y).lineTo(x + width, y + height).stroke();
|
|
1300
|
+
break;
|
|
1301
|
+
case "bottom":
|
|
1302
|
+
doc.moveTo(x, y + height).lineTo(x + width, y + height).stroke();
|
|
1303
|
+
break;
|
|
1304
|
+
case "left":
|
|
1305
|
+
doc.moveTo(x, y).lineTo(x, y + height).stroke();
|
|
1306
|
+
break;
|
|
1307
|
+
}
|
|
1308
|
+
doc.restore();
|
|
1309
|
+
};
|
|
1310
|
+
var drawCellBorder = (doc, border, x, y, width, height) => {
|
|
1311
|
+
drawBorderSide(doc, "top", border.top, x, y, width, height);
|
|
1312
|
+
drawBorderSide(doc, "right", border.right, x, y, width, height);
|
|
1313
|
+
drawBorderSide(doc, "bottom", border.bottom, x, y, width, height);
|
|
1314
|
+
drawBorderSide(doc, "left", border.left, x, y, width, height);
|
|
1315
|
+
};
|
|
880
1316
|
|
|
881
1317
|
// src/renderer-engine/blocks/text.ts
|
|
882
1318
|
var processTextBlock = (doc, ctx, styles, block, y, env, ensureSpaceFor) => {
|
|
883
1319
|
const tb = resolveTextBlock(styles, block);
|
|
1320
|
+
const mt = tb.marginTop ?? 0;
|
|
1321
|
+
const mb = tb.marginBottom ?? 0;
|
|
884
1322
|
const localLeft = tb.marginLeft ?? 0;
|
|
885
1323
|
const localRight = tb.marginRight ?? 0;
|
|
886
1324
|
const xLeft = env.marginLeft + localLeft;
|
|
887
1325
|
const width = Math.max(env.innerWidth - localLeft - localRight, 1);
|
|
888
|
-
const baseY = y ?? ctx.currentY;
|
|
889
|
-
const startY = baseY;
|
|
890
1326
|
doc.fontSize(tb.fontSize ?? 10);
|
|
891
1327
|
const isBold = !!tb.bold;
|
|
892
1328
|
const isItalic = !!tb.italic;
|
|
@@ -900,11 +1336,12 @@ var processTextBlock = (doc, ctx, styles, block, y, env, ensureSpaceFor) => {
|
|
|
900
1336
|
doc.font(fontName);
|
|
901
1337
|
if (tb.color) doc.fillColor(tb.color);
|
|
902
1338
|
else doc.fillColor("black");
|
|
903
|
-
const
|
|
1339
|
+
const lineGap = tb.lineGap ?? 4;
|
|
1340
|
+
const textHeight = doc.heightOfString(tb.text, { width, lineGap });
|
|
904
1341
|
if (y === null) {
|
|
905
|
-
|
|
906
|
-
ensureSpaceFor(textHeight + gapCheck, env);
|
|
1342
|
+
ensureSpaceFor(mt + textHeight + lineGap + mb, env);
|
|
907
1343
|
}
|
|
1344
|
+
const startY = (y ?? ctx.currentY) + mt;
|
|
908
1345
|
doc.text(tb.text, xLeft, startY, {
|
|
909
1346
|
width,
|
|
910
1347
|
align: tb.align ?? "left",
|
|
@@ -912,358 +1349,82 @@ var processTextBlock = (doc, ctx, styles, block, y, env, ensureSpaceFor) => {
|
|
|
912
1349
|
strike: !!tb.strike,
|
|
913
1350
|
link: tb.link
|
|
914
1351
|
});
|
|
915
|
-
const
|
|
916
|
-
const newY = startY + textHeight + gap;
|
|
1352
|
+
const newY = doc.y + lineGap + mb;
|
|
917
1353
|
if (y === null) ctx.currentY = newY;
|
|
918
1354
|
return newY;
|
|
919
1355
|
};
|
|
920
1356
|
|
|
921
|
-
// src/renderer-engine/utils/block-renderer.ts
|
|
922
|
-
function createBlockRenderer(deps) {
|
|
923
|
-
const { doc, ctx, styles, computeColumnPixelWidths: computeColumnPixelWidths2, finishPage: finishPage2, processSignatureBlock } = deps;
|
|
924
|
-
const bottomLimitForContent = createBottomLimitForContent(doc, ctx);
|
|
925
|
-
const ensureSpaceFor = createEnsureSpaceFor(ctx, bottomLimitForContent, finishPage2);
|
|
926
|
-
const measureBlockHeight = createMeasureBlockHeight({
|
|
927
|
-
doc,
|
|
928
|
-
styles,
|
|
929
|
-
computeColumnPixelWidths: computeColumnPixelWidths2
|
|
930
|
-
});
|
|
931
|
-
const renderBlock = (block, y, env) => {
|
|
932
|
-
if (block.visible === false) {
|
|
933
|
-
return y ?? ctx.currentY;
|
|
934
|
-
}
|
|
935
|
-
switch (block.type) {
|
|
936
|
-
case "text":
|
|
937
|
-
return processTextBlock(doc, ctx, styles, block, y, env, ensureSpaceFor);
|
|
938
|
-
case "image":
|
|
939
|
-
return processImageBlock(doc, ctx, block, y, env, ensureSpaceFor);
|
|
940
|
-
case "qr": {
|
|
941
|
-
const qb = block;
|
|
942
|
-
const imageLike = {
|
|
943
|
-
type: "image",
|
|
944
|
-
src: qb.src,
|
|
945
|
-
width: qb.size,
|
|
946
|
-
height: qb.size,
|
|
947
|
-
align: qb.align,
|
|
948
|
-
marginTop: qb.marginTop,
|
|
949
|
-
marginBottom: qb.marginBottom,
|
|
950
|
-
marginLeft: qb.marginLeft,
|
|
951
|
-
marginRight: qb.marginRight
|
|
952
|
-
};
|
|
953
|
-
return processImageBlock(doc, ctx, imageLike, y, env, ensureSpaceFor);
|
|
954
|
-
}
|
|
955
|
-
case "barcode":
|
|
956
|
-
return processBarcodeBlock(doc, ctx, block, y, env, ensureSpaceFor);
|
|
957
|
-
case "line":
|
|
958
|
-
return processLineBlock(doc, ctx, block, y, env, ensureSpaceFor);
|
|
959
|
-
case "table":
|
|
960
|
-
return processTableBlock(
|
|
961
|
-
doc,
|
|
962
|
-
ctx,
|
|
963
|
-
styles,
|
|
964
|
-
block,
|
|
965
|
-
y,
|
|
966
|
-
env,
|
|
967
|
-
computeColumnPixelWidths2,
|
|
968
|
-
bottomLimitForContent,
|
|
969
|
-
finishPage2
|
|
970
|
-
);
|
|
971
|
-
case "columns":
|
|
972
|
-
return processColumnsBlock(
|
|
973
|
-
ctx,
|
|
974
|
-
block,
|
|
975
|
-
y,
|
|
976
|
-
env,
|
|
977
|
-
computeColumnPixelWidths2,
|
|
978
|
-
renderBlock,
|
|
979
|
-
ensureSpaceFor,
|
|
980
|
-
measureBlockHeight
|
|
981
|
-
);
|
|
982
|
-
case "keyValueGrid":
|
|
983
|
-
return processKeyValueGridBlock(
|
|
984
|
-
doc,
|
|
985
|
-
ctx,
|
|
986
|
-
styles,
|
|
987
|
-
block,
|
|
988
|
-
y,
|
|
989
|
-
env,
|
|
990
|
-
computeColumnPixelWidths2,
|
|
991
|
-
ensureSpaceFor
|
|
992
|
-
);
|
|
993
|
-
case "signature":
|
|
994
|
-
if (!env.allowPageBreak) {
|
|
995
|
-
throw new PdfEngineError({
|
|
996
|
-
code: "PDF_ERROR_SIGNATURE_NOT_IN_MAIN_FLOW" /* PDF_ERROR_SIGNATURE_NOT_IN_MAIN_FLOW */,
|
|
997
|
-
message: "Signature block is only allowed in main content flow.",
|
|
998
|
-
statusCode: 400,
|
|
999
|
-
details: { blockType: "signature" }
|
|
1000
|
-
});
|
|
1001
|
-
}
|
|
1002
|
-
if (y !== null) {
|
|
1003
|
-
throw new PdfEngineError({
|
|
1004
|
-
code: "PDF_ERROR_SIGNATURE_EXPLICIT_Y_FORBIDDEN" /* PDF_ERROR_SIGNATURE_EXPLICIT_Y_FORBIDDEN */,
|
|
1005
|
-
message: "Signature block must be part of main flow, not drawn at explicit Y.",
|
|
1006
|
-
statusCode: 400,
|
|
1007
|
-
details: { blockType: "signature", y }
|
|
1008
|
-
});
|
|
1009
|
-
}
|
|
1010
|
-
processSignatureBlock(block);
|
|
1011
|
-
return ctx.currentY;
|
|
1012
|
-
case "pageBreak":
|
|
1013
|
-
if (!env.allowPageBreak || ctx.inFooter) {
|
|
1014
|
-
return y ?? ctx.currentY;
|
|
1015
|
-
}
|
|
1016
|
-
finishPage2(true);
|
|
1017
|
-
return ctx.currentY;
|
|
1018
|
-
default:
|
|
1019
|
-
return ctx.currentY;
|
|
1020
|
-
}
|
|
1021
|
-
};
|
|
1022
|
-
const renderBlockArray = (blocks, startY, env) => {
|
|
1023
|
-
let localY = startY;
|
|
1024
|
-
for (const block of blocks) {
|
|
1025
|
-
if (block.visible === false) {
|
|
1026
|
-
continue;
|
|
1027
|
-
}
|
|
1028
|
-
localY = renderBlock(block, localY, env);
|
|
1029
|
-
}
|
|
1030
|
-
return localY;
|
|
1031
|
-
};
|
|
1032
|
-
return {
|
|
1033
|
-
renderBlock,
|
|
1034
|
-
renderBlockArray
|
|
1035
|
-
};
|
|
1036
|
-
}
|
|
1037
|
-
|
|
1038
|
-
// src/renderer-engine/utils/context.ts
|
|
1039
|
-
function createInitialContext(doc) {
|
|
1040
|
-
return {
|
|
1041
|
-
pageNumber: 1,
|
|
1042
|
-
currentY: doc.page.margins.top,
|
|
1043
|
-
signatureBlock: null,
|
|
1044
|
-
signatureTopY: null,
|
|
1045
|
-
signatureHeight: 0,
|
|
1046
|
-
signaturePlaced: false,
|
|
1047
|
-
afterSignature: false,
|
|
1048
|
-
inFooter: false
|
|
1049
|
-
};
|
|
1050
|
-
}
|
|
1051
|
-
|
|
1052
1357
|
// src/renderer-engine/utils/ensure-space.ts
|
|
1053
|
-
function createEnsureSpaceFor(ctx, bottomLimitForContent, finishPage2) {
|
|
1358
|
+
function createEnsureSpaceFor(ctx, doc, bottomLimitForContent, finishPage2) {
|
|
1054
1359
|
return (heightNeeded, env) => {
|
|
1055
1360
|
if (!env.allowPageBreak || ctx.inFooter) return;
|
|
1056
1361
|
const bottomLimit = bottomLimitForContent();
|
|
1362
|
+
const fullContentHeight = bottomLimit - doc.page.margins.top;
|
|
1363
|
+
if (heightNeeded > fullContentHeight) {
|
|
1364
|
+
console.warn(
|
|
1365
|
+
`[pdf-engine] Block height (${Math.round(heightNeeded)}pt) exceeds page content area (${Math.round(fullContentHeight)}pt). Content will overflow.`
|
|
1366
|
+
);
|
|
1367
|
+
}
|
|
1057
1368
|
if (ctx.currentY + heightNeeded > bottomLimit) {
|
|
1058
1369
|
finishPage2(true);
|
|
1059
1370
|
}
|
|
1060
1371
|
};
|
|
1061
1372
|
}
|
|
1062
1373
|
|
|
1063
|
-
// src/renderer-engine/utils/
|
|
1064
|
-
var
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1374
|
+
// src/renderer-engine/utils/spacing.ts
|
|
1375
|
+
var emptySpacing = () => ({
|
|
1376
|
+
top: 0,
|
|
1377
|
+
right: 0,
|
|
1378
|
+
bottom: 0,
|
|
1379
|
+
left: 0
|
|
1068
1380
|
});
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
if (def.watermark && watermarkUsesLast(mode)) {
|
|
1082
|
-
const isLast = !addNewPage;
|
|
1083
|
-
drawWatermarkForPage(doc, def.watermark, ctx.pageNumber, isLast);
|
|
1381
|
+
var resolveSpacing = (value, overrides) => {
|
|
1382
|
+
const result = emptySpacing();
|
|
1383
|
+
if (typeof value === "number") {
|
|
1384
|
+
result.top = value;
|
|
1385
|
+
result.right = value;
|
|
1386
|
+
result.bottom = value;
|
|
1387
|
+
result.left = value;
|
|
1388
|
+
} else if (value) {
|
|
1389
|
+
result.top = value.top ?? 0;
|
|
1390
|
+
result.right = value.right ?? 0;
|
|
1391
|
+
result.bottom = value.bottom ?? 0;
|
|
1392
|
+
result.left = value.left ?? 0;
|
|
1084
1393
|
}
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
if (addNewPage) {
|
|
1091
|
-
doc.addPage();
|
|
1092
|
-
ctx.pageNumber += 1;
|
|
1093
|
-
startNewPageLayout();
|
|
1094
|
-
}
|
|
1095
|
-
}
|
|
1096
|
-
|
|
1097
|
-
// src/renderer-engine/utils/footer.ts
|
|
1098
|
-
function normalizeFooter(input, ctx, doc) {
|
|
1099
|
-
if (!input) return null;
|
|
1100
|
-
if (typeof input === "function") {
|
|
1101
|
-
const result = input(ctx.pageNumber, {
|
|
1102
|
-
width: doc.page.width,
|
|
1103
|
-
height: doc.page.height
|
|
1104
|
-
});
|
|
1105
|
-
if (!result) return null;
|
|
1106
|
-
return normalizeFooter(result, ctx, doc);
|
|
1107
|
-
}
|
|
1108
|
-
if (input.blocks && Array.isArray(input.blocks)) {
|
|
1109
|
-
const f = input;
|
|
1110
|
-
return {
|
|
1111
|
-
visible: f.visible,
|
|
1112
|
-
blocks: f.blocks,
|
|
1113
|
-
marginTop: f.marginTop,
|
|
1114
|
-
marginBottom: f.marginBottom,
|
|
1115
|
-
marginLeft: f.marginLeft,
|
|
1116
|
-
marginRight: f.marginRight,
|
|
1117
|
-
backgroundColor: f.backgroundColor,
|
|
1118
|
-
backgroundImage: f.backgroundImage
|
|
1119
|
-
};
|
|
1120
|
-
}
|
|
1121
|
-
if (input.type) {
|
|
1122
|
-
return { blocks: [input] };
|
|
1123
|
-
}
|
|
1124
|
-
if (Array.isArray(input)) {
|
|
1125
|
-
return { blocks: input };
|
|
1126
|
-
}
|
|
1127
|
-
return null;
|
|
1128
|
-
}
|
|
1129
|
-
function drawFooter(doc, def, ctx, footerBandHeight, renderBlockArray) {
|
|
1130
|
-
const footerConfig = def.footer;
|
|
1131
|
-
if (!footerConfig) return;
|
|
1132
|
-
const layout = normalizeFooter(footerConfig, ctx, doc);
|
|
1133
|
-
if (!layout || !layout.blocks.length) return;
|
|
1134
|
-
if (layout.visible === false) return;
|
|
1135
|
-
const bandHeight = footerBandHeight;
|
|
1136
|
-
if (!bandHeight) return;
|
|
1137
|
-
const { marginTop = 4, backgroundColor, backgroundImage, blocks } = layout;
|
|
1138
|
-
const footerMarginLeft = layout.marginLeft ?? 0;
|
|
1139
|
-
const footerMarginRight = layout.marginRight ?? 0;
|
|
1140
|
-
const contentWidth = doc.page.width - footerMarginLeft - footerMarginRight;
|
|
1141
|
-
const footerEnv = {
|
|
1142
|
-
marginLeft: footerMarginLeft,
|
|
1143
|
-
innerWidth: contentWidth,
|
|
1144
|
-
allowPageBreak: false
|
|
1145
|
-
};
|
|
1146
|
-
const pageHeight = doc.page.height;
|
|
1147
|
-
const bandTop = pageHeight - bandHeight;
|
|
1148
|
-
if (backgroundColor) {
|
|
1149
|
-
doc.save();
|
|
1150
|
-
doc.rect(0, bandTop, doc.page.width, bandHeight).fill(backgroundColor);
|
|
1151
|
-
doc.restore();
|
|
1152
|
-
}
|
|
1153
|
-
if (backgroundImage) {
|
|
1154
|
-
try {
|
|
1155
|
-
doc.image(backgroundImage, 0, bandTop, {
|
|
1156
|
-
width: doc.page.width,
|
|
1157
|
-
height: bandHeight
|
|
1158
|
-
});
|
|
1159
|
-
} catch (e) {
|
|
1160
|
-
console.warn("Failed to load footer background image:", e);
|
|
1161
|
-
}
|
|
1162
|
-
}
|
|
1163
|
-
doc.save();
|
|
1164
|
-
doc.rect(footerMarginLeft, bandTop, contentWidth, bandHeight).clip();
|
|
1165
|
-
doc.translate(0, bandTop);
|
|
1166
|
-
ctx.inFooter = true;
|
|
1167
|
-
const localStartY = marginTop;
|
|
1168
|
-
renderBlockArray(blocks, localStartY, footerEnv);
|
|
1169
|
-
ctx.inFooter = false;
|
|
1170
|
-
doc.restore();
|
|
1171
|
-
}
|
|
1172
|
-
|
|
1173
|
-
// src/renderer-engine/utils/header.ts
|
|
1174
|
-
function drawHeader(doc, def, headerBandHeight, header, renderBlockArray) {
|
|
1175
|
-
if (!header || !header.blocks.length) return;
|
|
1176
|
-
if (header.visible === false) return;
|
|
1177
|
-
if (!headerBandHeight) return;
|
|
1178
|
-
const bandTop = 0;
|
|
1179
|
-
const bandHeight = def.margins.top;
|
|
1180
|
-
const headerMarginLeft = header.marginLeft ?? 0;
|
|
1181
|
-
const headerMarginRight = header.marginRight ?? 0;
|
|
1182
|
-
const contentWidth = doc.page.width - headerMarginLeft - headerMarginRight;
|
|
1183
|
-
const headerEnv = {
|
|
1184
|
-
marginLeft: headerMarginLeft,
|
|
1185
|
-
innerWidth: contentWidth,
|
|
1186
|
-
allowPageBreak: false
|
|
1394
|
+
return {
|
|
1395
|
+
top: overrides?.top ?? result.top,
|
|
1396
|
+
right: overrides?.right ?? result.right,
|
|
1397
|
+
bottom: overrides?.bottom ?? result.bottom,
|
|
1398
|
+
left: overrides?.left ?? result.left
|
|
1187
1399
|
};
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
doc.image(header.backgroundImage, 0, bandTop, {
|
|
1196
|
-
width: doc.page.width,
|
|
1197
|
-
height: bandHeight
|
|
1198
|
-
});
|
|
1199
|
-
} catch (e) {
|
|
1200
|
-
console.warn("Failed to load header background image:", e);
|
|
1201
|
-
}
|
|
1202
|
-
}
|
|
1203
|
-
doc.save();
|
|
1204
|
-
doc.rect(headerMarginLeft, bandTop, contentWidth, bandHeight).clip();
|
|
1205
|
-
const startY = bandTop + (header.marginTop ?? 0);
|
|
1206
|
-
renderBlockArray(header.blocks, startY, headerEnv);
|
|
1207
|
-
doc.restore();
|
|
1208
|
-
}
|
|
1209
|
-
|
|
1210
|
-
// src/renderer-engine/utils/image-loader.ts
|
|
1211
|
-
var import_axios = __toESM(require("axios"));
|
|
1212
|
-
async function normalizeImageSrc(src) {
|
|
1213
|
-
if (!src) return src;
|
|
1214
|
-
if (Buffer.isBuffer(src)) return src;
|
|
1215
|
-
if (src.startsWith("http://") || src.startsWith("https://")) {
|
|
1216
|
-
try {
|
|
1217
|
-
const res = await import_axios.default.get(src, { responseType: "arraybuffer" });
|
|
1218
|
-
return Buffer.from(res.data);
|
|
1219
|
-
} catch (e) {
|
|
1220
|
-
throw toPdfEngineError(e, {
|
|
1221
|
-
code: "PDF_ERROR_IMAGE_FETCH_FAILED" /* PDF_ERROR_IMAGE_FETCH_FAILED */,
|
|
1222
|
-
message: "Failed to fetch remote image for PDF.",
|
|
1223
|
-
statusCode: 422,
|
|
1224
|
-
details: { url: src },
|
|
1225
|
-
retryable: false
|
|
1226
|
-
});
|
|
1227
|
-
}
|
|
1228
|
-
}
|
|
1229
|
-
return src;
|
|
1230
|
-
}
|
|
1231
|
-
async function materializeImagesInBlocks(blocks) {
|
|
1232
|
-
const out = [];
|
|
1233
|
-
for (const block of blocks) {
|
|
1234
|
-
if (block.type === "image") {
|
|
1235
|
-
const img = { ...block };
|
|
1236
|
-
img.src = await normalizeImageSrc(img.src);
|
|
1237
|
-
out.push(img);
|
|
1238
|
-
} else if (block.type === "columns") {
|
|
1239
|
-
out.push({
|
|
1240
|
-
...block,
|
|
1241
|
-
columns: await Promise.all(block.columns.map((col) => materializeImagesInBlocks(col)))
|
|
1242
|
-
});
|
|
1243
|
-
} else if (block.type === "signature" && block.blocks) {
|
|
1244
|
-
out.push({
|
|
1245
|
-
...block,
|
|
1246
|
-
blocks: await materializeImagesInBlocks(block.blocks)
|
|
1247
|
-
});
|
|
1248
|
-
} else {
|
|
1249
|
-
out.push(block);
|
|
1250
|
-
}
|
|
1251
|
-
}
|
|
1252
|
-
return out;
|
|
1253
|
-
}
|
|
1254
|
-
|
|
1255
|
-
// src/renderer-engine/utils/layout.ts
|
|
1256
|
-
function computeColumnPixelWidths(widths, totalWidth) {
|
|
1257
|
-
let fixedTotal = 0;
|
|
1258
|
-
let starCount = 0;
|
|
1259
|
-
widths.forEach((w) => {
|
|
1260
|
-
if (w === "*") starCount++;
|
|
1261
|
-
else fixedTotal += w;
|
|
1400
|
+
};
|
|
1401
|
+
var resolveBlockPadding = (block) => {
|
|
1402
|
+
return resolveSpacing(block.padding, {
|
|
1403
|
+
top: block.paddingTop,
|
|
1404
|
+
right: block.paddingRight,
|
|
1405
|
+
bottom: block.paddingBottom,
|
|
1406
|
+
left: block.paddingLeft
|
|
1262
1407
|
});
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
return
|
|
1266
|
-
|
|
1408
|
+
};
|
|
1409
|
+
var resolveHeaderPadding = (header) => {
|
|
1410
|
+
return resolveSpacing(header.padding, {
|
|
1411
|
+
top: header.paddingTop,
|
|
1412
|
+
right: header.paddingRight,
|
|
1413
|
+
bottom: header.paddingBottom,
|
|
1414
|
+
left: header.paddingLeft
|
|
1415
|
+
});
|
|
1416
|
+
};
|
|
1417
|
+
var resolveFooterPadding = (footer) => {
|
|
1418
|
+
return resolveSpacing(footer.padding, {
|
|
1419
|
+
top: footer.paddingTop,
|
|
1420
|
+
right: footer.paddingRight,
|
|
1421
|
+
bottom: footer.paddingBottom,
|
|
1422
|
+
left: footer.paddingLeft
|
|
1423
|
+
});
|
|
1424
|
+
};
|
|
1425
|
+
var hasPadding = (padding) => {
|
|
1426
|
+
return padding.top > 0 || padding.right > 0 || padding.bottom > 0 || padding.left > 0;
|
|
1427
|
+
};
|
|
1267
1428
|
|
|
1268
1429
|
// src/renderer-engine/utils/styles.ts
|
|
1269
1430
|
function mergeStyleDefs(styles, names) {
|
|
@@ -1359,191 +1520,772 @@ var drawStyledText = (doc, tb, x, y, width) => {
|
|
|
1359
1520
|
// src/renderer-engine/utils/measure-block-height.ts
|
|
1360
1521
|
function createMeasureBlockHeight(deps) {
|
|
1361
1522
|
const { doc, styles, computeColumnPixelWidths: computeColumnPixelWidths2 } = deps;
|
|
1362
|
-
const measureText = (
|
|
1363
|
-
const tb = resolveTextBlock(styles,
|
|
1364
|
-
const
|
|
1523
|
+
const measureText = (block, env) => {
|
|
1524
|
+
const tb = resolveTextBlock(styles, block);
|
|
1525
|
+
const mt = tb.marginTop ?? 0;
|
|
1526
|
+
const mb = tb.marginBottom ?? 0;
|
|
1527
|
+
const localLeft = tb.marginLeft ?? 0;
|
|
1528
|
+
const localRight = tb.marginRight ?? 0;
|
|
1529
|
+
const width = Math.max(env.innerWidth - localLeft - localRight, 1);
|
|
1365
1530
|
doc.font(getFontNameForText(tb));
|
|
1366
1531
|
doc.fontSize(tb.fontSize ?? 10);
|
|
1367
|
-
const
|
|
1368
|
-
const
|
|
1369
|
-
return
|
|
1532
|
+
const lineGap = tb.lineGap ?? 4;
|
|
1533
|
+
const height = doc.heightOfString(tb.text ?? "", { width, lineGap });
|
|
1534
|
+
return mt + height + lineGap + mb;
|
|
1370
1535
|
};
|
|
1371
|
-
const
|
|
1372
|
-
|
|
1373
|
-
const h = b.height ?? 50;
|
|
1374
|
-
return measureImageLike(b.marginTop, b.marginBottom, h);
|
|
1536
|
+
const measureImage = (block) => {
|
|
1537
|
+
return (block.marginTop ?? 0) + (block.height ?? 50) + (block.marginBottom ?? 0);
|
|
1375
1538
|
};
|
|
1376
|
-
const measureQr = (
|
|
1377
|
-
|
|
1378
|
-
return measureImageLike(b.marginTop, b.marginBottom, size);
|
|
1539
|
+
const measureQr = (block) => {
|
|
1540
|
+
return (block.marginTop ?? 0) + (block.size ?? 80) + (block.marginBottom ?? 0);
|
|
1379
1541
|
};
|
|
1380
|
-
const measureBarcode = (
|
|
1381
|
-
|
|
1382
|
-
return measureImageLike(b.marginTop, b.marginBottom, h);
|
|
1542
|
+
const measureBarcode = (block) => {
|
|
1543
|
+
return (block.marginTop ?? 0) + (block.height ?? 40) + (block.marginBottom ?? 0);
|
|
1383
1544
|
};
|
|
1384
|
-
const
|
|
1385
|
-
|
|
1386
|
-
const mt = b.marginTop ?? 0;
|
|
1387
|
-
const mb = b.marginBottom ?? 0;
|
|
1388
|
-
return mt + lw + mb;
|
|
1545
|
+
const measureShape = (block) => {
|
|
1546
|
+
return (block.marginTop ?? 0) + (block.height ?? block.lineWidth ?? 1) + (block.marginBottom ?? 0);
|
|
1389
1547
|
};
|
|
1390
|
-
const
|
|
1391
|
-
|
|
1392
|
-
const mb = b.marginBottom ?? 0;
|
|
1393
|
-
const ml = b.marginLeft ?? 0;
|
|
1394
|
-
const mr = b.marginRight ?? 0;
|
|
1395
|
-
const innerWidth = Math.max(env.innerWidth - ml - mr, 1);
|
|
1396
|
-
const fakeEnv = {
|
|
1397
|
-
marginLeft: 0,
|
|
1398
|
-
innerWidth,
|
|
1399
|
-
allowPageBreak: false
|
|
1400
|
-
};
|
|
1401
|
-
const h = measureTableHeight(doc, b, fakeEnv, styles, computeColumnPixelWidths2);
|
|
1402
|
-
return mt + h + mb;
|
|
1548
|
+
const measureLine = (block) => {
|
|
1549
|
+
return (block.marginTop ?? 0) + (block.lineWidth ?? 1) + (block.marginBottom ?? 0);
|
|
1403
1550
|
};
|
|
1404
|
-
const measureColumns = (
|
|
1405
|
-
const mt =
|
|
1406
|
-
const mb =
|
|
1407
|
-
const blockLeft =
|
|
1408
|
-
const blockRight =
|
|
1551
|
+
const measureColumns = (block, env) => {
|
|
1552
|
+
const mt = block.marginTop ?? 0;
|
|
1553
|
+
const mb = block.marginBottom ?? 0;
|
|
1554
|
+
const blockLeft = block.marginLeft ?? 0;
|
|
1555
|
+
const blockRight = block.marginRight ?? 0;
|
|
1409
1556
|
const totalWidth = Math.max(env.innerWidth - blockLeft - blockRight, 1);
|
|
1410
|
-
const cols =
|
|
1557
|
+
const cols = block.columns ?? [];
|
|
1411
1558
|
const n = cols.length;
|
|
1412
1559
|
if (!n) return mt + mb;
|
|
1413
1560
|
let colWidths;
|
|
1414
|
-
const mode =
|
|
1415
|
-
let gap;
|
|
1561
|
+
const mode = block.mode ?? "fixedGap";
|
|
1416
1562
|
if (mode === "spaceBetween" && n > 1) {
|
|
1417
|
-
if (
|
|
1418
|
-
colWidths = computeColumnPixelWidths2(
|
|
1563
|
+
if (block.widths && block.widths.length === n) {
|
|
1564
|
+
colWidths = computeColumnPixelWidths2(block.widths, totalWidth);
|
|
1419
1565
|
} else {
|
|
1420
1566
|
colWidths = Array(n).fill(totalWidth / n);
|
|
1421
1567
|
}
|
|
1422
|
-
const totalColsWidth = colWidths.reduce((a, x) => a + x, 0);
|
|
1423
|
-
const remaining = Math.max(totalWidth - totalColsWidth, 0);
|
|
1424
|
-
gap = remaining / (n - 1);
|
|
1425
|
-
void gap;
|
|
1426
1568
|
} else {
|
|
1427
|
-
gap =
|
|
1569
|
+
const gap = block.gap ?? 20;
|
|
1428
1570
|
const totalGapsWidth = gap * (n - 1);
|
|
1429
1571
|
const widthForCols = Math.max(totalWidth - totalGapsWidth, 1);
|
|
1430
|
-
if (
|
|
1431
|
-
colWidths = computeColumnPixelWidths2(
|
|
1572
|
+
if (block.widths && block.widths.length === n) {
|
|
1573
|
+
colWidths = computeColumnPixelWidths2(block.widths, widthForCols);
|
|
1432
1574
|
} else {
|
|
1433
1575
|
colWidths = Array(n).fill(widthForCols / n);
|
|
1434
1576
|
}
|
|
1435
1577
|
}
|
|
1436
|
-
const heights = [];
|
|
1437
|
-
for (let i = 0; i < n; i++) {
|
|
1438
|
-
const colBlocks = cols[i] ?? [];
|
|
1439
|
-
const colEnv = {
|
|
1440
|
-
marginLeft: 0,
|
|
1441
|
-
innerWidth: colWidths[i],
|
|
1442
|
-
allowPageBreak: false
|
|
1443
|
-
};
|
|
1444
|
-
let
|
|
1445
|
-
for (const child of colBlocks) {
|
|
1446
|
-
if (!child || child.visible === false) continue;
|
|
1447
|
-
|
|
1578
|
+
const heights = [];
|
|
1579
|
+
for (let i = 0; i < n; i++) {
|
|
1580
|
+
const colBlocks = cols[i] ?? [];
|
|
1581
|
+
const colEnv = {
|
|
1582
|
+
marginLeft: 0,
|
|
1583
|
+
innerWidth: colWidths[i],
|
|
1584
|
+
allowPageBreak: false
|
|
1585
|
+
};
|
|
1586
|
+
let colHeight = 0;
|
|
1587
|
+
for (const child of colBlocks) {
|
|
1588
|
+
if (!child || child.visible === false) continue;
|
|
1589
|
+
colHeight += measure(child, colEnv);
|
|
1590
|
+
}
|
|
1591
|
+
heights.push(colHeight);
|
|
1592
|
+
}
|
|
1593
|
+
return mt + Math.max(...heights, 0) + mb;
|
|
1594
|
+
};
|
|
1595
|
+
const measureTable = (block, env) => {
|
|
1596
|
+
const mt = block.marginTop ?? 0;
|
|
1597
|
+
const mb = block.marginBottom ?? 0;
|
|
1598
|
+
const ml = block.marginLeft ?? 0;
|
|
1599
|
+
const mr = block.marginRight ?? 0;
|
|
1600
|
+
const innerWidth = Math.max(env.innerWidth - ml - mr, 1);
|
|
1601
|
+
const fakeEnv = {
|
|
1602
|
+
marginLeft: 0,
|
|
1603
|
+
innerWidth,
|
|
1604
|
+
allowPageBreak: false
|
|
1605
|
+
};
|
|
1606
|
+
const height = measureTableHeight(doc, block, fakeEnv, styles, computeColumnPixelWidths2, measure);
|
|
1607
|
+
return mt + height + mb;
|
|
1608
|
+
};
|
|
1609
|
+
const measureKeyValueGrid = (block, env) => {
|
|
1610
|
+
const mt = block.marginTop ?? 0;
|
|
1611
|
+
const mb = block.marginBottom ?? 0;
|
|
1612
|
+
const ml = block.marginLeft ?? 0;
|
|
1613
|
+
const mr = block.marginRight ?? 0;
|
|
1614
|
+
const totalWidth = Math.max(env.innerWidth - ml - mr, 1);
|
|
1615
|
+
const cols = block.columns ?? [];
|
|
1616
|
+
const colCount = cols.length;
|
|
1617
|
+
if (!colCount) return mt + mb;
|
|
1618
|
+
const rowGap = block.rowGap ?? 4;
|
|
1619
|
+
const keyValueGap = block.verticalKeyValueGap ?? 2;
|
|
1620
|
+
const separatorText = block.separator ?? "";
|
|
1621
|
+
const separatorWidth = separatorText ? doc.widthOfString(separatorText) : 0;
|
|
1622
|
+
let colWidths;
|
|
1623
|
+
if (block.columnWidths && block.columnWidths.length === colCount) {
|
|
1624
|
+
colWidths = computeColumnPixelWidths2(
|
|
1625
|
+
block.columnWidths.map((w) => w ?? "*"),
|
|
1626
|
+
totalWidth
|
|
1627
|
+
);
|
|
1628
|
+
} else {
|
|
1629
|
+
colWidths = Array(colCount).fill(totalWidth / colCount);
|
|
1630
|
+
}
|
|
1631
|
+
const measureTextHeight2 = (text, width) => {
|
|
1632
|
+
doc.fontSize(10);
|
|
1633
|
+
return doc.heightOfString(text ?? "", { width }) + 4;
|
|
1634
|
+
};
|
|
1635
|
+
let totalHeight = mt;
|
|
1636
|
+
if (block.orientation === "vertical") {
|
|
1637
|
+
let maxColHeight = 0;
|
|
1638
|
+
for (let colIndex = 0; colIndex < colCount; colIndex++) {
|
|
1639
|
+
const col = cols[colIndex] ?? [];
|
|
1640
|
+
const colWidth = colWidths[colIndex];
|
|
1641
|
+
let colHeight = 0;
|
|
1642
|
+
for (const item of col) {
|
|
1643
|
+
const keyHeight = measureTextHeight2(item.key ?? "", colWidth);
|
|
1644
|
+
const valueHeight = measureTextHeight2(item.value ?? "", colWidth);
|
|
1645
|
+
colHeight += keyHeight + keyValueGap + valueHeight + rowGap;
|
|
1646
|
+
}
|
|
1647
|
+
maxColHeight = Math.max(maxColHeight, colHeight);
|
|
1648
|
+
}
|
|
1649
|
+
totalHeight += maxColHeight;
|
|
1650
|
+
} else {
|
|
1651
|
+
const maxRows = Math.max(...cols.map((c) => c ? c.length : 0), 0);
|
|
1652
|
+
for (let rowIndex = 0; rowIndex < maxRows; rowIndex++) {
|
|
1653
|
+
let rowHeight = 0;
|
|
1654
|
+
for (let colIndex = 0; colIndex < colCount; colIndex++) {
|
|
1655
|
+
const item = cols[colIndex]?.[rowIndex];
|
|
1656
|
+
if (!item) continue;
|
|
1657
|
+
const colWidth = colWidths[colIndex];
|
|
1658
|
+
const keyWidth = block.keyWidth === "*" ? Math.max(colWidth * 0.35, 20) : block.keyWidth ?? 80;
|
|
1659
|
+
const keyHeight = measureTextHeight2(item.key ?? "", keyWidth);
|
|
1660
|
+
const valueXInsideCol = keyWidth + (separatorText ? separatorWidth + 4 : 4);
|
|
1661
|
+
const valueWidth = Math.max(colWidth - valueXInsideCol, 1);
|
|
1662
|
+
const valueHeight = measureTextHeight2(item.value ?? "", valueWidth);
|
|
1663
|
+
rowHeight = Math.max(rowHeight, keyHeight, valueHeight);
|
|
1664
|
+
}
|
|
1665
|
+
if (rowHeight > 0) {
|
|
1666
|
+
totalHeight += rowHeight + rowGap;
|
|
1667
|
+
}
|
|
1668
|
+
}
|
|
1669
|
+
}
|
|
1670
|
+
return totalHeight + mb;
|
|
1671
|
+
};
|
|
1672
|
+
const stripBoxModelProps = (block) => {
|
|
1673
|
+
return {
|
|
1674
|
+
...block,
|
|
1675
|
+
marginTop: 0,
|
|
1676
|
+
marginBottom: 0,
|
|
1677
|
+
marginLeft: 0,
|
|
1678
|
+
marginRight: 0,
|
|
1679
|
+
backgroundColor: void 0,
|
|
1680
|
+
backgroundImage: void 0,
|
|
1681
|
+
backgroundOpacity: void 0,
|
|
1682
|
+
backgroundBlocks: void 0,
|
|
1683
|
+
padding: void 0,
|
|
1684
|
+
paddingTop: void 0,
|
|
1685
|
+
paddingRight: void 0,
|
|
1686
|
+
paddingBottom: void 0,
|
|
1687
|
+
paddingLeft: void 0
|
|
1688
|
+
};
|
|
1689
|
+
};
|
|
1690
|
+
const measureRaw = (block, env) => {
|
|
1691
|
+
switch (block.type) {
|
|
1692
|
+
case "text":
|
|
1693
|
+
return measureText(block, env);
|
|
1694
|
+
case "image":
|
|
1695
|
+
return measureImage(block);
|
|
1696
|
+
case "qr":
|
|
1697
|
+
return measureQr(block);
|
|
1698
|
+
case "barcode":
|
|
1699
|
+
return measureBarcode(block);
|
|
1700
|
+
case "line":
|
|
1701
|
+
return measureLine(block);
|
|
1702
|
+
case "shape":
|
|
1703
|
+
return measureShape(block);
|
|
1704
|
+
case "columns":
|
|
1705
|
+
return measureColumns(block, env);
|
|
1706
|
+
case "table":
|
|
1707
|
+
return measureTable(block, env);
|
|
1708
|
+
case "keyValueGrid":
|
|
1709
|
+
return measureKeyValueGrid(block, env);
|
|
1710
|
+
case "list":
|
|
1711
|
+
return measureListHeight(doc, styles, block, env);
|
|
1712
|
+
case "signature":
|
|
1713
|
+
return block.height ?? 0;
|
|
1714
|
+
case "pageBreak":
|
|
1715
|
+
return 0;
|
|
1716
|
+
default:
|
|
1717
|
+
return 0;
|
|
1718
|
+
}
|
|
1719
|
+
};
|
|
1720
|
+
const measure = (block, env) => {
|
|
1721
|
+
if (!block || block.visible === false) return 0;
|
|
1722
|
+
if (env.isBackgroundLayer) {
|
|
1723
|
+
return measureRaw(block, env);
|
|
1724
|
+
}
|
|
1725
|
+
const padding = resolveBlockPadding(block);
|
|
1726
|
+
const hasBoxBackground = !!block.backgroundColor || !!block.backgroundImage || !!block.backgroundBlocks?.length;
|
|
1727
|
+
const shouldUseBoxModel = hasPadding(padding) || hasBoxBackground;
|
|
1728
|
+
if (!shouldUseBoxModel) {
|
|
1729
|
+
return measureRaw(block, env);
|
|
1730
|
+
}
|
|
1731
|
+
const marginTop = block.marginTop ?? 0;
|
|
1732
|
+
const marginBottom = block.marginBottom ?? 0;
|
|
1733
|
+
const marginLeft = block.marginLeft ?? 0;
|
|
1734
|
+
const marginRight = block.marginRight ?? 0;
|
|
1735
|
+
const outerWidth = Math.max(env.innerWidth - marginLeft - marginRight, 1);
|
|
1736
|
+
const innerWidth = Math.max(outerWidth - padding.left - padding.right, 1);
|
|
1737
|
+
const innerEnv = {
|
|
1738
|
+
...env,
|
|
1739
|
+
marginLeft: 0,
|
|
1740
|
+
innerWidth
|
|
1741
|
+
};
|
|
1742
|
+
const innerBlock = stripBoxModelProps(block);
|
|
1743
|
+
const innerHeight = measureRaw(innerBlock, innerEnv);
|
|
1744
|
+
return marginTop + padding.top + innerHeight + padding.bottom + marginBottom;
|
|
1745
|
+
};
|
|
1746
|
+
return (block, env) => measure(block, env);
|
|
1747
|
+
}
|
|
1748
|
+
|
|
1749
|
+
// src/renderer-engine/utils/page-limit.ts
|
|
1750
|
+
function createBottomLimitForContent(doc, ctx) {
|
|
1751
|
+
return () => {
|
|
1752
|
+
const pageBottomForContent = doc.page.height - doc.page.margins.bottom;
|
|
1753
|
+
return ctx.signatureTopY ?? pageBottomForContent;
|
|
1754
|
+
};
|
|
1755
|
+
}
|
|
1756
|
+
|
|
1757
|
+
// src/renderer-engine/utils/block-renderer.ts
|
|
1758
|
+
function createBlockRenderer(deps) {
|
|
1759
|
+
const { doc, ctx, styles, computeColumnPixelWidths: computeColumnPixelWidths2, finishPage: finishPage2, processSignatureBlock, defaultImage } = deps;
|
|
1760
|
+
const bottomLimitForContent = createBottomLimitForContent(doc, ctx);
|
|
1761
|
+
const ensureSpaceFor = createEnsureSpaceFor(ctx, doc, bottomLimitForContent, finishPage2);
|
|
1762
|
+
const measureBlockHeight = createMeasureBlockHeight({
|
|
1763
|
+
doc,
|
|
1764
|
+
styles,
|
|
1765
|
+
computeColumnPixelWidths: computeColumnPixelWidths2
|
|
1766
|
+
});
|
|
1767
|
+
const stripBoxModelProps = (block) => {
|
|
1768
|
+
return {
|
|
1769
|
+
...block,
|
|
1770
|
+
marginTop: 0,
|
|
1771
|
+
marginBottom: 0,
|
|
1772
|
+
marginLeft: 0,
|
|
1773
|
+
marginRight: 0,
|
|
1774
|
+
backgroundColor: void 0,
|
|
1775
|
+
backgroundImage: void 0,
|
|
1776
|
+
backgroundOpacity: void 0,
|
|
1777
|
+
backgroundBlocks: void 0,
|
|
1778
|
+
padding: void 0,
|
|
1779
|
+
paddingTop: void 0,
|
|
1780
|
+
paddingRight: void 0,
|
|
1781
|
+
paddingBottom: void 0,
|
|
1782
|
+
paddingLeft: void 0
|
|
1783
|
+
};
|
|
1784
|
+
};
|
|
1785
|
+
const renderBlockCore = (block, y, env) => {
|
|
1786
|
+
if (block.visible === false) {
|
|
1787
|
+
return y ?? ctx.currentY;
|
|
1788
|
+
}
|
|
1789
|
+
switch (block.type) {
|
|
1790
|
+
case "text":
|
|
1791
|
+
return processTextBlock(doc, ctx, styles, block, y, env, ensureSpaceFor);
|
|
1792
|
+
case "image":
|
|
1793
|
+
return processImageBlock(doc, ctx, block, y, env, ensureSpaceFor, defaultImage);
|
|
1794
|
+
case "qr": {
|
|
1795
|
+
const qb = block;
|
|
1796
|
+
const imageLike = {
|
|
1797
|
+
type: "image",
|
|
1798
|
+
src: qb.src,
|
|
1799
|
+
width: qb.size,
|
|
1800
|
+
height: qb.size,
|
|
1801
|
+
align: qb.align,
|
|
1802
|
+
marginTop: qb.marginTop,
|
|
1803
|
+
marginBottom: qb.marginBottom,
|
|
1804
|
+
marginLeft: qb.marginLeft,
|
|
1805
|
+
marginRight: qb.marginRight
|
|
1806
|
+
};
|
|
1807
|
+
return processImageBlock(doc, ctx, imageLike, y, env, ensureSpaceFor, defaultImage);
|
|
1808
|
+
}
|
|
1809
|
+
case "barcode":
|
|
1810
|
+
return processBarcodeBlock(doc, ctx, block, y, env, ensureSpaceFor);
|
|
1811
|
+
case "line":
|
|
1812
|
+
return processLineBlock(doc, ctx, block, y, env, ensureSpaceFor);
|
|
1813
|
+
case "shape":
|
|
1814
|
+
return processShapeBlock(doc, ctx, block, y, env, ensureSpaceFor);
|
|
1815
|
+
case "columns":
|
|
1816
|
+
return processColumnsBlock(
|
|
1817
|
+
ctx,
|
|
1818
|
+
block,
|
|
1819
|
+
y,
|
|
1820
|
+
env,
|
|
1821
|
+
computeColumnPixelWidths2,
|
|
1822
|
+
renderBlock,
|
|
1823
|
+
ensureSpaceFor,
|
|
1824
|
+
measureBlockHeight
|
|
1825
|
+
);
|
|
1826
|
+
case "table":
|
|
1827
|
+
return processTableBlock(
|
|
1828
|
+
doc,
|
|
1829
|
+
ctx,
|
|
1830
|
+
styles,
|
|
1831
|
+
block,
|
|
1832
|
+
y,
|
|
1833
|
+
env,
|
|
1834
|
+
computeColumnPixelWidths2,
|
|
1835
|
+
bottomLimitForContent,
|
|
1836
|
+
finishPage2,
|
|
1837
|
+
renderBlock,
|
|
1838
|
+
measureBlockHeight
|
|
1839
|
+
);
|
|
1840
|
+
case "keyValueGrid":
|
|
1841
|
+
return processKeyValueGridBlock(
|
|
1842
|
+
doc,
|
|
1843
|
+
ctx,
|
|
1844
|
+
styles,
|
|
1845
|
+
block,
|
|
1846
|
+
y,
|
|
1847
|
+
env,
|
|
1848
|
+
computeColumnPixelWidths2,
|
|
1849
|
+
ensureSpaceFor
|
|
1850
|
+
);
|
|
1851
|
+
case "list":
|
|
1852
|
+
return processListBlock(
|
|
1853
|
+
doc,
|
|
1854
|
+
ctx,
|
|
1855
|
+
styles,
|
|
1856
|
+
block,
|
|
1857
|
+
y,
|
|
1858
|
+
env,
|
|
1859
|
+
ensureSpaceFor
|
|
1860
|
+
);
|
|
1861
|
+
case "pageBreak":
|
|
1862
|
+
finishPage2(true);
|
|
1863
|
+
return ctx.currentY;
|
|
1864
|
+
case "signature":
|
|
1865
|
+
processSignatureBlock(block);
|
|
1866
|
+
return y ?? ctx.currentY;
|
|
1867
|
+
default:
|
|
1868
|
+
throw new PdfEngineError({
|
|
1869
|
+
code: "PDF_ERROR_BLOCK_UNSUPPORTED" /* PDF_ERROR_BLOCK_UNSUPPORTED */,
|
|
1870
|
+
message: `Unsupported block type: ${block.type}`,
|
|
1871
|
+
statusCode: 422,
|
|
1872
|
+
details: { block }
|
|
1873
|
+
});
|
|
1874
|
+
}
|
|
1875
|
+
};
|
|
1876
|
+
const renderBlock = (block, y, env) => {
|
|
1877
|
+
if (block.visible === false) {
|
|
1878
|
+
return y ?? ctx.currentY;
|
|
1879
|
+
}
|
|
1880
|
+
if (env.isBackgroundLayer) {
|
|
1881
|
+
return renderBlockCore(block, y, env);
|
|
1882
|
+
}
|
|
1883
|
+
const padding = resolveBlockPadding(block);
|
|
1884
|
+
const hasBoxBackground = !!block.backgroundColor || !!block.backgroundImage || !!block.backgroundBlocks?.length;
|
|
1885
|
+
const shouldUseBoxModel = hasPadding(padding) || hasBoxBackground;
|
|
1886
|
+
if (!shouldUseBoxModel) {
|
|
1887
|
+
return renderBlockCore(block, y, env);
|
|
1888
|
+
}
|
|
1889
|
+
const marginTop = block.marginTop ?? 0;
|
|
1890
|
+
const marginBottom = block.marginBottom ?? 0;
|
|
1891
|
+
const marginLeft = block.marginLeft ?? 0;
|
|
1892
|
+
const marginRight = block.marginRight ?? 0;
|
|
1893
|
+
const outerX = env.marginLeft + marginLeft;
|
|
1894
|
+
const outerWidth = Math.max(env.innerWidth - marginLeft - marginRight, 1);
|
|
1895
|
+
const innerX = outerX + padding.left;
|
|
1896
|
+
const innerWidth = Math.max(outerWidth - padding.left - padding.right, 1);
|
|
1897
|
+
const innerEnv = {
|
|
1898
|
+
...env,
|
|
1899
|
+
marginLeft: innerX,
|
|
1900
|
+
innerWidth
|
|
1901
|
+
};
|
|
1902
|
+
const innerBlock = stripBoxModelProps(block);
|
|
1903
|
+
const innerHeight = measureBlockHeight(innerBlock, innerEnv);
|
|
1904
|
+
const boxHeight = padding.top + innerHeight + padding.bottom;
|
|
1905
|
+
const totalHeight = marginTop + boxHeight + marginBottom;
|
|
1906
|
+
if (y === null && env.allowPageBreak !== false && block.type !== "table") {
|
|
1907
|
+
ensureSpaceFor(totalHeight, env);
|
|
1908
|
+
}
|
|
1909
|
+
const finalOuterY = (y ?? ctx.currentY) + marginTop;
|
|
1910
|
+
if (block.backgroundColor) {
|
|
1911
|
+
doc.save();
|
|
1912
|
+
doc.fillOpacity(block.backgroundOpacity ?? 1).rect(outerX, finalOuterY, outerWidth, boxHeight).fill(block.backgroundColor);
|
|
1913
|
+
doc.restore();
|
|
1914
|
+
}
|
|
1915
|
+
if (block.backgroundImage) {
|
|
1916
|
+
try {
|
|
1917
|
+
doc.save();
|
|
1918
|
+
doc.opacity(block.backgroundOpacity ?? 1);
|
|
1919
|
+
doc.image(block.backgroundImage, outerX, finalOuterY, {
|
|
1920
|
+
width: outerWidth,
|
|
1921
|
+
height: boxHeight
|
|
1922
|
+
});
|
|
1923
|
+
doc.restore();
|
|
1924
|
+
} catch (_) {
|
|
1925
|
+
}
|
|
1926
|
+
}
|
|
1927
|
+
if (block.backgroundBlocks?.length) {
|
|
1928
|
+
doc.save();
|
|
1929
|
+
doc.opacity(block.backgroundOpacity ?? 1);
|
|
1930
|
+
renderBlockArray(block.backgroundBlocks, finalOuterY, {
|
|
1931
|
+
...env,
|
|
1932
|
+
marginLeft: outerX,
|
|
1933
|
+
innerWidth: outerWidth,
|
|
1934
|
+
allowPageBreak: false,
|
|
1935
|
+
isBackgroundLayer: true
|
|
1936
|
+
});
|
|
1937
|
+
doc.restore();
|
|
1938
|
+
}
|
|
1939
|
+
const innerEndY = renderBlockCore(innerBlock, finalOuterY + padding.top, innerEnv);
|
|
1940
|
+
const newY = innerEndY + padding.bottom + marginBottom;
|
|
1941
|
+
if (y === null) {
|
|
1942
|
+
ctx.currentY = newY;
|
|
1943
|
+
}
|
|
1944
|
+
return newY;
|
|
1945
|
+
};
|
|
1946
|
+
const renderBlockArray = (blocks, startY, env) => {
|
|
1947
|
+
let localY = startY;
|
|
1948
|
+
for (const block of blocks) {
|
|
1949
|
+
localY = renderBlock(block, localY, env);
|
|
1950
|
+
}
|
|
1951
|
+
return localY;
|
|
1952
|
+
};
|
|
1953
|
+
return { renderBlock, renderBlockArray, measureBlockHeight };
|
|
1954
|
+
}
|
|
1955
|
+
|
|
1956
|
+
// src/renderer-engine/utils/context.ts
|
|
1957
|
+
function createInitialContext(doc) {
|
|
1958
|
+
return {
|
|
1959
|
+
pageNumber: 1,
|
|
1960
|
+
currentY: doc.page.margins.top,
|
|
1961
|
+
signatureBlock: null,
|
|
1962
|
+
signatureTopY: null,
|
|
1963
|
+
signatureHeight: 0,
|
|
1964
|
+
signaturePlaced: false,
|
|
1965
|
+
afterSignature: false,
|
|
1966
|
+
inFooter: false,
|
|
1967
|
+
inManualPageAdd: false
|
|
1968
|
+
};
|
|
1969
|
+
}
|
|
1970
|
+
|
|
1971
|
+
// src/renderer-engine/utils/env.ts
|
|
1972
|
+
var contentEnv = (doc) => ({
|
|
1973
|
+
marginLeft: doc.page.margins.left,
|
|
1974
|
+
innerWidth: doc.page.width - doc.page.margins.left - doc.page.margins.right,
|
|
1975
|
+
allowPageBreak: true
|
|
1976
|
+
});
|
|
1977
|
+
|
|
1978
|
+
// src/renderer-engine/utils/finish-page.ts
|
|
1979
|
+
function finishPage({
|
|
1980
|
+
addNewPage,
|
|
1981
|
+
doc,
|
|
1982
|
+
def,
|
|
1983
|
+
ctx,
|
|
1984
|
+
footerBandHeight,
|
|
1985
|
+
renderBlockArray,
|
|
1986
|
+
startNewPageLayout
|
|
1987
|
+
}) {
|
|
1988
|
+
const mode = def.watermark?.mode;
|
|
1989
|
+
if (def.watermark && watermarkUsesLast(mode)) {
|
|
1990
|
+
const isLast = !addNewPage;
|
|
1991
|
+
drawWatermarkForPage(doc, def.watermark, ctx.pageNumber, isLast);
|
|
1992
|
+
}
|
|
1993
|
+
if (ctx.signatureBlock && ctx.signatureTopY !== null) {
|
|
1994
|
+
const env = contentEnv(doc);
|
|
1995
|
+
drawSignatureBlock(doc, ctx.signatureBlock, ctx.signatureTopY, env, renderBlockArray);
|
|
1996
|
+
}
|
|
1997
|
+
drawFooter(doc, def, ctx, footerBandHeight, renderBlockArray);
|
|
1998
|
+
if (addNewPage) {
|
|
1999
|
+
ctx.inManualPageAdd = true;
|
|
2000
|
+
doc.addPage();
|
|
2001
|
+
ctx.inManualPageAdd = false;
|
|
2002
|
+
ctx.pageNumber += 1;
|
|
2003
|
+
startNewPageLayout();
|
|
2004
|
+
}
|
|
2005
|
+
}
|
|
2006
|
+
|
|
2007
|
+
// src/renderer-engine/utils/footer.ts
|
|
2008
|
+
function normalizeFooter(input, ctx, doc) {
|
|
2009
|
+
if (!input) return null;
|
|
2010
|
+
if (typeof input === "function") {
|
|
2011
|
+
const result = input(ctx.pageNumber, {
|
|
2012
|
+
width: doc.page.width,
|
|
2013
|
+
height: doc.page.height
|
|
2014
|
+
});
|
|
2015
|
+
if (!result) return null;
|
|
2016
|
+
return normalizeFooter(result, ctx, doc);
|
|
2017
|
+
}
|
|
2018
|
+
if (input.blocks && Array.isArray(input.blocks)) {
|
|
2019
|
+
const footer = input;
|
|
2020
|
+
return {
|
|
2021
|
+
visible: footer.visible,
|
|
2022
|
+
blocks: footer.blocks,
|
|
2023
|
+
backgroundBlocks: footer.backgroundBlocks,
|
|
2024
|
+
marginTop: footer.marginTop,
|
|
2025
|
+
marginBottom: footer.marginBottom,
|
|
2026
|
+
marginLeft: footer.marginLeft,
|
|
2027
|
+
marginRight: footer.marginRight,
|
|
2028
|
+
padding: footer.padding,
|
|
2029
|
+
paddingTop: footer.paddingTop,
|
|
2030
|
+
paddingRight: footer.paddingRight,
|
|
2031
|
+
paddingBottom: footer.paddingBottom,
|
|
2032
|
+
paddingLeft: footer.paddingLeft,
|
|
2033
|
+
backgroundColor: footer.backgroundColor,
|
|
2034
|
+
backgroundImage: footer.backgroundImage,
|
|
2035
|
+
backgroundOpacity: footer.backgroundOpacity
|
|
2036
|
+
};
|
|
2037
|
+
}
|
|
2038
|
+
if (input.type) {
|
|
2039
|
+
return { blocks: [input] };
|
|
2040
|
+
}
|
|
2041
|
+
if (Array.isArray(input)) {
|
|
2042
|
+
return { blocks: input };
|
|
2043
|
+
}
|
|
2044
|
+
return null;
|
|
2045
|
+
}
|
|
2046
|
+
function drawFooter(doc, def, ctx, footerBandHeight, renderBlockArray) {
|
|
2047
|
+
const footerConfig = def.footer;
|
|
2048
|
+
if (!footerConfig) return;
|
|
2049
|
+
const layout = normalizeFooter(footerConfig, ctx, doc);
|
|
2050
|
+
if (!layout) return;
|
|
2051
|
+
if (layout.visible === false) return;
|
|
2052
|
+
const blocks = layout.blocks ?? [];
|
|
2053
|
+
const backgroundBlocks = layout.backgroundBlocks ?? [];
|
|
2054
|
+
if (!blocks.length && !backgroundBlocks.length && !layout.backgroundColor && !layout.backgroundImage) {
|
|
2055
|
+
return;
|
|
2056
|
+
}
|
|
2057
|
+
const bandHeight = footerBandHeight;
|
|
2058
|
+
if (!bandHeight) return;
|
|
2059
|
+
const footerMarginLeft = layout.marginLeft ?? 0;
|
|
2060
|
+
const footerMarginRight = layout.marginRight ?? 0;
|
|
2061
|
+
const outerX = footerMarginLeft;
|
|
2062
|
+
const outerWidth = doc.page.width - footerMarginLeft - footerMarginRight;
|
|
2063
|
+
const padding = resolveFooterPadding(layout);
|
|
2064
|
+
const innerX = outerX + padding.left;
|
|
2065
|
+
const innerWidth = Math.max(outerWidth - padding.left - padding.right, 1);
|
|
2066
|
+
const outerEnv = {
|
|
2067
|
+
marginLeft: outerX,
|
|
2068
|
+
innerWidth: outerWidth,
|
|
2069
|
+
allowPageBreak: false
|
|
2070
|
+
};
|
|
2071
|
+
const innerEnv = {
|
|
2072
|
+
marginLeft: innerX,
|
|
2073
|
+
innerWidth,
|
|
2074
|
+
allowPageBreak: false
|
|
2075
|
+
};
|
|
2076
|
+
const pageHeight = doc.page.height;
|
|
2077
|
+
const bandTop = pageHeight - bandHeight;
|
|
2078
|
+
const backgroundOpacity = layout.backgroundOpacity ?? 1;
|
|
2079
|
+
if (layout.backgroundColor) {
|
|
2080
|
+
doc.save();
|
|
2081
|
+
doc.fillOpacity(backgroundOpacity).rect(0, bandTop, doc.page.width, bandHeight).fill(layout.backgroundColor);
|
|
2082
|
+
doc.restore();
|
|
2083
|
+
}
|
|
2084
|
+
if (layout.backgroundImage) {
|
|
2085
|
+
try {
|
|
2086
|
+
doc.save();
|
|
2087
|
+
doc.opacity(backgroundOpacity);
|
|
2088
|
+
doc.image(layout.backgroundImage, 0, bandTop, {
|
|
2089
|
+
width: doc.page.width,
|
|
2090
|
+
height: bandHeight
|
|
2091
|
+
});
|
|
2092
|
+
doc.restore();
|
|
2093
|
+
} catch (e) {
|
|
2094
|
+
console.warn("Failed to load footer background image:", e);
|
|
2095
|
+
}
|
|
2096
|
+
}
|
|
2097
|
+
doc.save();
|
|
2098
|
+
doc.rect(outerX, bandTop, outerWidth, bandHeight).clip();
|
|
2099
|
+
doc.translate(0, bandTop);
|
|
2100
|
+
ctx.inFooter = true;
|
|
2101
|
+
const localStartY = layout.marginTop ?? 4;
|
|
2102
|
+
if (backgroundBlocks.length) {
|
|
2103
|
+
doc.save();
|
|
2104
|
+
doc.opacity(backgroundOpacity);
|
|
2105
|
+
renderBlockArray(backgroundBlocks, localStartY, {
|
|
2106
|
+
...outerEnv,
|
|
2107
|
+
allowPageBreak: false,
|
|
2108
|
+
isBackgroundLayer: true
|
|
2109
|
+
});
|
|
2110
|
+
doc.restore();
|
|
2111
|
+
}
|
|
2112
|
+
if (blocks.length) {
|
|
2113
|
+
renderBlockArray(blocks, localStartY + padding.top, innerEnv);
|
|
2114
|
+
}
|
|
2115
|
+
ctx.inFooter = false;
|
|
2116
|
+
doc.restore();
|
|
2117
|
+
}
|
|
2118
|
+
|
|
2119
|
+
// src/renderer-engine/utils/header.ts
|
|
2120
|
+
function drawHeader(doc, def, headerBandHeight, header, renderBlockArray) {
|
|
2121
|
+
if (!header) return;
|
|
2122
|
+
if (header.visible === false) return;
|
|
2123
|
+
if (!headerBandHeight) return;
|
|
2124
|
+
const blocks = header.blocks ?? [];
|
|
2125
|
+
const backgroundBlocks = header.backgroundBlocks ?? [];
|
|
2126
|
+
if (!blocks.length && !backgroundBlocks.length && !header.backgroundColor && !header.backgroundImage) {
|
|
2127
|
+
return;
|
|
2128
|
+
}
|
|
2129
|
+
const bandTop = 0;
|
|
2130
|
+
const bandHeight = def.margins.top;
|
|
2131
|
+
const headerMarginLeft = header.marginLeft ?? 0;
|
|
2132
|
+
const headerMarginRight = header.marginRight ?? 0;
|
|
2133
|
+
const outerX = headerMarginLeft;
|
|
2134
|
+
const outerWidth = doc.page.width - headerMarginLeft - headerMarginRight;
|
|
2135
|
+
const padding = resolveHeaderPadding(header);
|
|
2136
|
+
const innerX = outerX + padding.left;
|
|
2137
|
+
const innerWidth = Math.max(outerWidth - padding.left - padding.right, 1);
|
|
2138
|
+
const outerEnv = {
|
|
2139
|
+
marginLeft: outerX,
|
|
2140
|
+
innerWidth: outerWidth,
|
|
2141
|
+
allowPageBreak: false
|
|
2142
|
+
};
|
|
2143
|
+
const innerEnv = {
|
|
2144
|
+
marginLeft: innerX,
|
|
2145
|
+
innerWidth,
|
|
2146
|
+
allowPageBreak: false
|
|
2147
|
+
};
|
|
2148
|
+
const backgroundOpacity = header.backgroundOpacity ?? 1;
|
|
2149
|
+
if (header.backgroundColor) {
|
|
2150
|
+
doc.save();
|
|
2151
|
+
doc.fillOpacity(backgroundOpacity).rect(0, bandTop, doc.page.width, bandHeight).fill(header.backgroundColor);
|
|
2152
|
+
doc.restore();
|
|
2153
|
+
}
|
|
2154
|
+
if (header.backgroundImage) {
|
|
2155
|
+
try {
|
|
2156
|
+
doc.save();
|
|
2157
|
+
doc.opacity(backgroundOpacity);
|
|
2158
|
+
doc.image(header.backgroundImage, 0, bandTop, {
|
|
2159
|
+
width: doc.page.width,
|
|
2160
|
+
height: bandHeight
|
|
2161
|
+
});
|
|
2162
|
+
doc.restore();
|
|
2163
|
+
} catch (e) {
|
|
2164
|
+
console.warn("Failed to load header background image:", e);
|
|
2165
|
+
}
|
|
2166
|
+
}
|
|
2167
|
+
doc.save();
|
|
2168
|
+
doc.rect(outerX, bandTop, outerWidth, bandHeight).clip();
|
|
2169
|
+
const startY = bandTop + (header.marginTop ?? 0);
|
|
2170
|
+
if (backgroundBlocks.length) {
|
|
2171
|
+
doc.save();
|
|
2172
|
+
doc.opacity(backgroundOpacity);
|
|
2173
|
+
renderBlockArray(backgroundBlocks, startY, {
|
|
2174
|
+
...outerEnv,
|
|
2175
|
+
allowPageBreak: false,
|
|
2176
|
+
isBackgroundLayer: true
|
|
2177
|
+
});
|
|
2178
|
+
doc.restore();
|
|
2179
|
+
}
|
|
2180
|
+
if (blocks.length) {
|
|
2181
|
+
renderBlockArray(blocks, startY + padding.top, innerEnv);
|
|
2182
|
+
}
|
|
2183
|
+
doc.restore();
|
|
2184
|
+
}
|
|
2185
|
+
|
|
2186
|
+
// src/renderer-engine/utils/image-loader.ts
|
|
2187
|
+
var import_axios = __toESM(require("axios"));
|
|
2188
|
+
async function normalizeImageSrc(src, fallback) {
|
|
2189
|
+
if (!src) return fallback ?? src;
|
|
2190
|
+
if (Buffer.isBuffer(src)) return src;
|
|
2191
|
+
if (src.startsWith("data:")) {
|
|
2192
|
+
const commaIdx = src.indexOf(",");
|
|
2193
|
+
if (commaIdx !== -1) {
|
|
2194
|
+
return Buffer.from(src.slice(commaIdx + 1), "base64");
|
|
2195
|
+
}
|
|
2196
|
+
}
|
|
2197
|
+
if (src.startsWith("http://") || src.startsWith("https://")) {
|
|
2198
|
+
try {
|
|
2199
|
+
const res = await import_axios.default.get(src, {
|
|
2200
|
+
responseType: "arraybuffer"
|
|
2201
|
+
});
|
|
2202
|
+
return Buffer.from(res.data);
|
|
2203
|
+
} catch (e) {
|
|
2204
|
+
if (fallback !== void 0) {
|
|
2205
|
+
console.warn(`Failed to fetch remote image "${src}", using default image.`);
|
|
2206
|
+
return fallback;
|
|
1448
2207
|
}
|
|
1449
|
-
|
|
2208
|
+
throw toPdfEngineError(e, {
|
|
2209
|
+
code: "PDF_ERROR_IMAGE_FETCH_FAILED" /* PDF_ERROR_IMAGE_FETCH_FAILED */,
|
|
2210
|
+
message: "Failed to fetch remote image for PDF.",
|
|
2211
|
+
statusCode: 422,
|
|
2212
|
+
details: { url: src },
|
|
2213
|
+
retryable: false
|
|
2214
|
+
});
|
|
1450
2215
|
}
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
const
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
const colCount = cols.length;
|
|
1461
|
-
if (!colCount) return mt + mb;
|
|
1462
|
-
const blockLeft = b.marginLeft ?? 0;
|
|
1463
|
-
const blockRight = b.marginRight ?? 0;
|
|
1464
|
-
const totalWidth = Math.max(env.innerWidth - blockLeft - blockRight, 1);
|
|
1465
|
-
let colWidths;
|
|
1466
|
-
if (b.columnWidths && b.columnWidths.length === colCount) {
|
|
1467
|
-
const safe = b.columnWidths.map((w) => w === void 0 ? "*" : w);
|
|
1468
|
-
colWidths = computeColumnPixelWidths2(safe, totalWidth);
|
|
1469
|
-
} else {
|
|
1470
|
-
colWidths = Array(colCount).fill(totalWidth / colCount);
|
|
2216
|
+
}
|
|
2217
|
+
return src;
|
|
2218
|
+
}
|
|
2219
|
+
async function materializeImagesInBlocks(blocks, fallback) {
|
|
2220
|
+
const out = [];
|
|
2221
|
+
for (const block of blocks) {
|
|
2222
|
+
const blockAny = { ...block };
|
|
2223
|
+
if (blockAny.backgroundImage) {
|
|
2224
|
+
blockAny.backgroundImage = await normalizeImageSrc(blockAny.backgroundImage, fallback);
|
|
1471
2225
|
}
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
const baseKeyWidthRatio = 0.35;
|
|
1475
|
-
const measureKVText = (tb, width) => {
|
|
1476
|
-
const r = resolveTextBlock(styles, tb);
|
|
1477
|
-
const fontName = getFontNameForText(r);
|
|
1478
|
-
doc.font(fontName);
|
|
1479
|
-
doc.fontSize(r.fontSize ?? 10);
|
|
1480
|
-
return doc.heightOfString(r.text ?? "", { width });
|
|
1481
|
-
};
|
|
1482
|
-
let totalHeight = mt;
|
|
1483
|
-
if (orientation === "vertical") {
|
|
1484
|
-
const keyValueGap = b.verticalKeyValueGap ?? 2;
|
|
1485
|
-
let maxColHeight = 0;
|
|
1486
|
-
for (let colIndex = 0; colIndex < colCount; colIndex++) {
|
|
1487
|
-
const col = cols[colIndex] ?? [];
|
|
1488
|
-
const colWidth = colWidths[colIndex];
|
|
1489
|
-
let colHeight = 0;
|
|
1490
|
-
for (const item of col) {
|
|
1491
|
-
const keyH = measureKVText({ type: "text", text: item.key ?? "" }, colWidth);
|
|
1492
|
-
const valH = measureKVText({ type: "text", text: item.value ?? "" }, colWidth);
|
|
1493
|
-
colHeight += keyH + keyValueGap + valH + rowGap;
|
|
1494
|
-
}
|
|
1495
|
-
if (colHeight > maxColHeight) maxColHeight = colHeight;
|
|
1496
|
-
}
|
|
1497
|
-
totalHeight += maxColHeight;
|
|
1498
|
-
} else {
|
|
1499
|
-
const maxRows = Math.max(...cols.map((c) => c ? c.length : 0), 0);
|
|
1500
|
-
for (let rowIndex = 0; rowIndex < maxRows; rowIndex++) {
|
|
1501
|
-
let rowHeight = 0;
|
|
1502
|
-
for (let colIndex = 0; colIndex < colCount; colIndex++) {
|
|
1503
|
-
const item = cols[colIndex]?.[rowIndex];
|
|
1504
|
-
if (!item) continue;
|
|
1505
|
-
const colWidth = colWidths[colIndex];
|
|
1506
|
-
const keyWidthPx = b.keyWidth === "*" ? Math.max(colWidth * baseKeyWidthRatio, 20) : b.keyWidth ?? 80;
|
|
1507
|
-
const keyH = measureKVText({ type: "text", text: item.key ?? "" }, keyWidthPx);
|
|
1508
|
-
const valueXInsideCol = keyWidthPx + (separatorText ? sepBoxWidth + 4 : 4);
|
|
1509
|
-
const valueWidth = Math.max(colWidth - valueXInsideCol, 1);
|
|
1510
|
-
const valH = measureKVText({ type: "text", text: item.value ?? "" }, valueWidth);
|
|
1511
|
-
rowHeight = Math.max(rowHeight, Math.max(keyH, valH));
|
|
1512
|
-
}
|
|
1513
|
-
if (rowHeight > 0) totalHeight += rowHeight + rowGap;
|
|
1514
|
-
}
|
|
2226
|
+
if (blockAny.backgroundBlocks?.length) {
|
|
2227
|
+
blockAny.backgroundBlocks = await materializeImagesInBlocks(blockAny.backgroundBlocks, fallback);
|
|
1515
2228
|
}
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
if (
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
2229
|
+
if (block.type === "image") {
|
|
2230
|
+
const img = { ...blockAny };
|
|
2231
|
+
img.src = await normalizeImageSrc(img.src, fallback);
|
|
2232
|
+
out.push(img);
|
|
2233
|
+
} else if (block.type === "columns") {
|
|
2234
|
+
out.push({
|
|
2235
|
+
...blockAny,
|
|
2236
|
+
columns: await Promise.all(
|
|
2237
|
+
block.columns.map((col) => materializeImagesInBlocks(col, fallback))
|
|
2238
|
+
)
|
|
2239
|
+
});
|
|
2240
|
+
} else if (block.type === "signature" && block.blocks) {
|
|
2241
|
+
out.push({
|
|
2242
|
+
...blockAny,
|
|
2243
|
+
blocks: await materializeImagesInBlocks(block.blocks, fallback)
|
|
2244
|
+
});
|
|
2245
|
+
} else if (block.type === "table") {
|
|
2246
|
+
const tb = blockAny;
|
|
2247
|
+
const newBody = await Promise.all(
|
|
2248
|
+
tb.body.map(
|
|
2249
|
+
async (entry) => {
|
|
2250
|
+
const materializeCell = async (cell) => {
|
|
2251
|
+
if (!cell.blocks?.length) return cell;
|
|
2252
|
+
return {
|
|
2253
|
+
...cell,
|
|
2254
|
+
blocks: await materializeImagesInBlocks(cell.blocks, fallback)
|
|
2255
|
+
};
|
|
2256
|
+
};
|
|
2257
|
+
if (Array.isArray(entry)) {
|
|
2258
|
+
return await Promise.all(entry.map(materializeCell));
|
|
2259
|
+
}
|
|
2260
|
+
if (entry && typeof entry === "object" && "content" in entry && Array.isArray(entry.content)) {
|
|
2261
|
+
return {
|
|
2262
|
+
...entry,
|
|
2263
|
+
content: await Promise.all(entry.content.map(materializeCell))
|
|
2264
|
+
};
|
|
2265
|
+
}
|
|
2266
|
+
return entry;
|
|
2267
|
+
}
|
|
2268
|
+
)
|
|
2269
|
+
);
|
|
2270
|
+
out.push({ ...tb, body: newBody });
|
|
2271
|
+
} else {
|
|
2272
|
+
out.push(blockAny);
|
|
1544
2273
|
}
|
|
1545
|
-
}
|
|
1546
|
-
return
|
|
2274
|
+
}
|
|
2275
|
+
return out;
|
|
2276
|
+
}
|
|
2277
|
+
|
|
2278
|
+
// src/renderer-engine/utils/layout.ts
|
|
2279
|
+
function computeColumnPixelWidths(widths, totalWidth) {
|
|
2280
|
+
let fixedTotal = 0;
|
|
2281
|
+
let starCount = 0;
|
|
2282
|
+
widths.forEach((w) => {
|
|
2283
|
+
if (w === "*") starCount++;
|
|
2284
|
+
else fixedTotal += w;
|
|
2285
|
+
});
|
|
2286
|
+
const remaining = Math.max(totalWidth - fixedTotal, 0);
|
|
2287
|
+
const starWidth = starCount > 0 ? remaining / starCount : 0;
|
|
2288
|
+
return widths.map((w) => w === "*" ? starWidth : w);
|
|
1547
2289
|
}
|
|
1548
2290
|
|
|
1549
2291
|
// src/renderer-engine/utils/page-background.ts
|
|
@@ -1568,12 +2310,10 @@ function drawPageBackground(doc, pageBackground) {
|
|
|
1568
2310
|
doc.opacity(1);
|
|
1569
2311
|
}
|
|
1570
2312
|
|
|
1571
|
-
// src/renderer-engine/utils/page-
|
|
1572
|
-
function
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
return ctx.signatureTopY ?? pageBottomForContent;
|
|
1576
|
-
};
|
|
2313
|
+
// src/renderer-engine/utils/page-flow.ts
|
|
2314
|
+
function getBottomLimitForContent(doc, ctx) {
|
|
2315
|
+
const pageBottomForContent = doc.page.height - doc.page.margins.bottom;
|
|
2316
|
+
return ctx.signatureTopY ?? pageBottomForContent;
|
|
1577
2317
|
}
|
|
1578
2318
|
|
|
1579
2319
|
// src/renderer-engine/utils/qr-bar-code.ts
|
|
@@ -1596,7 +2336,10 @@ function generateQrBuffer(value, size, version, errorCorrectionLevel) {
|
|
|
1596
2336
|
code: "PDF_ERROR_QR_GENERATION_FAILED" /* PDF_ERROR_QR_GENERATION_FAILED */,
|
|
1597
2337
|
message: "Failed to generate QR code.",
|
|
1598
2338
|
statusCode: 500,
|
|
1599
|
-
details: {
|
|
2339
|
+
details: {
|
|
2340
|
+
valuePreview: String(value).slice(0, 60),
|
|
2341
|
+
size
|
|
2342
|
+
},
|
|
1600
2343
|
retryable: false
|
|
1601
2344
|
})
|
|
1602
2345
|
);
|
|
@@ -1623,97 +2366,109 @@ function mapBarcodeTypeToBcid(bcType) {
|
|
|
1623
2366
|
function generateBarcodeBuffer(value, options = {}) {
|
|
1624
2367
|
const { bcType, scale = 3, barHeight = 10, includetext = false, textalign = "center" } = options;
|
|
1625
2368
|
const bcid = mapBarcodeTypeToBcid(bcType);
|
|
2369
|
+
if (bcType === "EAN13" && !/^\d{12,13}$/.test(value)) {
|
|
2370
|
+
throw toPdfEngineError(new Error("Invalid EAN13 value"), {
|
|
2371
|
+
code: "PDF_ERROR_BARCODE_EAN13_INVALID_LENGTH" /* PDF_ERROR_BARCODE_EAN13_INVALID_LENGTH */,
|
|
2372
|
+
message: "EAN13 barcode value must be 12 or 13 digits.",
|
|
2373
|
+
statusCode: 422,
|
|
2374
|
+
details: { value },
|
|
2375
|
+
retryable: false
|
|
2376
|
+
});
|
|
2377
|
+
}
|
|
1626
2378
|
return new Promise((resolve, reject) => {
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
};
|
|
1653
|
-
bwipOptions.textxalign = textalign;
|
|
1654
|
-
import_bwip_js.default.toBuffer(bwipOptions, (err, png) => {
|
|
1655
|
-
if (err) {
|
|
1656
|
-
return reject(
|
|
1657
|
-
toPdfEngineError(err, {
|
|
1658
|
-
code: "PDF_ERROR_BARCODE_GENERATION_FAILED" /* PDF_ERROR_BARCODE_GENERATION_FAILED */,
|
|
1659
|
-
message: "Failed to generate barcode.",
|
|
1660
|
-
statusCode: 500,
|
|
1661
|
-
details: { bcType, valuePreview: String(value).slice(0, 60) },
|
|
1662
|
-
retryable: false
|
|
1663
|
-
})
|
|
1664
|
-
);
|
|
2379
|
+
import_bwip_js.default.toBuffer(
|
|
2380
|
+
{
|
|
2381
|
+
bcid,
|
|
2382
|
+
text: value,
|
|
2383
|
+
scale,
|
|
2384
|
+
height: barHeight,
|
|
2385
|
+
includetext,
|
|
2386
|
+
textxalign: textalign
|
|
2387
|
+
},
|
|
2388
|
+
(err, png) => {
|
|
2389
|
+
if (err) {
|
|
2390
|
+
return reject(
|
|
2391
|
+
toPdfEngineError(err, {
|
|
2392
|
+
code: "PDF_ERROR_BARCODE_GENERATION_FAILED" /* PDF_ERROR_BARCODE_GENERATION_FAILED */,
|
|
2393
|
+
message: "Failed to generate barcode.",
|
|
2394
|
+
statusCode: 500,
|
|
2395
|
+
details: {
|
|
2396
|
+
valuePreview: String(value).slice(0, 60),
|
|
2397
|
+
bcType
|
|
2398
|
+
},
|
|
2399
|
+
retryable: false
|
|
2400
|
+
})
|
|
2401
|
+
);
|
|
2402
|
+
}
|
|
2403
|
+
resolve(png);
|
|
1665
2404
|
}
|
|
1666
|
-
|
|
1667
|
-
});
|
|
2405
|
+
);
|
|
1668
2406
|
});
|
|
1669
2407
|
}
|
|
1670
2408
|
async function materializeQrAndBarcodesInBlocks(blocks) {
|
|
1671
2409
|
const out = [];
|
|
1672
2410
|
for (const block of blocks) {
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
out.push({
|
|
1680
|
-
...colBlock,
|
|
1681
|
-
columns: newCols
|
|
1682
|
-
});
|
|
1683
|
-
} else if (block.type === "signature") {
|
|
1684
|
-
const sig = block;
|
|
1685
|
-
if (sig.blocks && sig.blocks.length) {
|
|
1686
|
-
const newInner = await materializeQrAndBarcodesInBlocks(sig.blocks);
|
|
1687
|
-
out.push({
|
|
1688
|
-
...sig,
|
|
1689
|
-
blocks: newInner
|
|
1690
|
-
});
|
|
1691
|
-
} else {
|
|
1692
|
-
out.push(block);
|
|
1693
|
-
}
|
|
1694
|
-
} else if (block.type === "qr") {
|
|
1695
|
-
const qb = { ...block };
|
|
2411
|
+
const blockAny = { ...block };
|
|
2412
|
+
if (blockAny.backgroundBlocks?.length) {
|
|
2413
|
+
blockAny.backgroundBlocks = await materializeQrAndBarcodesInBlocks(blockAny.backgroundBlocks);
|
|
2414
|
+
}
|
|
2415
|
+
if (block.type === "qr") {
|
|
2416
|
+
const qb = blockAny;
|
|
1696
2417
|
if (!qb.src && qb.value) {
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
qb.src = buf;
|
|
2418
|
+
qb.size = qb.size ?? 80;
|
|
2419
|
+
qb.src = await generateQrBuffer(qb.value, qb.size, qb.qrVersion, qb.errorCorrectionLevel);
|
|
1700
2420
|
}
|
|
1701
2421
|
out.push(qb);
|
|
1702
2422
|
} else if (block.type === "barcode") {
|
|
1703
|
-
const bb =
|
|
2423
|
+
const bb = blockAny;
|
|
1704
2424
|
if (!bb.src && bb.value) {
|
|
1705
|
-
|
|
2425
|
+
bb.src = await generateBarcodeBuffer(bb.value, {
|
|
1706
2426
|
bcType: bb.bcType,
|
|
1707
2427
|
scale: bb.scale,
|
|
1708
2428
|
barHeight: bb.barHeight,
|
|
1709
2429
|
includetext: bb.includetext,
|
|
1710
2430
|
textalign: bb.textalign
|
|
1711
2431
|
});
|
|
1712
|
-
bb.src = buf;
|
|
1713
2432
|
}
|
|
1714
2433
|
out.push(bb);
|
|
2434
|
+
} else if (block.type === "columns") {
|
|
2435
|
+
out.push({
|
|
2436
|
+
...blockAny,
|
|
2437
|
+
columns: await Promise.all(block.columns.map((col) => materializeQrAndBarcodesInBlocks(col)))
|
|
2438
|
+
});
|
|
2439
|
+
} else if (block.type === "signature" && block.blocks) {
|
|
2440
|
+
out.push({
|
|
2441
|
+
...blockAny,
|
|
2442
|
+
blocks: await materializeQrAndBarcodesInBlocks(block.blocks)
|
|
2443
|
+
});
|
|
2444
|
+
} else if (block.type === "table") {
|
|
2445
|
+
const tb = blockAny;
|
|
2446
|
+
const newBody = await Promise.all(
|
|
2447
|
+
tb.body.map(
|
|
2448
|
+
async (entry) => {
|
|
2449
|
+
const materializeCell = async (cell) => {
|
|
2450
|
+
if (!cell.blocks?.length) return cell;
|
|
2451
|
+
return {
|
|
2452
|
+
...cell,
|
|
2453
|
+
blocks: await materializeQrAndBarcodesInBlocks(cell.blocks)
|
|
2454
|
+
};
|
|
2455
|
+
};
|
|
2456
|
+
if (Array.isArray(entry)) {
|
|
2457
|
+
return await Promise.all(entry.map(materializeCell));
|
|
2458
|
+
}
|
|
2459
|
+
if (entry && typeof entry === "object" && "content" in entry && Array.isArray(entry.content)) {
|
|
2460
|
+
return {
|
|
2461
|
+
...entry,
|
|
2462
|
+
content: await Promise.all(entry.content.map(materializeCell))
|
|
2463
|
+
};
|
|
2464
|
+
}
|
|
2465
|
+
return entry;
|
|
2466
|
+
}
|
|
2467
|
+
)
|
|
2468
|
+
);
|
|
2469
|
+
out.push({ ...tb, body: newBody });
|
|
1715
2470
|
} else {
|
|
1716
|
-
out.push(
|
|
2471
|
+
out.push(blockAny);
|
|
1717
2472
|
}
|
|
1718
2473
|
}
|
|
1719
2474
|
return out;
|
|
@@ -1967,96 +2722,143 @@ function drawWatermarkForPage(doc, watermark, pageNumber, isLast) {
|
|
|
1967
2722
|
}
|
|
1968
2723
|
|
|
1969
2724
|
// src/renderer-engine/index.ts
|
|
1970
|
-
|
|
1971
|
-
|
|
2725
|
+
var BUILT_IN_DEFAULT_IMAGE = Buffer.from(images.default.slice(images.default.indexOf(",") + 1), "base64");
|
|
2726
|
+
async function materializeFooterAssets(footer, fallbackImage) {
|
|
2727
|
+
if (!footer) return footer;
|
|
2728
|
+
if (typeof footer === "function") {
|
|
2729
|
+
return footer;
|
|
2730
|
+
}
|
|
2731
|
+
if (Array.isArray(footer)) {
|
|
2732
|
+
let blocks = await materializeQrAndBarcodesInBlocks(footer);
|
|
2733
|
+
blocks = await materializeImagesInBlocks(blocks, fallbackImage);
|
|
2734
|
+
return blocks;
|
|
2735
|
+
}
|
|
2736
|
+
if (footer.type) {
|
|
2737
|
+
let blocks = await materializeQrAndBarcodesInBlocks([footer]);
|
|
2738
|
+
blocks = await materializeImagesInBlocks(blocks, fallbackImage);
|
|
2739
|
+
return blocks[0];
|
|
2740
|
+
}
|
|
2741
|
+
const footerDef = footer;
|
|
2742
|
+
if (footerDef.backgroundImage) {
|
|
2743
|
+
footerDef.backgroundImage = await normalizeImageSrc(footerDef.backgroundImage, fallbackImage);
|
|
2744
|
+
}
|
|
2745
|
+
if (footerDef.blocks?.length) {
|
|
2746
|
+
footerDef.blocks = await materializeQrAndBarcodesInBlocks(footerDef.blocks);
|
|
2747
|
+
footerDef.blocks = await materializeImagesInBlocks(footerDef.blocks, fallbackImage);
|
|
2748
|
+
}
|
|
2749
|
+
if (footerDef.backgroundBlocks?.length) {
|
|
2750
|
+
footerDef.backgroundBlocks = await materializeQrAndBarcodesInBlocks(footerDef.backgroundBlocks);
|
|
2751
|
+
footerDef.backgroundBlocks = await materializeImagesInBlocks(footerDef.backgroundBlocks, fallbackImage);
|
|
2752
|
+
}
|
|
2753
|
+
return footerDef;
|
|
2754
|
+
}
|
|
2755
|
+
async function materializeDocAssets(def, fallbackImage) {
|
|
2756
|
+
if (def.header?.blocks?.length) {
|
|
1972
2757
|
def.header.blocks = await materializeQrAndBarcodesInBlocks(def.header.blocks);
|
|
1973
|
-
def.header.blocks = await materializeImagesInBlocks(def.header.blocks);
|
|
2758
|
+
def.header.blocks = await materializeImagesInBlocks(def.header.blocks, fallbackImage);
|
|
2759
|
+
}
|
|
2760
|
+
if (def.header?.backgroundImage) {
|
|
2761
|
+
def.header.backgroundImage = await normalizeImageSrc(def.header.backgroundImage, fallbackImage);
|
|
2762
|
+
}
|
|
2763
|
+
if (def.header?.backgroundBlocks?.length) {
|
|
2764
|
+
def.header.backgroundBlocks = await materializeQrAndBarcodesInBlocks(def.header.backgroundBlocks);
|
|
2765
|
+
def.header.backgroundBlocks = await materializeImagesInBlocks(def.header.backgroundBlocks, fallbackImage);
|
|
1974
2766
|
}
|
|
1975
2767
|
def.content = await materializeQrAndBarcodesInBlocks(def.content);
|
|
1976
|
-
def.content = await materializeImagesInBlocks(def.content);
|
|
2768
|
+
def.content = await materializeImagesInBlocks(def.content, fallbackImage);
|
|
1977
2769
|
if (def.pageBackground?.src) {
|
|
1978
|
-
def.pageBackground.src = await normalizeImageSrc(def.pageBackground.src);
|
|
2770
|
+
def.pageBackground.src = await normalizeImageSrc(def.pageBackground.src, fallbackImage);
|
|
1979
2771
|
}
|
|
1980
|
-
|
|
1981
|
-
|
|
2772
|
+
def.footer = await materializeFooterAssets(def.footer, fallbackImage);
|
|
2773
|
+
}
|
|
2774
|
+
function runRender(doc, def, fallbackImage) {
|
|
2775
|
+
const headerBandHeight = def.margins.top ?? 0;
|
|
2776
|
+
const footerBandHeight = def.margins.bottom ?? 0;
|
|
2777
|
+
if (def.fonts && def.fonts.length) {
|
|
2778
|
+
for (const font of def.fonts) {
|
|
2779
|
+
try {
|
|
2780
|
+
doc.registerFont(font.name, font.src);
|
|
2781
|
+
} catch (e) {
|
|
2782
|
+
console.warn("Failed to register font:", font.name, e);
|
|
2783
|
+
}
|
|
2784
|
+
}
|
|
1982
2785
|
}
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
2786
|
+
const ctx = createInitialContext(doc);
|
|
2787
|
+
const styles = def.styles ?? {};
|
|
2788
|
+
const finishPage2 = (addNewPage) => finishPage({
|
|
2789
|
+
addNewPage,
|
|
2790
|
+
doc,
|
|
2791
|
+
def,
|
|
2792
|
+
ctx,
|
|
2793
|
+
footerBandHeight,
|
|
2794
|
+
renderBlockArray,
|
|
2795
|
+
startNewPageLayout
|
|
2796
|
+
});
|
|
2797
|
+
const processSignatureBlock = createProcessSignatureBlock({
|
|
2798
|
+
doc,
|
|
2799
|
+
ctx,
|
|
2800
|
+
styles,
|
|
2801
|
+
finishPage: finishPage2,
|
|
2802
|
+
contentEnvFn: contentEnv
|
|
2803
|
+
});
|
|
2804
|
+
const { renderBlock, renderBlockArray } = createBlockRenderer({
|
|
2805
|
+
doc,
|
|
2806
|
+
ctx,
|
|
2807
|
+
styles,
|
|
2808
|
+
computeColumnPixelWidths,
|
|
2809
|
+
finishPage: finishPage2,
|
|
2810
|
+
processSignatureBlock,
|
|
2811
|
+
defaultImage: fallbackImage
|
|
2812
|
+
});
|
|
2813
|
+
const startNewPageLayout = createStartNewPageLayout({
|
|
2814
|
+
doc,
|
|
2815
|
+
def,
|
|
2816
|
+
ctx,
|
|
2817
|
+
headerBandHeight,
|
|
2818
|
+
renderBlockArray
|
|
2819
|
+
});
|
|
2820
|
+
doc.on("pageAdded", () => {
|
|
2821
|
+
if (ctx.inManualPageAdd) return;
|
|
2822
|
+
ctx.pageNumber += 1;
|
|
2823
|
+
drawPageBackground(doc, def.pageBackground);
|
|
2824
|
+
drawHeader(doc, def, headerBandHeight, def.header ?? void 0, renderBlockArray);
|
|
2825
|
+
const mode = def.watermark?.mode;
|
|
2826
|
+
if (def.watermark && !watermarkUsesLast(mode)) {
|
|
2827
|
+
drawWatermarkForPage(doc, def.watermark, ctx.pageNumber, false);
|
|
2828
|
+
}
|
|
2829
|
+
ctx.currentY = doc.page.margins.top;
|
|
2830
|
+
});
|
|
2831
|
+
startNewPageLayout();
|
|
2832
|
+
for (const block of def.content) {
|
|
2833
|
+
if (block.type === "signature") {
|
|
2834
|
+
processSignatureBlock(block);
|
|
2835
|
+
continue;
|
|
2836
|
+
}
|
|
2837
|
+
if (ctx.afterSignature) {
|
|
2838
|
+
finishPage2(true);
|
|
2839
|
+
ctx.afterSignature = false;
|
|
1987
2840
|
}
|
|
2841
|
+
renderBlock(block, null, contentEnv(doc));
|
|
1988
2842
|
}
|
|
2843
|
+
finishPage2(false);
|
|
2844
|
+
doc.end();
|
|
2845
|
+
}
|
|
2846
|
+
async function renderCustomPdf(def, outputPath) {
|
|
2847
|
+
const fallbackImage = def.defaultImage ?? BUILT_IN_DEFAULT_IMAGE;
|
|
2848
|
+
await materializeDocAssets(def, fallbackImage);
|
|
1989
2849
|
return new Promise((resolve, reject) => {
|
|
1990
|
-
const headerBandHeight = def.margins.top ?? 0;
|
|
1991
|
-
const footerBandHeight = def.margins.bottom ?? 0;
|
|
1992
2850
|
const doc = new import_pdfkit.default({
|
|
1993
2851
|
size: def.pageSize || "A4",
|
|
1994
2852
|
layout: def.pageOrientation === "landscape" ? "landscape" : "portrait",
|
|
1995
2853
|
margins: {
|
|
1996
|
-
top:
|
|
1997
|
-
bottom:
|
|
2854
|
+
top: def.margins.top ?? 0,
|
|
2855
|
+
bottom: def.margins.bottom ?? 0,
|
|
1998
2856
|
left: def.margins.left,
|
|
1999
2857
|
right: def.margins.right
|
|
2000
2858
|
}
|
|
2001
2859
|
});
|
|
2002
|
-
if (def.fonts && def.fonts.length) {
|
|
2003
|
-
for (const f of def.fonts) {
|
|
2004
|
-
try {
|
|
2005
|
-
doc.registerFont(f.name, f.src);
|
|
2006
|
-
} catch (e) {
|
|
2007
|
-
console.warn("Failed to register font:", f.name, e);
|
|
2008
|
-
}
|
|
2009
|
-
}
|
|
2010
|
-
}
|
|
2011
2860
|
const stream = import_fs.default.createWriteStream(outputPath);
|
|
2012
2861
|
doc.pipe(stream);
|
|
2013
|
-
const ctx = createInitialContext(doc);
|
|
2014
|
-
const styles = def.styles ?? {};
|
|
2015
|
-
const finishPage2 = (addNewPage) => finishPage({
|
|
2016
|
-
addNewPage,
|
|
2017
|
-
doc,
|
|
2018
|
-
def,
|
|
2019
|
-
ctx,
|
|
2020
|
-
footerBandHeight,
|
|
2021
|
-
renderBlockArray,
|
|
2022
|
-
startNewPageLayout
|
|
2023
|
-
});
|
|
2024
|
-
const processSignatureBlock = createProcessSignatureBlock({
|
|
2025
|
-
doc,
|
|
2026
|
-
ctx,
|
|
2027
|
-
styles,
|
|
2028
|
-
finishPage: finishPage2,
|
|
2029
|
-
contentEnvFn: contentEnv
|
|
2030
|
-
});
|
|
2031
|
-
const { renderBlock, renderBlockArray } = createBlockRenderer({
|
|
2032
|
-
doc,
|
|
2033
|
-
ctx,
|
|
2034
|
-
styles,
|
|
2035
|
-
computeColumnPixelWidths,
|
|
2036
|
-
finishPage: finishPage2,
|
|
2037
|
-
processSignatureBlock
|
|
2038
|
-
});
|
|
2039
|
-
const startNewPageLayout = createStartNewPageLayout({
|
|
2040
|
-
doc,
|
|
2041
|
-
def,
|
|
2042
|
-
ctx,
|
|
2043
|
-
headerBandHeight,
|
|
2044
|
-
renderBlockArray
|
|
2045
|
-
});
|
|
2046
|
-
startNewPageLayout();
|
|
2047
|
-
for (const block of def.content) {
|
|
2048
|
-
if (block.type === "signature") {
|
|
2049
|
-
processSignatureBlock(block);
|
|
2050
|
-
continue;
|
|
2051
|
-
}
|
|
2052
|
-
if (ctx.afterSignature) {
|
|
2053
|
-
finishPage2(true);
|
|
2054
|
-
ctx.afterSignature = false;
|
|
2055
|
-
}
|
|
2056
|
-
renderBlock(block, null, contentEnv(doc));
|
|
2057
|
-
}
|
|
2058
|
-
finishPage2(false);
|
|
2059
|
-
doc.end();
|
|
2060
2862
|
stream.on("finish", () => resolve());
|
|
2061
2863
|
stream.on(
|
|
2062
2864
|
"error",
|
|
@@ -2070,113 +2872,38 @@ async function renderCustomPdf(def, outputPath) {
|
|
|
2070
2872
|
})
|
|
2071
2873
|
)
|
|
2072
2874
|
);
|
|
2875
|
+
runRender(doc, def, fallbackImage);
|
|
2073
2876
|
});
|
|
2074
2877
|
}
|
|
2075
2878
|
async function renderCustomPdfToBuffer(def) {
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
def.header.blocks = await materializeImagesInBlocks(def.header.blocks);
|
|
2079
|
-
}
|
|
2080
|
-
def.content = await materializeQrAndBarcodesInBlocks(def.content);
|
|
2081
|
-
def.content = await materializeImagesInBlocks(def.content);
|
|
2082
|
-
if (def.pageBackground?.src) {
|
|
2083
|
-
def.pageBackground.src = await normalizeImageSrc(def.pageBackground.src);
|
|
2084
|
-
}
|
|
2085
|
-
if (def.header?.backgroundImage) {
|
|
2086
|
-
def.header.backgroundImage = await normalizeImageSrc(def.header.backgroundImage);
|
|
2087
|
-
}
|
|
2088
|
-
if (def.footer && typeof def.footer !== "function") {
|
|
2089
|
-
const footer = def.footer;
|
|
2090
|
-
if (footer.backgroundImage) {
|
|
2091
|
-
footer.backgroundImage = await normalizeImageSrc(footer.backgroundImage);
|
|
2092
|
-
}
|
|
2093
|
-
}
|
|
2879
|
+
const fallbackImage = def.defaultImage ?? BUILT_IN_DEFAULT_IMAGE;
|
|
2880
|
+
await materializeDocAssets(def, fallbackImage);
|
|
2094
2881
|
return new Promise((resolve, reject) => {
|
|
2095
|
-
const headerBandHeight = def.margins.top ?? 0;
|
|
2096
|
-
const footerBandHeight = def.margins.bottom ?? 0;
|
|
2097
2882
|
const doc = new import_pdfkit.default({
|
|
2098
2883
|
size: def.pageSize || "A4",
|
|
2099
2884
|
layout: def.pageOrientation === "landscape" ? "landscape" : "portrait",
|
|
2100
2885
|
margins: {
|
|
2101
|
-
top:
|
|
2102
|
-
bottom:
|
|
2886
|
+
top: def.margins.top ?? 0,
|
|
2887
|
+
bottom: def.margins.bottom ?? 0,
|
|
2103
2888
|
left: def.margins.left,
|
|
2104
2889
|
right: def.margins.right
|
|
2105
2890
|
}
|
|
2106
2891
|
});
|
|
2107
2892
|
const chunks = [];
|
|
2108
|
-
doc.on("data", (chunk) =>
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
});
|
|
2114
|
-
doc.on("error", (err) => {
|
|
2115
|
-
reject(
|
|
2893
|
+
doc.on("data", (chunk) => chunks.push(chunk));
|
|
2894
|
+
doc.on("end", () => resolve(Buffer.concat(chunks)));
|
|
2895
|
+
doc.on(
|
|
2896
|
+
"error",
|
|
2897
|
+
(err) => reject(
|
|
2116
2898
|
toPdfEngineError(err, {
|
|
2117
2899
|
code: "PDF_ERROR_PDFKIT_ERROR" /* PDF_ERROR_PDFKIT_ERROR */,
|
|
2118
2900
|
message: "PDFKit emitted an error while rendering.",
|
|
2119
2901
|
statusCode: 500,
|
|
2120
2902
|
retryable: true
|
|
2121
2903
|
})
|
|
2122
|
-
)
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
for (const f of def.fonts) {
|
|
2126
|
-
try {
|
|
2127
|
-
doc.registerFont(f.name, f.src);
|
|
2128
|
-
} catch (e) {
|
|
2129
|
-
console.warn("Failed to register font:", f.name, e);
|
|
2130
|
-
}
|
|
2131
|
-
}
|
|
2132
|
-
}
|
|
2133
|
-
const ctx = createInitialContext(doc);
|
|
2134
|
-
const styles = def.styles ?? {};
|
|
2135
|
-
const finishPage2 = (addNewPage) => finishPage({
|
|
2136
|
-
addNewPage,
|
|
2137
|
-
doc,
|
|
2138
|
-
def,
|
|
2139
|
-
ctx,
|
|
2140
|
-
footerBandHeight,
|
|
2141
|
-
renderBlockArray,
|
|
2142
|
-
startNewPageLayout
|
|
2143
|
-
});
|
|
2144
|
-
const processSignatureBlock = createProcessSignatureBlock({
|
|
2145
|
-
doc,
|
|
2146
|
-
ctx,
|
|
2147
|
-
styles,
|
|
2148
|
-
finishPage: finishPage2,
|
|
2149
|
-
contentEnvFn: contentEnv
|
|
2150
|
-
});
|
|
2151
|
-
const { renderBlock, renderBlockArray } = createBlockRenderer({
|
|
2152
|
-
doc,
|
|
2153
|
-
ctx,
|
|
2154
|
-
styles,
|
|
2155
|
-
computeColumnPixelWidths,
|
|
2156
|
-
finishPage: finishPage2,
|
|
2157
|
-
processSignatureBlock
|
|
2158
|
-
});
|
|
2159
|
-
const startNewPageLayout = createStartNewPageLayout({
|
|
2160
|
-
doc,
|
|
2161
|
-
def,
|
|
2162
|
-
ctx,
|
|
2163
|
-
headerBandHeight,
|
|
2164
|
-
renderBlockArray
|
|
2165
|
-
});
|
|
2166
|
-
startNewPageLayout();
|
|
2167
|
-
for (const block of def.content) {
|
|
2168
|
-
if (block.type === "signature") {
|
|
2169
|
-
processSignatureBlock(block);
|
|
2170
|
-
continue;
|
|
2171
|
-
}
|
|
2172
|
-
if (ctx.afterSignature) {
|
|
2173
|
-
finishPage2(true);
|
|
2174
|
-
ctx.afterSignature = false;
|
|
2175
|
-
}
|
|
2176
|
-
renderBlock(block, null, contentEnv(doc));
|
|
2177
|
-
}
|
|
2178
|
-
finishPage2(false);
|
|
2179
|
-
doc.end();
|
|
2904
|
+
)
|
|
2905
|
+
);
|
|
2906
|
+
runRender(doc, def, fallbackImage);
|
|
2180
2907
|
});
|
|
2181
2908
|
}
|
|
2182
2909
|
// Annotate the CommonJS export names for ESM import in node:
|
|
@@ -2185,8 +2912,42 @@ async function renderCustomPdfToBuffer(def) {
|
|
|
2185
2912
|
PdfEngineError,
|
|
2186
2913
|
PdfEngineErrorCode,
|
|
2187
2914
|
QR_ERROR_LEVEL,
|
|
2915
|
+
computeColumnPixelWidths,
|
|
2916
|
+
contentEnv,
|
|
2917
|
+
createBlockRenderer,
|
|
2918
|
+
createBottomLimitForContent,
|
|
2919
|
+
createEnsureSpaceFor,
|
|
2920
|
+
createInitialContext,
|
|
2921
|
+
createMeasureBlockHeight,
|
|
2922
|
+
createProcessSignatureBlock,
|
|
2923
|
+
createStartNewPageLayout,
|
|
2924
|
+
drawFooter,
|
|
2925
|
+
drawHeader,
|
|
2926
|
+
drawPageBackground,
|
|
2927
|
+
drawSignatureBlock,
|
|
2928
|
+
drawStyledText,
|
|
2929
|
+
drawWatermarkForPage,
|
|
2930
|
+
finishPage,
|
|
2931
|
+
generateBarcodeBuffer,
|
|
2932
|
+
generateQrBuffer,
|
|
2933
|
+
getBottomLimitForContent,
|
|
2934
|
+
getFontNameForText,
|
|
2935
|
+
hasPadding,
|
|
2936
|
+
images,
|
|
2188
2937
|
isPdfEngineError,
|
|
2938
|
+
mapBarcodeTypeToBcid,
|
|
2939
|
+
materializeImagesInBlocks,
|
|
2940
|
+
materializeQrAndBarcodesInBlocks,
|
|
2941
|
+
mergeStyleDefs,
|
|
2942
|
+
normalizeImageSrc,
|
|
2189
2943
|
renderCustomPdf,
|
|
2190
2944
|
renderCustomPdfToBuffer,
|
|
2191
|
-
|
|
2945
|
+
resolveBlockPadding,
|
|
2946
|
+
resolveFooterPadding,
|
|
2947
|
+
resolveHeaderPadding,
|
|
2948
|
+
resolveSpacing,
|
|
2949
|
+
resolveTableCell,
|
|
2950
|
+
resolveTextBlock,
|
|
2951
|
+
toPdfEngineError,
|
|
2952
|
+
watermarkUsesLast
|
|
2192
2953
|
});
|