nx_cdmap_export.nx source
↩ module page · 93 lines · 5181 B
1// nx_cdmap_export.nx -- EXPORT A COMPARE PAGE'S POSITION MAP AS A STANDALONE SVG AND A PNG (datavis DV6, 2026-09-15).
2// Composes nx_cdmap_raster_lib: the page's :root colour tokens are read, the inline <svg class='cdmap'> is sliced,
3// written as a self-contained SVG (namespace declared, every var(--nx-color-*) resolved to the rgb the page defined) and
4// rasterised through the sovereign font engine and PNG writer at an integer scale. Every element class the figure carries
5// is COUNTED on the receipt line, and every construct outside the drawn subset is counted too (skipped, unresolved
6// colours, rotations the subset does not draw), so a reader can tell a complete render from a partial one by reading
7// the line, never by opening the picture. The receipt's LAST token is the verdict.
8// nx_cdmap_export <index.html> <out.svg> <out.png> [regular.ttf [bold.ttf [scale]]]
9// Fonts default to the Liberation Sans faces probed at the NAS path, the buildroot-relative path and the laptop path.
10// Exit 0 = both files landed, 1 = refused (the code is named), 2 = usage. license_tier: ORIGINAL
11import "nx_cdmap_raster_lib.nx"
12import "nx_syscalls.nx"
13
14const XP_EXIT_OK: i64 = 0
15const XP_EXIT_REFUSED: i64 = 1
16const XP_EXIT_USAGE: i64 = 2
17const XP_ARGS_MIN: i64 = 4
18const XP_A_PAGE: i64 = 1
19const XP_A_SVG: i64 = 2
20const XP_A_PNG: i64 = 3
21const XP_A_FREG: i64 = 4
22const XP_A_FBOLD: i64 = 5
23const XP_A_SCALE: i64 = 6
24const XP_LINE_BYTES: i64 = 1024
25const XP_FONT_NAS: *u8 = "knowledge/fonts/LiberationSans-Regular.ttf"
26const XP_FONT_NAS_BOLD: *u8 = "knowledge/fonts/LiberationSans-Bold.ttf"
27const XP_FONT_UP: *u8 = "../knowledge/fonts/LiberationSans-Regular.ttf"
28const XP_FONT_UP_BOLD: *u8 = "../knowledge/fonts/LiberationSans-Bold.ttf"
29const XP_FONT_LAPTOP: *u8 = "web_assets/fonts/LiberationSans-Regular.ttf"
30const XP_FONT_LAPTOP_BOLD: *u8 = "web_assets/fonts/LiberationSans-Bold.ttf"
31const XP_CH_0: i64 = 48
32const XP_CH_9: i64 = 57
33const XP_BASE10: i64 = 10
34
35func xp_put(s: *u8) -> i64 { sys_write(1, s, rs_slen(s)); return 0 }
36func xp_kv(k: *u8, v: i64) -> i64 {
37 let b: *u8 = sys_mmap(XP_LINE_BYTES)
38 var o: i64 = 0
39 b[o] = 32 as u8; o = o + 1
40 var i: i64 = 0
41 while k[i] != (0 as u8) { b[o] = k[i]; o = o + 1; i = i + 1 }
42 b[o] = 61 as u8; o = o + 1
43 o = rs_dec_into(b, o, v)
44 sys_write(1, b, o)
45 sys_munmap(b, XP_LINE_BYTES)
46 return 0
47}
48func xp_ks(k: *u8, v: *u8) -> i64 { xp_put(" " as *u8); xp_put(k); xp_put("=" as *u8); xp_put(v); return 0 }
49func xp_atoi(s: *u8) -> i64 {
50 var v: i64 = 0
51 var i: i64 = 0
52 while s[i] != (0 as u8) { let c: i64 = s[i] as i64; if c >= XP_CH_0 { if c <= XP_CH_9 { v = v * XP_BASE10 + (c - XP_CH_0) } } i = i + 1 }
53 return v
54}
55func xp_exists(path: *u8) -> i64 { let fd: i64 = sys_openat_rd(path); if fd < 0 { return 0 } sys_close(fd); return 1 }
56// the regular face: an explicit argument wins, else the first of the three known homes that opens
57func xp_font(argv: *i64, argc: i64, idx: i64, nas: *u8, up: *u8, laptop: *u8) -> *u8 {
58 if argc > idx { let a: *u8 = argv[idx] as *u8; if a[0] != (0 as u8) { return a } }
59 if xp_exists(nas) == 1 { return nas }
60 if xp_exists(up) == 1 { return up }
61 return laptop
62}
63
64func main(argc: i64, argv: *i64) -> i64 {
65 if argc < XP_ARGS_MIN {
66 xp_put("usage: nx_cdmap_export <index.html> <out.svg> <out.png> [regular.ttf [bold.ttf [scale]]]\n" as *u8)
67 return XP_EXIT_USAGE
68 }
69 let page: *u8 = argv[XP_A_PAGE] as *u8
70 let svgp: *u8 = argv[XP_A_SVG] as *u8
71 let pngp: *u8 = argv[XP_A_PNG] as *u8
72 let freg: *u8 = xp_font(argv, argc, XP_A_FREG, XP_FONT_NAS, XP_FONT_UP, XP_FONT_LAPTOP)
73 let fbold: *u8 = xp_font(argv, argc, XP_A_FBOLD, XP_FONT_NAS_BOLD, XP_FONT_UP_BOLD, XP_FONT_LAPTOP_BOLD)
74 var scale: i64 = RS_SCALE_DEFAULT
75 if argc > XP_A_SCALE { scale = xp_atoi(argv[XP_A_SCALE] as *u8) }
76 let stats: *i64 = rs_i64(RS_S_SLOTS)
77 let out: *i64 = rs_i64(2)
78 let rc: i64 = rs_export(page, svgp, pngp, freg, fbold, scale, stats, out)
79 xp_put("CDMAP-EXPORT" as *u8)
80 xp_ks("page" as *u8, page); xp_ks("svg" as *u8, svgp); xp_ks("png" as *u8, pngp)
81 xp_ks("font_regular" as *u8, freg); xp_ks("font_bold" as *u8, fbold)
82 xp_kv("scale" as *u8, scale); xp_kv("png_w" as *u8, stats[RS_S_W])
83 xp_kv("rect" as *u8, stats[RS_S_RECT]); xp_kv("circle" as *u8, stats[RS_S_CIRCLE]); xp_kv("line" as *u8, stats[RS_S_LINE])
84 xp_kv("polyline" as *u8, stats[RS_S_POLYLINE]); xp_kv("polygon" as *u8, stats[RS_S_POLYGON]); xp_kv("text" as *u8, stats[RS_S_TEXT])
85 xp_kv("notes" as *u8, stats[RS_S_NOTES]); xp_kv("arrows" as *u8, stats[RS_S_ARROWS]); xp_kv("rotated" as *u8, stats[RS_S_ROTATED])
86 xp_kv("rotated_skipped" as *u8, stats[RS_S_ROTSKIP]); xp_kv("skipped" as *u8, stats[RS_S_SKIPPED]); xp_kv("unresolved_colors" as *u8, stats[RS_S_UNRESOLVED])
87 xp_kv("glyphs" as *u8, stats[RS_S_GLYPHS]); xp_kv("ink_px" as *u8, stats[RS_S_INK]); xp_kv("tokens" as *u8, stats[RS_S_TOKENS])
88 xp_kv("svg_bytes" as *u8, out[0]); xp_kv("png_bytes" as *u8, out[1])
89 xp_ks("verdict" as *u8, rs_rc_name(rc))
90 xp_put("\n" as *u8)
91 if rc != RS_OK { return XP_EXIT_REFUSED }
92 return XP_EXIT_OK
93}