code wiki / _hdl_build / nx_img_sbs.nx

nx_img_sbs.nx source

↩ module page · 62 lines · 3119 B

1// nx_img_sbs.nx -- sovereign SIDE-BY-SIDE evidence compositor: oracle screenshot | Nishi screenshot into 2// ONE image, so a visual-parity claim is a single artifact a human can eyeball (the "show me the comp" 3// primitive of the evidence workstream). Crops each input to the same row window (skips browser chrome 4// bars), places A left / B right with a neutral gutter. usage: 5// nx_img_sbs <A.png> <ay> <B.png> <by> <H> <out.png> 6// A rows [ay..ay+H) left, B rows [by..by+H) right, gutter 20px #303845. license_tier: ORIGINAL 7import "nx_visual_diff.nx" 8import "nx_itoa_lib.nx" // shared MSB-first emitter (zero-alloc) 9import "nx_png_write.nx" 10 11const SBS_GUTTER: i64 = 20 12 13func sb_w(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 14// MIGRATED to the shared emitter (debt 1785563586). The old body mmapped a scratch buffer 15// per call and never freed it. At PAGE granularity that is 4096B leaked PER CALL -- the 16// defect that took 28.5GB of a 36GB host in nx_ts_lumadiff (2MB input, ~3.66M calls). 17// nxi_* is MSB-first, allocates NOTHING, and emits identical bytes including the sign. 18func sb_n(v: i64) -> i64 { nxi_out(v); return 0 } 19func sb_atoi(s: *u8) -> i64 { var v: i64=0; var i: i64=0; while s[i]!=(0 as u8){ let c: i64=(s[i] as i64)&255; if c>=48 { if c<=57 { v=v*10+(c-48) } } i=i+1 } return v } 20 21// copy H rows of src (starting src row yoff) into dst at (dx,0); dst is RGB w=dw 22func sb_blit(dst: *u8, dw: i64, im: *VdImg, yoff: i64, dx: i64, hh: i64) -> i64 { 23 var y: i64 = 0 24 while y < hh { 25 var x: i64 = 0 26 while x < im.w { 27 let so: i64 = ((y + yoff) * im.w + x) * im.nc 28 let dof: i64 = (y * dw + dx + x) * 3 29 dst[dof] = im.px[so] 30 dst[dof+1] = im.px[so+1] 31 dst[dof+2] = im.px[so+2] 32 x = x + 1 33 } 34 y = y + 1 35 } 36 return 0 37} 38 39func main(argc: i64, argv: *i64) -> i64 { 40 if argc < 7 { sb_w("usage: nx_img_sbs <A.png> <ay> <B.png> <by> <H> <out.png>\n" as *u8); sys_exit(2); return 2 } 41 let a: *VdImg = vd_load(argv[1] as *u8) 42 if (a as i64) == 0 { sb_w("cannot load A\n" as *u8); sys_exit(3); return 3 } 43 let ay: i64 = sb_atoi(argv[2] as *u8) 44 let b: *VdImg = vd_load(argv[3] as *u8) 45 if (b as i64) == 0 { sb_w("cannot load B\n" as *u8); sys_exit(3); return 3 } 46 let by: i64 = sb_atoi(argv[4] as *u8) 47 var hh: i64 = sb_atoi(argv[5] as *u8) 48 if ay + hh > a.h { hh = a.h - ay } 49 if by + hh > b.h { hh = b.h - by } 50 if hh <= 0 { sb_w("empty crop\n" as *u8); sys_exit(4); return 4 } 51 let dw: i64 = a.w + SBS_GUTTER + b.w 52 let dst: *u8 = sys_mmap((dw * hh * 3) as nx_size) 53 // gutter fill #303845 (neutral slate) 54 var i: i64 = 0 55 while i < dw * hh { dst[i*3]=48 as u8; dst[i*3+1]=56 as u8; dst[i*3+2]=69 as u8; i = i + 1 } 56 sb_blit(dst, dw, a, ay, 0, hh) 57 sb_blit(dst, dw, b, by, a.w + SBS_GUTTER, hh) 58 nx_png_write_rgb(argv[6] as *u8, dst, dw, hh) 59 sb_w("sbs " as *u8); sb_n(dw); sb_w("x" as *u8); sb_n(hh); sb_w(" -> " as *u8); sb_w(argv[6] as *u8); sb_w("\n" as *u8) 60 sys_exit(0) 61 return 0 62}