@jasy/pdf 1.0.0-alpha.1
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 +171 -0
- package/dist/api/args.d.ts +10 -0
- package/dist/api/args.js +13 -0
- package/dist/api/color.d.ts +24 -0
- package/dist/api/color.js +215 -0
- package/dist/api/content.d.ts +36 -0
- package/dist/api/content.js +50 -0
- package/dist/api/descriptor.d.ts +25 -0
- package/dist/api/descriptor.js +71 -0
- package/dist/api/index.d.ts +8 -0
- package/dist/api/index.js +27 -0
- package/dist/api/insets.d.ts +16 -0
- package/dist/api/insets.js +21 -0
- package/dist/api/layout.d.ts +72 -0
- package/dist/api/layout.js +99 -0
- package/dist/api/structure.d.ts +80 -0
- package/dist/api/structure.js +125 -0
- package/dist/api/table.d.ts +37 -0
- package/dist/api/table.js +87 -0
- package/dist/api/text.d.ts +28 -0
- package/dist/api/text.js +61 -0
- package/dist/assets/Courier-Bold.afm +342 -0
- package/dist/assets/Courier-BoldOblique.afm +342 -0
- package/dist/assets/Courier-Oblique.afm +342 -0
- package/dist/assets/Courier.afm +342 -0
- package/dist/assets/Helvetica-Bold.afm +2827 -0
- package/dist/assets/Helvetica-BoldOblique.afm +2827 -0
- package/dist/assets/Helvetica-Oblique.afm +3051 -0
- package/dist/assets/Helvetica.afm +3051 -0
- package/dist/assets/Symbol.afm +213 -0
- package/dist/assets/Times-Bold.afm +2588 -0
- package/dist/assets/Times-BoldItalic.afm +2384 -0
- package/dist/assets/Times-Italic.afm +2667 -0
- package/dist/assets/Times-Roman.afm +2419 -0
- package/dist/assets/ZapfDingbats.afm +225 -0
- package/dist/assets/agl.txt +695 -0
- package/dist/common/color.d.ts +37 -0
- package/dist/common/color.js +62 -0
- package/dist/constants/page-sizes.d.ts +44 -0
- package/dist/constants/page-sizes.js +92 -0
- package/dist/constants/pdf-parts.d.ts +5 -0
- package/dist/constants/pdf-parts.js +8 -0
- package/dist/elements/container-element.d.ts +35 -0
- package/dist/elements/container-element.js +91 -0
- package/dist/elements/image-element.d.ts +56 -0
- package/dist/elements/image-element.js +151 -0
- package/dist/elements/index.d.ts +10 -0
- package/dist/elements/index.js +28 -0
- package/dist/elements/layout/deferred-element.d.ts +19 -0
- package/dist/elements/layout/deferred-element.js +33 -0
- package/dist/elements/layout/expanded-element.d.ts +30 -0
- package/dist/elements/layout/expanded-element.js +68 -0
- package/dist/elements/layout/padding-element.d.ts +29 -0
- package/dist/elements/layout/padding-element.js +76 -0
- package/dist/elements/layout/repeating-header-element.d.ts +29 -0
- package/dist/elements/layout/repeating-header-element.js +60 -0
- package/dist/elements/layout/sized-container-element.d.ts +14 -0
- package/dist/elements/layout/sized-container-element.js +37 -0
- package/dist/elements/line-element.d.ts +31 -0
- package/dist/elements/line-element.js +44 -0
- package/dist/elements/page-element.d.ts +58 -0
- package/dist/elements/page-element.js +90 -0
- package/dist/elements/pdf-document-element.d.ts +13 -0
- package/dist/elements/pdf-document-element.js +22 -0
- package/dist/elements/pdf-element.d.ts +67 -0
- package/dist/elements/pdf-element.js +55 -0
- package/dist/elements/rectangle-element.d.ts +55 -0
- package/dist/elements/rectangle-element.js +120 -0
- package/dist/elements/row-element.d.ts +42 -0
- package/dist/elements/row-element.js +54 -0
- package/dist/elements/text-element.d.ts +59 -0
- package/dist/elements/text-element.js +137 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +21 -0
- package/dist/ir/display-list.d.ts +74 -0
- package/dist/ir/display-list.js +2 -0
- package/dist/layout/box-constraints.d.ts +56 -0
- package/dist/layout/box-constraints.js +73 -0
- package/dist/layout/fragmentation.d.ts +42 -0
- package/dist/layout/fragmentation.js +61 -0
- package/dist/renderer/container-renderer.d.ts +6 -0
- package/dist/renderer/container-renderer.js +30 -0
- package/dist/renderer/deferred-renderer.d.ts +6 -0
- package/dist/renderer/deferred-renderer.js +25 -0
- package/dist/renderer/expanded-renderer.d.ts +6 -0
- package/dist/renderer/expanded-renderer.js +23 -0
- package/dist/renderer/image-renderer.d.ts +6 -0
- package/dist/renderer/image-renderer.js +85 -0
- package/dist/renderer/index.d.ts +10 -0
- package/dist/renderer/index.js +26 -0
- package/dist/renderer/line-renderer.d.ts +6 -0
- package/dist/renderer/line-renderer.js +30 -0
- package/dist/renderer/padding-renderer.d.ts +6 -0
- package/dist/renderer/padding-renderer.js +23 -0
- package/dist/renderer/page-renderer.d.ts +5 -0
- package/dist/renderer/page-renderer.js +81 -0
- package/dist/renderer/pdf-backend.d.ts +45 -0
- package/dist/renderer/pdf-backend.js +184 -0
- package/dist/renderer/pdf-config.d.ts +8 -0
- package/dist/renderer/pdf-config.js +17 -0
- package/dist/renderer/pdf-document-class.d.ts +42 -0
- package/dist/renderer/pdf-document-class.js +118 -0
- package/dist/renderer/pdf-document-renderer.d.ts +20 -0
- package/dist/renderer/pdf-document-renderer.js +104 -0
- package/dist/renderer/pdf-renderer.d.ts +5 -0
- package/dist/renderer/pdf-renderer.js +92 -0
- package/dist/renderer/rectangle-renderer.d.ts +8 -0
- package/dist/renderer/rectangle-renderer.js +61 -0
- package/dist/renderer/repeating-header-renderer.d.ts +6 -0
- package/dist/renderer/repeating-header-renderer.js +28 -0
- package/dist/renderer/row-renderer.d.ts +6 -0
- package/dist/renderer/row-renderer.js +30 -0
- package/dist/renderer/text-renderer.d.ts +9 -0
- package/dist/renderer/text-renderer.js +125 -0
- package/dist/text/line-breaker.d.ts +40 -0
- package/dist/text/line-breaker.js +106 -0
- package/dist/utils/afm-parser.d.ts +12 -0
- package/dist/utils/afm-parser.js +91 -0
- package/dist/utils/flex-layout.d.ts +53 -0
- package/dist/utils/flex-layout.js +119 -0
- package/dist/utils/font-metrics.d.ts +12 -0
- package/dist/utils/font-metrics.js +2 -0
- package/dist/utils/font-path.d.ts +1 -0
- package/dist/utils/font-path.js +19 -0
- package/dist/utils/image-helper.d.ts +43 -0
- package/dist/utils/image-helper.js +206 -0
- package/dist/utils/pdf-object-manager.d.ts +97 -0
- package/dist/utils/pdf-object-manager.js +645 -0
- package/dist/utils/renderer-registry.d.ts +6 -0
- package/dist/utils/renderer-registry.js +19 -0
- package/dist/utils/ttf-parser.d.ts +29 -0
- package/dist/utils/ttf-parser.js +191 -0
- package/dist/utils/ttf-subsetter.d.ts +1 -0
- package/dist/utils/ttf-subsetter.js +161 -0
- package/dist/utils/utf8-to-windows1252-encoder.d.ts +2 -0
- package/dist/utils/utf8-to-windows1252-encoder.js +55 -0
- package/dist/validators/element-validator.d.ts +8 -0
- package/dist/validators/element-validator.js +61 -0
- package/package.json +50 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.toEdges = toEdges;
|
|
4
|
+
/** Normalizes any `Insets` to the engine's `[top, right, bottom, left]`. */
|
|
5
|
+
function toEdges(i) {
|
|
6
|
+
var _a, _b, _c, _d, _e, _f;
|
|
7
|
+
if (typeof i === "number")
|
|
8
|
+
return [i, i, i, i];
|
|
9
|
+
if (Array.isArray(i))
|
|
10
|
+
return i;
|
|
11
|
+
// Axis form ({x, y}) and per-side form ({top,...}) are both all-optional objects (TS
|
|
12
|
+
// can't discriminate them), so read through one shape: an axis key present picks the
|
|
13
|
+
// axis interpretation (an empty object is all-zero either way).
|
|
14
|
+
const o = i;
|
|
15
|
+
if (o.x !== undefined || o.y !== undefined) {
|
|
16
|
+
const x = (_a = o.x) !== null && _a !== void 0 ? _a : 0;
|
|
17
|
+
const y = (_b = o.y) !== null && _b !== void 0 ? _b : 0;
|
|
18
|
+
return [y, x, y, x];
|
|
19
|
+
}
|
|
20
|
+
return [(_c = o.top) !== null && _c !== void 0 ? _c : 0, (_d = o.right) !== null && _d !== void 0 ? _d : 0, (_e = o.bottom) !== null && _e !== void 0 ? _e : 0, (_f = o.left) !== null && _f !== void 0 ? _f : 0];
|
|
21
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { ContainerElement } from "../elements/container-element";
|
|
2
|
+
import { RowElement } from "../elements/row-element";
|
|
3
|
+
import { RectangleElement } from "../elements/rectangle-element";
|
|
4
|
+
import { ExpandedElement } from "../elements/layout/expanded-element";
|
|
5
|
+
import { PaddingElement } from "../elements/layout/padding-element";
|
|
6
|
+
import { PDFElement } from "../elements/pdf-element";
|
|
7
|
+
import { MainAlign, CrossAlign } from "../utils/flex-layout";
|
|
8
|
+
import { ColorInput } from "./color";
|
|
9
|
+
import { Insets } from "./insets";
|
|
10
|
+
/** Options shared by the `Column` and `Row` stacks (locked §4). */
|
|
11
|
+
export interface StackOptions {
|
|
12
|
+
/** Space inserted between children, in points. */
|
|
13
|
+
gap?: number;
|
|
14
|
+
/** Distribution along the main axis (CSS `justify-content`): start (default) · center · end ·
|
|
15
|
+
* between · around. */
|
|
16
|
+
justify?: MainAlign;
|
|
17
|
+
/** Position across the axis (CSS `align-items`): start (default) · center · end · stretch. */
|
|
18
|
+
align?: CrossAlign;
|
|
19
|
+
}
|
|
20
|
+
/** A vertical stack. `Column(children)` or `Column(opts, children)`. */
|
|
21
|
+
export declare function Column(children: PDFElement[]): ContainerElement;
|
|
22
|
+
export declare function Column(opts: StackOptions, children: PDFElement[]): ContainerElement;
|
|
23
|
+
/** A horizontal stack. `Row(children)` or `Row(opts, children)`. */
|
|
24
|
+
export declare function Row(children: PDFElement[]): RowElement;
|
|
25
|
+
export declare function Row(opts: StackOptions, children: PDFElement[]): RowElement;
|
|
26
|
+
/** A bordered / filled box that wraps its children (locked §4). */
|
|
27
|
+
export interface BoxOptions {
|
|
28
|
+
/** Border (stroke) colour. A box has a border only when `border` or `borderWidth` is set. */
|
|
29
|
+
border?: ColorInput;
|
|
30
|
+
/** Per-side border colours - override/add to `border`. Any of these makes the box draw
|
|
31
|
+
* individual side lines (sharp corners) instead of a uniform frame - this is how you get
|
|
32
|
+
* grid lines (e.g. a cell with only `borderBottom` + `borderRight`). */
|
|
33
|
+
borderTop?: ColorInput;
|
|
34
|
+
borderRight?: ColorInput;
|
|
35
|
+
borderBottom?: ColorInput;
|
|
36
|
+
borderLeft?: ColorInput;
|
|
37
|
+
/** Border thickness in points (default 1 when a border is present). */
|
|
38
|
+
borderWidth?: number;
|
|
39
|
+
/** Background fill colour. */
|
|
40
|
+
bg?: ColorInput;
|
|
41
|
+
/** Inner padding between the border and the children. */
|
|
42
|
+
padding?: Insets;
|
|
43
|
+
/** Fixed size; omit to fill the offered width and shrink-wrap the height. */
|
|
44
|
+
width?: number;
|
|
45
|
+
height?: number;
|
|
46
|
+
/** Corner radius in points. */
|
|
47
|
+
radius?: number;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* A box: maps to a `RectangleElement` (fill + border + radius) whose children are stacked
|
|
51
|
+
* inside it, optionally inset by `padding` (a `PaddingElement` wrapping a `Column` of the
|
|
52
|
+
* children). With no `border`/`borderWidth` the box has no outline (`borderWidth` 0).
|
|
53
|
+
*/
|
|
54
|
+
export declare function Box(children: PDFElement[]): RectangleElement;
|
|
55
|
+
export declare function Box(opts: BoxOptions, children: PDFElement[]): RectangleElement;
|
|
56
|
+
/** Insets a single child by `padding` (a number / `{x,y}` / `{top,…}` / 4-tuple). */
|
|
57
|
+
export declare function Padding(padding: Insets, child: PDFElement): PaddingElement;
|
|
58
|
+
/**
|
|
59
|
+
* A flexible empty gap that pushes its siblings apart - `Row([a, Spacer(), b])` sends `a`
|
|
60
|
+
* and `b` to the edges. `flex` weights it against other flex children (default 1).
|
|
61
|
+
*/
|
|
62
|
+
export declare function Spacer(flex?: number): ExpandedElement;
|
|
63
|
+
export interface ExpandedOptions {
|
|
64
|
+
/** Share of the leftover space vs other flex children (default 1). */
|
|
65
|
+
flex?: number;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Makes a child fill the leftover space along the stack's main axis (height in a Column,
|
|
69
|
+
* width in a Row). `Expanded(child)` or `Expanded({ flex }, child)`.
|
|
70
|
+
*/
|
|
71
|
+
export declare function Expanded(child: PDFElement): ExpandedElement;
|
|
72
|
+
export declare function Expanded(opts: ExpandedOptions, child: PDFElement): ExpandedElement;
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Column = Column;
|
|
4
|
+
exports.Row = Row;
|
|
5
|
+
exports.Box = Box;
|
|
6
|
+
exports.Padding = Padding;
|
|
7
|
+
exports.Spacer = Spacer;
|
|
8
|
+
exports.Expanded = Expanded;
|
|
9
|
+
const container_element_1 = require("../elements/container-element");
|
|
10
|
+
const row_element_1 = require("../elements/row-element");
|
|
11
|
+
const rectangle_element_1 = require("../elements/rectangle-element");
|
|
12
|
+
const expanded_element_1 = require("../elements/layout/expanded-element");
|
|
13
|
+
const padding_element_1 = require("../elements/layout/padding-element");
|
|
14
|
+
const color_1 = require("./color");
|
|
15
|
+
const insets_1 = require("./insets");
|
|
16
|
+
const args_1 = require("./args");
|
|
17
|
+
// The public default for `cross` is `start` (locked §5) - i.e. don't stretch a child unless
|
|
18
|
+
// asked. The engine default is `stretch`; the factory sets the friendlier public one.
|
|
19
|
+
const DEFAULT_CROSS = "start";
|
|
20
|
+
function Column(a, b) {
|
|
21
|
+
var _a;
|
|
22
|
+
const { opts, children } = (0, args_1.splitArgs)(a, b);
|
|
23
|
+
return new container_element_1.ContainerElement({
|
|
24
|
+
x: 0,
|
|
25
|
+
y: 0,
|
|
26
|
+
children,
|
|
27
|
+
gap: opts.gap,
|
|
28
|
+
main: opts.justify, // undefined → engine default `start` (matches §5)
|
|
29
|
+
cross: (_a = opts.align) !== null && _a !== void 0 ? _a : DEFAULT_CROSS,
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
function Row(a, b) {
|
|
33
|
+
var _a;
|
|
34
|
+
const { opts, children } = (0, args_1.splitArgs)(a, b);
|
|
35
|
+
return new row_element_1.RowElement({
|
|
36
|
+
children,
|
|
37
|
+
gap: opts.gap,
|
|
38
|
+
main: opts.justify,
|
|
39
|
+
cross: (_a = opts.align) !== null && _a !== void 0 ? _a : DEFAULT_CROSS,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
function Box(a, b) {
|
|
43
|
+
var _a;
|
|
44
|
+
const { opts, children } = (0, args_1.splitArgs)(a, b);
|
|
45
|
+
const content = opts.padding !== undefined && children.length > 0
|
|
46
|
+
? [
|
|
47
|
+
new padding_element_1.PaddingElement({
|
|
48
|
+
margin: (0, insets_1.toEdges)(opts.padding),
|
|
49
|
+
child: children.length === 1 ? children[0] : Column(children),
|
|
50
|
+
}),
|
|
51
|
+
]
|
|
52
|
+
: children;
|
|
53
|
+
// A side is set if it (or the uniform `border`) is given. If ANY differs from a plain
|
|
54
|
+
// uniform border, we hand the engine per-side colours (which draws individual lines).
|
|
55
|
+
const sideKeys = [opts.borderTop, opts.borderRight, opts.borderBottom, opts.borderLeft];
|
|
56
|
+
const hasPerSide = sideKeys.some((s) => s !== undefined);
|
|
57
|
+
const side = (s) => {
|
|
58
|
+
const c = s !== null && s !== void 0 ? s : opts.border;
|
|
59
|
+
return c !== undefined ? (0, color_1.toColor)(c) : undefined;
|
|
60
|
+
};
|
|
61
|
+
const hasBorder = opts.border !== undefined || opts.borderWidth !== undefined || hasPerSide;
|
|
62
|
+
return new rectangle_element_1.RectangleElement({
|
|
63
|
+
x: 0,
|
|
64
|
+
y: 0,
|
|
65
|
+
children: content,
|
|
66
|
+
color: opts.border !== undefined ? (0, color_1.toColor)(opts.border) : undefined,
|
|
67
|
+
backgroundColor: opts.bg !== undefined ? (0, color_1.toColor)(opts.bg) : undefined,
|
|
68
|
+
borderWidth: hasBorder ? ((_a = opts.borderWidth) !== null && _a !== void 0 ? _a : 1) : 0,
|
|
69
|
+
width: opts.width,
|
|
70
|
+
height: opts.height,
|
|
71
|
+
radius: opts.radius,
|
|
72
|
+
sideBorders: hasPerSide
|
|
73
|
+
? {
|
|
74
|
+
top: side(opts.borderTop),
|
|
75
|
+
right: side(opts.borderRight),
|
|
76
|
+
bottom: side(opts.borderBottom),
|
|
77
|
+
left: side(opts.borderLeft),
|
|
78
|
+
}
|
|
79
|
+
: undefined,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
/** Insets a single child by `padding` (a number / `{x,y}` / `{top,…}` / 4-tuple). */
|
|
83
|
+
function Padding(padding, child) {
|
|
84
|
+
return new padding_element_1.PaddingElement({ margin: (0, insets_1.toEdges)(padding), child });
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* A flexible empty gap that pushes its siblings apart - `Row([a, Spacer(), b])` sends `a`
|
|
88
|
+
* and `b` to the edges. `flex` weights it against other flex children (default 1).
|
|
89
|
+
*/
|
|
90
|
+
function Spacer(flex = 1) {
|
|
91
|
+
return new expanded_element_1.ExpandedElement({ flex, child: Column([]) });
|
|
92
|
+
}
|
|
93
|
+
function Expanded(a, b) {
|
|
94
|
+
var _a;
|
|
95
|
+
const isOptsForm = b !== undefined;
|
|
96
|
+
const opts = (isOptsForm ? a : {});
|
|
97
|
+
const child = (isOptsForm ? b : a);
|
|
98
|
+
return new expanded_element_1.ExpandedElement({ flex: (_a = opts.flex) !== null && _a !== void 0 ? _a : 1, child });
|
|
99
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { PDFDocumentElement } from "../elements/pdf-document-element";
|
|
2
|
+
import { PageElement } from "../elements/page-element";
|
|
3
|
+
import { PDFElement } from "../elements/pdf-element";
|
|
4
|
+
import { PageSize } from "../constants/page-sizes";
|
|
5
|
+
import { StackOptions } from "./layout";
|
|
6
|
+
import { Insets } from "./insets";
|
|
7
|
+
/** A page size: a `PageSize` enum, or a friendly name like `"A4"` / `"letter"` (any case). */
|
|
8
|
+
export type PageSizeInput = PageSize | string;
|
|
9
|
+
export interface PageOptions extends StackOptions {
|
|
10
|
+
/** Page size (default A4). */
|
|
11
|
+
size?: PageSizeInput;
|
|
12
|
+
orientation?: "portrait" | "landscape";
|
|
13
|
+
/** Page margin (default 56pt all sides). */
|
|
14
|
+
margin?: Insets;
|
|
15
|
+
/** Laid out at the top, repeated on every physical page. */
|
|
16
|
+
header?: PDFElement;
|
|
17
|
+
/** Laid out at the bottom, repeated on every physical page. */
|
|
18
|
+
footer?: PDFElement;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* One page template. `Page(children)` or `Page(opts, children)`. The children are stacked
|
|
22
|
+
* (auto-wrapped in a `Column`, locked §6) inside the content box; `header`/`footer` repeat
|
|
23
|
+
* on every physical page the content paginates onto.
|
|
24
|
+
*/
|
|
25
|
+
export declare function Page(children: PDFElement[]): PageElement;
|
|
26
|
+
export declare function Page(opts: PageOptions, children: PDFElement[]): PageElement;
|
|
27
|
+
export interface DocumentOptions {
|
|
28
|
+
/** PDF metadata. */
|
|
29
|
+
meta?: {
|
|
30
|
+
title?: string;
|
|
31
|
+
author?: string;
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
/** The document root. `Document(pages)` or `Document(opts, pages)`. */
|
|
35
|
+
export declare function Document(pages: PageElement[]): PDFDocumentElement;
|
|
36
|
+
export declare function Document(opts: DocumentOptions, pages: PageElement[]): PDFDocumentElement;
|
|
37
|
+
export type FontBytes = Buffer | Uint8Array;
|
|
38
|
+
/** A font family: one `.ttf` per style. Only `normal` is required; `bold`/`italic`/`boldItalic`
|
|
39
|
+
* are picked up automatically by `Text({ bold, italic })`, falling back to `normal` if absent. */
|
|
40
|
+
export interface FontFamily {
|
|
41
|
+
normal: FontBytes;
|
|
42
|
+
bold?: FontBytes;
|
|
43
|
+
italic?: FontBytes;
|
|
44
|
+
boldItalic?: FontBytes;
|
|
45
|
+
}
|
|
46
|
+
/** A file to embed in the PDF as an associated file (PDF/A-3 / PDF 2.0). */
|
|
47
|
+
export interface Attachment {
|
|
48
|
+
/** Display file name, e.g. `"factur-x.xml"`. */
|
|
49
|
+
name: string;
|
|
50
|
+
data: FontBytes;
|
|
51
|
+
/** `/AFRelationship`, e.g. `"Data"` (ZUGFeRD), `"Source"`, `"Alternative"`. Default `"Unspecified"`. */
|
|
52
|
+
relationship?: string;
|
|
53
|
+
/** MIME type, e.g. `"text/xml"`. Default `"application/octet-stream"`. */
|
|
54
|
+
mimeType?: string;
|
|
55
|
+
description?: string;
|
|
56
|
+
}
|
|
57
|
+
export interface RenderOptions {
|
|
58
|
+
/** Embedded TrueType fonts, keyed by the name used in `Text({ font })`. The value is either the
|
|
59
|
+
* raw `.ttf` bytes (registered as `normal`) or a `FontFamily` with per-style files. */
|
|
60
|
+
fonts?: Record<string, FontBytes | FontFamily>;
|
|
61
|
+
/** Files to embed as associated files (e.g. the ZUGFeRD `factur-x.xml`). */
|
|
62
|
+
attachments?: Attachment[];
|
|
63
|
+
/** Document XMP metadata packet (catalog `/Metadata`), e.g. PDF/A-3 + Factur-X. Keep it ASCII. */
|
|
64
|
+
xmp?: string;
|
|
65
|
+
/** ICC profile bytes for a PDF/A `/OutputIntent` (an RGB profile, e.g. sRGB). */
|
|
66
|
+
outputIntent?: FontBytes;
|
|
67
|
+
/** PDF header version, e.g. `"1.7"` for PDF/A-3 (default `"1.4"`). */
|
|
68
|
+
pdfVersion?: string;
|
|
69
|
+
/** Write a trailer `/ID` (required by PDF/A); the id is a deterministic content hash. */
|
|
70
|
+
documentId?: boolean;
|
|
71
|
+
/** Register the standard-14 fonts (default true). Set false for PDF/A so only embedded fonts
|
|
72
|
+
* appear - then every font name used must be supplied via `fonts`. */
|
|
73
|
+
standardFonts?: boolean;
|
|
74
|
+
/** FlateDecode-compress the streams (default true). Set false for a greppable, uncompressed PDF. */
|
|
75
|
+
compress?: boolean;
|
|
76
|
+
}
|
|
77
|
+
/** Renders a `Document(...)` tree to the raw PDF string. */
|
|
78
|
+
export declare function renderPdf(doc: PDFDocumentElement, options?: RenderOptions): Promise<string>;
|
|
79
|
+
/** Renders a `Document(...)` tree to PDF bytes (e.g. for a download / save dialog). */
|
|
80
|
+
export declare function renderToBytes(doc: PDFDocumentElement, options?: RenderOptions): Promise<Uint8Array>;
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.Page = Page;
|
|
13
|
+
exports.Document = Document;
|
|
14
|
+
exports.renderPdf = renderPdf;
|
|
15
|
+
exports.renderToBytes = renderToBytes;
|
|
16
|
+
const pdf_document_element_1 = require("../elements/pdf-document-element");
|
|
17
|
+
const page_element_1 = require("../elements/page-element");
|
|
18
|
+
const page_sizes_1 = require("../constants/page-sizes");
|
|
19
|
+
const pdf_config_1 = require("../renderer/pdf-config");
|
|
20
|
+
const pdf_document_class_1 = require("../renderer/pdf-document-class");
|
|
21
|
+
const pdf_object_manager_1 = require("../utils/pdf-object-manager");
|
|
22
|
+
const utf8_to_windows1252_encoder_1 = require("../utils/utf8-to-windows1252-encoder");
|
|
23
|
+
const layout_1 = require("./layout");
|
|
24
|
+
const insets_1 = require("./insets");
|
|
25
|
+
const PAGE_SIZE_VALUES = new Set(Object.values(page_sizes_1.PageSize));
|
|
26
|
+
function toPageSize(input) {
|
|
27
|
+
const v = String(input).toLowerCase();
|
|
28
|
+
if (!PAGE_SIZE_VALUES.has(v))
|
|
29
|
+
throw new Error(`Unknown page size: "${input}"`);
|
|
30
|
+
return v;
|
|
31
|
+
}
|
|
32
|
+
/** Default page margin (all sides, points) when a `Page` doesn't set one. */
|
|
33
|
+
const DEFAULT_MARGIN = 56;
|
|
34
|
+
function Page(a, b) {
|
|
35
|
+
var _a;
|
|
36
|
+
const isOpts = !Array.isArray(a);
|
|
37
|
+
const opts = (isOpts ? a : {});
|
|
38
|
+
const children = (isOpts ? (b !== null && b !== void 0 ? b : []) : a);
|
|
39
|
+
const [top, right, bottom, left] = (0, insets_1.toEdges)((_a = opts.margin) !== null && _a !== void 0 ? _a : DEFAULT_MARGIN);
|
|
40
|
+
const config = {
|
|
41
|
+
pageSize: opts.size !== undefined ? toPageSize(opts.size) : page_sizes_1.PageSize.A4,
|
|
42
|
+
orientation: opts.orientation === "landscape" ? pdf_config_1.Orientation.landscape : pdf_config_1.Orientation.portrait,
|
|
43
|
+
margin: { top, right, bottom, left },
|
|
44
|
+
};
|
|
45
|
+
return new page_element_1.PageElement({
|
|
46
|
+
config,
|
|
47
|
+
header: opts.header,
|
|
48
|
+
footer: opts.footer,
|
|
49
|
+
children: [(0, layout_1.Column)({ gap: opts.gap, justify: opts.justify, align: opts.align }, children)],
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
// Document metadata is a document-render concern, not part of the element tree, so it is
|
|
53
|
+
// kept beside the returned element and picked up by `renderPdf`.
|
|
54
|
+
const docMeta = new WeakMap();
|
|
55
|
+
function Document(a, b) {
|
|
56
|
+
const isOpts = !Array.isArray(a);
|
|
57
|
+
const opts = (isOpts ? a : {});
|
|
58
|
+
const pages = (isOpts ? (b !== null && b !== void 0 ? b : []) : a);
|
|
59
|
+
const doc = new pdf_document_element_1.PDFDocumentElement({ children: pages });
|
|
60
|
+
if (opts.meta)
|
|
61
|
+
docMeta.set(doc, opts.meta);
|
|
62
|
+
return doc;
|
|
63
|
+
}
|
|
64
|
+
function isFontBytes(v) {
|
|
65
|
+
return Buffer.isBuffer(v) || v instanceof Uint8Array;
|
|
66
|
+
}
|
|
67
|
+
/** Renders a `Document(...)` tree to the raw PDF string. */
|
|
68
|
+
function renderPdf(doc, options) {
|
|
69
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
70
|
+
var _a, _b;
|
|
71
|
+
const meta = docMeta.get(doc);
|
|
72
|
+
const config = Object.assign(Object.assign({}, (meta ? { metaData: { title: meta.title, author: meta.author, keywords: [] } } : {})), ((options === null || options === void 0 ? void 0 : options.standardFonts) === false ? { registerStandardFonts: false } : {}));
|
|
73
|
+
const fonts = (_a = options === null || options === void 0 ? void 0 : options.fonts) !== null && _a !== void 0 ? _a : {};
|
|
74
|
+
const attachments = (_b = options === null || options === void 0 ? void 0 : options.attachments) !== null && _b !== void 0 ? _b : [];
|
|
75
|
+
// A throwaway PDFDocument whose build() yields this tree, reusing the engine's standard
|
|
76
|
+
// font registration + config handling (the constructor does both). Custom fonts are
|
|
77
|
+
// registered here, before layout/render, so both the metrics and the backend see them.
|
|
78
|
+
const Anon = class extends pdf_document_class_1.PDFDocument {
|
|
79
|
+
constructor() {
|
|
80
|
+
super(config);
|
|
81
|
+
const om = this.objectManager;
|
|
82
|
+
om.setCompress((options === null || options === void 0 ? void 0 : options.compress) !== false); // FlateDecode streams by default
|
|
83
|
+
for (const [name, value] of Object.entries(fonts)) {
|
|
84
|
+
if (isFontBytes(value)) {
|
|
85
|
+
om.registerCustomFont(name, Buffer.from(value));
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
om.registerCustomFont(name, Buffer.from(value.normal), pdf_object_manager_1.FontStyle.Normal);
|
|
89
|
+
if (value.bold)
|
|
90
|
+
om.registerCustomFont(name, Buffer.from(value.bold), pdf_object_manager_1.FontStyle.Bold);
|
|
91
|
+
if (value.italic)
|
|
92
|
+
om.registerCustomFont(name, Buffer.from(value.italic), pdf_object_manager_1.FontStyle.Italic);
|
|
93
|
+
if (value.boldItalic)
|
|
94
|
+
om.registerCustomFont(name, Buffer.from(value.boldItalic), pdf_object_manager_1.FontStyle.BoldItalic);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
for (const a of attachments) {
|
|
98
|
+
om.attachFile(a.name, Buffer.from(a.data), {
|
|
99
|
+
relationship: a.relationship,
|
|
100
|
+
mimeType: a.mimeType,
|
|
101
|
+
description: a.description,
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
if (options === null || options === void 0 ? void 0 : options.xmp)
|
|
105
|
+
om.setXmpMetadata(options.xmp);
|
|
106
|
+
if (options === null || options === void 0 ? void 0 : options.outputIntent)
|
|
107
|
+
om.setOutputIntent(Buffer.from(options.outputIntent));
|
|
108
|
+
if (options === null || options === void 0 ? void 0 : options.pdfVersion)
|
|
109
|
+
om.setPdfVersion(options.pdfVersion);
|
|
110
|
+
if (options === null || options === void 0 ? void 0 : options.documentId)
|
|
111
|
+
om.enableDocumentId();
|
|
112
|
+
}
|
|
113
|
+
build() {
|
|
114
|
+
return doc;
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
return Anon.render();
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
/** Renders a `Document(...)` tree to PDF bytes (e.g. for a download / save dialog). */
|
|
121
|
+
function renderToBytes(doc, options) {
|
|
122
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
123
|
+
return new Uint8Array((0, utf8_to_windows1252_encoder_1.getArrayBuffer)(yield renderPdf(doc, options)));
|
|
124
|
+
});
|
|
125
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { PDFElement } from "../elements/pdf-element";
|
|
2
|
+
import { Insets } from "./insets";
|
|
3
|
+
import { ColorInput } from "./color";
|
|
4
|
+
/**
|
|
5
|
+
* A column width: a `number` of points (fixed), an `"Nfr"` fraction (splits the leftover
|
|
6
|
+
* width), or `"auto"` (as wide as the widest cell in that column - measured at layout time).
|
|
7
|
+
*/
|
|
8
|
+
export type ColumnWidth = number | string;
|
|
9
|
+
/** A table cell: any element, or a string (wrapped in `Text`). */
|
|
10
|
+
export type Cell = PDFElement | string;
|
|
11
|
+
export interface TableOptions {
|
|
12
|
+
/** One entry per column: a fixed point width, an `"Nfr"` fraction, or `"auto"`. */
|
|
13
|
+
columns: ColumnWidth[];
|
|
14
|
+
/** A header row that REPEATS at the top of every page the table flows onto. */
|
|
15
|
+
header?: Cell[];
|
|
16
|
+
/** Gap between both columns and rows (default 0). */
|
|
17
|
+
gap?: number;
|
|
18
|
+
/** Gap between rows (overrides `gap`). */
|
|
19
|
+
rowGap?: number;
|
|
20
|
+
/** Gap between columns (overrides `gap`). */
|
|
21
|
+
colGap?: number;
|
|
22
|
+
/** Padding inside every cell (default none). */
|
|
23
|
+
cellPadding?: Insets;
|
|
24
|
+
/** Grid line colour around every cell. Draws the complete grid once - don't add your own
|
|
25
|
+
* frame Box, or the outer edges double up. */
|
|
26
|
+
cellBorder?: ColorInput;
|
|
27
|
+
/** A single thin horizontal rule under the header row and along the foot of the table (e.g. a
|
|
28
|
+
* light-grey separator). Independent of `cellBorder`, which draws the full grid. */
|
|
29
|
+
rule?: ColorInput;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* A `Column` of `Row`s. Fixed-point columns sit in a fixed-width `Box`, `"Nfr"` fractions
|
|
33
|
+
* become `Expanded`, so columns align across rows. Being a Column of atomic Rows, it
|
|
34
|
+
* paginates at row boundaries for free (a row that doesn't fit moves whole). `"auto"`
|
|
35
|
+
* columns are resolved at layout time (a `DeferredElement`), once metrics are available.
|
|
36
|
+
*/
|
|
37
|
+
export declare function Table(opts: TableOptions, rows: Cell[][]): PDFElement;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Table = Table;
|
|
4
|
+
const box_constraints_1 = require("../layout/box-constraints");
|
|
5
|
+
const repeating_header_element_1 = require("../elements/layout/repeating-header-element");
|
|
6
|
+
const deferred_element_1 = require("../elements/layout/deferred-element");
|
|
7
|
+
const layout_1 = require("./layout");
|
|
8
|
+
const text_1 = require("./text");
|
|
9
|
+
function asElement(c) {
|
|
10
|
+
return typeof c === "string" ? (0, text_1.Text)(c) : c;
|
|
11
|
+
}
|
|
12
|
+
/** `"2fr"` → 2, `"fr"` → 1; not a fraction → null. */
|
|
13
|
+
function fractionOf(col) {
|
|
14
|
+
if (typeof col !== "string" || !col.endsWith("fr"))
|
|
15
|
+
return null;
|
|
16
|
+
const n = parseFloat(col);
|
|
17
|
+
return Number.isFinite(n) ? n : 1;
|
|
18
|
+
}
|
|
19
|
+
/** The cell's unbounded (max-content) width - what an `"auto"` column sizes to. */
|
|
20
|
+
function naturalWidth(cell, cellPadding, ctx) {
|
|
21
|
+
const el = cellPadding !== undefined ? (0, layout_1.Padding)(cellPadding, asElement(cell)) : asElement(cell);
|
|
22
|
+
return el.calculateLayout(box_constraints_1.BoxConstraints.loose(Infinity, Infinity), { x: 0, y: 0 }, ctx).width;
|
|
23
|
+
}
|
|
24
|
+
/** Replaces every `"auto"` column with the widest cell width measured down that column. */
|
|
25
|
+
function resolveAutoColumns(opts, rows, ctx) {
|
|
26
|
+
// The composed cell sits in a 1pt-border Box (border-box) that eats 1pt each side, which the
|
|
27
|
+
// measured content doesn't include; add it back, and `ceil` so a single-word cell can't land
|
|
28
|
+
// a hair over the width and wrap to an empty first line.
|
|
29
|
+
const slack = opts.cellBorder !== undefined || opts.rule !== undefined ? 2 : 0;
|
|
30
|
+
return opts.columns.map((col, i) => {
|
|
31
|
+
if (col !== "auto")
|
|
32
|
+
return col;
|
|
33
|
+
let w = opts.header ? naturalWidth(opts.header[i], opts.cellPadding, ctx) : 0;
|
|
34
|
+
for (const r of rows) {
|
|
35
|
+
if (r[i] !== undefined)
|
|
36
|
+
w = Math.max(w, naturalWidth(r[i], opts.cellPadding, ctx));
|
|
37
|
+
}
|
|
38
|
+
return Math.ceil(w + slack);
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
/** Builds the table tree for already-resolved column widths (no `"auto"`). */
|
|
42
|
+
function composeTable(opts, rows, columns) {
|
|
43
|
+
var _a, _b, _c, _d;
|
|
44
|
+
const { cellPadding } = opts;
|
|
45
|
+
const colGap = (_b = (_a = opts.colGap) !== null && _a !== void 0 ? _a : opts.gap) !== null && _b !== void 0 ? _b : 0;
|
|
46
|
+
const rowGap = (_d = (_c = opts.rowGap) !== null && _c !== void 0 ? _c : opts.gap) !== null && _d !== void 0 ? _d : 0;
|
|
47
|
+
const cb = opts.cellBorder;
|
|
48
|
+
const rule = opts.rule;
|
|
49
|
+
// The complete grid, once: every cell bottom+right, first row also top, first col also left.
|
|
50
|
+
const borderFor = (firstRow, firstCol) => cb === undefined
|
|
51
|
+
? {}
|
|
52
|
+
: Object.assign(Object.assign({ borderBottom: cb, borderRight: cb }, (firstRow ? { borderTop: cb } : {})), (firstCol ? { borderLeft: cb } : {}));
|
|
53
|
+
// `ruled` rows get just a bottom line (the header underline / the table foot), without the full grid.
|
|
54
|
+
const wrap = (cell, col, firstRow, firstCol, ruled) => {
|
|
55
|
+
const inner = cellPadding !== undefined ? (0, layout_1.Padding)(cellPadding, asElement(cell)) : asElement(cell);
|
|
56
|
+
// The border lives on the wrapper, which stretches to the row height (crisp lines).
|
|
57
|
+
const border = Object.assign(Object.assign({}, borderFor(firstRow, firstCol)), (ruled && rule !== undefined ? { borderBottom: rule } : {}));
|
|
58
|
+
const boxed = cb !== undefined || (ruled && rule !== undefined);
|
|
59
|
+
if (typeof col === "number")
|
|
60
|
+
return (0, layout_1.Box)(Object.assign({ width: col }, border), [inner]);
|
|
61
|
+
const fr = fractionOf(col);
|
|
62
|
+
if (fr !== null)
|
|
63
|
+
return (0, layout_1.Expanded)({ flex: fr }, boxed ? (0, layout_1.Box)(Object.assign({}, border), [inner]) : inner);
|
|
64
|
+
throw new Error(`Unsupported column width "${col}" - use a number of points or "<n>fr"`);
|
|
65
|
+
};
|
|
66
|
+
// align:stretch → equal-height cells, so a wrapping cell keeps the row's bottom rule straight.
|
|
67
|
+
const buildRow = (cells, firstRow, ruled = false) => (0, layout_1.Row)({ gap: colGap, align: "stretch" }, cells.map((cell, i) => { var _a; return wrap(cell, (_a = columns[i]) !== null && _a !== void 0 ? _a : "1fr", firstRow, i === 0, ruled); }));
|
|
68
|
+
// The first row (which gets the top border) is the header if present, else body row 0.
|
|
69
|
+
// `rule` underlines the header and the last body row (the table foot).
|
|
70
|
+
const last = rows.length - 1;
|
|
71
|
+
const body = (0, layout_1.Column)({ gap: rowGap }, rows.map((cells, idx) => buildRow(cells, !opts.header && idx === 0, rule !== undefined && idx === last)));
|
|
72
|
+
return opts.header
|
|
73
|
+
? new repeating_header_element_1.RepeatingHeaderElement(buildRow(opts.header, true, rule !== undefined), body, rowGap)
|
|
74
|
+
: body;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* A `Column` of `Row`s. Fixed-point columns sit in a fixed-width `Box`, `"Nfr"` fractions
|
|
78
|
+
* become `Expanded`, so columns align across rows. Being a Column of atomic Rows, it
|
|
79
|
+
* paginates at row boundaries for free (a row that doesn't fit moves whole). `"auto"`
|
|
80
|
+
* columns are resolved at layout time (a `DeferredElement`), once metrics are available.
|
|
81
|
+
*/
|
|
82
|
+
function Table(opts, rows) {
|
|
83
|
+
if (opts.columns.some((c) => c === "auto")) {
|
|
84
|
+
return new deferred_element_1.DeferredElement((ctx) => composeTable(opts, rows, resolveAutoColumns(opts, rows, ctx)));
|
|
85
|
+
}
|
|
86
|
+
return composeTable(opts, rows, opts.columns);
|
|
87
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { TextElement, TextSegment } from "../elements/text-element";
|
|
2
|
+
import { ColorInput } from "./color";
|
|
3
|
+
/** Text styling shared by `Text`, `Paragraph` and `span`. `bold`/`italic` are booleans
|
|
4
|
+
* (locked §7.3) and combine into one engine `FontStyle`. */
|
|
5
|
+
export interface TextStyle {
|
|
6
|
+
size?: number;
|
|
7
|
+
font?: string;
|
|
8
|
+
bold?: boolean;
|
|
9
|
+
italic?: boolean;
|
|
10
|
+
color?: ColorInput;
|
|
11
|
+
}
|
|
12
|
+
export interface TextOptions extends TextStyle {
|
|
13
|
+
/** Text-internal alignment (left/center/right) - independent of a parent's `cross` (§5). */
|
|
14
|
+
align?: "left" | "center" | "right";
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* An inline run for mixed-style `Text` (`Text([span("a", {bold:true}), span("b")])`). Each
|
|
18
|
+
* field overrides the enclosing `Text`'s defaults for just this run; omitted fields inherit.
|
|
19
|
+
*/
|
|
20
|
+
export declare function span(text: string, style?: TextStyle): TextSegment;
|
|
21
|
+
/**
|
|
22
|
+
* Text. `content` is a plain string or a list of `span(...)` runs for mixed styling. The
|
|
23
|
+
* options set the defaults (size/font/style/color) that any spans inherit, plus the
|
|
24
|
+
* text-internal `align`.
|
|
25
|
+
*/
|
|
26
|
+
export declare function Text(content: string | TextSegment[], opts?: TextOptions): TextElement;
|
|
27
|
+
/** `Text` with body-paragraph defaults (same options; a separate name reads as intent). */
|
|
28
|
+
export declare function Paragraph(content: string | TextSegment[], opts?: TextOptions): TextElement;
|
package/dist/api/text.js
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.span = span;
|
|
4
|
+
exports.Text = Text;
|
|
5
|
+
exports.Paragraph = Paragraph;
|
|
6
|
+
const text_element_1 = require("../elements/text-element");
|
|
7
|
+
const pdf_element_1 = require("../elements/pdf-element");
|
|
8
|
+
const pdf_object_manager_1 = require("../utils/pdf-object-manager");
|
|
9
|
+
const color_1 = require("./color");
|
|
10
|
+
/** Body-text default size when none is given (matches the engine default font). */
|
|
11
|
+
const DEFAULT_SIZE = 12;
|
|
12
|
+
/** bold + italic → the single engine `FontStyle`. */
|
|
13
|
+
function toFontStyle(bold, italic) {
|
|
14
|
+
if (bold && italic)
|
|
15
|
+
return pdf_object_manager_1.FontStyle.BoldItalic;
|
|
16
|
+
if (bold)
|
|
17
|
+
return pdf_object_manager_1.FontStyle.Bold;
|
|
18
|
+
if (italic)
|
|
19
|
+
return pdf_object_manager_1.FontStyle.Italic;
|
|
20
|
+
return pdf_object_manager_1.FontStyle.Normal;
|
|
21
|
+
}
|
|
22
|
+
const ALIGN = {
|
|
23
|
+
left: pdf_element_1.HorizontalAlignment.left,
|
|
24
|
+
center: pdf_element_1.HorizontalAlignment.center,
|
|
25
|
+
right: pdf_element_1.HorizontalAlignment.right,
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* An inline run for mixed-style `Text` (`Text([span("a", {bold:true}), span("b")])`). Each
|
|
29
|
+
* field overrides the enclosing `Text`'s defaults for just this run; omitted fields inherit.
|
|
30
|
+
*/
|
|
31
|
+
function span(text, style = {}) {
|
|
32
|
+
return {
|
|
33
|
+
content: text,
|
|
34
|
+
fontSize: style.size,
|
|
35
|
+
fontFamily: style.font,
|
|
36
|
+
fontStyle: style.bold !== undefined || style.italic !== undefined
|
|
37
|
+
? toFontStyle(style.bold, style.italic)
|
|
38
|
+
: undefined,
|
|
39
|
+
fontColor: style.color !== undefined ? (0, color_1.toColor)(style.color) : undefined,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Text. `content` is a plain string or a list of `span(...)` runs for mixed styling. The
|
|
44
|
+
* options set the defaults (size/font/style/color) that any spans inherit, plus the
|
|
45
|
+
* text-internal `align`.
|
|
46
|
+
*/
|
|
47
|
+
function Text(content, opts = {}) {
|
|
48
|
+
var _a;
|
|
49
|
+
return new text_element_1.TextElement({
|
|
50
|
+
content,
|
|
51
|
+
fontSize: (_a = opts.size) !== null && _a !== void 0 ? _a : DEFAULT_SIZE,
|
|
52
|
+
fontFamily: opts.font,
|
|
53
|
+
fontStyle: toFontStyle(opts.bold, opts.italic),
|
|
54
|
+
color: opts.color !== undefined ? (0, color_1.toColor)(opts.color) : undefined,
|
|
55
|
+
textAlignment: opts.align ? ALIGN[opts.align] : undefined,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
/** `Text` with body-paragraph defaults (same options; a separate name reads as intent). */
|
|
59
|
+
function Paragraph(content, opts = {}) {
|
|
60
|
+
return Text(content, opts);
|
|
61
|
+
}
|