code wiki / (root) / nx_img_core.nx

nx_img_core.nx source

↩ module page · 111 lines · 4375 B

1// nx_img_core.nx -- R1 of the SOVEREIGN scanning stack (hardware rung up): raw bytes -> pixels. A sovereign image 2// decoder + pixel buffer, the foundation every later rung (R2 threshold, R3 segment, R4 OCR) stands on. Decodes 3// the netpbm graymap format PGM -- P2 (ASCII) + P5 (binary) -- into a row-major 8-bit grayscale buffer. Netpbm is 4// the trivial, uncompressed, sovereign image format (a scanner or our own capture can emit it, or we convert to 5// it). Integer-exact, zero dependencies. Next rungs read this buffer. license_tier: ORIGINAL 6import "nx_syscalls.nx" 7 8const IMG_FMT: i64 = 0 // dims[]: 2 = P2 (ASCII), 5 = P5 (binary) 9const IMG_W: i64 = 1 10const IMG_H: i64 = 2 11const IMG_MAX: i64 = 3 12 13func img_is_ws(ch: i64) -> i64 { 14 if ch == 32 { return 1 } 15 if ch == 9 { return 1 } 16 if ch == 10 { return 1 } 17 if ch == 13 { return 1 } 18 return 0 19} 20 21// skip whitespace + '#' comments (to end of line) starting at p; return the new position. 22func img_skip_ws(src: *u8, len: i64, p: i64) -> i64 { 23 var i: i64 = p; var run: i64 = 1 24 while run == 1 { 25 if i >= len { run = 0 } 26 else { 27 let ch: i64 = src[i] as i64 28 if img_is_ws(ch) == 1 { i = i + 1 } 29 else { 30 if ch == 35 { // '#' 31 var c2: i64 = 1 32 while c2 == 1 { if i >= len { c2 = 0 } else { if src[i] == (10 as u8) { c2 = 0 } else { i = i + 1 } } } 33 } else { run = 0 } 34 } 35 } 36 } 37 return i 38} 39 40// read an unsigned int (skipping leading ws/comments); advance pos[0] to the char after the last digit. 41func img_next_uint(src: *u8, len: i64, pos: *i64) -> i64 { 42 var i: i64 = img_skip_ws(src, len, pos[0]) 43 var v: i64 = 0; var run: i64 = 1 44 while run == 1 { 45 if i >= len { run = 0 } 46 else { 47 let ch: i64 = src[i] as i64 48 if ch >= 48 { if ch <= 57 { v = v * 10 + (ch - 48); i = i + 1 } else { run = 0 } } 49 else { run = 0 } 50 } 51 } 52 pos[0] = i 53 return v 54} 55 56// parse the PGM header; fill dims[IMG_FMT/W/H/MAX]; return the offset where pixel data begins, or -1 on bad magic. 57func img_parse_header(src: *u8, len: i64, dims: *i64) -> i64 { 58 if len < 2 { return 0 - 1 } 59 if src[0] != (80 as u8) { return 0 - 1 } // 'P' 60 let f: i64 = src[1] as i64 61 var fmt: i64 = 0 62 if f == 50 { fmt = 2 } 63 if f == 53 { fmt = 5 } 64 if fmt == 0 { return 0 - 1 } 65 dims[IMG_FMT] = fmt 66 let pos: *i64 = sys_mmap(16) as *i64 67 pos[0] = 2 68 dims[IMG_W] = img_next_uint(src, len, pos) 69 dims[IMG_H] = img_next_uint(src, len, pos) 70 dims[IMG_MAX] = img_next_uint(src, len, pos) 71 var dstart: i64 = pos[0] 72 if fmt == 5 { dstart = dstart + 1 } // P5: exactly ONE whitespace separates maxval from the raw bytes 73 return dstart 74} 75 76// decode a PGM (P2 or P5) into pix[0..w*h) as 8-bit grayscale, row-major. Returns pixel count (0 on failure). 77func img_pgm_decode(src: *u8, len: i64, pix: *u8, cap: i64, dims: *i64) -> i64 { 78 let hdr_end: i64 = img_parse_header(src, len, dims) 79 if hdr_end < 0 { return 0 } 80 let w: i64 = dims[IMG_W]; let h: i64 = dims[IMG_H] 81 if w <= 0 { return 0 } 82 if h <= 0 { return 0 } 83 let npix: i64 = w * h 84 if npix > cap { return 0 } 85 if dims[IMG_FMT] == 5 { 86 var i: i64 = 0 87 while i < npix { 88 if hdr_end + i < len { pix[i] = src[hdr_end + i] } else { pix[i] = 0 as u8 } 89 i = i + 1 90 } 91 } else { 92 let pos: *i64 = sys_mmap(16) as *i64 93 pos[0] = hdr_end 94 var i: i64 = 0 95 while i < npix { pix[i] = img_next_uint(src, len, pos) as u8; i = i + 1 } 96 } 97 return npix 98} 99 100// --- pixel buffer ops (the surface later rungs use) --- 101func img_get(pix: *u8, w: i64, x: i64, y: i64) -> i64 { return pix[y * w + x] as i64 } 102func img_set(pix: *u8, w: i64, x: i64, y: i64, v: i64) -> i64 { pix[y * w + x] = v as u8; return 0 } 103func img_invert(pix: *u8, npix: i64, maxval: i64) -> i64 { 104 var i: i64 = 0; while i < npix { pix[i] = (maxval - (pix[i] as i64)) as u8; i = i + 1 } return 0 105} 106// 256-bin intensity histogram (feeds R2 Otsu thresholding). 107func img_histogram(pix: *u8, npix: i64, hist: *i64) -> i64 { 108 var i: i64 = 0; while i < 256 { hist[i] = 0; i = i + 1 } 109 i = 0; while i < npix { let v: i64 = pix[i] as i64; hist[v] = hist[v] + 1; i = i + 1 } 110 return 0 111}