code wiki / _hdl_build / nx_uiq_visual_lib.nx
nx_uiq_visual_lib.nx source
↩ module page · 180 lines · 8456 B
1// nx_uiq_visual_lib.nx -- SOVEREIGN visual-render metrics: the deterministic-pixel half of the
2// perceptual axis, computed on a REAL rendered PNG. Attacks the marker-vs-rendered gap no other
3// sovereign UI tool can (none execute CSS): a page that passes every structural/console check yet
4// renders BLANK (the banked "google scored 97% while rendering nothing" failure). DRY (rule 15):
5// reuses the shipped sovereign PNG decoder via nx_visual_diff's vd_load (VdImg{px,w,h,nc}) + its
6// vd_content_extent (rendered height / layout parity) -- ZERO new decode code. nx_png_write for KAT fixtures.
7// HONEST ENVELOPE (declared in output): measures the pixels of WHATEVER png it is given; render
8// FIDELITY is the input's property (a Chrome screenshot = real CSS/JS; the sovereign br_shot_png = no-JS).
9// Deterministic GUARDRAILS half; perceptual "premium" judging stays partnership-gated (VLM, will-not-fake).
10// license_tier: ORIGINAL genealogy: experiential visual; composes nx_visual_diff + nx_png_decoder + nx_png_write
11import "nx_visual_diff.nx"
12import "nx_itoa_lib.nx" // shared MSB-first emitter (zero-alloc)
13import "nx_png_write.nx"
14const UV_MAGIC_1024: i64 = 1024
15
16const UV_BLANK_PERMILLE: i64 = 20
17const UV_SPARSE_PERMILLE: i64 = 50
18const UV_INK_DELTA: i64 = 24
19const UV_STEP: i64 = 6
20
21func uv_w(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
22func uv_abs(v: i64) -> i64 { if v<0 { return 0-v } return v }
23func uv_slen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n }
24func uv_streq(s: *u8, sl: i64, lit: *u8) -> i64 { var i: i64=0; while lit[i]!=(0 as u8){ if i>=sl { return 0 } if s[i]!=lit[i] { return 0 } i=i+1 } if i!=sl { return 0 } return 1 }
25// MIGRATED to the shared emitter (debt 1785563586). The old body mmapped a scratch buffer
26// per call and never freed it. At PAGE granularity that is 4096B leaked PER CALL -- the
27// defect that took 28.5GB of a 36GB host in nx_ts_lumadiff (2MB input, ~3.66M calls).
28// nxi_* is MSB-first, allocates NOTHING, and emits identical bytes including the sign.
29func uv_pn(v: i64) -> i64 { nxi_out(v); return 0 }
30func uv_catn(d: *u8, off: i64, v: i64) -> i64 {
31 let t: *u8 = sys_mmap(28); var m: i64=v; var o: i64=off; if m<0 { d[o]=45 as u8; o=o+1; m=0-m }
32 var k: i64=0; if m==0 { t[0]=48 as u8; k=1 } while m>0 { t[k]=(48+(m%10)) as u8; m=m/10; k=k+1 }
33 var i: i64=0; while i<k { d[o]=t[k-1-i]; o=o+1; i=i+1 } return o
34}
35func uv_cat(d: *u8, off: i64, s: *u8) -> i64 { var i: i64=0; var o: i64=off; while s[i]!=(0 as u8){d[o]=s[i]; o=o+1; i=i+1} return o }
36
37// metrics over a VdImg: out[0]=ink_permille out[1]=distinct_colors out[2]=mean_lum out[3]=sampled_px
38func uv_metrics(im: *VdImg, out: *i64) -> i64 {
39 let w: i64 = im.w
40 let h: i64 = im.h
41 let nc: i64 = im.nc
42 let px: *u8 = im.px
43 out[0]=0; out[1]=0; out[2]=0; out[3]=0
44 if w<4 { return 0 }
45 if h<4 { return 0 }
46 let bo: i64 = (2*w + 2)*nc
47 let bR: i64 = px[bo] as i64
48 let bG: i64 = px[bo+1] as i64
49 let bB: i64 = px[bo+2] as i64
50 let seen: *u8 = sys_mmap(512)
51 var nonbg: i64=0
52 var tot: i64=0
53 var lum: i64=0
54 var y: i64=0
55 while y<h {
56 var x: i64=0
57 while x<w {
58 let o: i64 = (y*w + x)*nc
59 let R: i64 = px[o] as i64
60 let G: i64 = px[o+1] as i64
61 let B: i64 = px[o+2] as i64
62 tot=tot+1
63 lum = lum + (54*R + 183*G + 19*B)/256
64 let bk: i64 = (R>>5)*64 + (G>>5)*8 + (B>>5)
65 seen[bk]=1 as u8
66 let d: i64 = uv_abs(R-bR)+uv_abs(G-bG)+uv_abs(B-bB)
67 if d>UV_INK_DELTA { nonbg=nonbg+1 }
68 x=x+UV_STEP
69 }
70 y=y+UV_STEP
71 }
72 var ncnt: i64=0
73 var i: i64=0
74 while i<512 { if seen[i]==(1 as u8) { ncnt=ncnt+1 } i=i+1 }
75 if tot==0 { return 0 }
76 out[0] = 1000*nonbg/tot
77 out[1] = ncnt
78 out[2] = lum/tot
79 out[3] = tot
80 return 0
81}
82
83func uv_verdict(d: *u8, off: i64, ink: i64) -> i64 {
84 if ink<UV_BLANK_PERMILLE { return uv_cat(d, off, "BLANK-SUSPECT" as *u8) }
85 if ink<UV_SPARSE_PERMILLE { return uv_cat(d, off, "SPARSE" as *u8) }
86 return uv_cat(d, off, "RENDERED" as *u8)
87}
88
89// analyze a PNG path -> emit JSON (emit=1) ; returns ink_permille (or -1 on load failure)
90func uv_analyze(path: *u8, emit: i64) -> i64 {
91 let im: *VdImg = vd_load(path)
92 if (im as i64)==0 {
93 if emit==1 { uv_w("{\"organ\":\"nx_uiq_visual\",\"error\":\"cannot load/decode png (unsupported: Adam7 interlace or 16-bit depth (palette IS supported))\"}\n" as *u8) }
94 return 0-1
95 }
96 let out: *i64 = sys_mmap(64) as *i64
97 uv_metrics(im, out)
98 let ext: i64 = vd_content_extent(im, UV_INK_DELTA)
99 if emit==1 {
100 let jb: *u8 = sys_mmap(UV_MAGIC_1024)
101 var j: i64=0
102 j = uv_cat(jb, 0, "{\"organ\":\"nx_uiq_visual\",\"w\":" as *u8)
103 j = uv_catn(jb, j, im.w)
104 j = uv_cat(jb, j, ",\"h\":" as *u8)
105 j = uv_catn(jb, j, im.h)
106 j = uv_cat(jb, j, ",\"channels\":" as *u8)
107 j = uv_catn(jb, j, im.nc)
108 j = uv_cat(jb, j, ",\"ink_permille\":" as *u8)
109 j = uv_catn(jb, j, out[0])
110 j = uv_cat(jb, j, ",\"distinct_colors\":" as *u8)
111 j = uv_catn(jb, j, out[1])
112 j = uv_cat(jb, j, ",\"mean_lum\":" as *u8)
113 j = uv_catn(jb, j, out[2])
114 j = uv_cat(jb, j, ",\"content_extent_px\":" as *u8)
115 j = uv_catn(jb, j, ext)
116 j = uv_cat(jb, j, ",\"sampled_px\":" as *u8)
117 j = uv_catn(jb, j, out[3])
118 j = uv_cat(jb, j, ",\"verdict\":\"" as *u8)
119 j = uv_verdict(jb, j, out[0])
120 j = uv_cat(jb, j, "\",\"env\":\"real-pixel;ink-vs-corner-bg;blank<2pct;sparse<5pct;render-fidelity=input-property;guardrails-not-perceptual-VLM\"}\n" as *u8)
121 sys_write(1, jb, j)
122 }
123 return out[0]
124}
125
126// ---- KAT fixtures: encode known RGB via the sovereign nx_png_write_rgb, decode+analyze, assert ----
127func uv_mk_solid(path: *u8, w: i64, h: i64, r: i64, g: i64, b: i64) -> i64 {
128 let rgb: *u8 = sys_mmap(w*h*3 + 16)
129 var i: i64=0
130 while i<w*h { rgb[i*3]=r as u8; rgb[i*3+1]=g as u8; rgb[i*3+2]=b as u8; i=i+1 }
131 return nx_png_write_rgb(path, rgb, w, h)
132}
133// gradient over a BLACK corner (bg) = many colors, high ink
134func uv_mk_rich(path: *u8, w: i64, h: i64) -> i64 {
135 let rgb: *u8 = sys_mmap(w*h*3 + 16)
136 var y: i64=0
137 while y<h { var x: i64=0; while x<w { let o: i64=(y*w+x)*3; rgb[o]=(x*4) as u8; rgb[o+1]=(y*4) as u8; rgb[o+2]=((x+y)*2) as u8; x=x+1 } y=y+1 }
138 let s: i64=(2*w+2)*3; rgb[s]=0 as u8; rgb[s+1]=0 as u8; rgb[s+2]=0 as u8
139 rgb[0]=0 as u8; rgb[1]=0 as u8; rgb[2]=0 as u8
140 return nx_png_write_rgb(path, rgb, w, h)
141}
142// bg everywhere except a content band [y0,y1) -> exercises content_extent
143func uv_mk_band(path: *u8, w: i64, h: i64, y0: i64, y1: i64) -> i64 {
144 let rgb: *u8 = sys_mmap(w*h*3 + 16)
145 var y: i64=0
146 while y<h { var x: i64=0; while x<w { let o: i64=(y*w+x)*3; if y>=y0 { if y<y1 { rgb[o]=200 as u8; rgb[o+1]=50 as u8; rgb[o+2]=50 as u8 } else { rgb[o]=20 as u8; rgb[o+1]=20 as u8; rgb[o+2]=20 as u8 } } else { rgb[o]=20 as u8; rgb[o+1]=20 as u8; rgb[o+2]=20 as u8 } x=x+1 } y=y+1 }
147 return nx_png_write_rgb(path, rgb, w, h)
148}
149
150// selftest: encode->decode->analyze, assert blank vs rich discrimination + exact content extent. 0=GREEN.
151func uv_selftest() -> i64 {
152 var f: i64=0
153 uv_mk_rich("uiqviskat_rich.png" as *u8, 64, 64)
154 let ir: *VdImg = vd_load("uiqviskat_rich.png" as *u8)
155 if (ir as i64)==0 { return 99 }
156 let orr: *i64 = sys_mmap(64) as *i64
157 uv_metrics(ir, orr)
158 if orr[0]<500 { f=f+1 }
159 if orr[1]<8 { f=f+1 }
160 let er: i64 = vd_content_extent(ir, UV_INK_DELTA)
161 if er!=64 { f=f+1 }
162 uv_mk_solid("uiqviskat_blank.png" as *u8, 64, 64, 128, 128, 128)
163 let ib: *VdImg = vd_load("uiqviskat_blank.png" as *u8)
164 if (ib as i64)==0 { return 98 }
165 let ob: *i64 = sys_mmap(64) as *i64
166 uv_metrics(ib, ob)
167 if ob[0]!=0 { f=f+1 }
168 if ob[0]>=UV_BLANK_PERMILLE { f=f+1 }
169 let eb: i64 = vd_content_extent(ib, UV_INK_DELTA)
170 if eb!=0 { f=f+1 }
171 uv_mk_band("uiqviskat_band.png" as *u8, 64, 64, 16, 48)
172 let iband: *VdImg = vd_load("uiqviskat_band.png" as *u8)
173 if (iband as i64)==0 { return 97 }
174 let ext: i64 = vd_content_extent(iband, UV_INK_DELTA)
175 if ext!=48 { f=f+1 }
176 let oband: *i64 = sys_mmap(64) as *i64
177 uv_metrics(iband, oband)
178 if oband[0]<UV_SPARSE_PERMILLE { f=f+1 }
179 return f
180}