normordis-pdf
Pure-Rust institutional PDF generation for the NORMAXIS mini-app framework.
This repository now contains the standalone normordis-pdf library crate along with two helper tools:
tools/dotx2ndttools/ndt-tools
A backup/restore helper is also available in scripts/.
Documentação bilingue / Bilingual documentation
Este repositório oferece documentação em português e inglês.
- Português: introdução e início rápido abaixo.
- English: see the English sections below.
- Manual:
MANUAL.mdé atualmente em português;MANUAL.en.mdfornece um ponto de entrada em inglês.
Português (pt-PT)
normordis-pdf gera documentos formais — relatórios, cartas, certificados e formulários — diretamente em Rust, sem dependências externas (sem LaTeX, sem Typst, sem Chromium). Está orientado para padrões de administração pública portuguesa e inclui Liberation Sans para renderização pronta a usar.
Três modelos de composição, todos combináveis num único documento:
| Modelo | Descrição |
|---|---|
| Flow | Elementos empilham-se verticalmente; quebras de página automáticas; cabeçalho re-injectado |
| Fixed Box | Elementos posicionados em coordenadas absolutas; não afeta o cursor |
| Templates NDT | Templates JSON com injeção de dados em tempo de execução |
Início rápido
# Cargo.toml
[]
= "1.0.0"
Documento Flow
use ;
let pdf = new
.push
.push
.push
.render_to_bytes?;
write?;
English
Overview
normordis-pdf generates formal documents — reports, letters, certificates, forms — directly from Rust, with no external binary dependency (no LaTeX, no Typst, no Chromium). It targets Portuguese public administration document standards and embeds Liberation Sans for out-of-the-box rendering with real glyph metrics.
Three composition models, all mixable in a single document:
| Model | Description |
|---|---|
| Flow | Elements stack vertically; automatic page breaks; header re-injection |
| Fixed Box | Elements placed at absolute coordinates; no cursor effect |
| NDT Templates | JSON-driven document templates with runtime data injection |
Quick Start
# Cargo.toml
[]
= "1.0.0"
Flow document
use ;
let pdf = new
.push
.push
.push
.render_to_bytes?;
write?;
NCRTF rich text
use DocumentBuilder;
let ncrtf = r#"{
"ncrtf": "1.0",
"blocks": [
{"type":"heading","level":1,"children":[{"type":"text","text":"Título","marks":[]}]},
{"type":"paragraph","alignment":"justify","children":[
{"type":"text","text":"Texto com ","marks":[]},
{"type":"text","text":"negrito","marks":["bold"]},
{"type":"text","text":" e itálico.","marks":["italic"]}
]}
]
}"#;
let pdf = new
.push_ncrtf?
.render_to_bytes?;
NDT template
use DocumentBuilder;
const TEMPLATE: &str = include_str!;
let data = json!.to_string;
let pdf = new
.push_ndt?
.render_to_bytes?;
Features
Flow elements
| Type | Struct / method |
|---|---|
| Paragraph (plain or rich) | Paragraph::new(text) |
| Section heading | Section::new(text, level) |
| Ordered / bullet / checklist | List::new(items, ListType::Bullet) |
| Table | Table::new(headers, rows) |
| Image | FlowImage::new(bytes, width_mm) |
| Spacer | Spacer::new(height_mm) |
| Horizontal rule | HorizontalRule::new() |
| Page break | PageBreak |
Fixed Box elements
| Type | Builder method |
|---|---|
| Text at absolute position | DocumentBuilder::fixed_text(box, text, align) |
| Image at absolute position | DocumentBuilder::fixed_image(box, bytes, fit) |
| Decorative line | DocumentBuilder::fixed_line(x1, y1, x2, y2, color) |
NCRTF v1.0 — rich text format
NCRTF (NORMAXIS Canonical Rich Text Format) is a JSON schema for inline-styled paragraphs. It is the interchange format between editors (such as @normaxis/nx-doc) and this renderer.
Supported block types: paragraph, heading (levels 1–4), list (bullet / ordered / checklist).
Supported inline marks: bold, italic, underline, strikethrough, code.
NDT v1.0.0 — document templates
NDT (NORMAXIS Document Template) is a JSON-driven template format for institutional documents. Templates define a layout schema; runtime data is injected at render time.
Template file (*.ndt.json):
Data file (*.ndt-data.json):
Supported body element types: paragraph, heading, rich_text, table, list, image,
spacer, horizontal_rule, page_break, fixed_text, fixed_image, fixed_line,
fixed_box, zone_ref, conditional, repeat, include.
Supported conditional operators: exists, empty, eq, neq, gt, lt.
Bundled templates
Ready-to-use NDT templates are provided under examples/templates/:
| File | Description |
|---|---|
relatorio-simples.ndt.json |
Simple institutional report |
oficio-nacional.ndt.json |
Official letter (ofício) |
certidao-generica.ndt.json |
Generic certificate (certidão) |
formulario-generico.ndt.json |
Generic two-section form |
Examples
Run any example with:
| Example | Description |
|---|---|
01_basic_document |
Flow document with headings, paragraphs, table, list |
02_ncrtf_document |
Document built from NCRTF rich text JSON |
03_ndt_template |
Document rendered from an NDT template + runtime data |
04_mixed_layout |
Flow + Fixed Box mixed (office letter style) |
Fonts
Liberation Sans (Regular, Bold, Italic, Bold Italic) is embedded at compile time via include_bytes!. No system fonts are required. The FontRegistry type allows registering additional TTF/OTF families at runtime.
Version constants
VERSION // "1.0.0" — crate version
NDT_VERSION // "1.0.0" — NDT engine version
NCRTF_VERSION // "1.0" — NCRTF parser version
API stability
All public items re-exported from normordis_pdf::* are considered stable from v1.0.0 onwards. Internal modules (normordis_pdf::template::*, normordis_pdf::richtext::*, etc.) are not stable and may change between minor versions.
License
EUPL-1.2 — see LICENSE or https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12.