Writes an upstream Document to a paginated PDF under output_path. Each block is drawn inside the box it occupies on its source page, over that page's raster, so the written PDF keeps the page's layout. A Document.Page stream accumulates into one growing PDF rewritten as pages arrive.
Typical backends
Rasterize a PDF into a Document, then re-render the Document to a fresh PDF on disk whose text is selectable and sits where the source page carried it.
Detect page layout, then write the structured Document out as a viewable PDF archive.
Caveats
- Hard constraint
render must be image, text, replace or both, and page_size must be source, a4 or letter; any other value aborts startup. - I/O contractInput is oneof[Document, Document.Page] resolved at deploy. The Document arm writes one PDF per document under a rotating filename index; the Document.Page arm accumulates pages and rewrites one growing PDF.
- Parameter interaction
render selects what a page carries. "image" writes the page raster alone. "text" draws the blocks alone on a blank sheet, each inside its own box. "replace" writes the raster, repaints every text box with the background colour sampled around it and draws the block text back into that box, which changes the wording while rules, tables, logos and photographs stay in place. "both" draws the block text over the untouched raster. - Parameter interactionDrawn text is real PDF text: shaped, embedded as a font subset with a ToUnicode mapping, and selectable and searchable in the written file. Every typographic property is taken from the document rather than inferred: a run is set at the size, face, weight, slope and colour it states, a paragraph is leaded and aligned as it states, and a run that states none of these is set in the component's own face at the paragraph's measure. On a blank sheet a block whose wording grew takes the lines it needs and the blocks below it move down by one line per extra line. Over the page's own raster nothing moves: the rules, bullets and borders underneath sit at fixed heights, so each block keeps the footprint the source gave it and its type shrinks just far enough to fit.
- I/O contractEach page's image_url is read as an inline base64 data URL. A page with no usable raster still yields a PDF page, and under text, replace or both its blocks still render.
- Hard constraintUnder page_size "source" each sheet is the width and height the page states, in points — the size the source sheet actually was, rather than a size re-derived from the raster's pixel count and its dpi. A page that states no size is rejected instead of written at a guessed one.
- State lifetimeOn the Document arm the filename index is a process-local counter that resets on restart, so reusing output_path overwrites earlier PDFs. On the Document.Page arm accumulated pages live only for the process lifetime.
- State lifetimeOnly stream_flush_every can be retuned mid-run and only affects the Document.Page arm; every other key is captured at startup.
- LimitationA codepoint is drawn with a face that can spell it: script chooses the face, and where that face has no glyph the first bundled face that does is used instead, so a word can be set across two faces. Mathematics, arrows and set notation read as Latin and are only partly covered by the body face; the bundled Noto Sans, Noto Sans Math and Noto Sans Symbols cover the rest, and between them every character a Symbol run can respell to has a face that can set it. A codepoint no bundled face carries is drawn as a missing glyph rather than silently dropped.
- LimitationLatin is set in Liberation Sans, which carries Helvetica's and Arial's metrics, so text drawn over a page set in either keeps its letterforms and its line breaks. Bundled Noto faces cover Greek, Cyrillic, CJK, Arabic, Hebrew, Devanagari and Thai. Bidirectional reordering across a mixed left-to-right and right-to-left line is not applied: each run is shaped in its own direction.