import { PdfArray, PdfDict, PdfValue, PdfStream } from '../pdf/objects.js'; /** A PDF rectangle `[llx, lly, urx, ury]` in default user-space units (§7.9.5). */ export type Rectangle = readonly [number, number, number, number]; /** A resolved leaf page: its dictionary plus its inherited `/MediaBox` and `/Resources`. */ export interface PdfPage { readonly dict: PdfDict; readonly mediaBox: Rectangle; /** * §14.11.2 `/CropBox` — the region of the page a viewer SHOWS, which is what * a page's size means to anyone looking at it. Defaults to the media box and * is clipped to it; inherited down the page tree like the media box is. */ readonly cropBox: Rectangle; /** * §14.11.1 `/Rotate` — how far the page turns CLOCKWISE when it is shown, * normalised to 0, 90, 180 or 270 and inherited down the page tree. */ readonly rotate: 0 | 90 | 180 | 270; readonly resources: PdfDict | undefined; } /** * The document layer (E-PDF EP1/EP7): wraps a whole PDF byte buffer and exposes * its objects — the cross-reference table (classic `xref` + `trailer` and * cross-reference streams), cached indirect-reference resolution (including * objects packed inside object streams), the page tree (walked with attribute * inheritance), and stream decoding (FlateDecode + predictors). A brute-force * object scan recovers files whose xref is broken. Construct via {@link PdfFile.parse}. */ export declare class PdfFile { private readonly buf; private readonly xref; readonly trailer: PdfDict; /** Caller-supplied decoders, by `/Filter` name (see {@link StreamFilters}). */ readonly filters: StreamFilters; private readonly cache; private readonly objStmCache; private decryptor; private encryptObjNum; private constructor(); /** * Parse a whole PDF byte buffer: read the cross-reference chain (or brute-force * recover a broken one) and initialize decryption from `/Encrypt` (§7.6). * * @param bytes The complete PDF file bytes. * @param password The user password for an encrypted source (EP14); the empty * string opens permissions-only encryption. * @param filters Decoders for `/Filter` names this reader does not implement. * @returns A ready-to-query {@link PdfFile}. */ static parse(bytes: Uint8Array, password?: string, filters?: StreamFilters): PdfFile; /** * Build the decryptor from `/Encrypt` (§7.6). Runs before any other object is * resolved, so the `/Encrypt` dictionary itself is read in the clear; its object * is then never decrypted. */ private initEncryption; /** Resolve a stream's `/Length` when it is an indirect reference. */ private readonly lengthResolver; /** * Dereference one level: a `PdfRef` becomes the object it points at (parsed and * cached); any other value is returned unchanged. Decrypts each resolved * string/stream (§7.6) except the `/Encrypt` dictionary itself, and guards * against self-referential cycles. */ resolve(value: PdfValue): PdfValue; /** Decode (once) the members of an object stream (§7.5.7) and return objNum → value. */ private objectFromStream; /** Resolve `dict[key]` in one step (look up then dereference). */ get(dict: PdfDict, key: string): PdfValue; /** The document catalog (`/Root`), or an empty dict when it cannot be resolved. */ get catalog(): PdfDict; /** * The document is encrypted but no decryptor could be built (an unsupported * handler, or a wrong/missing user password) — its content is unreadable. */ get encryptionUnsupported(): boolean; /** The leaf pages, in document order, each with its inherited `/MediaBox` and `/Resources`. */ pages(): Array; /** * Recurse the `/Pages` tree, accumulating leaf pages into `out` with inherited * `/MediaBox` and `/Resources`. Bounded by `MAX_PAGES` and a `seen` set (cycle * guard). */ private walkPageTree; /** * A page's concatenated, decoded content stream bytes (`/Contents` may be a * single stream or an array of streams joined with a separator, per §7.8.2). */ pageContent(page: PdfPage): Uint8Array; /** * Decode a stream's bytes, applying its `/Filter` chain (FlateDecode + any * `/Predictor` supported; unknown filters pass through undecoded). */ streamData(stream: PdfStream): Uint8Array; /** Filter names met in this file that nothing here can undo. */ readonly unknownFilters: Set; } /** * A decoder for one `/Filter` name, supplied by the caller. * * §7.4 leaves the filter set open, and a reader is not obliged to implement * every one — but it cannot pretend, either: an undecoded stream is not the * stream. Brotli-Prototype-FileA.pdf compresses all thirty of its streams with * `/BrotliDecode` (PDF 2.0), including the cross-reference, so unread it is a * document with no pages at all. * * Rather than carry a decoder for every filter anyone might write — Brotli * alone is RFC 7932's context-modelled Huffman scheme and a 122 KB static * dictionary, in every bundle, for a filter almost nothing produces — the * reader takes one from whoever needs it: * * ```ts * // browser: any wasm/JS decoder you ship — brotli-dec-wasm is ~200 KB * import brotliPromise from 'brotli-dec-wasm'; * const brotli = await brotliPromise; * Ream.parse(pdf, { filters: { BrotliDecode: (b) => brotli.decompress(b) } }); * ``` * * ```ts * // node, where the runtime already carries one * import { brotliDecompressSync } from 'node:zlib'; * Ream.parse(pdf, { filters: { BrotliDecode: (b) => brotliDecompressSync(b) } }); * ``` * * A decoder that throws is treated as one that was never supplied: the filter * is reported unreadable rather than its failure escaping into the parse. */ export type StreamFilter = (bytes: Uint8Array) => Uint8Array; /** Caller-supplied {@link StreamFilter}s, keyed by `/Filter` name (no slash). */ export type StreamFilters = Readonly>; /** Re-export for callers that walk a resolved dict's array values. */ export type { PdfArray };