/** * PDF document builder — high-level API for creating PDFs with free-form content. * * Unlike the table-oriented `pdf()` function, this builder gives direct control * over text positioning, vector drawing, images, and page management. * * @example Basic usage: * ```typescript * import { PdfDocumentBuilder } from "@cj-tech-master/excelts/pdf"; * * const doc = new PdfDocumentBuilder(); * const page = doc.addPage({ width: 595, height: 842 }); // A4 * * page.drawText("Hello, World!", { x: 72, y: 750, fontSize: 24 }); * page.drawRect({ x: 72, y: 700, width: 200, height: 30 }); * page.drawCircle({ cx: 300, cy: 400, r: 50, fill: { r: 1, g: 0, b: 0 } }); * * const bytes = await doc.build(); * ``` */ import { PdfContentStream } from "../core/pdf-stream.js"; import type { PdfColor, PdfExportOptions } from "../types.js"; /** Page size configuration. */ export interface PageOptions { /** Page width in points (72pt = 1 inch). Default: 595.28 (A4). */ width?: number; /** Page height in points (72pt = 1 inch). Default: 841.89 (A4). */ height?: number; } /** Text drawing options. */ export interface DrawTextOptions { /** X position in points (from left edge). */ x: number; /** Y position in points (from bottom edge — PDF coordinate system). */ y: number; /** Font size in points. Default: 12. */ fontSize?: number; /** Font family name. Default: "Helvetica". */ fontFamily?: string; /** Bold. Default: false. */ bold?: boolean; /** Italic. Default: false. */ italic?: boolean; /** Text color. Default: black. */ color?: PdfColor; /** Maximum width before word-wrap. Omit for no wrap. */ maxWidth?: number; /** Line height multiplier. Default: 1.2. */ lineHeight?: number; /** * Rotation in degrees, counter-clockwise in the PDF coordinate system * (which has +Y pointing up, so visually clockwise on a page viewer). * The rotation pivot is `(x, y)`. Default: `0` (no rotation). * * Incompatible with `maxWidth` (word-wrapping + rotation requires per- * line matrix transforms that the current implementation does not * support — supplying both leaves the wrap ignoring rotation so the * text remains readable). If you need rotated wrapped text, break it * into lines yourself and call `drawText` per line. */ rotation?: number; /** * Horizontal alignment of the text around `x`. Default: `"start"` * (the conventional PDF behaviour where `x` is the baseline left * edge). Implemented by pre-shifting `x` using the chosen font's * measured width — no deferred layout, so the computed position is * stable across font subsetting. */ anchor?: "start" | "middle" | "end"; } /** Rectangle drawing options. */ export interface DrawRectOptions { x: number; y: number; width: number; height: number; /** Fill color. Omit for no fill. */ fill?: PdfColor; /** Stroke color. Omit for no stroke. */ stroke?: PdfColor; /** Line width for stroke. Default: 1. */ lineWidth?: number; /** Corner radius for rounded rectangles. Default: 0. */ borderRadius?: number; } /** Circle drawing options. */ export interface DrawCircleOptions { /** Center X. */ cx: number; /** Center Y. */ cy: number; /** Radius. */ r: number; /** Fill color. Omit for no fill. */ fill?: PdfColor; /** Stroke color. Omit for no stroke. */ stroke?: PdfColor; /** Line width for stroke. Default: 1. */ lineWidth?: number; } /** Ellipse drawing options. */ export interface DrawEllipseOptions { /** Center X. */ cx: number; /** Center Y. */ cy: number; /** Horizontal radius. */ rx: number; /** Vertical radius. */ ry: number; /** Fill color. Omit for no fill. */ fill?: PdfColor; /** Stroke color. Omit for no stroke. */ stroke?: PdfColor; /** Line width for stroke. Default: 1. */ lineWidth?: number; } /** Line drawing options. */ export interface DrawLineOptions { /** Start X. */ x1: number; /** Start Y. */ y1: number; /** End X. */ x2: number; /** End Y. */ y2: number; /** Stroke color. Default: black. */ color?: PdfColor; /** Line width. Default: 1. */ lineWidth?: number; /** Dash pattern. Default: solid. */ dashPattern?: number[]; } /** Path drawing options. */ export interface DrawPathOptions { /** Fill color. Omit for no fill. */ fill?: PdfColor; /** Stroke color. Omit for no stroke. */ stroke?: PdfColor; /** Line width. Default: 1. */ lineWidth?: number; /** Close the path before painting. Default: false. */ closePath?: boolean; } /** A point in a path. */ export type PathOp = { op: "move"; x: number; y: number; } | { op: "line"; x: number; y: number; } | { op: "curve"; x1: number; y1: number; x2: number; y2: number; x3: number; y3: number; } | { op: "close"; }; /** Image drawing options. */ export interface DrawImageOptions { /** Raw image bytes. */ data: Uint8Array; /** Image format. */ format: "jpeg" | "png"; /** X position. */ x: number; /** Y position (bottom edge of image in PDF coordinates). */ y: number; /** Display width in points. */ width: number; /** Display height in points. */ height: number; } /** Options for drawing a simple SVG document onto a PDF page. */ export interface DrawSvgOptions { /** Raw SVG markup. */ svg: string; /** Destination X position in points. */ x: number; /** Destination Y position in points. */ y: number; /** Destination width in points. If omitted, uses the SVG width/viewBox width. */ width?: number; /** Destination height in points. If omitted, uses the SVG height/viewBox height. */ height?: number; } /** Document metadata. */ export interface DocumentMetadata { title?: string; author?: string; subject?: string; creator?: string; } /** Options for table of contents generation. */ export interface TocOptions { /** Title displayed at the top of the TOC page. Default: "Table of Contents". */ title?: string; /** Font size for TOC entries in points. Default: 12. */ fontSize?: number; /** Indentation in points per nesting level. Default: 20. */ indent?: number; } /** Annotation types that can be created via the builder API. */ export type AnnotationType = "Highlight" | "Underline" | "StrikeOut" | "Squiggly" | "Text" | "FreeText" | "Stamp"; /** Options for text markup annotations (Highlight, Underline, StrikeOut, Squiggly). */ export interface TextMarkupAnnotationOptions { /** Annotation subtype. */ type: "Highlight" | "Underline" | "StrikeOut" | "Squiggly"; /** Bounding rectangle [x1, y1, x2, y2]. */ rect: [number, number, number, number]; /** * QuadPoints — four pairs of (x,y) defining the marked text region. * Must be groups of 8 numbers (4 corners per quad). Order per PDF spec: * bottom-left, bottom-right, top-left, top-right (some viewers use * top-left, top-right, bottom-left, bottom-right — the spec is ambiguous). * If omitted, defaults to the corners of `rect`. */ quadPoints?: number[]; /** Annotation color (RGB, 0–1). Default: yellow for highlight, red for others. */ color?: PdfColor; /** Text contents (e.g., comment text). */ contents?: string; /** Author / title. */ author?: string; } /** Options for a sticky note (Text) annotation. */ export interface TextAnnotationOptions { type: "Text"; /** Position — the icon appears at this point. */ rect: [number, number, number, number]; /** Comment text. */ contents?: string; /** Author. */ author?: string; /** Icon name. Default: "Note". */ iconName?: "Comment" | "Key" | "Note" | "Help" | "NewParagraph" | "Paragraph" | "Insert"; /** Annotation color. Default: yellow. */ color?: PdfColor; /** Whether the popup is initially open. Default: false. */ open?: boolean; } /** Options for a free-text annotation (in-line text). */ export interface FreeTextAnnotationOptions { type: "FreeText"; /** Bounding rectangle [x1, y1, x2, y2]. */ rect: [number, number, number, number]; /** The displayed text. */ contents: string; /** Font size. Default: 12. */ fontSize?: number; /** Text color. Default: black. */ color?: PdfColor; /** Border color. Omit for no border. */ borderColor?: PdfColor; /** Author. */ author?: string; } /** Options for a rubber stamp annotation. */ export interface StampAnnotationOptions { type: "Stamp"; /** Bounding rectangle [x1, y1, x2, y2]. */ rect: [number, number, number, number]; /** Standard stamp name. */ stampName?: "Approved" | "Experimental" | "NotApproved" | "AsIs" | "Expired" | "NotForPublicRelease" | "Confidential" | "Final" | "Sold" | "Departmental" | "ForComment" | "TopSecret" | "Draft" | "ForPublicRelease"; /** Annotation color. */ color?: PdfColor; /** Comment text. */ contents?: string; /** Author. */ author?: string; } /** Union of all annotation option types. */ export type AnnotationOptions = TextMarkupAnnotationOptions | TextAnnotationOptions | FreeTextAnnotationOptions | StampAnnotationOptions; /** Common options shared by all form field types. */ interface FormFieldBaseOptions { /** Fully qualified field name (e.g., "form.name"). */ name: string; /** Bounding rectangle [x1, y1, x2, y2]. */ rect: [number, number, number, number]; /** Default value. */ value?: string; /** Read-only. Default: false. */ readOnly?: boolean; /** Required. Default: false. */ required?: boolean; } /** Options for creating a text input field. */ export interface TextFieldOptions extends FormFieldBaseOptions { type: "text"; /** Maximum character count. Omit for unlimited. */ maxLength?: number; /** Multiline. Default: false. */ multiline?: boolean; /** Password field (masked input). Default: false. */ password?: boolean; } /** Options for creating a checkbox. */ export interface CheckboxOptions extends FormFieldBaseOptions { type: "checkbox"; /** Whether initially checked. Default: false. */ checked?: boolean; } /** Options for creating a dropdown (combo box). */ export interface DropdownOptions extends FormFieldBaseOptions { type: "dropdown"; /** Available options. */ options: string[]; /** Allow typing a custom value. Default: false. */ editable?: boolean; } /** Options for creating a radio button group. */ export interface RadioGroupOptions { type: "radio"; /** Fully qualified field name for the group. */ name: string; /** Individual radio buttons. */ buttons: Array<{ /** Bounding rectangle. */ rect: [number, number, number, number]; /** Export value for this button. */ value: string; }>; /** Initially selected value. */ selected?: string; /** Read-only. Default: false. */ readOnly?: boolean; /** Required. Default: false. */ required?: boolean; } /** Union of all form field creation options. */ export type FormFieldOptions = TextFieldOptions | CheckboxOptions | DropdownOptions | RadioGroupOptions; /** Options for digitally signing a PDF. */ export interface PdfSignatureOptions { /** DER-encoded X.509 certificate. */ certificate: Uint8Array; /** DER-encoded PKCS#8 private key. */ privateKey: Uint8Array; /** Signer name (displayed in PDF viewers). */ name?: string; /** Reason for signing. */ reason?: string; /** Location of signing. */ location?: string; /** Contact info. */ contactInfo?: string; } /** * Builder for a single PDF page. * * Provides methods for drawing text, shapes, and images at arbitrary positions. * All coordinates use PDF's coordinate system: origin at bottom-left, Y increases upward. */ export declare class PdfPageBuilder { /** Page width in points. */ get width(): number; /** Page height in points. */ get height(): number; /** * Draw text at a specific position. * * @param text - The text string to draw * @param options - Position, font, color, etc. */ drawText(text: string, options: DrawTextOptions): this; /** * Measure text width in points. */ measureText(text: string, options?: { fontSize?: number; fontFamily?: string; bold?: boolean; italic?: boolean; }): number; /** * Draw a rectangle (filled and/or stroked). */ drawRect(options: DrawRectOptions): this; /** * Draw a circle (filled and/or stroked). */ drawCircle(options: DrawCircleOptions): this; /** * Draw an ellipse (filled and/or stroked). */ drawEllipse(options: DrawEllipseOptions): this; /** * Draw a straight line. */ drawLine(options: DrawLineOptions): this; /** * Draw a complex path from a list of path operations. */ drawPath(ops: PathOp[], options?: DrawPathOptions): this; /** * Draw an image at a specific position. */ drawImage(options: DrawImageOptions): this; /** * Add an annotation to this page. * * Supports: Highlight, Underline, StrikeOut, Squiggly, Text (sticky note), * FreeText (inline text), and Stamp. */ addAnnotation(options: AnnotationOptions): this; /** * Add a form field to this page. * * Supports: text input, checkbox, dropdown (combo box), and radio button groups. */ addFormField(options: FormFieldOptions): this; /** * Draw an SVG path from a `d` attribute string. * * Supports all SVG path commands: M, L, H, V, C, S, Q, T, A, Z * (both absolute and relative). * * @param d - The SVG path data string (e.g., "M10 10 L90 90 Z") * @param options - Fill/stroke options */ drawSvgPath(d: string, options?: DrawPathOptions): this; /** * Draw a simple SVG document onto this page. * * Supports the SVG primitives emitted by ExcelTS chart rendering: * `rect`, `line`, `circle`, `polyline`, `polygon`, `path`, and `text`. */ drawSvg(options: DrawSvgOptions): this; /** * Get the raw content stream for advanced operations. * Use this when the high-level API doesn't cover your use case. */ getContentStream(): PdfContentStream; } /** * Builder for constructing multi-page PDF documents with free-form content. * * Provides fine-grained control over text positioning, vector graphics, * and page management — complementing the table-oriented `pdf()` function. */ export declare class PdfDocumentBuilder { private _pages; private _bookmarks; private _fontManager; private _metadata; private _encryption; private _embeddedFont; private _pdfA; private _signatureOptions; /** * Sink for non-fatal diagnostics produced during `build()`. Populated by * {@link onWarning}; defaults to undefined so unaware consumers see * pre-diagnostic behaviour unchanged. Fires for every warning in a * single build, not just the first. */ private _onWarning; /** * Set via {@link disableFontAutoDiscovery} — opts out of the system-font * auto-embed path in `build()`. Authors who need byte-stable output * across machines (golden tests, reproducible build pipelines) should * enable this so a host-only CJK font doesn't sneak into one run but * not another. */ private _disableFontAutoDiscovery; /** * Add a new blank page to the document. * * @param options - Page dimensions. Default: A4 (595.28 x 841.89 points). * @returns A PdfPageBuilder for the new page. */ addPage(options?: PageOptions): PdfPageBuilder; /** * Set document metadata (title, author, etc.). */ setMetadata(metadata: DocumentMetadata): this; /** * Set encryption options (AES-256). */ setEncryption(encryption: PdfExportOptions["encryption"]): this; /** * Embed a TrueType font for Unicode/CJK support. * * @param fontBytes - Raw .ttf file bytes */ embedFont(fontBytes: Uint8Array): this; /** * Register a callback invoked once per non-fatal diagnostic during * `build()`. Currently raised for: * * - auto-embedded system fonts (`'Auto-embedded system font ...'`) * - non-WinAnsi characters with no covering font (`'...non-WinAnsi character(s) present...'`) * * The callback is synchronous and runs inside `build()`; throwing * from it will abort the build. Return value is ignored. */ onWarning(handler: (message: string) => void): this; /** * Opt out of the best-effort system-font auto-discovery that `build()` * performs when the document contains non-WinAnsi characters and no * font was explicitly embedded. Use this to keep output byte-stable * across hosts: one machine may have SimSun installed while another * does not. */ disableFontAutoDiscovery(): this; /** * Enable PDF/A compliance output. * * Currently supports PDF/A-1b (ISO 19005-1, Level B — visual appearance * preservation). When enabled, `build()` will: * * - Set PDF version to 1.4 * - Write XMP metadata with `pdfaid:part=1` and `pdfaid:conformance=B` * - Write OutputIntents with an embedded sRGB ICC profile * - Add `/MarkInfo << /Marked true >>` to the catalog * * **Limitation:** Type1 base fonts (Helvetica, Times-Roman, Courier, etc.) * are not embedded. For strict PDF/A-1b font compliance, use `embedFont()` * to embed a TrueType font. * * @param _level - Conformance level. Currently only "1b" is supported. */ setPdfACompliance(_level?: "1b"): this; /** * Digitally sign the PDF during `build()`. * * When set, `build()` will: * 1. Embed a signature dictionary with placeholder in the PDF * 2. Compute the byte ranges and sign with RSA PKCS#1 v1.5 + SHA-256 * 3. Return the fully signed PDF bytes * * @param options - Certificate, private key, and optional signer metadata * * @example * ```typescript * doc.sign({ * certificate: certDerBytes, * privateKey: pkcs8DerBytes, * name: "John Doe", * reason: "Document approval" * }); * const signedPdf = await doc.build(); * ``` */ sign(options: PdfSignatureOptions): this; /** * Add a bookmark (PDF outline entry) pointing to a specific page. * * @param title - Bookmark display title * @param pageIndex - Zero-based page index * @param parent - Index of a previously added top-level bookmark to nest under (zero-based in insertion order). Omit for top-level. * @returns this for chaining */ addBookmark(title: string, pageIndex: number, parent?: number): this; /** * Generate a table of contents page with clickable entries. * * Each entry displays the bookmark title and a right-aligned page number, * connected by a dotted leader. Entries link to their target pages. * * @param options - TOC formatting options * @returns The created PdfPageBuilder for further customization */ generateTableOfContents(options?: TocOptions): PdfPageBuilder; /** Get all pages. */ get pages(): readonly PdfPageBuilder[]; /** * Build the final PDF document. * * @returns The PDF file as Uint8Array. */ build(): Promise; } /** * Parse an SVG path `d` attribute into PathOp array. * * Supports all SVG path commands: * - M/m (moveTo), L/l (lineTo), H/h (horizontal), V/v (vertical) * - C/c (cubic Bézier), S/s (smooth cubic) * - Q/q (quadratic Bézier), T/t (smooth quadratic) * - A/a (elliptical arc), Z/z (close) * * Arc commands are approximated with cubic Bézier curves. */ export declare function parseSvgPath(d: string): PathOp[]; export {};