@reportwright/engine 0.11.0 → 0.12.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.
@@ -0,0 +1,38 @@
1
+ // @ts-check
2
+ // A paint worker of a streaming PDF (pdfstream.js, opts.parallel): it lays out the windows of rows it is sent
3
+ // (engine/paged.js jobs, with the pages already counted) and paints their pages with the same painter and names as the
4
+ // writer, then sends back each page's compressed content stream and what it used (fonts, glyphs, opacities). Node only.
5
+ import { render, FontStore, __streamPaint } from './index.js';
6
+ const { createPdfStream, paintPage, paintEnv, latin1 } = __streamPaint;
7
+
8
+ const proc = /** @type {any} */ (globalThis).process;
9
+ const { parentPort, workerData } = proc.getBuiltinModule('node:worker_threads');
10
+ const zlib = proc.getBuiltinModule('node:zlib');
11
+ const bytes = new Map(workerData.fonts);
12
+ const fontStore = new FontStore(async (k) => {
13
+ const b = bytes.get(k);
14
+ if (!b) throw new Error(`The font "${k}" was not sent to the paint worker`);
15
+ return b;
16
+ });
17
+
18
+ parentPort.on('message', async (/** @type {any} */ job) => {
19
+ try {
20
+ const t0 = Date.now();
21
+ const m = await render(job.def, { ...job.opts, fontStore, sources: { __rows: { rows: job.rows } }, pageWindow: job.pageWindow });
22
+ // a writer of its own for the names and glyphs (nothing is written): the pages' links name pages by placeholder
23
+ const rec = createPdfStream({ write() {} }, { fontStore });
24
+ const env = paintEnv(rec, fontStore, { drillBase: job.drillBase, pageRef: (i) => `@@P${i}@@` });
25
+ const pages = [], transfer = [];
26
+ for (let k = 0; k < Math.min(job.keep, m.pages.length); k++) {
27
+ const pg = m.pages[k];
28
+ const { content, annots } = paintPage(pg, pg.height ?? job.height, env);
29
+ const z = new Uint8Array(zlib.deflateSync(latin1(content), { level: 9 })); // as pdfpaint.js's deflate
30
+ transfer.push(z.buffer);
31
+ pages.push({ deflated: z, annots, width: pg.width, height: pg.height, firstRow: pg.firstRow, rowHead: pg.rowHead, headLevel: pg.headLevel });
32
+ }
33
+ parentPort.postMessage({ id: job.id, count: m.pages.length, nextFirst: m.pages[job.keep]?.firstRow, pages, used: rec.used(),
34
+ shaped: [...env.shaped].map(([k, g]) => [k, [...g]]), bookmarks: m.bookmarks, headings: m.headings, warnings: m.warnings, ms: Date.now() - t0 }, transfer);
35
+ } catch (e) {
36
+ parentPort.postMessage({ id: job.id, error: { message: String(/** @type {any} */ (e)?.message || e), status: /** @type {any} */ (e)?.status, timeout: /** @type {any} */ (e)?.timeout } });
37
+ }
38
+ });
@@ -48,11 +48,43 @@ export function exportDocx(model: any, options?: NonNullable<Parameters<typeof e
48
48
  export function exportPptx(model: any, options?: NonNullable<Parameters<typeof exportPptxFull>[1]> & {
49
49
  fonts?: FontStore;
50
50
  }, ...args: any[]): Promise<Uint8Array>;
51
+ /**
52
+ * @typedef {RenderOptions & Omit<PdfOptions, 'fonts'> & { fonts?: FontStore, tagged?: { lang?: string },
53
+ * window?: number, parallel?: number, maxRows?: number, id?: string }} PdfStreamOptions
54
+ * render()'s options and exportPdf's, plus: window (rows laid out at once, 1000), parallel (Node: worker threads
55
+ * that lay out and paint pages, opt-in; the file is the same), maxRows (rows read, 5,000,000), id (the file ID).
56
+ */
57
+ /**
58
+ * Report definition → PDF written to a sink as it is made, for reports too large to hold as a page model: a flowing
59
+ * table (and its groups) is laid out a window of rows at a time and each page leaves memory once written. Other
60
+ * reports are rendered whole and written by exportPdf in one piece (the result says why). sink: a Node Writable
61
+ * (fs.createWriteStream) or anything with write(bytes) that may return a promise (back-pressure); it is not closed.
62
+ * @param {any} def the report definition
63
+ * @param {PdfStreamOptions} options
64
+ * @param {{ write(bytes: Uint8Array): any, once?: (ev: string, cb: () => void) => any }} sink
65
+ * @returns {Promise<{ streamed: boolean, pages: number, warnings: string[], why?: string }>}
66
+ */
67
+ export function exportPdfStream(def: any, options: PdfStreamOptions, sink: {
68
+ write(bytes: Uint8Array): any;
69
+ once?: (ev: string, cb: () => void) => any;
70
+ }): Promise<{
71
+ streamed: boolean;
72
+ pages: number;
73
+ warnings: string[];
74
+ why?: string;
75
+ }>;
51
76
  export { validate } from "../../src/engine/schema/validate.js";
52
77
  export { exportHtml } from "../../src/exporters/html.js";
53
78
  export { exportCsv } from "../../src/exporters/csv.js";
54
79
  export { needsExportData } from "../../src/exporters/regions.js";
55
80
  export { pageToSvg } from "../../src/exporters/svg.js";
81
+ export namespace __streamPaint {
82
+ export { createPdfStream };
83
+ export { paintPage };
84
+ export { paintEnv };
85
+ export { latin1 };
86
+ }
87
+ export { planPaged } from "../../src/engine/paged.js";
56
88
  export type PdfOptions = Omit<NonNullable<Parameters<typeof exportPdfFull>[2]>, "subset" | "pdfa"> & {
57
89
  fonts?: FontStore;
58
90
  subset?: false | NonNullable<Parameters<typeof exportPdfFull>[2]>["subset"];
@@ -61,6 +93,20 @@ export type PdfOptions = Omit<NonNullable<Parameters<typeof exportPdfFull>[2]>,
61
93
  [k: string]: unknown;
62
94
  };
63
95
  };
96
+ /**
97
+ * render()'s options and exportPdf's, plus: window (rows laid out at once, 1000), parallel (Node: worker threads
98
+ * that lay out and paint pages, opt-in; the file is the same), maxRows (rows read, 5,000,000), id (the file ID).
99
+ */
100
+ export type PdfStreamOptions = RenderOptions & Omit<PdfOptions, "fonts"> & {
101
+ fonts?: FontStore;
102
+ tagged?: {
103
+ lang?: string;
104
+ };
105
+ window?: number;
106
+ parallel?: number;
107
+ maxRows?: number;
108
+ id?: string;
109
+ };
64
110
  export type RenderOptions = import("../../src/engine/index.js").RenderOptions;
65
111
  import { FontStore } from '../../src/engine/index.js';
66
112
  import { exportXlsx as exportXlsxFull } from '../../src/exporters/xlsx.js';
@@ -68,6 +114,10 @@ import { exportDocx as exportDocxFull } from '../../src/exporters/docx.js';
68
114
  import { exportPptx as exportPptxFull } from '../../src/exporters/pptx.js';
69
115
  import { fontFile } from '../../src/engine/text/fonts.js';
70
116
  import { createSubsetter } from '../../src/exporters/subset.js';
117
+ import { createPdfStream } from '../../src/exporters/pdfstream.js';
118
+ import { paintPage } from '../../src/exporters/pdfstream.js';
119
+ import { paintEnv } from '../../src/exporters/pdfstream.js';
120
+ import { latin1 } from '../../src/exporters/pdfpaint.js';
71
121
  import { exportPdf as exportPdfFull } from '../../src/exporters/pdf.js';
72
122
  export { fontFile, createSubsetter };
73
123
  export { render, FontStore, ITEMS, parameterOptions, resolveParameters } from "../../src/engine/index.js";
@@ -0,0 +1,48 @@
1
+ /**
2
+ * The keys a JSONPath walks to reach the rows, when the splitter can follow it: $, $.a.b, $['a b'], with a [*] at the
3
+ * end at most. Null for any other path (indexes, spreads in the middle): read the whole body instead.
4
+ * @param {string} [path] @returns {string[]|null}
5
+ */
6
+ export function splitPath(path?: string): string[] | null;
7
+ /**
8
+ * The rows of a JSON body at a path, in batches, without holding the body: the bytes are scanned for the array the
9
+ * path names, and its elements are parsed (JSON.parse, a batch at a time) as they complete. A body whose shape the path
10
+ * does not meet that way (an object where the rows should be, a path with indexes) is read whole and taken through
11
+ * jsonPathRows, exactly as a whole-body read would: maxWholeBytes caps that case. Every cap counts the text actually read
12
+ * (characters), not a declared length: the body before the rows (maxWholeBytes), one row (maxElementBytes, so one huge
13
+ * string or a row that never ends cannot grow without bound) and the nesting (maxDepth).
14
+ * @param {any} body @param {string|undefined} path
15
+ * @param {{ maxElementBytes?: number, maxWholeBytes?: number, maxDepth?: number, batch?: number }} [o]
16
+ * @returns {AsyncGenerator<any[]>}
17
+ */
18
+ export function jsonRows(body: any, path: string | undefined, { maxElementBytes, maxWholeBytes, maxDepth, batch }?: {
19
+ maxElementBytes?: number;
20
+ maxWholeBytes?: number;
21
+ maxDepth?: number;
22
+ batch?: number;
23
+ }): AsyncGenerator<any[]>;
24
+ /**
25
+ * CSV records as they arrive: the same reading as parseCsv (a quote opens a quoted field only at the start of a field;
26
+ * inside, a doubled quote is a quote and separators and line breaks are data; text after the closing quote is kept;
27
+ * \n, \r\n and \r end a record), across chunk boundaries.
28
+ * @param {any} body @param {{ sep: string, quote: string, maxFieldBytes?: number }} o @returns {AsyncGenerator<string[][]>}
29
+ */
30
+ export function csvRecords(body: any, { sep, quote, maxFieldBytes }: {
31
+ sep: string;
32
+ quote: string;
33
+ maxFieldBytes?: number;
34
+ }, batch?: number): AsyncGenerator<string[][]>;
35
+ /**
36
+ * CSV rows as objects, as parseCsv gives them (startRow, the header row's names, blank lines dropped), in batches.
37
+ * headerRow: false needs every row's width first: not read this way (null).
38
+ * @param {any} body @param {{ separator?: string, quote?: string, headerRow?: boolean, startRow?: number }} src
39
+ * @param {(v: any, d: string, what: string) => string} csvChar @param {number} [maxFieldBytes]
40
+ */
41
+ export function csvRows(body: any, src: {
42
+ separator?: string;
43
+ quote?: string;
44
+ headerRow?: boolean;
45
+ startRow?: number;
46
+ }, csvChar: (v: any, d: string, what: string) => string, maxFieldBytes?: number): AsyncGenerator<{
47
+ [k: string]: string;
48
+ }[], void, unknown>;
@@ -216,6 +216,21 @@ export type RenderOptions = {
216
216
  * internal: the images drawn so far, shared with subreports
217
217
  */
218
218
  imageBudget?: any;
219
+ /**
220
+ * internal (paged.js): these pages are a window of a longer report: numbered from offset + 1 of total ('…' when not known
221
+ * yet); final: the window holds the report's last page; first: the report's first row; rowOffset: the rows before this
222
+ * window; cont: per group level, the group the window's first row continues (its first row), or null
223
+ */
224
+ pageWindow?: {
225
+ offset: number;
226
+ total?: number | null;
227
+ final: boolean;
228
+ first?: any;
229
+ rowOffset?: number;
230
+ cont?: ({
231
+ first: any;
232
+ } | null)[];
233
+ };
219
234
  };
220
235
  import { FontStore } from './text/fonts.js';
221
236
  import { TextMeasurer } from './text/measure.js';
@@ -0,0 +1,19 @@
1
+ /**
2
+ * @param {any} def0 @param {any} opts render() options, and maxRows/sorter/sqlRows as planStream takes them;
3
+ * window: rows per window (tests)
4
+ * @returns {Promise<{ why: string } | { why?: undefined, pages: () => AsyncGenerator<any>, info: { width: number, height: number, bookmarks: any[], headings: any[], warnings: string[], pages: number } }>}
5
+ */
6
+ export function planPaged(def0: any, opts?: any): Promise<{
7
+ why: string;
8
+ } | {
9
+ why?: undefined;
10
+ pages: () => AsyncGenerator<any>;
11
+ info: {
12
+ width: number;
13
+ height: number;
14
+ bookmarks: any[];
15
+ headings: any[];
16
+ warnings: string[];
17
+ pages: number;
18
+ };
19
+ }>;
@@ -0,0 +1,54 @@
1
+ /**
2
+ * An in-memory sorter (the browser, the CLI): the server passes one that spills runs to disk (server/spill.js).
3
+ * @param {(a: any, b: any) => number} cmp
4
+ */
5
+ export function memorySorter(cmp: (a: any, b: any) => number): {
6
+ push(r: any): void;
7
+ drain(): AsyncGenerator<any, void, unknown>;
8
+ close(): Promise<void>;
9
+ };
10
+ /**
11
+ * @param {any} def0 the report definition
12
+ * @param {{ format: 'csv'|'xlsx', parameters?: object, timeZone?: string, now?: Date, state?: any, loadReport?: (id: string) => Promise<any>,
13
+ * reportId?: string, fetch?: typeof fetch, baseUrl?: string, sql?: (src: any, p: any) => Promise<object[]>,
14
+ * sqlRows?: (src: any, p: any) => AsyncIterable<object[]>, sources?: Record<string, any>, sorter?: (cmp: (a: any, b: any) => number) => any,
15
+ * deadline?: number, timeoutMs?: number, maxRows?: number, maxJsonRowBytes?: number, maxJsonWholeBytes?: number }} opts
16
+ * @returns {Promise<{ why: string } | { why?: undefined, name: string, columns: number[], title: string, timeZone: string|null, locale: string|null, currency: string|null, warnings: string[], rows: () => AsyncGenerator<any>, records: () => AsyncGenerator<any>, grouped: () => AsyncGenerator<any>, stats: { rows: number } }>}
17
+ */
18
+ export function planStream(def0: any, opts: {
19
+ format: "csv" | "xlsx";
20
+ parameters?: object;
21
+ timeZone?: string;
22
+ now?: Date;
23
+ state?: any;
24
+ loadReport?: (id: string) => Promise<any>;
25
+ reportId?: string;
26
+ fetch?: typeof fetch;
27
+ baseUrl?: string;
28
+ sql?: (src: any, p: any) => Promise<object[]>;
29
+ sqlRows?: (src: any, p: any) => AsyncIterable<object[]>;
30
+ sources?: Record<string, any>;
31
+ sorter?: (cmp: (a: any, b: any) => number) => any;
32
+ deadline?: number;
33
+ timeoutMs?: number;
34
+ maxRows?: number;
35
+ maxJsonRowBytes?: number;
36
+ maxJsonWholeBytes?: number;
37
+ }): Promise<{
38
+ why: string;
39
+ } | {
40
+ why?: undefined;
41
+ name: string;
42
+ columns: number[];
43
+ title: string;
44
+ timeZone: string | null;
45
+ locale: string | null;
46
+ currency: string | null;
47
+ warnings: string[];
48
+ rows: () => AsyncGenerator<any>;
49
+ records: () => AsyncGenerator<any>;
50
+ grouped: () => AsyncGenerator<any>;
51
+ stats: {
52
+ rows: number;
53
+ };
54
+ }>;
@@ -20,6 +20,17 @@ export function makePdfA(doc: import("pdf-lib").PDFDocument, { icc, title, autho
20
20
  * @param {Date} when
21
21
  */
22
22
  export function setInfoDates(doc: import("pdf-lib").PDFDocument, when: Date): void;
23
+ /**
24
+ * The XMP metadata packet: title, author, dates, and the PDF/A and PDF/UA identifiers when asked.
25
+ * @param {{ title: string, author?: string, stamp: string, pdfa?: string|null, ua?: boolean }} o
26
+ */
27
+ export function xmpPacket({ title, author, stamp, pdfa, ua }: {
28
+ title: string;
29
+ author?: string;
30
+ stamp: string;
31
+ pdfa?: string | null;
32
+ ua?: boolean;
33
+ }): string;
23
34
  /**
24
35
  * PDF/UA-1 without PDF/A: XMP metadata with the title and the PDF/UA identifier (the Info dictionary says the same).
25
36
  * @param {import('pdf-lib').PDFDocument} doc
@@ -0,0 +1,107 @@
1
+ /**
2
+ * Draw one run of shaped glyphs by ID, where the engine placed them: a TJ array whose numbers move each
3
+ * glyph from where the font's own advance (the W array) leaves it to the shaper's position; marks that sit
4
+ * higher or lower use the text rise. /ActualText gives copy and search the characters: for a left-to-right
5
+ * run the whole run in reading order; a right-to-left run (drawn in visual order, which readers reorder
6
+ * themselves) reads through ToUnicode, glyph by glyph, and only a cluster ToUnicode cannot spell gets a span
7
+ * (`spans`, from glyphText); glyphs that stand for nothing (`texts`: '') go last. A span per joined letter, and
8
+ * the dots of joined letters drawn among the letters, made pdftotext split words ("الج ميل", "الت قن ية").
9
+ * @param {Content} c @param {Set<number>} [spans] @param {Map<number, string>} [texts]
10
+ */
11
+ export function drawRun(c: Content, run: any, x: any, y: any, size: any, pf: any, color: any, spans?: Set<number>, texts?: Map<number, string>): void;
12
+ /**
13
+ * The text each shaped glyph stands for, for the font's ToUnicode map: the character whose own (character-map)
14
+ * glyph it is; the characters of its cluster that have no glyph of their own there (a conjunct, a joined
15
+ * Arabic form, a reph) go to ONE glyph, the first that is not a mark, and the cluster's other glyphs (dots,
16
+ * marks) stand for nothing, so a reader gets each character once. A glyph keeps its first text: a
17
+ * right-to-left cluster that would read differently with the texts already set goes into `spans` (drawRun
18
+ * gives it /ActualText). Left-to-right runs always get one span for the whole run.
19
+ * @param {any} run @param {any} font fontkit font @param {Map<number, string>} out
20
+ * @param {WeakMap<any, Set<number>>} [spans]
21
+ */
22
+ export function glyphText(run: any, font: any, out: Map<number, string>, spans?: WeakMap<any, Set<number>>): void;
23
+ /**
24
+ * Text inside its clip box needs no clip: the lines' advances within it across, the font's ascent and descent
25
+ * within it down. A cell's text almost always fits, and a clip per cell is most of a table page's operators.
26
+ */
27
+ export function insideClip(it: any, m: any): any;
28
+ /** one byte per char: the content stream holds the glyph bytes of literal strings as chars 0–255 */
29
+ export function latin1(s: any): any;
30
+ /**
31
+ * zlib (Flate) compression: Node's zlib on its thread pool (pages compress in parallel, off the main thread), else
32
+ * the platform's CompressionStream (browsers; in Node it is the same zlib behind web streams, slower), else fflate.
33
+ */
34
+ export function deflate(bytes: any): Promise<any>;
35
+ export function col(c: any): any;
36
+ export namespace BLACK {
37
+ let color: import("pdf-lib").RGB;
38
+ let opacity: number;
39
+ let rgb: string;
40
+ }
41
+ export function n2(v: any): number;
42
+ export function n3(v: any): number;
43
+ export function n4(v: any): number;
44
+ export function hex4(id: any): any;
45
+ export const KAPPA: number;
46
+ export function cleanText(t: any): any;
47
+ /**
48
+ * A page's operators as text. The graphics state is tracked, so a colour, line width, dash, opacity or font
49
+ * that is already set is not set again; q/Q save and restore it as the PDF does.
50
+ */
51
+ export class Content {
52
+ constructor(shared: any);
53
+ shared: any;
54
+ _s: string;
55
+ bt: boolean;
56
+ tx: number;
57
+ ty: number;
58
+ st: {
59
+ fill: string;
60
+ stroke: string;
61
+ lw: number;
62
+ dash: string;
63
+ ca: number;
64
+ CA: number;
65
+ font: string;
66
+ size: number;
67
+ };
68
+ /** @type {any[]} */ saved: any[];
69
+ /** straight lines waiting to be drawn after the text around them: { key, stroke, w, dash, segs: [x1, y1, x2, y2][] } */
70
+ lines: any;
71
+ tagged: boolean;
72
+ set s(v: string);
73
+ /**
74
+ * The operators so far. Any other drawing reads or appends to it, so the lines waiting are drawn first: the text
75
+ * of a table's cells stays in one text object (relative moves, which compress to little) instead of one per cell.
76
+ */
77
+ get s(): string;
78
+ /**
79
+ * A straight line. Untagged, it waits until something other than text is drawn (table borders between cell
80
+ * texts); collinear segments that touch, in the same stroke, become one (a row's border is one line).
81
+ * ponytail: lines move after the text drawn just after them; both are thin and do not cover each other.
82
+ */
83
+ line(stroke: any, w: any, dash: any, x1: any, y1: any, x2: any, y2: any): void;
84
+ flushLines(): void;
85
+ q(): void;
86
+ Q(): void;
87
+ /**
88
+ * A line of plain text at (x, y). Lines follow one another in one text object, each placed relative to the
89
+ * last (in whole hundredths, so nothing drifts): most of a table page is these.
90
+ * @param {string} str the glyphs, as a literal string's escaped body (array: a TJ array's body)
91
+ */
92
+ text(pf: any, size: any, color: any, x: any, y: any, str: string, array?: boolean): void;
93
+ /** end the open text object, if any: anything but text needs that (and draws the lines waiting) */
94
+ et(): void;
95
+ lineWidth(w: any): void;
96
+ setLineWidth(w: any): void;
97
+ /** the graphics state that sets these opacities, or undefined when they are set already */
98
+ gsFor(ca: any, CA: any): any;
99
+ alpha(ca: any, CA: any): void;
100
+ setAlpha(ca: any, CA: any): void;
101
+ /** set up to fill with fill and/or stroke with stroke (width w, dash); the lines waiting are drawn first */
102
+ paint(fill: any, stroke: any, w?: number, dash?: any): void;
103
+ setPaint(fill: any, stroke: any, w?: number, dash?: any): void;
104
+ font(pf: any, size: any): void;
105
+ setFont(pf: any, size: any): void;
106
+ }
107
+ export const NODE_ZLIB: any;
@@ -0,0 +1,198 @@
1
+ /**
2
+ * @typedef {{ write(u8: Uint8Array): any, once?: (ev: string, cb: () => void) => any }} Sink
3
+ * write may return a promise (awaited: back-pressure), or false with a 'drain' event to wait for (a Node Writable).
4
+ * @typedef {{ title: string, page: number, top?: number, level?: number }} OutlineEntry
5
+ * page: 1-based; top: the destination's y in PDF space (from the bottom), else the page fits the window.
6
+ */
7
+ /**
8
+ * @param {Sink} sink
9
+ * @param {{ fontStore: import('../engine/text/fonts.js').FontStore, fonts?: string[],
10
+ * subset?: (font: Uint8Array, codePoints: Iterable<number>, opt?: { glyphs?: Iterable<number> }) => Promise<Uint8Array>,
11
+ * id?: string }} opt
12
+ * fonts: font keys to name now (F1, F2… in this order); any other font is named on first use.
13
+ * subset: subset.js's subsetter; without it fonts embed in full. id: the file ID (32 hex digits), else random.
14
+ */
15
+ export function createPdfStream(sink: Sink, opt: {
16
+ fontStore: import("../engine/text/fonts.js").FontStore;
17
+ fonts?: string[];
18
+ subset?: (font: Uint8Array, codePoints: Iterable<number>, opt?: {
19
+ glyphs?: Iterable<number>;
20
+ }) => Promise<Uint8Array>;
21
+ id?: string;
22
+ }): {
23
+ /** @param {string} key @returns {string} the font's resource name (F1…) */
24
+ fontName: (key: string) => string;
25
+ /**
26
+ * The text's glyphs, one per character (as the engine measured it: no layout features), as hex for <…> Tj, with
27
+ * the glyphs recorded for the subset, W and ToUnicode.
28
+ * @param {string} key @param {string} text
29
+ */
30
+ encode(key: string, text: string): string;
31
+ /**
32
+ * The same glyphs as a literal string's body, two bytes each, escaped (as pdf.js draws plain text): ( … ) Tj.
33
+ * @param {string} key @param {string} text
34
+ */
35
+ literal(key: string, text: string): string;
36
+ /**
37
+ * Shaped glyphs drawn by ID (conjuncts, joined forms): [glyph ID, the text it stands for ('' for none)].
38
+ * @param {string} key @param {Iterable<[number, string]>} glyphs
39
+ */
40
+ addGlyphs(key: string, glyphs: Iterable<[number, string]>): void;
41
+ /**
42
+ * A name in the shared Resources dictionary for a value (an indirect ref "12 0 R" or an inline dictionary).
43
+ * @param {'ExtGState'|'XObject'|'Pattern'|'Shading'|'ColorSpace'} kind @param {string} value
44
+ */
45
+ resource(kind: "ExtGState" | "XObject" | "Pattern" | "Shading" | "ColorSpace", value: string, name?: any): string;
46
+ /**
47
+ * The ExtGState name for fill and stroke opacity, named by its values (the same name in every writer: pages
48
+ * painted elsewhere, parallel.js, use it too). @param {number} ca @param {number} CA
49
+ */
50
+ gs: (ca: number, CA: number) => string;
51
+ /** What this writer's pages used, for another writer to take over (pages painted elsewhere). */
52
+ used: () => {
53
+ fonts: (string | number[] | [number, string][])[][];
54
+ gs: string[];
55
+ };
56
+ /** Take over what pages painted elsewhere used (used() of their writer). @param {any} u */
57
+ take(u: any): void;
58
+ /**
59
+ * Write an object now (an image: its dictionary and its stream, already filtered). @returns {Promise<number>} its number
60
+ * @param {string} dict @param {Uint8Array} [stream]
61
+ */
62
+ object(dict: string, stream?: Uint8Array): Promise<number>;
63
+ /** An object number to write later (objectAt). */
64
+ reserve: () => number;
65
+ /** Write a reserved object. @param {number} n @param {string} dict @param {Uint8Array} [stream] */
66
+ objectAt: (n: number, dict: string, stream?: Uint8Array) => Promise<void>;
67
+ /**
68
+ * Write a reserved object whose text may be long (an array of every row's element): head, the parts as they come,
69
+ * tail; written out in place, never held whole. @param {number} n @param {string} head @param {Iterable<string>} parts @param {string} tail
70
+ */
71
+ bigObject(n: number, head: string, parts: Iterable<string>, tail: string): Promise<void>;
72
+ /** The object number of page i (0-based), written or not: links and outline entries may point ahead. @param {number} i */
73
+ pageRef(i: number): number;
74
+ /**
75
+ * The total page count, drawn at the end: a Form XObject whose origin is the text's baseline at the box's left;
76
+ * draw it with `q 1 0 0 1 x y cm /<name> Do Q`. align: within width.
77
+ * @param {{ font: string, size: number, width: number, align?: 'left'|'center'|'right', color?: string }} o
78
+ */
79
+ totalPages(o: {
80
+ font: string;
81
+ size: number;
82
+ width: number;
83
+ align?: "left" | "center" | "right";
84
+ color?: string;
85
+ }): string;
86
+ /**
87
+ * Write a page: its content stream (deflated) and its dictionary, now. Nothing of it stays but two offsets.
88
+ * @param {{ width: number, height: number, content?: string | Uint8Array, deflated?: Uint8Array, annots?: (string | { ref: number, dict: string })[], extra?: string }} p
89
+ * deflated: the content stream already compressed (zlib), as pages painted elsewhere come.
90
+ * content: the page's operators (a string holds bytes 0–255, as pdf.js's Content makes). annots: annotation
91
+ * dictionaries (with a reserved number: { ref, dict }). extra: more entries for the page dictionary (/StructParents 3).
92
+ */
93
+ addPage(p: {
94
+ width: number;
95
+ height: number;
96
+ content?: string | Uint8Array;
97
+ deflated?: Uint8Array;
98
+ annots?: (string | {
99
+ ref: number;
100
+ dict: string;
101
+ })[];
102
+ extra?: string;
103
+ }): Promise<void>;
104
+ /**
105
+ * The end of the file: totals, fonts, resources, page tree, outline, catalog, Info, xref, trailer.
106
+ * @param {{ outline?: OutlineEntry[], info?: { title?: string, author?: string, subject?: string, creationDate?: Date }, catalog?: string }} [o]
107
+ * catalog: more entries for the catalog (the structure tree, metadata, output intents).
108
+ * @returns {Promise<{ pages: number, bytes: number }>}
109
+ */
110
+ finish(o?: {
111
+ outline?: OutlineEntry[];
112
+ info?: {
113
+ title?: string;
114
+ author?: string;
115
+ subject?: string;
116
+ creationDate?: Date;
117
+ };
118
+ catalog?: string;
119
+ }): Promise<{
120
+ pages: number;
121
+ bytes: number;
122
+ }>;
123
+ };
124
+ /**
125
+ * A report to PDF bytes written to sink as its pages are laid out (planPaged: a flowing table, one window of rows at a
126
+ * time), else rendered whole and exported by exportPdf, the same file it always was, written to sink in one piece.
127
+ * opts: render()'s options and exportPdf's (fontStore, subset, title, author, creationDate, drillBase…). Tagged,
128
+ * PDF/A, encrypted and signed files take the whole-model path.
129
+ * @param {any} def @param {any} opts @param {Sink} sink
130
+ * @returns {Promise<{ streamed: boolean, pages: number, warnings: string[], why?: string }>}
131
+ */
132
+ export function exportPdfStream(def: any, opts: any, sink: Sink): Promise<{
133
+ streamed: boolean;
134
+ pages: number;
135
+ warnings: string[];
136
+ why?: string;
137
+ }>;
138
+ /**
139
+ * The pages of a paged plan (planPaged) as a PDF written to sink, page by page.
140
+ * @param {any} plan @param {any} opts fontStore, subset, title, author, creationDate, drillBase @param {Sink} sink
141
+ * @returns {Promise<{ pages: number, warnings: string[] }>}
142
+ */
143
+ export function writePagedPdf(plan: any, opts: any, sink: Sink): Promise<{
144
+ pages: number;
145
+ warnings: string[];
146
+ }>;
147
+ /**
148
+ * A page of the model as its content stream's operators and its link annotations, drawn with the shared painter
149
+ * (pdfpaint.js) as exportPdf draws it. env (paintEnv): the writer's names and glyph records, the page refs links jump
150
+ * to, the tagger when tagged. Pages painted in parallel (parallel.js) use a writer of their own and the same names.
151
+ * @param {any} pg @param {number} H @param {any} env
152
+ * @returns {{ content: string, annots: any[] }}
153
+ */
154
+ export function paintPage(pg: any, H: number, env: any): {
155
+ content: string;
156
+ annots: any[];
157
+ };
158
+ /**
159
+ * What paintPage draws with: a writer's resource names and glyph records (w), the fonts, shaped glyphs' texts.
160
+ * @param {any} w @param {any} fontStore @param {{ drillBase?: string, pageRef?: (i: number) => any, tags?: any }} [o]
161
+ */
162
+ export function paintEnv(w: any, fontStore: any, o?: {
163
+ drillBase?: string;
164
+ pageRef?: (i: number) => any;
165
+ tags?: any;
166
+ }): {
167
+ shared: {
168
+ font: (f: any) => any;
169
+ gs: (ca: any, CA: any) => any;
170
+ image: () => never;
171
+ };
172
+ pf: (key: string) => any;
173
+ font: (key: string) => any;
174
+ shaped: Map<string, Map<number, string>>;
175
+ shapedOf: (key: string) => Map<number, string>;
176
+ vmetrics: (key: string) => any;
177
+ literal: (key: string, text: string) => any;
178
+ pageRef: (i: number) => any;
179
+ reserve: () => any;
180
+ drillBase: string;
181
+ tags: any;
182
+ };
183
+ /**
184
+ * write may return a promise (awaited: back-pressure), or false with a 'drain' event to wait for (a Node Writable).
185
+ */
186
+ export type Sink = {
187
+ write(u8: Uint8Array): any;
188
+ once?: (ev: string, cb: () => void) => any;
189
+ };
190
+ /**
191
+ * page: 1-based; top: the destination's y in PDF space (from the bottom), else the page fits the window.
192
+ */
193
+ export type OutlineEntry = {
194
+ title: string;
195
+ page: number;
196
+ top?: number;
197
+ level?: number;
198
+ };
@@ -0,0 +1,38 @@
1
+ /**
2
+ * The structure tree of a streamed, tagged PDF (PDF/UA-1, and PDF/A-2a with it): pdfua.js's tree for the shapes that
3
+ * stream (engine/paged.js), written as the pages are. Document > P / H1–H6 (text boxes), Table > TR > TH/TD (the table's
4
+ * header rows TH with Scope Column the first time, an artifact where they repeat; empty cells as empty TD; spans as
5
+ * ColSpan), Link > OBJR inside the element whose text it covers; page header and footer, borders and boxes artifacts.
6
+ * Each page's rows (TR, TD), its parent-tree array and its links' elements are written when the page ends; what stays
7
+ * is one number per row (the Table's kids) and two per page and link (the parent tree), written at the end.
8
+ */
9
+ /**
10
+ * @param {any} w the PDF writer (pdfstream.js createPdfStream)
11
+ */
12
+ export function createStreamTagger(w: any): {
13
+ /** a new page (window: the paged window it came from; row ids are its own) @param {number} window */
14
+ page(window: number): void;
15
+ /**
16
+ * The marked content that opens item it: a structure element's MCID, or an artifact; null for a link.
17
+ * @param {any} it
18
+ */
19
+ open(it: any): string;
20
+ /**
21
+ * A link annotation of the page: its Link element (in the element of the text it covers, else the Document).
22
+ * @returns {number} the annotation's StructParent
23
+ * @param {any} it @param {number} annot the annotation's object number
24
+ */
25
+ link(it: any, annot: number): number;
26
+ /**
27
+ * The page is drawn: its elements and parent-tree array are written. @returns {Promise<string>} the page's entries
28
+ * @param {number} pageRef
29
+ */
30
+ end(pageRef: number): Promise<string>;
31
+ /**
32
+ * The tree's top: Table, Document, the parent tree, the root. @returns {Promise<string>} the catalog's entries
33
+ * @param {{ lang?: string }} o
34
+ */
35
+ finish({ lang }?: {
36
+ lang?: string;
37
+ }): Promise<string>;
38
+ };