Skip to content

Commit f51a8f7

Browse files
JheisonMBCopilot
andcommitted
fix: load system and platform fonts for diagram text rendering
Load fonts from system directories and Windows font path (WSL) into fontdb. Map generic CSS families (sans-serif, serif, monospace) to concrete fonts available in the database. This fixes text not appearing in mermaid and graphviz diagram PNGs. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 11212c2 commit f51a8f7

4 files changed

Lines changed: 73 additions & 45 deletions

File tree

Cargo.lock

Lines changed: 5 additions & 29 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@ notify = { version = "7", features = ["macos_fsevent"] }
4747
# Mermaid diagram rendering
4848
mermaid-rs-renderer = { version = "0.2", default-features = false }
4949
resvg = "0.46"
50-
fontdb = "0.20"
5150

5251
# Graphviz/DOT diagram rendering
5352
layout-rs = "0.1"

README.md

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,17 +21,10 @@ Self-contained LaTeX to PDF compiler — one curl, zero friction. No TeX Live, n
2121

2222
---
2323

24-
### Demos
25-
26-
#### Uso básico del CLI
24+
### Demo CLI
2725

2826
![Demo CLI](assets/texforge.gif)
2927

30-
#### Integración con agentes en OpenCode
31-
32-
![Demo OpenCode](assets/opencode.gif)
33-
34-
3528
---
3629

3730
## Installation
@@ -105,6 +98,10 @@ An [texforge Skill](https://skills.sh/jheisonmb/skills/texforge) is available fo
10598
npx skills add https://github.com/jheisonmb/skills --skill texforge
10699
```
107100

101+
### Demo Agent with opencode
102+
103+
![Demo OpenCode](assets/opencode.gif)
104+
108105
## Quick Start
109106

110107
```bash

src/diagrams/mod.rs

Lines changed: 63 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -212,15 +212,71 @@ fn resolve_tex(root: &Path, input: &str) -> PathBuf {
212212
}
213213
}
214214

215+
/// Build a font database with system fonts and platform-specific fallbacks.
216+
fn build_fontdb() -> resvg::usvg::fontdb::Database {
217+
use resvg::usvg::fontdb::Database;
218+
219+
let mut db = Database::new();
220+
db.load_system_fonts();
221+
222+
// On WSL / Windows, also load the Windows font directory
223+
let win_fonts = std::path::Path::new("/mnt/c/Windows/Fonts");
224+
if win_fonts.is_dir() {
225+
db.load_fonts_dir(win_fonts);
226+
}
227+
228+
// If the DB still has no fonts at all, try common directories explicitly.
229+
if db.is_empty() {
230+
for dir in ["/usr/share/fonts", "/usr/local/share/fonts"] {
231+
let p = std::path::Path::new(dir);
232+
if p.is_dir() {
233+
db.load_fonts_dir(p);
234+
}
235+
}
236+
}
237+
238+
// Collect the set of available family names once (avoids borrow conflicts).
239+
let available: std::collections::HashSet<String> = db
240+
.faces()
241+
.flat_map(|f| f.families.iter().map(|(name, _)| name.clone()))
242+
.collect();
243+
244+
// Map generic CSS families to the first concrete font we find in the DB.
245+
let sans = ["Arial", "DejaVu Sans", "Liberation Sans", "Noto Sans"];
246+
if let Some(f) = sans.iter().find(|n| available.contains(**n)) {
247+
db.set_sans_serif_family(*f);
248+
}
249+
let serif = [
250+
"Times New Roman",
251+
"DejaVu Serif",
252+
"Liberation Serif",
253+
"Noto Serif",
254+
];
255+
if let Some(f) = serif.iter().find(|n| available.contains(**n)) {
256+
db.set_serif_family(*f);
257+
}
258+
let mono = [
259+
"Courier New",
260+
"DejaVu Sans Mono",
261+
"Liberation Mono",
262+
"Noto Sans Mono",
263+
];
264+
if let Some(f) = mono.iter().find(|n| available.contains(**n)) {
265+
db.set_monospace_family(*f);
266+
}
267+
268+
db
269+
}
270+
215271
/// Convert SVG string to PNG bytes at 2x scale for print quality.
216272
fn svg_to_png(svg: &str) -> Result<Vec<u8>> {
217-
let mut options = resvg::usvg::Options::default();
218-
219-
// Load system fonts for text rendering
220-
let mut fontdb = resvg::usvg::fontdb::Database::new();
221-
fontdb.load_system_fonts();
222-
options.fontdb = std::sync::Arc::new(fontdb);
223-
273+
let fontdb = build_fontdb();
274+
275+
let options = resvg::usvg::Options {
276+
fontdb: std::sync::Arc::new(fontdb),
277+
..Default::default()
278+
};
279+
224280
let tree = resvg::usvg::Tree::from_str(svg, &options).context("Failed to parse SVG")?;
225281

226282
let scale = 2.0_f32;

0 commit comments

Comments
 (0)