/** * Page renderer for PDF generation. * * Takes LayoutPage objects (produced by the layout engine) and renders them * as PDF content streams. Handles: * - Cell background fills * - Cell borders (with proper overlap handling) * - Text rendering with alignment, wrapping, and clipping * - Grid lines * - Page headers (sheet names) and footers (page numbers) */ import { PdfContentStream } from "../core/pdf-stream.js"; import type { FontManager } from "../font/font-manager.js"; import type { LayoutPage, ResolvedPdfOptions, PdfRect, PdfWatermark } from "../types.js"; /** * Result of rendering a page. */ export interface PageRenderResult { stream: PdfContentStream; /** Set of unique alpha values (0-1) used on this page. Empty if all opaque. */ alphaValues: Set; } /** * Render a single page to a PDF content stream. */ export declare function renderPage(page: LayoutPage, options: ResolvedPdfOptions, fontManager: FontManager, totalPages: number): PageRenderResult; /** * Render a text string with a custom text matrix, using Type3-aware splitting * when needed. For each sub-run the matrix origin is advanced along the * text direction (cos, sin) by the rendered width. * * The emitted operators are written as a *deferred* fragment (see * `PdfContentStream.deferred`). The fragment is only evaluated at * serialization time, by which point `PdfDocumentBuilder.build()` has * finalised the document's fonts (auto-discovered embedded CIDFont, * Type3 fallback, or plain Type1). This is essential: at draw time the * font manager has not yet decided whether a non-WinAnsi code point (e.g. * U+2192 →) will be served by an embedded font or a Type3 glyph, so eager * encoding would irreversibly degrade those characters to spaces via the * WinAnsi fallback. Deferring the encode keeps the fragment at its exact * draw-order slot (preserving z-order) while choosing the correct bytes * once fonts are known. * * The `useType3` argument is the caller's *draw-time* guess and is ignored; * the deferred body recomputes the routing from the now-settled font * manager state. */ export declare function emitTextWithMatrix(stream: PdfContentStream, text: string, a: number, b: number, c: number, d: number, tx: number, ty: number, type1ResourceName: string, fontSize: number, fontManager: FontManager, _useType3: boolean): void; /** Options for a deferred, font-aware text block (see `emitTextBlock`). */ export interface TextBlockOptions { /** The text to draw (may contain `\n` when `maxWidth` is set). */ text: string; /** Left/anchor x in unrotated page space. */ x: number; /** Baseline y of the first line in unrotated page space. */ y: number; /** Draw-time-resolved Type1 resource name; re-routed at build time. */ type1ResourceName: string; fontSize: number; /** Horizontal anchor; applied per line (including each wrapped line). */ anchor: "start" | "middle" | "end"; /** Word-wrap width in points; enables multi-line layout when set. */ maxWidth?: number; /** Line-height multiple applied to `fontSize` for wrapped lines. */ lineHeightFactor: number; /** Clockwise rotation in degrees about (x, y); applied to every line. */ rotation: number; } /** * Emit a text block as a single *deferred* fragment so that anchor * alignment, word wrapping, and glyph encoding are all computed at * serialization time — after `PdfDocumentBuilder.build()` has finalised the * document's fonts. * * This matters because text measurement (anchor offset, line breaking) must * use the *same* font that ultimately renders the glyphs. At draw time the * font may still be unresolved (a non-WinAnsi run can trigger a build-time * auto-embed of a system CIDFont), so measuring against the provisional * Type1/Helvetica metrics would misplace centred/right-aligned text and * break lines at the wrong points. Deferring keeps measurement and encoding * consistent while preserving the fragment's draw-order slot (z-order). */ export declare function emitTextBlock(stream: PdfContentStream, options: TextBlockOptions, fontManager: FontManager): void; /** * Generate a deterministic ExtGState resource name for a given alpha value. * Uses 4 decimal digits to avoid collisions between close alpha values. * E.g. alpha=0.504 → "GS5040", alpha=0.506 → "GS5060" */ export declare function alphaGsName(alpha: number): string; export declare function computeTextStartY(verticalAlign: "top" | "middle" | "bottom", rect: PdfRect, totalTextHeight: number, ascent: number, padVTop?: number, padVBottom?: number): number; export declare function computeTextX(align: "left" | "center" | "right", rect: { x: number; width: number; }, textWidth: number, indentPts?: number, padHLeft?: number, padHRight?: number): number; /** * Wrap text into lines that fit within the given width. * Uses a greedy word-wrap algorithm. */ export declare function wrapTextLines(text: string, measure: (s: string) => number, maxWidth: number): string[]; /** * Result of rendering a watermark on a page. * Contains any alpha values and image XObjects that need to be registered * in the page's resource dictionary. */ export interface WatermarkRenderResult { /** Alpha values used by the watermark. */ alphaValues: number[]; /** Image XObject entries: name → raw image data + format. */ imageXObjects: Array<{ name: string; data: Uint8Array; format: "jpeg" | "png"; }>; } /** * Render a watermark onto a PDF content stream. * This should be called BEFORE the cell/grid content is rendered so the * watermark sits behind everything (under-content). */ export declare function renderWatermark(stream: PdfContentStream, page: LayoutPage, watermark: PdfWatermark, fontManager: FontManager): WatermarkRenderResult;