av6-pdf-engine 1.0.9 → 1.1.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/dist/index.d.mts +14 -1
- package/dist/index.d.ts +14 -1
- package/dist/index.js +215 -86
- package/dist/index.mjs +215 -86
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -61,6 +61,12 @@ interface TableCell {
|
|
|
61
61
|
color?: string;
|
|
62
62
|
fillColor?: string;
|
|
63
63
|
style?: StyleRef;
|
|
64
|
+
colSpan?: number;
|
|
65
|
+
rowSpan?: number;
|
|
66
|
+
paddingTop?: number;
|
|
67
|
+
paddingRight?: number;
|
|
68
|
+
paddingBottom?: number;
|
|
69
|
+
paddingLeft?: number;
|
|
64
70
|
}
|
|
65
71
|
interface TableBlock extends BaseBlock {
|
|
66
72
|
type: "table";
|
|
@@ -78,6 +84,12 @@ interface TableBlock extends BaseBlock {
|
|
|
78
84
|
marginLeft?: number;
|
|
79
85
|
marginRight?: number;
|
|
80
86
|
}
|
|
87
|
+
interface PlacedCell {
|
|
88
|
+
cell: TableCell;
|
|
89
|
+
startCol: number;
|
|
90
|
+
colSpan: number;
|
|
91
|
+
rowSpan: number;
|
|
92
|
+
}
|
|
81
93
|
|
|
82
94
|
interface ColumnsBlock extends BaseBlock {
|
|
83
95
|
type: "columns";
|
|
@@ -217,6 +229,7 @@ interface FontRegistration {
|
|
|
217
229
|
interface CustomDocDefinition {
|
|
218
230
|
pageSize?: string;
|
|
219
231
|
margins: PageMargins;
|
|
232
|
+
pageOrientation?: "portrait" | "landscape";
|
|
220
233
|
/** Optional font registrations (custom TTF/OTF) */
|
|
221
234
|
fonts?: FontRegistration[];
|
|
222
235
|
header?: HeaderDef;
|
|
@@ -339,4 +352,4 @@ declare function toPdfEngineError(cause: unknown, fallback: {
|
|
|
339
352
|
declare function renderCustomPdf(def: CustomDocDefinition, outputPath: string): Promise<void>;
|
|
340
353
|
declare function renderCustomPdfToBuffer(def: CustomDocDefinition): Promise<Buffer>;
|
|
341
354
|
|
|
342
|
-
export { type Alignment, BARCODE_TYPES, type BarcodeBlock, type BarcodeType, type BaseBlock, type Block, type BuiltInFont, type ColumnsBlock, type CustomDocDefinition, type FontName, type FontRegistration, type FooterDef, type FooterInput, type HeaderDef, type ImageBlock, type InlineTextStyle, type KeyValueGridBlock, type KeyValueItem, type LineBlock, type Orientation, type PDFDoc, type PageBackgroundDef, type PageBreakBlock, type PageContext, type PageMargins, PdfEngineError, PdfEngineErrorCode, type QRErrorLevel, QR_ERROR_LEVEL, type QrCodeBlock, type RenderEnv, type SignatureBlock, type StyleDef, type StyleRef, type TableBlock, type TableCell, type TextBlock, type WatermarkDef, type WatermarkMode, type Width, isPdfEngineError, renderCustomPdf, renderCustomPdfToBuffer, toPdfEngineError };
|
|
355
|
+
export { type Alignment, BARCODE_TYPES, type BarcodeBlock, type BarcodeType, type BaseBlock, type Block, type BuiltInFont, type ColumnsBlock, type CustomDocDefinition, type FontName, type FontRegistration, type FooterDef, type FooterInput, type HeaderDef, type ImageBlock, type InlineTextStyle, type KeyValueGridBlock, type KeyValueItem, type LineBlock, type Orientation, type PDFDoc, type PageBackgroundDef, type PageBreakBlock, type PageContext, type PageMargins, PdfEngineError, PdfEngineErrorCode, type PlacedCell, type QRErrorLevel, QR_ERROR_LEVEL, type QrCodeBlock, type RenderEnv, type SignatureBlock, type StyleDef, type StyleRef, type TableBlock, type TableCell, type TextBlock, type WatermarkDef, type WatermarkMode, type Width, isPdfEngineError, renderCustomPdf, renderCustomPdfToBuffer, toPdfEngineError };
|
package/dist/index.d.ts
CHANGED
|
@@ -61,6 +61,12 @@ interface TableCell {
|
|
|
61
61
|
color?: string;
|
|
62
62
|
fillColor?: string;
|
|
63
63
|
style?: StyleRef;
|
|
64
|
+
colSpan?: number;
|
|
65
|
+
rowSpan?: number;
|
|
66
|
+
paddingTop?: number;
|
|
67
|
+
paddingRight?: number;
|
|
68
|
+
paddingBottom?: number;
|
|
69
|
+
paddingLeft?: number;
|
|
64
70
|
}
|
|
65
71
|
interface TableBlock extends BaseBlock {
|
|
66
72
|
type: "table";
|
|
@@ -78,6 +84,12 @@ interface TableBlock extends BaseBlock {
|
|
|
78
84
|
marginLeft?: number;
|
|
79
85
|
marginRight?: number;
|
|
80
86
|
}
|
|
87
|
+
interface PlacedCell {
|
|
88
|
+
cell: TableCell;
|
|
89
|
+
startCol: number;
|
|
90
|
+
colSpan: number;
|
|
91
|
+
rowSpan: number;
|
|
92
|
+
}
|
|
81
93
|
|
|
82
94
|
interface ColumnsBlock extends BaseBlock {
|
|
83
95
|
type: "columns";
|
|
@@ -217,6 +229,7 @@ interface FontRegistration {
|
|
|
217
229
|
interface CustomDocDefinition {
|
|
218
230
|
pageSize?: string;
|
|
219
231
|
margins: PageMargins;
|
|
232
|
+
pageOrientation?: "portrait" | "landscape";
|
|
220
233
|
/** Optional font registrations (custom TTF/OTF) */
|
|
221
234
|
fonts?: FontRegistration[];
|
|
222
235
|
header?: HeaderDef;
|
|
@@ -339,4 +352,4 @@ declare function toPdfEngineError(cause: unknown, fallback: {
|
|
|
339
352
|
declare function renderCustomPdf(def: CustomDocDefinition, outputPath: string): Promise<void>;
|
|
340
353
|
declare function renderCustomPdfToBuffer(def: CustomDocDefinition): Promise<Buffer>;
|
|
341
354
|
|
|
342
|
-
export { type Alignment, BARCODE_TYPES, type BarcodeBlock, type BarcodeType, type BaseBlock, type Block, type BuiltInFont, type ColumnsBlock, type CustomDocDefinition, type FontName, type FontRegistration, type FooterDef, type FooterInput, type HeaderDef, type ImageBlock, type InlineTextStyle, type KeyValueGridBlock, type KeyValueItem, type LineBlock, type Orientation, type PDFDoc, type PageBackgroundDef, type PageBreakBlock, type PageContext, type PageMargins, PdfEngineError, PdfEngineErrorCode, type QRErrorLevel, QR_ERROR_LEVEL, type QrCodeBlock, type RenderEnv, type SignatureBlock, type StyleDef, type StyleRef, type TableBlock, type TableCell, type TextBlock, type WatermarkDef, type WatermarkMode, type Width, isPdfEngineError, renderCustomPdf, renderCustomPdfToBuffer, toPdfEngineError };
|
|
355
|
+
export { type Alignment, BARCODE_TYPES, type BarcodeBlock, type BarcodeType, type BaseBlock, type Block, type BuiltInFont, type ColumnsBlock, type CustomDocDefinition, type FontName, type FontRegistration, type FooterDef, type FooterInput, type HeaderDef, type ImageBlock, type InlineTextStyle, type KeyValueGridBlock, type KeyValueItem, type LineBlock, type Orientation, type PDFDoc, type PageBackgroundDef, type PageBreakBlock, type PageContext, type PageMargins, PdfEngineError, PdfEngineErrorCode, type PlacedCell, type QRErrorLevel, QR_ERROR_LEVEL, type QrCodeBlock, type RenderEnv, type SignatureBlock, type StyleDef, type StyleRef, type TableBlock, type TableCell, type TextBlock, type WatermarkDef, type WatermarkMode, type Width, isPdfEngineError, renderCustomPdf, renderCustomPdfToBuffer, toPdfEngineError };
|
package/dist/index.js
CHANGED
|
@@ -519,29 +519,117 @@ var processLineBlock = (doc, ctx, block, y, env, ensureSpaceFor) => {
|
|
|
519
519
|
};
|
|
520
520
|
|
|
521
521
|
// src/renderer-engine/blocks/table.ts
|
|
522
|
+
var normalizeSpan = (value) => {
|
|
523
|
+
if (!value || value < 1) return 1;
|
|
524
|
+
return Math.floor(value);
|
|
525
|
+
};
|
|
526
|
+
var sum = (arr) => arr.reduce((a, b) => a + b, 0);
|
|
527
|
+
var getCellFontName = (cell) => {
|
|
528
|
+
const isBold = !!cell.bold;
|
|
529
|
+
const isItalic = !!cell.italic;
|
|
530
|
+
if (cell.font) return cell.font;
|
|
531
|
+
if (isBold && isItalic) return "Helvetica-BoldOblique";
|
|
532
|
+
if (isBold) return "Helvetica-Bold";
|
|
533
|
+
if (isItalic) return "Helvetica-Oblique";
|
|
534
|
+
return "Helvetica";
|
|
535
|
+
};
|
|
536
|
+
var decrementActiveSpans = (activeRowSpans) => {
|
|
537
|
+
for (let i = 0; i < activeRowSpans.length; i++) {
|
|
538
|
+
if (activeRowSpans[i] > 0) {
|
|
539
|
+
activeRowSpans[i] -= 1;
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
};
|
|
543
|
+
var findNextFreeCol = (activeRowSpans, fromIndex) => {
|
|
544
|
+
let col = fromIndex;
|
|
545
|
+
while (col < activeRowSpans.length && activeRowSpans[col] > 0) {
|
|
546
|
+
col++;
|
|
547
|
+
}
|
|
548
|
+
return col;
|
|
549
|
+
};
|
|
550
|
+
var buildPlacedRow = (row, totalCols, activeRowSpans) => {
|
|
551
|
+
const placed = [];
|
|
552
|
+
let cursor = 0;
|
|
553
|
+
for (const rawCell of row) {
|
|
554
|
+
cursor = findNextFreeCol(activeRowSpans, cursor);
|
|
555
|
+
if (cursor >= totalCols) break;
|
|
556
|
+
const colSpan = Math.min(normalizeSpan(rawCell.colSpan), totalCols - cursor);
|
|
557
|
+
const rowSpan = normalizeSpan(rawCell.rowSpan);
|
|
558
|
+
placed.push({
|
|
559
|
+
cell: rawCell,
|
|
560
|
+
startCol: cursor,
|
|
561
|
+
colSpan,
|
|
562
|
+
rowSpan
|
|
563
|
+
});
|
|
564
|
+
if (rowSpan > 1) {
|
|
565
|
+
for (let c = cursor; c < cursor + colSpan; c++) {
|
|
566
|
+
activeRowSpans[c] = Math.max(activeRowSpans[c], rowSpan - 1);
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
cursor += colSpan;
|
|
570
|
+
}
|
|
571
|
+
return placed;
|
|
572
|
+
};
|
|
573
|
+
var getPlacedCellWidth = (colWidths, startCol, colSpan) => {
|
|
574
|
+
return sum(colWidths.slice(startCol, startCol + colSpan));
|
|
575
|
+
};
|
|
576
|
+
var getRowSpanGroupHeight = (rowHeights, rowIndex, rowSpan) => {
|
|
577
|
+
return sum(rowHeights.slice(rowIndex, rowIndex + rowSpan));
|
|
578
|
+
};
|
|
522
579
|
var measureTableHeight = (doc, table, env, styles, computeColumnPixelWidths2) => {
|
|
523
580
|
const localLeft = table.marginLeft ?? 0;
|
|
524
581
|
const localRight = table.marginRight ?? 0;
|
|
525
582
|
const width = Math.max(env.innerWidth - localLeft - localRight, 1);
|
|
583
|
+
const totalCols = table.widths.length;
|
|
526
584
|
const colWidths = computeColumnPixelWidths2(table.widths, width);
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
row
|
|
585
|
+
const rowHeights = [];
|
|
586
|
+
const activeRowSpans = Array(totalCols).fill(0);
|
|
587
|
+
const placedRows = [];
|
|
588
|
+
for (let rowIndex = 0; rowIndex < table.body.length; rowIndex++) {
|
|
589
|
+
const row = table.body[rowIndex];
|
|
590
|
+
const placedRow = buildPlacedRow(row, totalCols, activeRowSpans);
|
|
591
|
+
placedRows.push(placedRow);
|
|
592
|
+
let rowHeight = 12;
|
|
593
|
+
placedRow.forEach(({ cell: rawCell, startCol, colSpan }) => {
|
|
532
594
|
const cell = resolveTableCell(styles, rawCell);
|
|
533
|
-
const
|
|
534
|
-
const
|
|
535
|
-
const
|
|
536
|
-
const
|
|
537
|
-
const
|
|
538
|
-
|
|
539
|
-
doc.
|
|
540
|
-
|
|
541
|
-
|
|
595
|
+
const paddingLeft = cell.paddingLeft ?? 2;
|
|
596
|
+
const paddingRight = cell.paddingRight ?? 2;
|
|
597
|
+
const paddingTop = cell.paddingTop ?? 2;
|
|
598
|
+
const paddingBottom = cell.paddingBottom ?? 2;
|
|
599
|
+
const colW = getPlacedCellWidth(colWidths, startCol, colSpan);
|
|
600
|
+
const textWidth = Math.max(colW - paddingLeft - paddingRight, 1);
|
|
601
|
+
doc.font(getCellFontName(cell));
|
|
602
|
+
doc.fontSize(cell.fontSize ?? 10);
|
|
603
|
+
const h = doc.heightOfString(cell.text, { width: textWidth }) + paddingTop + paddingBottom;
|
|
604
|
+
rowHeight = Math.max(rowHeight, h);
|
|
542
605
|
});
|
|
543
|
-
|
|
544
|
-
|
|
606
|
+
rowHeights.push(rowHeight);
|
|
607
|
+
decrementActiveSpans(activeRowSpans);
|
|
608
|
+
}
|
|
609
|
+
for (let rowIndex = 0; rowIndex < placedRows.length; rowIndex++) {
|
|
610
|
+
const placedRow = placedRows[rowIndex];
|
|
611
|
+
placedRow.forEach(({ cell: rawCell, startCol, colSpan, rowSpan }) => {
|
|
612
|
+
if (rowSpan <= 1) return;
|
|
613
|
+
const cell = resolveTableCell(styles, rawCell);
|
|
614
|
+
const paddingLeft = cell.paddingLeft ?? 2;
|
|
615
|
+
const paddingRight = cell.paddingRight ?? 2;
|
|
616
|
+
const paddingTop = cell.paddingTop ?? 2;
|
|
617
|
+
const paddingBottom = cell.paddingBottom ?? 2;
|
|
618
|
+
const colW = getPlacedCellWidth(colWidths, startCol, colSpan);
|
|
619
|
+
const textWidth = Math.max(colW - paddingLeft - paddingRight, 1);
|
|
620
|
+
doc.font(getCellFontName(cell));
|
|
621
|
+
doc.fontSize(cell.fontSize ?? 10);
|
|
622
|
+
const neededHeight = doc.heightOfString(cell.text, { width: textWidth }) + paddingTop + paddingBottom;
|
|
623
|
+
const currentGroupHeight = getRowSpanGroupHeight(rowHeights, rowIndex, rowSpan);
|
|
624
|
+
if (neededHeight > currentGroupHeight) {
|
|
625
|
+
const deficit = neededHeight - currentGroupHeight;
|
|
626
|
+
rowHeights[rowIndex + rowSpan - 1] = (rowHeights[rowIndex + rowSpan - 1] ?? 12) + deficit;
|
|
627
|
+
}
|
|
628
|
+
});
|
|
629
|
+
}
|
|
630
|
+
let totalHeight = 0;
|
|
631
|
+
totalHeight += table.marginTop ?? 0;
|
|
632
|
+
totalHeight += sum(rowHeights);
|
|
545
633
|
totalHeight += table.lineGap ?? 6;
|
|
546
634
|
totalHeight += table.marginBottom ?? 0;
|
|
547
635
|
return totalHeight;
|
|
@@ -555,6 +643,7 @@ var processTableBlock = (doc, ctx, styles, table, y, env, computeColumnPixelWidt
|
|
|
555
643
|
const mb = table.marginBottom ?? 0;
|
|
556
644
|
const baseY = y ?? ctx.currentY;
|
|
557
645
|
const startY = baseY + mt;
|
|
646
|
+
const totalCols = table.widths.length;
|
|
558
647
|
const colWidths = computeColumnPixelWidths2(table.widths, width);
|
|
559
648
|
const layout = table.layout ?? {
|
|
560
649
|
border: "all",
|
|
@@ -563,56 +652,84 @@ var processTableBlock = (doc, ctx, styles, table, y, env, computeColumnPixelWidt
|
|
|
563
652
|
};
|
|
564
653
|
const borderAll = layout.border !== "none";
|
|
565
654
|
const headerRows = table.headerRows ?? 0;
|
|
566
|
-
const
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
const
|
|
572
|
-
const
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
655
|
+
const buildPlacementAndHeights = (rows) => {
|
|
656
|
+
const placedRows = [];
|
|
657
|
+
const rowHeights = [];
|
|
658
|
+
const activeRowSpans = Array(totalCols).fill(0);
|
|
659
|
+
for (let rowIndex = 0; rowIndex < rows.length; rowIndex++) {
|
|
660
|
+
const row = rows[rowIndex];
|
|
661
|
+
const placedRow = buildPlacedRow(row, totalCols, activeRowSpans);
|
|
662
|
+
placedRows.push(placedRow);
|
|
663
|
+
let rowHeight = 12;
|
|
664
|
+
placedRow.forEach(({ cell: rawCell, startCol, colSpan }) => {
|
|
665
|
+
const cell = resolveTableCell(styles, rawCell);
|
|
666
|
+
const paddingLeft = cell.paddingLeft ?? 2;
|
|
667
|
+
const paddingRight = cell.paddingRight ?? 2;
|
|
668
|
+
const paddingTop = cell.paddingTop ?? 2;
|
|
669
|
+
const paddingBottom = cell.paddingBottom ?? 2;
|
|
670
|
+
const colW = getPlacedCellWidth(colWidths, startCol, colSpan);
|
|
671
|
+
const textWidth = Math.max(colW - paddingLeft - paddingRight, 1);
|
|
672
|
+
doc.font(getCellFontName(cell));
|
|
673
|
+
doc.fontSize(cell.fontSize ?? 10);
|
|
674
|
+
const h = doc.heightOfString(cell.text, { width: textWidth }) + paddingTop + paddingBottom;
|
|
675
|
+
rowHeight = Math.max(rowHeight, h);
|
|
676
|
+
});
|
|
677
|
+
rowHeights.push(rowHeight);
|
|
678
|
+
decrementActiveSpans(activeRowSpans);
|
|
679
|
+
}
|
|
680
|
+
for (let rowIndex = 0; rowIndex < placedRows.length; rowIndex++) {
|
|
681
|
+
const placedRow = placedRows[rowIndex];
|
|
682
|
+
placedRow.forEach(({ cell: rawCell, startCol, colSpan, rowSpan }) => {
|
|
683
|
+
if (rowSpan <= 1) return;
|
|
684
|
+
const cell = resolveTableCell(styles, rawCell);
|
|
685
|
+
const paddingLeft = cell.paddingLeft ?? 2;
|
|
686
|
+
const paddingRight = cell.paddingRight ?? 2;
|
|
687
|
+
const paddingTop = cell.paddingTop ?? 2;
|
|
688
|
+
const paddingBottom = cell.paddingBottom ?? 2;
|
|
689
|
+
const colW = getPlacedCellWidth(colWidths, startCol, colSpan);
|
|
690
|
+
const textWidth = Math.max(colW - paddingLeft - paddingRight, 1);
|
|
691
|
+
doc.font(getCellFontName(cell));
|
|
692
|
+
doc.fontSize(cell.fontSize ?? 10);
|
|
693
|
+
const neededHeight = doc.heightOfString(cell.text, { width: textWidth }) + paddingTop + paddingBottom;
|
|
694
|
+
const currentGroupHeight = getRowSpanGroupHeight(rowHeights, rowIndex, rowSpan);
|
|
695
|
+
if (neededHeight > currentGroupHeight) {
|
|
696
|
+
const deficit = neededHeight - currentGroupHeight;
|
|
697
|
+
rowHeights[rowIndex + rowSpan - 1] = (rowHeights[rowIndex + rowSpan - 1] ?? 12) + deficit;
|
|
698
|
+
}
|
|
699
|
+
});
|
|
700
|
+
}
|
|
701
|
+
return { placedRows, rowHeights };
|
|
582
702
|
};
|
|
583
|
-
const
|
|
584
|
-
|
|
703
|
+
const allLayout = buildPlacementAndHeights(table.body);
|
|
704
|
+
const drawPlacedRow = (placedRow, rowTop2, rowHeight, rowIndex, rowHeights, isHeaderRow, drawTopBorder) => {
|
|
705
|
+
placedRow.forEach(({ cell: rawCell, startCol, colSpan, rowSpan }) => {
|
|
585
706
|
const cell = resolveTableCell(styles, rawCell);
|
|
586
|
-
const colW = colWidths
|
|
587
|
-
const x = baseLeft + colWidths.slice(0,
|
|
707
|
+
const colW = getPlacedCellWidth(colWidths, startCol, colSpan);
|
|
708
|
+
const x = baseLeft + sum(colWidths.slice(0, startCol));
|
|
588
709
|
const fontSize = cell.fontSize ?? 10;
|
|
710
|
+
const drawHeight = getRowSpanGroupHeight(rowHeights, rowIndex, rowSpan);
|
|
711
|
+
const paddingLeft = cell.paddingLeft ?? 2;
|
|
712
|
+
const paddingRight = cell.paddingRight ?? 2;
|
|
713
|
+
const paddingTop = cell.paddingTop ?? 2;
|
|
714
|
+
const paddingBottom = cell.paddingBottom ?? 2;
|
|
589
715
|
doc.save();
|
|
590
716
|
if (cell.fillColor) {
|
|
591
|
-
doc.rect(x, rowTop2, colW,
|
|
717
|
+
doc.rect(x, rowTop2, colW, drawHeight).fillOpacity(1).fill(cell.fillColor);
|
|
592
718
|
doc.fillOpacity(1);
|
|
593
719
|
}
|
|
594
|
-
|
|
595
|
-
const isItalic = !!cell.italic;
|
|
596
|
-
const fontName = cell.font ? cell.font : isBold && isItalic ? "Helvetica-BoldOblique" : isBold ? "Helvetica-Bold" : isItalic ? "Helvetica-Oblique" : "Helvetica";
|
|
597
|
-
doc.font(fontName);
|
|
720
|
+
doc.font(getCellFontName(cell));
|
|
598
721
|
doc.fontSize(fontSize);
|
|
599
|
-
|
|
600
|
-
doc.fillColor(cell.color);
|
|
601
|
-
} else {
|
|
602
|
-
doc.fillColor("black");
|
|
603
|
-
}
|
|
722
|
+
doc.fillColor(cell.color ?? "black");
|
|
604
723
|
const align = cell.align ?? "left";
|
|
605
|
-
const textWidth = Math.max(colW -
|
|
606
|
-
const textHeight = doc.heightOfString(cell.text, {
|
|
607
|
-
|
|
608
|
-
});
|
|
609
|
-
let textY = rowTop2 + 2;
|
|
724
|
+
const textWidth = Math.max(colW - paddingLeft - paddingRight, 1);
|
|
725
|
+
const textHeight = doc.heightOfString(cell.text, { width: textWidth });
|
|
726
|
+
let textY = rowTop2 + paddingTop;
|
|
610
727
|
if (isHeaderRow) {
|
|
611
|
-
const available =
|
|
728
|
+
const available = Math.max(drawHeight - paddingTop - paddingBottom, 0);
|
|
612
729
|
const offset = Math.max((available - textHeight) / 2, 0);
|
|
613
|
-
textY = rowTop2 +
|
|
730
|
+
textY = rowTop2 + paddingTop + offset;
|
|
614
731
|
}
|
|
615
|
-
doc.text(cell.text, x +
|
|
732
|
+
doc.text(cell.text, x + paddingLeft, textY, {
|
|
616
733
|
width: textWidth,
|
|
617
734
|
align,
|
|
618
735
|
underline: !!cell.underline,
|
|
@@ -620,52 +737,58 @@ var processTableBlock = (doc, ctx, styles, table, y, env, computeColumnPixelWidt
|
|
|
620
737
|
link: cell.link
|
|
621
738
|
});
|
|
622
739
|
doc.restore();
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
doc.strokeColor(layout.vLineColor ?? "#ccc");
|
|
637
|
-
let x = baseLeft;
|
|
638
|
-
colWidths.forEach((colW) => {
|
|
740
|
+
if (borderAll) {
|
|
741
|
+
const bottomY = rowTop2 + drawHeight;
|
|
742
|
+
doc.save();
|
|
743
|
+
doc.lineWidth(0.5);
|
|
744
|
+
doc.strokeColor(layout.hLineColor ?? "#ccc");
|
|
745
|
+
if (drawTopBorder) {
|
|
746
|
+
doc.moveTo(x, rowTop2).lineTo(x + colW, rowTop2).stroke();
|
|
747
|
+
}
|
|
748
|
+
doc.moveTo(x, bottomY).lineTo(x + colW, bottomY).stroke();
|
|
749
|
+
doc.restore();
|
|
750
|
+
doc.save();
|
|
751
|
+
doc.lineWidth(0.5);
|
|
752
|
+
doc.strokeColor(layout.vLineColor ?? "#ccc");
|
|
639
753
|
doc.moveTo(x, rowTop2).lineTo(x, bottomY).stroke();
|
|
640
|
-
x
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
}
|
|
754
|
+
doc.moveTo(x + colW, rowTop2).lineTo(x + colW, bottomY).stroke();
|
|
755
|
+
doc.restore();
|
|
756
|
+
}
|
|
757
|
+
});
|
|
645
758
|
return rowTop2 + rowHeight;
|
|
646
759
|
};
|
|
760
|
+
const headerRowsSource = table.body.slice(0, headerRows);
|
|
647
761
|
const drawHeaderRowsOnNewPage = () => {
|
|
648
762
|
if (!headerRows) return doc.page.margins.top + mt;
|
|
763
|
+
const headerLayout = buildPlacementAndHeights(headerRowsSource);
|
|
649
764
|
let rowTop2 = doc.page.margins.top + mt;
|
|
650
|
-
for (let i = 0; i <
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
765
|
+
for (let i = 0; i < headerLayout.placedRows.length; i++) {
|
|
766
|
+
rowTop2 = drawPlacedRow(
|
|
767
|
+
headerLayout.placedRows[i],
|
|
768
|
+
rowTop2,
|
|
769
|
+
headerLayout.rowHeights[i],
|
|
770
|
+
i,
|
|
771
|
+
headerLayout.rowHeights,
|
|
772
|
+
true,
|
|
773
|
+
true
|
|
774
|
+
);
|
|
654
775
|
}
|
|
655
776
|
return rowTop2;
|
|
656
777
|
};
|
|
657
778
|
let rowTop = startY;
|
|
658
|
-
table.body.
|
|
779
|
+
for (let rowIndex = 0; rowIndex < table.body.length; rowIndex++) {
|
|
659
780
|
const isHeaderRow = rowIndex < headerRows;
|
|
660
|
-
const
|
|
781
|
+
const placedRow = allLayout.placedRows[rowIndex];
|
|
782
|
+
const rowHeight = allLayout.rowHeights[rowIndex];
|
|
783
|
+
const maxRowSpan = Math.max(...placedRow.map((p) => p.rowSpan), 1);
|
|
784
|
+
const reservedHeight = getRowSpanGroupHeight(allLayout.rowHeights, rowIndex, maxRowSpan);
|
|
661
785
|
const bottomLimit = bottomLimitForContent();
|
|
662
|
-
if (rowTop +
|
|
786
|
+
if (rowTop + reservedHeight > bottomLimit) {
|
|
663
787
|
finishPage2(true);
|
|
664
788
|
rowTop = headerRows ? drawHeaderRowsOnNewPage() : doc.page.margins.top + mt;
|
|
665
789
|
}
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
});
|
|
790
|
+
rowTop = drawPlacedRow(placedRow, rowTop, rowHeight, rowIndex, allLayout.rowHeights, isHeaderRow, true);
|
|
791
|
+
}
|
|
669
792
|
const newY = rowTop + (table.lineGap ?? 6) + mb;
|
|
670
793
|
if (y === null) ctx.currentY = newY;
|
|
671
794
|
return newY;
|
|
@@ -1109,7 +1232,11 @@ function resolveTableCell(styles, cell) {
|
|
|
1109
1232
|
italic: cell.italic ?? styleDef.italic,
|
|
1110
1233
|
color: cell.color ?? styleDef.color,
|
|
1111
1234
|
fillColor: cell.fillColor ?? styleDef.fillColor,
|
|
1112
|
-
font: cell.font ?? styleDef.font
|
|
1235
|
+
font: cell.font ?? styleDef.font,
|
|
1236
|
+
paddingTop: cell.paddingTop,
|
|
1237
|
+
paddingRight: cell.paddingRight,
|
|
1238
|
+
paddingBottom: cell.paddingBottom,
|
|
1239
|
+
paddingLeft: cell.paddingLeft
|
|
1113
1240
|
};
|
|
1114
1241
|
}
|
|
1115
1242
|
var getFontNameForText = (tb) => {
|
|
@@ -1780,6 +1907,7 @@ async function renderCustomPdf(def, outputPath) {
|
|
|
1780
1907
|
const footerBandHeight = def.margins.bottom ?? 0;
|
|
1781
1908
|
const doc = new import_pdfkit.default({
|
|
1782
1909
|
size: def.pageSize || "A4",
|
|
1910
|
+
layout: def.pageOrientation === "landscape" ? "landscape" : "portrait",
|
|
1783
1911
|
margins: {
|
|
1784
1912
|
top: headerBandHeight,
|
|
1785
1913
|
bottom: footerBandHeight,
|
|
@@ -1884,6 +2012,7 @@ async function renderCustomPdfToBuffer(def) {
|
|
|
1884
2012
|
const footerBandHeight = def.margins.bottom ?? 0;
|
|
1885
2013
|
const doc = new import_pdfkit.default({
|
|
1886
2014
|
size: def.pageSize || "A4",
|
|
2015
|
+
layout: def.pageOrientation === "landscape" ? "landscape" : "portrait",
|
|
1887
2016
|
margins: {
|
|
1888
2017
|
top: headerBandHeight,
|
|
1889
2018
|
bottom: footerBandHeight,
|
package/dist/index.mjs
CHANGED
|
@@ -476,29 +476,117 @@ var processLineBlock = (doc, ctx, block, y, env, ensureSpaceFor) => {
|
|
|
476
476
|
};
|
|
477
477
|
|
|
478
478
|
// src/renderer-engine/blocks/table.ts
|
|
479
|
+
var normalizeSpan = (value) => {
|
|
480
|
+
if (!value || value < 1) return 1;
|
|
481
|
+
return Math.floor(value);
|
|
482
|
+
};
|
|
483
|
+
var sum = (arr) => arr.reduce((a, b) => a + b, 0);
|
|
484
|
+
var getCellFontName = (cell) => {
|
|
485
|
+
const isBold = !!cell.bold;
|
|
486
|
+
const isItalic = !!cell.italic;
|
|
487
|
+
if (cell.font) return cell.font;
|
|
488
|
+
if (isBold && isItalic) return "Helvetica-BoldOblique";
|
|
489
|
+
if (isBold) return "Helvetica-Bold";
|
|
490
|
+
if (isItalic) return "Helvetica-Oblique";
|
|
491
|
+
return "Helvetica";
|
|
492
|
+
};
|
|
493
|
+
var decrementActiveSpans = (activeRowSpans) => {
|
|
494
|
+
for (let i = 0; i < activeRowSpans.length; i++) {
|
|
495
|
+
if (activeRowSpans[i] > 0) {
|
|
496
|
+
activeRowSpans[i] -= 1;
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
};
|
|
500
|
+
var findNextFreeCol = (activeRowSpans, fromIndex) => {
|
|
501
|
+
let col = fromIndex;
|
|
502
|
+
while (col < activeRowSpans.length && activeRowSpans[col] > 0) {
|
|
503
|
+
col++;
|
|
504
|
+
}
|
|
505
|
+
return col;
|
|
506
|
+
};
|
|
507
|
+
var buildPlacedRow = (row, totalCols, activeRowSpans) => {
|
|
508
|
+
const placed = [];
|
|
509
|
+
let cursor = 0;
|
|
510
|
+
for (const rawCell of row) {
|
|
511
|
+
cursor = findNextFreeCol(activeRowSpans, cursor);
|
|
512
|
+
if (cursor >= totalCols) break;
|
|
513
|
+
const colSpan = Math.min(normalizeSpan(rawCell.colSpan), totalCols - cursor);
|
|
514
|
+
const rowSpan = normalizeSpan(rawCell.rowSpan);
|
|
515
|
+
placed.push({
|
|
516
|
+
cell: rawCell,
|
|
517
|
+
startCol: cursor,
|
|
518
|
+
colSpan,
|
|
519
|
+
rowSpan
|
|
520
|
+
});
|
|
521
|
+
if (rowSpan > 1) {
|
|
522
|
+
for (let c = cursor; c < cursor + colSpan; c++) {
|
|
523
|
+
activeRowSpans[c] = Math.max(activeRowSpans[c], rowSpan - 1);
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
cursor += colSpan;
|
|
527
|
+
}
|
|
528
|
+
return placed;
|
|
529
|
+
};
|
|
530
|
+
var getPlacedCellWidth = (colWidths, startCol, colSpan) => {
|
|
531
|
+
return sum(colWidths.slice(startCol, startCol + colSpan));
|
|
532
|
+
};
|
|
533
|
+
var getRowSpanGroupHeight = (rowHeights, rowIndex, rowSpan) => {
|
|
534
|
+
return sum(rowHeights.slice(rowIndex, rowIndex + rowSpan));
|
|
535
|
+
};
|
|
479
536
|
var measureTableHeight = (doc, table, env, styles, computeColumnPixelWidths2) => {
|
|
480
537
|
const localLeft = table.marginLeft ?? 0;
|
|
481
538
|
const localRight = table.marginRight ?? 0;
|
|
482
539
|
const width = Math.max(env.innerWidth - localLeft - localRight, 1);
|
|
540
|
+
const totalCols = table.widths.length;
|
|
483
541
|
const colWidths = computeColumnPixelWidths2(table.widths, width);
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
row
|
|
542
|
+
const rowHeights = [];
|
|
543
|
+
const activeRowSpans = Array(totalCols).fill(0);
|
|
544
|
+
const placedRows = [];
|
|
545
|
+
for (let rowIndex = 0; rowIndex < table.body.length; rowIndex++) {
|
|
546
|
+
const row = table.body[rowIndex];
|
|
547
|
+
const placedRow = buildPlacedRow(row, totalCols, activeRowSpans);
|
|
548
|
+
placedRows.push(placedRow);
|
|
549
|
+
let rowHeight = 12;
|
|
550
|
+
placedRow.forEach(({ cell: rawCell, startCol, colSpan }) => {
|
|
489
551
|
const cell = resolveTableCell(styles, rawCell);
|
|
490
|
-
const
|
|
491
|
-
const
|
|
492
|
-
const
|
|
493
|
-
const
|
|
494
|
-
const
|
|
495
|
-
|
|
496
|
-
doc.
|
|
497
|
-
|
|
498
|
-
|
|
552
|
+
const paddingLeft = cell.paddingLeft ?? 2;
|
|
553
|
+
const paddingRight = cell.paddingRight ?? 2;
|
|
554
|
+
const paddingTop = cell.paddingTop ?? 2;
|
|
555
|
+
const paddingBottom = cell.paddingBottom ?? 2;
|
|
556
|
+
const colW = getPlacedCellWidth(colWidths, startCol, colSpan);
|
|
557
|
+
const textWidth = Math.max(colW - paddingLeft - paddingRight, 1);
|
|
558
|
+
doc.font(getCellFontName(cell));
|
|
559
|
+
doc.fontSize(cell.fontSize ?? 10);
|
|
560
|
+
const h = doc.heightOfString(cell.text, { width: textWidth }) + paddingTop + paddingBottom;
|
|
561
|
+
rowHeight = Math.max(rowHeight, h);
|
|
499
562
|
});
|
|
500
|
-
|
|
501
|
-
|
|
563
|
+
rowHeights.push(rowHeight);
|
|
564
|
+
decrementActiveSpans(activeRowSpans);
|
|
565
|
+
}
|
|
566
|
+
for (let rowIndex = 0; rowIndex < placedRows.length; rowIndex++) {
|
|
567
|
+
const placedRow = placedRows[rowIndex];
|
|
568
|
+
placedRow.forEach(({ cell: rawCell, startCol, colSpan, rowSpan }) => {
|
|
569
|
+
if (rowSpan <= 1) return;
|
|
570
|
+
const cell = resolveTableCell(styles, rawCell);
|
|
571
|
+
const paddingLeft = cell.paddingLeft ?? 2;
|
|
572
|
+
const paddingRight = cell.paddingRight ?? 2;
|
|
573
|
+
const paddingTop = cell.paddingTop ?? 2;
|
|
574
|
+
const paddingBottom = cell.paddingBottom ?? 2;
|
|
575
|
+
const colW = getPlacedCellWidth(colWidths, startCol, colSpan);
|
|
576
|
+
const textWidth = Math.max(colW - paddingLeft - paddingRight, 1);
|
|
577
|
+
doc.font(getCellFontName(cell));
|
|
578
|
+
doc.fontSize(cell.fontSize ?? 10);
|
|
579
|
+
const neededHeight = doc.heightOfString(cell.text, { width: textWidth }) + paddingTop + paddingBottom;
|
|
580
|
+
const currentGroupHeight = getRowSpanGroupHeight(rowHeights, rowIndex, rowSpan);
|
|
581
|
+
if (neededHeight > currentGroupHeight) {
|
|
582
|
+
const deficit = neededHeight - currentGroupHeight;
|
|
583
|
+
rowHeights[rowIndex + rowSpan - 1] = (rowHeights[rowIndex + rowSpan - 1] ?? 12) + deficit;
|
|
584
|
+
}
|
|
585
|
+
});
|
|
586
|
+
}
|
|
587
|
+
let totalHeight = 0;
|
|
588
|
+
totalHeight += table.marginTop ?? 0;
|
|
589
|
+
totalHeight += sum(rowHeights);
|
|
502
590
|
totalHeight += table.lineGap ?? 6;
|
|
503
591
|
totalHeight += table.marginBottom ?? 0;
|
|
504
592
|
return totalHeight;
|
|
@@ -512,6 +600,7 @@ var processTableBlock = (doc, ctx, styles, table, y, env, computeColumnPixelWidt
|
|
|
512
600
|
const mb = table.marginBottom ?? 0;
|
|
513
601
|
const baseY = y ?? ctx.currentY;
|
|
514
602
|
const startY = baseY + mt;
|
|
603
|
+
const totalCols = table.widths.length;
|
|
515
604
|
const colWidths = computeColumnPixelWidths2(table.widths, width);
|
|
516
605
|
const layout = table.layout ?? {
|
|
517
606
|
border: "all",
|
|
@@ -520,56 +609,84 @@ var processTableBlock = (doc, ctx, styles, table, y, env, computeColumnPixelWidt
|
|
|
520
609
|
};
|
|
521
610
|
const borderAll = layout.border !== "none";
|
|
522
611
|
const headerRows = table.headerRows ?? 0;
|
|
523
|
-
const
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
const
|
|
529
|
-
const
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
612
|
+
const buildPlacementAndHeights = (rows) => {
|
|
613
|
+
const placedRows = [];
|
|
614
|
+
const rowHeights = [];
|
|
615
|
+
const activeRowSpans = Array(totalCols).fill(0);
|
|
616
|
+
for (let rowIndex = 0; rowIndex < rows.length; rowIndex++) {
|
|
617
|
+
const row = rows[rowIndex];
|
|
618
|
+
const placedRow = buildPlacedRow(row, totalCols, activeRowSpans);
|
|
619
|
+
placedRows.push(placedRow);
|
|
620
|
+
let rowHeight = 12;
|
|
621
|
+
placedRow.forEach(({ cell: rawCell, startCol, colSpan }) => {
|
|
622
|
+
const cell = resolveTableCell(styles, rawCell);
|
|
623
|
+
const paddingLeft = cell.paddingLeft ?? 2;
|
|
624
|
+
const paddingRight = cell.paddingRight ?? 2;
|
|
625
|
+
const paddingTop = cell.paddingTop ?? 2;
|
|
626
|
+
const paddingBottom = cell.paddingBottom ?? 2;
|
|
627
|
+
const colW = getPlacedCellWidth(colWidths, startCol, colSpan);
|
|
628
|
+
const textWidth = Math.max(colW - paddingLeft - paddingRight, 1);
|
|
629
|
+
doc.font(getCellFontName(cell));
|
|
630
|
+
doc.fontSize(cell.fontSize ?? 10);
|
|
631
|
+
const h = doc.heightOfString(cell.text, { width: textWidth }) + paddingTop + paddingBottom;
|
|
632
|
+
rowHeight = Math.max(rowHeight, h);
|
|
633
|
+
});
|
|
634
|
+
rowHeights.push(rowHeight);
|
|
635
|
+
decrementActiveSpans(activeRowSpans);
|
|
636
|
+
}
|
|
637
|
+
for (let rowIndex = 0; rowIndex < placedRows.length; rowIndex++) {
|
|
638
|
+
const placedRow = placedRows[rowIndex];
|
|
639
|
+
placedRow.forEach(({ cell: rawCell, startCol, colSpan, rowSpan }) => {
|
|
640
|
+
if (rowSpan <= 1) return;
|
|
641
|
+
const cell = resolveTableCell(styles, rawCell);
|
|
642
|
+
const paddingLeft = cell.paddingLeft ?? 2;
|
|
643
|
+
const paddingRight = cell.paddingRight ?? 2;
|
|
644
|
+
const paddingTop = cell.paddingTop ?? 2;
|
|
645
|
+
const paddingBottom = cell.paddingBottom ?? 2;
|
|
646
|
+
const colW = getPlacedCellWidth(colWidths, startCol, colSpan);
|
|
647
|
+
const textWidth = Math.max(colW - paddingLeft - paddingRight, 1);
|
|
648
|
+
doc.font(getCellFontName(cell));
|
|
649
|
+
doc.fontSize(cell.fontSize ?? 10);
|
|
650
|
+
const neededHeight = doc.heightOfString(cell.text, { width: textWidth }) + paddingTop + paddingBottom;
|
|
651
|
+
const currentGroupHeight = getRowSpanGroupHeight(rowHeights, rowIndex, rowSpan);
|
|
652
|
+
if (neededHeight > currentGroupHeight) {
|
|
653
|
+
const deficit = neededHeight - currentGroupHeight;
|
|
654
|
+
rowHeights[rowIndex + rowSpan - 1] = (rowHeights[rowIndex + rowSpan - 1] ?? 12) + deficit;
|
|
655
|
+
}
|
|
656
|
+
});
|
|
657
|
+
}
|
|
658
|
+
return { placedRows, rowHeights };
|
|
539
659
|
};
|
|
540
|
-
const
|
|
541
|
-
|
|
660
|
+
const allLayout = buildPlacementAndHeights(table.body);
|
|
661
|
+
const drawPlacedRow = (placedRow, rowTop2, rowHeight, rowIndex, rowHeights, isHeaderRow, drawTopBorder) => {
|
|
662
|
+
placedRow.forEach(({ cell: rawCell, startCol, colSpan, rowSpan }) => {
|
|
542
663
|
const cell = resolveTableCell(styles, rawCell);
|
|
543
|
-
const colW = colWidths
|
|
544
|
-
const x = baseLeft + colWidths.slice(0,
|
|
664
|
+
const colW = getPlacedCellWidth(colWidths, startCol, colSpan);
|
|
665
|
+
const x = baseLeft + sum(colWidths.slice(0, startCol));
|
|
545
666
|
const fontSize = cell.fontSize ?? 10;
|
|
667
|
+
const drawHeight = getRowSpanGroupHeight(rowHeights, rowIndex, rowSpan);
|
|
668
|
+
const paddingLeft = cell.paddingLeft ?? 2;
|
|
669
|
+
const paddingRight = cell.paddingRight ?? 2;
|
|
670
|
+
const paddingTop = cell.paddingTop ?? 2;
|
|
671
|
+
const paddingBottom = cell.paddingBottom ?? 2;
|
|
546
672
|
doc.save();
|
|
547
673
|
if (cell.fillColor) {
|
|
548
|
-
doc.rect(x, rowTop2, colW,
|
|
674
|
+
doc.rect(x, rowTop2, colW, drawHeight).fillOpacity(1).fill(cell.fillColor);
|
|
549
675
|
doc.fillOpacity(1);
|
|
550
676
|
}
|
|
551
|
-
|
|
552
|
-
const isItalic = !!cell.italic;
|
|
553
|
-
const fontName = cell.font ? cell.font : isBold && isItalic ? "Helvetica-BoldOblique" : isBold ? "Helvetica-Bold" : isItalic ? "Helvetica-Oblique" : "Helvetica";
|
|
554
|
-
doc.font(fontName);
|
|
677
|
+
doc.font(getCellFontName(cell));
|
|
555
678
|
doc.fontSize(fontSize);
|
|
556
|
-
|
|
557
|
-
doc.fillColor(cell.color);
|
|
558
|
-
} else {
|
|
559
|
-
doc.fillColor("black");
|
|
560
|
-
}
|
|
679
|
+
doc.fillColor(cell.color ?? "black");
|
|
561
680
|
const align = cell.align ?? "left";
|
|
562
|
-
const textWidth = Math.max(colW -
|
|
563
|
-
const textHeight = doc.heightOfString(cell.text, {
|
|
564
|
-
|
|
565
|
-
});
|
|
566
|
-
let textY = rowTop2 + 2;
|
|
681
|
+
const textWidth = Math.max(colW - paddingLeft - paddingRight, 1);
|
|
682
|
+
const textHeight = doc.heightOfString(cell.text, { width: textWidth });
|
|
683
|
+
let textY = rowTop2 + paddingTop;
|
|
567
684
|
if (isHeaderRow) {
|
|
568
|
-
const available =
|
|
685
|
+
const available = Math.max(drawHeight - paddingTop - paddingBottom, 0);
|
|
569
686
|
const offset = Math.max((available - textHeight) / 2, 0);
|
|
570
|
-
textY = rowTop2 +
|
|
687
|
+
textY = rowTop2 + paddingTop + offset;
|
|
571
688
|
}
|
|
572
|
-
doc.text(cell.text, x +
|
|
689
|
+
doc.text(cell.text, x + paddingLeft, textY, {
|
|
573
690
|
width: textWidth,
|
|
574
691
|
align,
|
|
575
692
|
underline: !!cell.underline,
|
|
@@ -577,52 +694,58 @@ var processTableBlock = (doc, ctx, styles, table, y, env, computeColumnPixelWidt
|
|
|
577
694
|
link: cell.link
|
|
578
695
|
});
|
|
579
696
|
doc.restore();
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
doc.strokeColor(layout.vLineColor ?? "#ccc");
|
|
594
|
-
let x = baseLeft;
|
|
595
|
-
colWidths.forEach((colW) => {
|
|
697
|
+
if (borderAll) {
|
|
698
|
+
const bottomY = rowTop2 + drawHeight;
|
|
699
|
+
doc.save();
|
|
700
|
+
doc.lineWidth(0.5);
|
|
701
|
+
doc.strokeColor(layout.hLineColor ?? "#ccc");
|
|
702
|
+
if (drawTopBorder) {
|
|
703
|
+
doc.moveTo(x, rowTop2).lineTo(x + colW, rowTop2).stroke();
|
|
704
|
+
}
|
|
705
|
+
doc.moveTo(x, bottomY).lineTo(x + colW, bottomY).stroke();
|
|
706
|
+
doc.restore();
|
|
707
|
+
doc.save();
|
|
708
|
+
doc.lineWidth(0.5);
|
|
709
|
+
doc.strokeColor(layout.vLineColor ?? "#ccc");
|
|
596
710
|
doc.moveTo(x, rowTop2).lineTo(x, bottomY).stroke();
|
|
597
|
-
x
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
}
|
|
711
|
+
doc.moveTo(x + colW, rowTop2).lineTo(x + colW, bottomY).stroke();
|
|
712
|
+
doc.restore();
|
|
713
|
+
}
|
|
714
|
+
});
|
|
602
715
|
return rowTop2 + rowHeight;
|
|
603
716
|
};
|
|
717
|
+
const headerRowsSource = table.body.slice(0, headerRows);
|
|
604
718
|
const drawHeaderRowsOnNewPage = () => {
|
|
605
719
|
if (!headerRows) return doc.page.margins.top + mt;
|
|
720
|
+
const headerLayout = buildPlacementAndHeights(headerRowsSource);
|
|
606
721
|
let rowTop2 = doc.page.margins.top + mt;
|
|
607
|
-
for (let i = 0; i <
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
722
|
+
for (let i = 0; i < headerLayout.placedRows.length; i++) {
|
|
723
|
+
rowTop2 = drawPlacedRow(
|
|
724
|
+
headerLayout.placedRows[i],
|
|
725
|
+
rowTop2,
|
|
726
|
+
headerLayout.rowHeights[i],
|
|
727
|
+
i,
|
|
728
|
+
headerLayout.rowHeights,
|
|
729
|
+
true,
|
|
730
|
+
true
|
|
731
|
+
);
|
|
611
732
|
}
|
|
612
733
|
return rowTop2;
|
|
613
734
|
};
|
|
614
735
|
let rowTop = startY;
|
|
615
|
-
table.body.
|
|
736
|
+
for (let rowIndex = 0; rowIndex < table.body.length; rowIndex++) {
|
|
616
737
|
const isHeaderRow = rowIndex < headerRows;
|
|
617
|
-
const
|
|
738
|
+
const placedRow = allLayout.placedRows[rowIndex];
|
|
739
|
+
const rowHeight = allLayout.rowHeights[rowIndex];
|
|
740
|
+
const maxRowSpan = Math.max(...placedRow.map((p) => p.rowSpan), 1);
|
|
741
|
+
const reservedHeight = getRowSpanGroupHeight(allLayout.rowHeights, rowIndex, maxRowSpan);
|
|
618
742
|
const bottomLimit = bottomLimitForContent();
|
|
619
|
-
if (rowTop +
|
|
743
|
+
if (rowTop + reservedHeight > bottomLimit) {
|
|
620
744
|
finishPage2(true);
|
|
621
745
|
rowTop = headerRows ? drawHeaderRowsOnNewPage() : doc.page.margins.top + mt;
|
|
622
746
|
}
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
});
|
|
747
|
+
rowTop = drawPlacedRow(placedRow, rowTop, rowHeight, rowIndex, allLayout.rowHeights, isHeaderRow, true);
|
|
748
|
+
}
|
|
626
749
|
const newY = rowTop + (table.lineGap ?? 6) + mb;
|
|
627
750
|
if (y === null) ctx.currentY = newY;
|
|
628
751
|
return newY;
|
|
@@ -1066,7 +1189,11 @@ function resolveTableCell(styles, cell) {
|
|
|
1066
1189
|
italic: cell.italic ?? styleDef.italic,
|
|
1067
1190
|
color: cell.color ?? styleDef.color,
|
|
1068
1191
|
fillColor: cell.fillColor ?? styleDef.fillColor,
|
|
1069
|
-
font: cell.font ?? styleDef.font
|
|
1192
|
+
font: cell.font ?? styleDef.font,
|
|
1193
|
+
paddingTop: cell.paddingTop,
|
|
1194
|
+
paddingRight: cell.paddingRight,
|
|
1195
|
+
paddingBottom: cell.paddingBottom,
|
|
1196
|
+
paddingLeft: cell.paddingLeft
|
|
1070
1197
|
};
|
|
1071
1198
|
}
|
|
1072
1199
|
var getFontNameForText = (tb) => {
|
|
@@ -1737,6 +1864,7 @@ async function renderCustomPdf(def, outputPath) {
|
|
|
1737
1864
|
const footerBandHeight = def.margins.bottom ?? 0;
|
|
1738
1865
|
const doc = new PDFDocument({
|
|
1739
1866
|
size: def.pageSize || "A4",
|
|
1867
|
+
layout: def.pageOrientation === "landscape" ? "landscape" : "portrait",
|
|
1740
1868
|
margins: {
|
|
1741
1869
|
top: headerBandHeight,
|
|
1742
1870
|
bottom: footerBandHeight,
|
|
@@ -1841,6 +1969,7 @@ async function renderCustomPdfToBuffer(def) {
|
|
|
1841
1969
|
const footerBandHeight = def.margins.bottom ?? 0;
|
|
1842
1970
|
const doc = new PDFDocument({
|
|
1843
1971
|
size: def.pageSize || "A4",
|
|
1972
|
+
layout: def.pageOrientation === "landscape" ? "landscape" : "portrait",
|
|
1844
1973
|
margins: {
|
|
1845
1974
|
top: headerBandHeight,
|
|
1846
1975
|
bottom: footerBandHeight,
|