1pub mod config;
9pub mod error;
10pub mod fonts;
11pub mod render_utils;
12pub mod renderer;
13pub mod styles;
14
15use config::PrintConfig;
16use error::Result;
17use oxipdf::ir::config::RenderConfig;
18use oxipdf::ir::page_template::{PageMargins, PageTemplate};
19
20pub fn render_to_pdf(root: &rdx_ast::Root, config: &PrintConfig) -> Result<Vec<u8>> {
27 let tree = renderer::render_to_tree(root, config)?;
29
30 let page_width = config.page.size.width();
32 let page_height = config.page.size.height();
33
34 let margins = PageMargins {
35 top: config.page.margin_top,
36 bottom: config.page.margin_bottom,
37 left: config.page.margin_inner,
38 right: config.page.margin_outer,
39 };
40
41 let render_config = RenderConfig {
42 page_width,
43 page_height,
44 page_template: Some(PageTemplate {
45 margins,
46 ..PageTemplate::default()
47 }),
48 hyphenation: oxipdf::ir::config::HyphenationConfig {
49 enabled: true,
50 min_word_length: 5,
51 min_left: 2,
52 min_right: 2,
53 },
54 ..RenderConfig::default()
55 };
56
57 let families = [
59 config.fonts.body.as_str(),
60 config.fonts.heading.as_str(),
61 config.fonts.mono.as_str(),
62 ];
63 let font_provider = fonts::build_font_provider_for_families(&config.fonts.font_dirs, &families);
64
65 let pdf_bytes = match font_provider {
67 Some(provider) => {
68 tracing::info!(
69 families = ?provider.available_families().len(),
70 "Using shaped rendering with system fonts"
71 );
72 oxipdf::render_paginated_shaped_doc(&tree, &render_config, provider.as_ref())?
73 }
74 None => {
75 tracing::warn!("No fonts found — using hardcoded metrics (output quality reduced)");
76 oxipdf::render_paginated_doc(&tree, &render_config)?
77 }
78 };
79
80 Ok(pdf_bytes)
81}
82
83pub fn render_file_to_pdf(rdx_source: &str, config: &PrintConfig) -> Result<Vec<u8>> {
87 use rdx_transform::Transform;
88
89 let mut root = rdx_parser::parse(rdx_source);
90
91 let auto_slug = rdx_transform::AutoSlug::new();
93 let auto_number = rdx_transform::AutoNumber::new();
94
95 auto_slug.transform(&mut root, rdx_source);
96 auto_number.transform(&mut root, rdx_source);
97
98 let strip = rdx_transform::StripTarget {
100 target: "print".into(),
101 };
102 let fallback = rdx_transform::PrintFallback;
103
104 strip.transform(&mut root, rdx_source);
105 fallback.transform(&mut root, rdx_source);
106
107 let registry = auto_number.registry();
109 let cross_ref = rdx_transform::CrossRefResolve::new(
110 rdx_transform::NumberRegistry {
111 entries: registry.entries.clone(),
112 },
113 "print",
114 );
115 drop(registry);
116 cross_ref.transform(&mut root, rdx_source);
117
118 let abbrev = rdx_transform::AbbreviationExpand;
120 abbrev.transform(&mut root, rdx_source);
121
122 render_to_pdf(&root, config)
123}