code wiki / (root) / nx_cdmap_export.nx

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}