code wiki / _hdl_build / nx_ocr_bench_render.nx
nx_ocr_bench_render.nx source
↩ module page · 63 lines · 4010 B
1// nx_ocr_bench_render.nx -- OCR-LEGIBILITY harness, OUR side: render the bench page through the REAL
2// browser core (br_layout -> CSS cascade -> box layout -> br_draw_fb paint) exactly as the shipping
3// shot path does, at TWO zooms: scale=1 (100%, the honest apples-to-apples vs Chrome/Edge at the same
4// 1000px viewport) and scale=2 (200% zoom row, labeled separately). The browser-chrome strip is whited
5// out so the URL-bar text can't pollute the OCR of PAGE content. Outputs:
6// knowledge/status/ocr_bench_ours.png (scale 1)
7// knowledge/status/ocr_bench_ours2x.png (scale 2, supplementary labeled row)
8// The OCR judge (Windows.Media.Ocr -- a 3rd-party MEASURING INSTRUMENT, same instrument for all sides,
9// like qemu/openssl oracles) + the sovereign scorer live in the census organ. license_tier: ORIGINAL
10// expect_exit: 0
11import "nx_browser_render.nx"
12import "nx_itoa_lib.nx" // shared MSB-first emitter (zero-alloc)
13const K_MAGIC_1500: i64 = 1500
14
15func ob_puts(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
16// MIGRATED to the shared emitter (debt 1785563586). The old body mmapped a scratch buffer
17// per call and never freed it. At PAGE granularity that is 4096B leaked PER CALL -- the
18// defect that took 28.5GB of a 36GB host in nx_ts_lumadiff (2MB input, ~3.66M calls).
19// nxi_* is MSB-first, allocates NOTHING, and emits identical bytes including the sign.
20func ob_num(v: i64) -> i64 { nxi_out(v); return 0 }
21
22// render `page` (already laid out at layout-width lw) into a (lw*scale) x H png at `path`.
23func ob_shot(page: *Page, lw: i64, scale: i64, path: *u8) -> i64 {
24 let W: i64 = lw*scale
25 var H: i64 = (page.page_h + NX_CHROME_H + 40) * scale
26 if H > K_MAGIC_1500*scale { H = K_MAGIC_1500*scale }
27 let fb: *Framebuffer = sys_mmap(NX_FRAMEBUFFER_BYTES) as *Framebuffer
28 let px: *u8 = sys_mmap(W*H*4 + 64)
29 nx_framebuffer_init(fb, px, W, H)
30 br_draw_fb(fb, page, lw, "bench\x00" as *u8, 5, scale)
31 // white out the browser chrome so URL-bar/button glyphs can't pollute the PAGE-content OCR
32 nx_paint_solid_rect(fb, 0, 0, W, NX_CHROME_H*scale, br_color_from_int(0x00FFFFFF))
33 let rgb: *u8 = sys_mmap(W*H*3 + 64)
34 var p: i64 = 0
35 while p < W*H { rgb[p*3]=px[p*4]; rgb[p*3+1]=px[p*4+1]; rgb[p*3+2]=px[p*4+2]; p=p+1 }
36 nx_png_write_rgb(path, rgb, W, H)
37 return H
38}
39
40func main() -> i64 {
41 let lp: *i64 = sys_mmap(16) as *i64
42 let html: *u8 = sys_read_file("knowledge/status/ocr_bench_page.html\x00" as *u8, lp)
43 if lp[0] <= 0 { ob_puts("ocr_bench_render: no bench page\n" as *u8); return 1 }
44 // NEW DEFAULT (the legibility fix, zero shared-layout edits): lay out at HALF the viewport and paint
45 // at scale=2 -> the SAME 1000px-wide 100%-zoom image, but body glyphs render 16px (Chrome's default)
46 // in an ~55-char column instead of 8px in a 100-char wall. The OCR judge grades it below.
47 let page: *Page = sys_mmap(NX_PAGE_BYTES) as *Page
48 page.raw = html
49 page.raw_len = lp[0]
50 br_layout(page, 500)
51 page.vec_headings = 2 // 2 = vector font for HEADINGS **and body** (kill the bitmap typewriter)
52 if page.ok != 1 { ob_puts("ocr_bench_render: layout failed\n" as *u8); return 2 }
53 ob_puts("ocr_bench_render[new-16px]: boxes=" as *u8); ob_num(page.tree.count); ob_puts(" page_h=" as *u8); ob_num(page.page_h); ob_puts("\n" as *u8)
54 let h1: i64 = ob_shot(page, 500, 2, "knowledge/status/ocr_bench_ours.png\x00" as *u8)
55 // the PRIOR baseline (8px body @100%) kept as a labeled comparison row
56 let page2: *Page = sys_mmap(NX_PAGE_BYTES) as *Page
57 page2.raw = html
58 page2.raw_len = lp[0]
59 br_layout(page2, 1000)
60 let h2: i64 = ob_shot(page2, 1000, 1, "knowledge/status/ocr_bench_old8.png\x00" as *u8)
61 ob_puts("ocr_bench_render: wrote ocr_bench_ours.png [16px default] (1000x" as *u8); ob_num(h1); ob_puts(") + ocr_bench_old8.png [old 8px] (1000x" as *u8); ob_num(h2); ob_puts(")\n" as *u8)
62 return 0
63}