renderpdf-js 0.2.1 → 0.3.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/API.md ADDED
@@ -0,0 +1,204 @@
1
+ # Document API
2
+
3
+ RenderPDF.js provides three ways to create a PDF: `renderPDF()` for supported HTML,
4
+ `imageToPDF()` for image files, and `createDocument()` for programmatic drawing.
5
+ All return or finalize into the same immutable `RenderPDFResult` with `pageCount`,
6
+ `warnings`, `toBlob()`, `toUint8Array()` and `download()`.
7
+
8
+ ## Documents and fonts
9
+
10
+ ```ts
11
+ import { createDocument } from 'renderpdf-js';
12
+
13
+ const response = await fetch('/fonts/ReportSans-Regular.ttf');
14
+ if (!response.ok) throw new Error('The font could not be loaded.');
15
+
16
+ const document = await createDocument({
17
+ unit: 'mm',
18
+ format: 'A4',
19
+ fonts: [{ family: 'Report Sans', data: await response.arrayBuffer() }],
20
+ metadata: { title: 'Report' },
21
+ });
22
+ const page = document.addPage();
23
+ page.drawText('Příliš žluťoučký kůň', {
24
+ x: 15,
25
+ y: 25,
26
+ font: 'Report Sans',
27
+ fontSize: 12,
28
+ });
29
+ await (await document.toResult()).download('report.pdf');
30
+ ```
31
+
32
+ `createDocument()` is asynchronous because it prepares fonts. Drawing and
33
+ measurement are synchronous afterwards, except `drawImage()` and `appendPDF()`,
34
+ which must be awaited. The document API does not require a browser or font
35
+ registration in the DOM. Use `registerFont()` separately for HTML exports.
36
+
37
+ | Setting | Default | Meaning |
38
+ | ------------- | ----------------------- | ----------------------------------------------------------------------------- |
39
+ | `unit` | `'pt'` | `'pt'`, `'mm'` or `'px'` for coordinates and dimensions. |
40
+ | `format` | `'A4'` | `'A4'`, `'A3'`, `'Letter'` or `{ width, height }` in document units. |
41
+ | `orientation` | `'portrait'` | Landscape swaps the supplied base axes. |
42
+ | `fonts` | Standard PDF fonts | Static TTF/OTF programs with `family`, `data`, optional `weight` and `style`. |
43
+ | `metadata` | Title: `'RenderPDF.js'` | Unicode title, author, subject and keyword strings. |
44
+ | `signal` | — | Cooperative cancellation via `AbortSignal`. |
45
+
46
+ Coordinates start at the top-left. Text `y` is a **baseline**, while rectangle and
47
+ image `y` is a top edge. Font sizes always use **points**, independent of `unit`.
48
+ `1 mm = 72/25.4 pt`; `1 px = 0.75 pt`. Rotation uses clockwise degrees.
49
+
50
+ Helvetica, Times and Courier include regular, bold, italic and bold-italic faces.
51
+ Their character sets are limited. For Czech and other Unicode text, provide an
52
+ appropriate font program. Select an exact face using `font`, `fontWeight` and
53
+ `fontStyle`; missing fonts and glyphs fail explicitly. Fonts are not substituted.
54
+
55
+ ## Page management
56
+
57
+ `addPage(options?)` returns a page handle. It inherits document defaults; each page
58
+ can override its format and orientation. Documents start without an implicit page.
59
+
60
+ - `getPage(number)` and `getPages()` return existing handles in document order.
61
+ - `pageCount` reports the number of physical pages.
62
+ - `insertPage(number, options?)` inserts before a one-based position.
63
+ - `movePage(from, to)` reorders an existing page.
64
+ - `removePage(number)` removes an unreferenced page. Bookmark/link targets and
65
+ pages containing interactive fields cannot be removed; flatten fields first.
66
+ - `appendPDF(source, pageNumbers?)` imports supported native pages asynchronously.
67
+ - `addBookmark(title, { pageNumber, parent? })` creates a hierarchical page bookmark.
68
+ - `flattenForms()` replaces prepared form appearances with ordinary page content.
69
+ - `toResult()` finalizes once and reuses the completed result on later calls.
70
+
71
+ Page handles expose `width`, `height`, `rotation` and `setRotation(degrees)`.
72
+ Drawing coordinates are relative to the unrotated MediaBox; imported page origins
73
+ and `UserUnit` are normalized into physical document units. Crop boxes and view
74
+ rotation remain part of the page.
75
+ Page numbers are one-based. Removed handles cannot be drawn into. Bookmarks remain
76
+ attached to the same page when pages move. A finalized document cannot be edited.
77
+
78
+ ## Text, graphics and images
79
+
80
+ `document.measureText(text, options?)` returns `width`, `height`, `ascent` and
81
+ `descent` in document units, using the same exact font as drawing.
82
+
83
+ | Page method | Input |
84
+ | ---------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
85
+ | `drawText(text, options)` | `x`, baseline `y`; optional font face, `fontSize`, `color`, `align`, `lineHeight`, `rotation`, `maxWidth`, `opacity` and `link`. |
86
+ | `drawLine(options)` | `x1`, `y1`, `x2`, `y2`; optional `color`, `width`, `opacity`. |
87
+ | `drawRectangle(options)` | `x`, `y`, `width`, `height` and paint settings. |
88
+ | `drawEllipse(options)` | Bounding rectangle and paint settings. |
89
+ | `drawCircle(options)` | Center `x`, `y`, `radius` and paint settings. |
90
+ | `drawSvgPath(path, options)` | SVG path data, `x`, `y`, optional `scale`, `rotation` and paint settings. |
91
+ | `drawImage(source, options)` | PNG/JPEG bytes, Blob, data URL, browser canvas/image; rectangle and optional rotation/opacity. **Await this call.** |
92
+
93
+ Paint settings are `fill`, `stroke`, `strokeWidth` and `opacity`. Colors accept
94
+ hexadecimal, `rgb()`/`rgba()` and common named colors. Unsupported colors fail
95
+ explicitly. Text line spacing defaults to `1.15` times the point size.
96
+ `drawSvgPath` draws native vector geometry; it does not interpret full SVG files.
97
+ Image placement uses the supplied rectangle and applies image orientation. For
98
+ multipage TIFF, use `imageToPDF()` and append its PDF result.
99
+
100
+ Paths use `moveTo()`, `lineTo()`, `curveTo()` and `closePath()`, followed by
101
+ `stroke()`, `fill()` or `fillAndStroke()`. `clip()` intersects the clip with the
102
+ current path; `discardPath()` ends the path afterwards. `clipRectangle()` combines
103
+ these steps. Use `saveGraphicsState()` and `restoreGraphicsState()` to bound
104
+ clipping and `transform([a,b,c,d,e,f])` changes.
105
+
106
+ Pending images, unfinished paths and unmatched graphics states prevent
107
+ finalization. Await each asynchronous image before further drawing on that page.
108
+
109
+ ## Links, notes and forms
110
+
111
+ ```ts
112
+ page.addLink('https://example.com/report', { x: 15, y: 10, width: 100, height: 20 });
113
+ page.addNote('Please review this value.', { x: 150, y: 30, width: 8, height: 8 });
114
+ page.addTextField(
115
+ 'name',
116
+ { x: 15, y: 50, width: 100, height: 12 },
117
+ {
118
+ value: 'Český text',
119
+ font: 'Report Sans',
120
+ fontSize: 12,
121
+ },
122
+ );
123
+ page.addCheckBox('approved', { x: 15, y: 70, width: 6, height: 6 }, { checked: true });
124
+ page.addDropdown('status', { x: 15, y: 90, width: 60, height: 12 }, ['Draft', 'Approved'], {
125
+ value: 'Draft',
126
+ });
127
+ ```
128
+
129
+ Field options include font face, `fontSize`, `textColor`, `borderColor`,
130
+ `backgroundColor`, `borderWidth`, `readOnly` and `required`. Text fields support
131
+ `multiline` and `maxLength`; dropdowns support `editable` and `multiselect`.
132
+ Field names must be unique. Supply a suitable font for Unicode appearances.
133
+ Fields are axis-aligned and reject nonidentity graphics transforms.
134
+ Field appearance colors must be opaque.
135
+ Links accept HTTP, HTTPS, mailto and telephone URLs; executable schemes are rejected.
136
+
137
+ For a left/right footer, draw independent text objects after the page count is known:
138
+
139
+ ```ts
140
+ for (const [index, output] of document.getPages().entries()) {
141
+ output.drawText('Printed by: Example', { x: 15, y: output.height - 8, fontSize: 8 });
142
+ output.drawText(`Page ${index + 1} of ${document.pageCount}`, {
143
+ x: output.width - 15,
144
+ y: output.height - 8,
145
+ fontSize: 8,
146
+ align: 'right',
147
+ });
148
+ }
149
+ ```
150
+
151
+ ## PDF composition
152
+
153
+ `mergePDFs(sources, options?)` creates one PDF in source/page order.
154
+ `extractPDFPages(source, pageNumbers, options?)` preserves the requested one-based
155
+ order, including repeats. `splitPDF(source, options?)` returns one result per page.
156
+ Inputs accept `File`/`Blob`, `ArrayBuffer`, `Uint8Array` and completed export results;
157
+ the application fetches URLs itself. Options support `metadata`, `signal` and
158
+ `onProgress` with stage-local counters.
159
+
160
+ Pages retain text, vectors, image resources, sizes, crop boxes and rotation.
161
+ Explicit internal page links are remapped to the new page references. Named
162
+ destinations, links to omitted pages, encrypted/malformed PDFs and interactive
163
+ AcroForm/XFA inputs fail explicitly. Flatten fields before composition.
164
+ Document-level outlines, signatures, attachments and original metadata are not copied.
165
+ Composition is limited to 1,000 pages, 128 MiB per input and 256 MiB total input.
166
+
167
+ ## DevExtreme adapter
168
+
169
+ ```ts
170
+ import { createJsPDFAdapter } from 'renderpdf-js';
171
+ import { exportDataGrid } from 'devextreme/pdf_exporter';
172
+
173
+ const doc = await createJsPDFAdapter({
174
+ unit: 'mm',
175
+ format: 'A4',
176
+ orientation: 'landscape',
177
+ fonts: [{ family: 'Report Sans', data: fontBytes }],
178
+ });
179
+ doc.setFont('Report Sans');
180
+ await exportDataGrid({ jsPDFDocument: doc, component: grid, selectedRowsOnly: true });
181
+ await doc.save('grid.pdf');
182
+ ```
183
+
184
+ The adapter is verified with DevExtreme 25.1.5. Its default unit is
185
+ `'mm'`, and it creates an initial page. Font metrics and drawing methods are
186
+ synchronous; ordered operations are flushed during asynchronous finalization.
187
+ Use `await doc.output('blob')`, `await doc.toBlob()` or `await doc.save(name)`.
188
+ Synchronous jsPDF output is not emulated. Fonts must be supplied to the factory;
189
+ VFS/runtime font registration and arbitrary jsPDF plugins are unsupported.
190
+
191
+ Supported methods include page selection/addition, font and color state, text
192
+ measurement/wrapping, text/line/rectangle/image drawing, clipping, graphics-state
193
+ save/restore and the exporter's unit/color compatibility properties. The adapter
194
+ does not expose all jsPDF APIs or its advanced scripting features.
195
+
196
+ Run the optional integration against your separately installed DevExtreme:
197
+
198
+ ```sh
199
+ # Set RENDERPDF_DEVEXTREME_DIR to the absolute installed devextreme package directory.
200
+ npm run test:devextreme
201
+ ```
202
+
203
+ The regular checks do not require DevExtreme. Its implementation is not copied
204
+ into RenderPDF.js, and it is not a runtime or development dependency of the package.
package/README.md CHANGED
@@ -4,25 +4,35 @@
4
4
 
5
5
  # RenderPDF.js
6
6
 
7
- **Convert HTML, PNG, JPEG and multipage TIFF to PDF in the browser.**
7
+ **Create PDFs from HTML, images or code, and merge or split existing PDFs.**
8
8
 
9
9
  [![npm version](https://img.shields.io/npm/v/renderpdf-js)](https://www.npmjs.com/package/renderpdf-js)
10
10
  [![CI](https://github.com/MichalekJan93/renderPDF.js/actions/workflows/check.yml/badge.svg?branch=main)](https://github.com/MichalekJan93/renderPDF.js/actions/workflows/check.yml)
11
11
  [![MIT License](https://img.shields.io/badge/license-MIT-blue)](https://github.com/MichalekJan93/renderPDF.js/blob/main/LICENSE)
12
12
 
13
+ RenderPDF.js is a JavaScript and TypeScript library for creating PDF documents,
14
+ converting HTML and images, and working with existing PDF pages. It runs locally,
15
+ without a conversion server.
16
+
13
17
  HTML exports use the browser's layout, keep text selectable and split content
14
- across pages. Conversion runs locally, without a conversion server.
18
+ across pages. Document creation and PDF composition also work in Node.js,
19
+ without a DOM.
15
20
 
16
- **Experimental.** Chromium is the verified browser. Firefox and Safari have not
17
- been verified. HTML rendering supports the [subset described below](#supported-scope).
21
+ **Experimental.** HTML rendering is verified in Chromium; Firefox and Safari have
22
+ not been verified. Supported HTML and CSS are [described below](#supported-scope).
18
23
 
19
24
  ## Features
20
25
 
21
- - Selectable HTML text with embedded fonts, native boxes, images and tables.
22
- - Automatic pagination, repeated table headers, page headers and page numbers.
23
- - PNG/JPEG conversion and one PDF page per frame of a multipage TIFF.
24
- - Paper sizes, margins, document properties, progress events and cancellation.
25
- - ESM package with TypeScript declarations.
26
+ - Create documents with text, images, vector graphics, links and form fields.
27
+ - Merge PDFs, extract selected pages and split documents without rasterizing them.
28
+ - Export supported HTML/CSS with selectable text and automatic pagination.
29
+ - Convert PNG/JPEG and multipage TIFF files to PDF.
30
+ - Add repeated table headers, page text, page numbers and document properties.
31
+ - Use the DevExtreme PDF exporter through an optional compatibility adapter.
32
+ - ESM package with TypeScript declarations, cancellation and conversion progress.
33
+
34
+ See the [API guide](https://github.com/MichalekJan93/renderPDF.js/blob/main/API.md)
35
+ for methods, coordinate conventions and compatibility limits.
26
36
 
27
37
  ## Getting started
28
38
 
@@ -30,10 +40,61 @@ been verified. HTML rendering supports the [subset described below](#supported-s
30
40
  npm install renderpdf-js
31
41
  ```
32
42
 
33
- Use the package in a browser application with an ESM bundler, such as Vite.
43
+ For browser applications, use an ESM bundler such as Vite.
34
44
  The [playground](https://github.com/MichalekJan93/renderPDF.js/tree/main/playground)
35
45
  provides an HTML editor, preview and PDF download from a source checkout.
36
46
 
47
+ ## Create a document
48
+
49
+ ```ts
50
+ import { createDocument } from 'renderpdf-js';
51
+
52
+ const document = await createDocument({ unit: 'mm', format: 'A4' });
53
+ const page = document.addPage();
54
+ page.drawText('Invoice', { x: 20, y: 25, fontSize: 18 });
55
+ page.drawRectangle({ x: 20, y: 35, width: 170, height: 20, stroke: '#333333' });
56
+
57
+ const pdf = await document.toResult();
58
+ await pdf.download('invoice.pdf');
59
+ ```
60
+
61
+ Coordinates start at the top-left; text `y` is its baseline. Font sizes always use
62
+ points. The document API works without a DOM. Built-in Helvetica, Times and Courier
63
+ cover basic text; provide static TTF/OTF bytes in `fonts` for Czech and other Unicode
64
+ characters. Fonts are prepared before drawing. After `toResult()`, the document is
65
+ immutable.
66
+
67
+ Use `pdf.toUint8Array()` or `pdf.toBlob()` outside the browser; `download()` is a
68
+ browser action.
69
+
70
+ ## Combine and split PDFs
71
+
72
+ ```ts
73
+ import { mergePDFs, extractPDFPages, splitPDF } from 'renderpdf-js';
74
+
75
+ const combined = await mergePDFs([firstFile, secondFile]);
76
+ await combined.download('combined.pdf');
77
+
78
+ const selected = await extractPDFPages(firstFile, [3, 1]);
79
+ const individualPages = await splitPDF(firstFile);
80
+ ```
81
+
82
+ Inputs can be `File`/`Blob`, `ArrayBuffer`, `Uint8Array` or a completed export result.
83
+ Page numbers are one-based. Pages retain their native text, vectors, sizes and
84
+ rotation. Flatten interactive forms before importing them; encrypted PDFs and
85
+ unsupported destinations fail explicitly. Document-level bookmarks, signatures and
86
+ metadata are not merged. See the [composition limits](https://github.com/MichalekJan93/renderPDF.js/blob/main/API.md#pdf-composition).
87
+
88
+ ## DevExtreme integration
89
+
90
+ `createJsPDFAdapter()` provides the synchronous drawing and text measurement
91
+ contract used by the DevExtreme PDF exporter. Supply fonts when creating it, pass
92
+ the result as `jsPDFDocument`, then **await** `save()` or `output('blob')`.
93
+ The adapter covers the tested exporter contract; it does not emulate every jsPDF
94
+ plugin or its synchronous serialization. The [API guide](https://github.com/MichalekJan93/renderPDF.js/blob/main/API.md#devextreme-adapter)
95
+ includes an example and the optional integration test command. DevExtreme is not
96
+ a dependency of this library.
97
+
37
98
  ## HTML usage
38
99
 
39
100
  Register a font, select an existing element and export it:
@@ -0,0 +1,26 @@
1
+ import { PDFDocument } from 'pdf-lib';
2
+ import type { PDFPage } from 'pdf-lib';
3
+ import type { PDFMetadata, RenderPDFResult, RenderProgress } from './api-types.js';
4
+ /** An existing PDF or an immutable export result; URLs are fetched by the application. */
5
+ export type PDFSource = Blob | ArrayBuffer | Uint8Array | Pick<RenderPDFResult, 'toUint8Array'>;
6
+ /** Shared metadata and cooperative cancellation for native page composition. */
7
+ export interface PDFCompositionOptions {
8
+ /** Properties of the new document; source document metadata is not merged. */
9
+ metadata?: PDFMetadata;
10
+ /** Cancel between loading, page copying and serialization stages. */
11
+ signal?: AbortSignal;
12
+ /** Frozen stage-local counters, using preparing/resources/pages/saving/complete. */
13
+ onProgress?: (progress: RenderProgress) => void;
14
+ }
15
+ /** Share strict PDF input loading with the document builder; not a public entry-point export. */
16
+ export declare function loadPDFSource(source: PDFSource, signal?: AbortSignal): Promise<PDFDocument>;
17
+ /** Reuse validated native page copying and local navigation in the document builder. */
18
+ export declare function appendPDFPages(target: PDFDocument, donor: PDFDocument, pageNumbers?: readonly number[], signal?: AbortSignal): Promise<readonly PDFPage[]>;
19
+ /** Merge native pages in source order, preserving text, vectors, dimensions and rotation.
20
+ * Interactive forms must be flattened. Document-level outlines, signatures and attachments are not copied.
21
+ */
22
+ export declare function mergePDFs(sources: readonly PDFSource[], options?: PDFCompositionOptions): Promise<RenderPDFResult>;
23
+ /** Copy selected one-based pages in caller order; repeated numbers produce repeated pages. */
24
+ export declare function extractPDFPages(source: PDFSource, pageNumbers: readonly number[], options?: PDFCompositionOptions): Promise<RenderPDFResult>;
25
+ /** Split into one PDF per page; cross-page links require a multi-page extraction instead. */
26
+ export declare function splitPDF(source: PDFSource, options?: PDFCompositionOptions): Promise<readonly RenderPDFResult[]>;
@@ -0,0 +1,8 @@
1
+ import type { RGB } from 'pdf-lib';
2
+ /** Color components and alpha stay separate so native PDF paint retains transparency. */
3
+ export interface DocumentColor {
4
+ color: RGB;
5
+ opacity: number;
6
+ }
7
+ /** Parse portable CSS hex/rgb colors without relying on a browser document. */
8
+ export declare function parseDocumentColor(value: string): DocumentColor;
@@ -0,0 +1,115 @@
1
+ import type { PDFPage } from 'pdf-lib';
2
+ import type { DocumentCheckBoxOptions, DocumentDropdownOptions, DocumentImageOptions, DocumentImageSource, DocumentLineOptions, DocumentPageContext, DocumentRectangle, DocumentShapeOptions, DocumentTextFieldOptions, DocumentTextOptions } from './document-types.js';
3
+ /** Six coefficients map top-left document coordinates to transformed document coordinates. */
4
+ type Matrix = readonly [number, number, number, number, number, number];
5
+ /** Native drawing surface; asynchronous image calls must finish before later drawing. */
6
+ export declare class PDFPageBuilder {
7
+ private readonly page;
8
+ private readonly context;
9
+ /** Path and graphics state are tracked because PDF readers otherwise accept accidental leakage. */
10
+ private pathOpen;
11
+ private pendingImages;
12
+ private matrix;
13
+ private readonly stack;
14
+ private readonly userUnit;
15
+ private readonly scale;
16
+ /** The owning document supplies registered fonts, units and finalization/cancellation checks. */
17
+ constructor(page: PDFPage, context: DocumentPageContext);
18
+ /** Physical page width in document units. */
19
+ get width(): number;
20
+ /** Physical page height in document units. */
21
+ get height(): number;
22
+ /** Reader-facing page rotation does not change its unrotated drawing coordinates. */
23
+ get rotation(): number;
24
+ /** Rotate the completed page view by an integral number of quarter turns. */
25
+ setRotation(angle: number): this;
26
+ /** Guard both finalization and paint order before a synchronous operation changes the page. */
27
+ private ready;
28
+ /** Finalization refuses incomplete operations instead of silently saving partial content. */
29
+ assertComplete(): void;
30
+ /** Convert a caller point to the backend's upward-pointing page coordinates. */
31
+ private point;
32
+ /** Emit a separate native text run per line so alignment remains correct after wrapping. */
33
+ drawText(text: string, options: DocumentTextOptions): this;
34
+ /** Draw one native line with a width in document units. */
35
+ drawLine(options: DocumentLineOptions): this;
36
+ /** Resolve shared paint before rectangle, ellipse or SVG operators are appended. */
37
+ private paint;
38
+ /** Rectangle coordinates identify its top-left corner. */
39
+ drawRectangle(options: DocumentRectangle & DocumentShapeOptions): this;
40
+ /** Ellipses use a top-left bounding rectangle, matching other document shapes. */
41
+ drawEllipse(options: DocumentRectangle & DocumentShapeOptions): this;
42
+ /** Circle x/y identify its center; radius uses document units. */
43
+ drawCircle(options: {
44
+ x: number;
45
+ y: number;
46
+ radius: number;
47
+ } & DocumentShapeOptions): this;
48
+ /** Draw SVG path geometry; this API does not load or interpret SVG documents. */
49
+ drawSvgPath(path: string, options: {
50
+ x: number;
51
+ y: number;
52
+ scale?: number;
53
+ rotation?: number;
54
+ } & DocumentShapeOptions): this;
55
+ /** Save clipping and transforms together with the PDF graphics state. */
56
+ saveGraphicsState(): this;
57
+ /** Restore a previously saved state; an unmatched restore is an error. */
58
+ restoreGraphicsState(): this;
59
+ /** Compose an affine transform expressed in top-left document coordinates. */
60
+ transform(matrix: Matrix): this;
61
+ /** Start a new subpath without implicitly discarding an earlier subpath. */
62
+ moveTo(x: number, y: number): this;
63
+ /** Append a native straight segment to the current path. */
64
+ lineTo(x: number, y: number): this;
65
+ /** Append a cubic Bezier curve using two control points and one end point. */
66
+ curveTo(x1: number, y1: number, x2: number, y2: number, x3: number, y3: number): this;
67
+ /** Close the current subpath while retaining it for painting or clipping. */
68
+ closePath(): this;
69
+ /** Require actual geometry before a path-ending operation. */
70
+ private requirePath;
71
+ /** Intersect the clip with the current path; discardPath ends the path afterwards. */
72
+ clip(rule?: 'nonzero' | 'evenodd'): this;
73
+ /** Clip to one rectangle and consume its path. */
74
+ clipRectangle(options: DocumentRectangle): this;
75
+ /** Discard pending geometry without painting it. */
76
+ discardPath(): this;
77
+ /** Stroke an accumulated native path. */
78
+ stroke(options?: {
79
+ color?: string;
80
+ width?: number;
81
+ opacity?: number;
82
+ }): this;
83
+ /** Fill an accumulated native path. */
84
+ fill(options?: {
85
+ color?: string;
86
+ opacity?: number;
87
+ }): this;
88
+ /** Fill and stroke an accumulated native path in one paint operation. */
89
+ fillAndStroke(options?: DocumentShapeOptions): this;
90
+ /** Alpha is stored in a page resource and scoped to this path operation. */
91
+ private paintPath;
92
+ /** Read image bytes before modifying page paint; no network is initiated for string inputs. */
93
+ private imageBytes;
94
+ /** Embed one PNG/JPEG at explicit dimensions, applying EXIF orientation and clockwise rotation. */
95
+ drawImage(source: DocumentImageSource, options: DocumentImageOptions): Promise<this>;
96
+ /** Transform annotation rectangles separately because PDF annotations do not inherit page graphics state. */
97
+ private annotationRectangle;
98
+ /** Add a clickable external link without an opaque border. */
99
+ addLink(url: string, rect: DocumentRectangle): this;
100
+ /** Add a Unicode note annotation; it remains separate from visible page content. */
101
+ addNote(text: string, rect: DocumentRectangle, options?: {
102
+ title?: string;
103
+ }): this;
104
+ /** Field appearances cannot faithfully represent sheared or arbitrary transformed widgets. */
105
+ private fieldOptions;
106
+ /** Apply common flags after creating a field but before marking appearances clean. */
107
+ private fieldFlags;
108
+ /** Create a Unicode-capable text input with its explicitly selected embedded font. */
109
+ addTextField(name: string, rect: DocumentRectangle, options?: DocumentTextFieldOptions): this;
110
+ /** Create an interactive checkbox with a native checkmark appearance. */
111
+ addCheckBox(name: string, rect: DocumentRectangle, options?: DocumentCheckBoxOptions): this;
112
+ /** Create a dropdown with copied choices and a validated initial selection. */
113
+ addDropdown(name: string, rect: DocumentRectangle, choices: readonly string[], options?: DocumentDropdownOptions): this;
114
+ }
115
+ export {};
@@ -0,0 +1,135 @@
1
+ import type { PDFFont, PDFDocument } from 'pdf-lib';
2
+ import type { FontSource, PDFMetadata, ImageSource } from './api-types.js';
3
+ /** Coordinate unit; font sizes always use typographic points. */
4
+ export type DocumentUnit = 'pt' | 'mm' | 'px';
5
+ /** Physical page dimensions in the document's chosen coordinate unit. */
6
+ export interface DocumentPageOptions {
7
+ /** Named paper or explicit width and height, including page edges. */
8
+ format?: 'A4' | 'A3' | 'Letter' | {
9
+ width: number;
10
+ height: number;
11
+ };
12
+ /** Landscape swaps the supplied base dimensions. */
13
+ orientation?: 'portrait' | 'landscape';
14
+ }
15
+ /** Prepare a document independently of browser layout and the DOM. */
16
+ export interface PDFDocumentOptions extends DocumentPageOptions {
17
+ /** Coordinate unit, defaulting to points. */
18
+ unit?: DocumentUnit;
19
+ /** Static fonts embedded before synchronous drawing and measurement begin. */
20
+ fonts?: readonly FontSource[];
21
+ /** PDF document properties. */
22
+ metadata?: PDFMetadata;
23
+ /** Cooperative cancellation during resource preparation and serialization. */
24
+ signal?: AbortSignal;
25
+ }
26
+ /** Exact font face; all built-in families have regular, bold and italic variants. */
27
+ export interface DocumentFontOptions {
28
+ /** Registered family, defaulting to Helvetica. */
29
+ font?: string;
30
+ /** Static weight, defaulting to 400. */
31
+ fontWeight?: number;
32
+ /** Static face style, defaulting to normal. */
33
+ fontStyle?: 'normal' | 'italic';
34
+ }
35
+ /** Text metrics use the document's coordinate unit. */
36
+ export interface DocumentTextMetrics {
37
+ /** Largest line width. */
38
+ width: number;
39
+ /** Total line advance, including line spacing. */
40
+ height: number;
41
+ /** Distance from the baseline to the top of the font. */
42
+ ascent: number;
43
+ /** Positive distance below the baseline. */
44
+ descent: number;
45
+ }
46
+ /** Axis-aligned rectangle measured from the page's top-left corner. */
47
+ export interface DocumentRectangle {
48
+ x: number;
49
+ y: number;
50
+ width: number;
51
+ height: number;
52
+ }
53
+ /** Vector paint settings; colors use CSS color strings. */
54
+ export interface DocumentShapeOptions {
55
+ fill?: string;
56
+ stroke?: string;
57
+ strokeWidth?: number;
58
+ opacity?: number;
59
+ }
60
+ /** Text position uses a baseline measured down from the top edge. */
61
+ export interface DocumentTextOptions extends DocumentFontOptions {
62
+ x: number;
63
+ y: number;
64
+ /** Font size in points, independent of coordinate units. */
65
+ fontSize?: number;
66
+ color?: string;
67
+ align?: 'left' | 'center' | 'right';
68
+ /** Baseline advance as a multiple of fontSize, defaulting to 1.15. */
69
+ lineHeight?: number;
70
+ rotation?: number;
71
+ maxWidth?: number;
72
+ opacity?: number;
73
+ link?: string;
74
+ }
75
+ /** One line segment in top-left page coordinates. */
76
+ export interface DocumentLineOptions {
77
+ x1: number;
78
+ y1: number;
79
+ x2: number;
80
+ y2: number;
81
+ color?: string;
82
+ width?: number;
83
+ opacity?: number;
84
+ }
85
+ /** Native bitmap bytes, a data URL, or an existing browser image/canvas. */
86
+ export type DocumentImageSource = ImageSource | string | HTMLCanvasElement | HTMLImageElement;
87
+ /** Explicit image placement; dimensions use document units. */
88
+ export interface DocumentImageOptions extends DocumentRectangle {
89
+ rotation?: number;
90
+ opacity?: number;
91
+ }
92
+ /** Common interactive field appearance and validation settings. */
93
+ export interface DocumentFieldOptions extends DocumentFontOptions {
94
+ fontSize?: number;
95
+ textColor?: string;
96
+ borderColor?: string;
97
+ backgroundColor?: string;
98
+ borderWidth?: number;
99
+ readOnly?: boolean;
100
+ required?: boolean;
101
+ }
102
+ /** Text field content and display behavior. */
103
+ export interface DocumentTextFieldOptions extends DocumentFieldOptions {
104
+ value?: string;
105
+ multiline?: boolean;
106
+ maxLength?: number;
107
+ }
108
+ /** Checkbox initial state. */
109
+ export interface DocumentCheckBoxOptions extends DocumentFieldOptions {
110
+ checked?: boolean;
111
+ }
112
+ /** Dropdown selection and editability. */
113
+ export interface DocumentDropdownOptions extends DocumentFieldOptions {
114
+ value?: string | readonly string[];
115
+ editable?: boolean;
116
+ multiselect?: boolean;
117
+ }
118
+ /** Internal page services; the public page API does not expose backend objects. */
119
+ export interface DocumentPageContext {
120
+ readonly pdf: PDFDocument;
121
+ readonly scale: number;
122
+ resolveFont(options?: DocumentFontOptions): PDFFont;
123
+ assertActive(): void;
124
+ }
125
+ /** Page destinations are one-based and belong to the current document. */
126
+ export interface DocumentBookmarkOptions {
127
+ pageNumber: number;
128
+ /** Optional parent returned by addBookmark. */
129
+ parent?: DocumentBookmark;
130
+ }
131
+ /** Opaque destination handle used to build a bookmark hierarchy. */
132
+ export interface DocumentBookmark {
133
+ readonly title: string;
134
+ readonly pageNumber: number;
135
+ }
@@ -0,0 +1,64 @@
1
+ import type { RenderPDFResult } from './api-types.js';
2
+ import type { DocumentBookmark, DocumentBookmarkOptions, DocumentFontOptions, DocumentPageOptions, DocumentTextMetrics, DocumentUnit, PDFDocumentOptions } from './document-types.js';
3
+ import type { PDFSource } from './compose-pdf.js';
4
+ import { PDFPageBuilder } from './document-page.js';
5
+ /** Mutable PDF document; drawing is synchronous after resources are prepared. */
6
+ export declare class PDFBuilder {
7
+ private readonly pdf;
8
+ private readonly fonts;
9
+ private readonly fontNames;
10
+ private readonly defaults;
11
+ private readonly signal;
12
+ /** Point conversion shared by page drawing and compatibility adapters. */
13
+ readonly unitScale: number;
14
+ /** Coordinate unit selected at document creation. */
15
+ readonly unit: DocumentUnit;
16
+ private readonly pages;
17
+ private readonly activePages;
18
+ private readonly characterSets;
19
+ private readonly bookmarks;
20
+ private readonly roots;
21
+ private readonly outlines;
22
+ private finished;
23
+ private pending;
24
+ private output;
25
+ private constructor();
26
+ /** Prepare font programs without reading any browser globals. */
27
+ static create(options?: PDFDocumentOptions): Promise<PDFBuilder>;
28
+ /** Number of physical pages currently in the document. */
29
+ get pageCount(): number;
30
+ /** Snapshot of registered family names, including standard PDF fonts. */
31
+ getFontNames(): readonly string[];
32
+ private assertMutable;
33
+ private assertActive;
34
+ private resolveFont;
35
+ private wrapPage;
36
+ /** Add an independently sized page; no empty page is created implicitly. */
37
+ addPage(options?: DocumentPageOptions): PDFPageBuilder;
38
+ /** Insert a page before the given one-based position; pageCount + 1 appends. */
39
+ insertPage(pageNumber: number, options?: DocumentPageOptions): PDFPageBuilder;
40
+ /** Reorder existing pages while retaining native destination references. */
41
+ movePage(from: number, to: number): this;
42
+ /** Remove a page only when it is not a bookmark/link target or interactive form owner. */
43
+ removePage(pageNumber: number): this;
44
+ /** Look up an existing page by its one-based number. */
45
+ getPage(pageNumber: number): PDFPageBuilder;
46
+ /** Return page handles in document order without exposing the mutable page list. */
47
+ getPages(): readonly PDFPageBuilder[];
48
+ /** Measure using the same embedded font program used by page drawing. */
49
+ measureText(text: string, options?: DocumentFontOptions & {
50
+ fontSize?: number;
51
+ lineHeight?: number;
52
+ }): DocumentTextMetrics;
53
+ /** Append native PDF pages, preserving page geometry and supported page content. */
54
+ appendPDF(source: PDFSource, pageNumbers?: readonly number[]): Promise<this>;
55
+ /** Flatten prepared interactive appearances into ordinary page content. */
56
+ flattenForms(): this;
57
+ /** Create a bookmark pointing to an existing page, optionally below another bookmark. */
58
+ addBookmark(title: string, options: DocumentBookmarkOptions): DocumentBookmark;
59
+ private writeBookmarks;
60
+ /** Finalize once; subsequent output requests reuse the same immutable PDF. */
61
+ toResult(): Promise<RenderPDFResult>;
62
+ }
63
+ /** Prepare an empty document with registered fonts and explicit coordinate units. */
64
+ export declare function createDocument(options?: PDFDocumentOptions): Promise<PDFBuilder>;