code wiki / (root) / nx_image_load_raw.nx

nx_image_load_raw.nx source

↩ module page · 118 lines · 4264 B

1// nx_image_load_raw.nx -- load real images via raw-binary header + pixels. 2// 3// The substrate bridges to real images via a SIMPLE raw format that any 4// preprocessor (PIL, ImageMagick, ffmpeg, custom script) can produce: 5// 6// bytes 0..7 width (little-endian i64) 7// bytes 8..15 height (little-endian i64) 8// bytes 16..23 channels (little-endian i64) 9// bytes 24.. raw pixel data, row-major, width * height * channels bytes 10// 11// This is the LAST-MILE primitive — once it lands, nx_color_skin_mask / 12// nx_region_segment / nx_eye_detect / etc all consume real PNG renders 13// via this conversion bridge: 14// 15// # Python preprocessing (svc-quality does this once per image): 16// import struct, PIL.Image, numpy as np 17// arr = np.array(PIL.Image.open(path).convert("RGB")) 18// h, w, c = arr.shape 19// with open("/tmp/img.raw", "wb") as f: 20// f.write(struct.pack("<QQQ", w, h, c)) 21// f.write(arr.tobytes()) 22// 23// # nxc2-compiled detector reads /tmp/img.raw, runs the full pipeline, 24// # writes verdict.json. svc-quality reads verdict.json, emits to UI. 25 26// nx_safety_envelope: 27// intended_use: AUTO_APPLIED -- primitive-specific tuning queued 28// sil_target: SIL1 29// evidence: [bulk_applied_2026-05-16, see-file-comment-for-detail] 30// verdict: NOT_YET_EVALUATED 31 32import "nx_syscalls.nx" 33import "nx_image.nx" 34 35// Read 8 bytes (little-endian i64) starting at buf+offset. 36func nx_image_load_read_i64_le(buf: *u8, offset: i64) -> i64 { 37 let b0: i64 = buf[offset + 0] 38 let b1: i64 = buf[offset + 1] 39 let b2: i64 = buf[offset + 2] 40 let b3: i64 = buf[offset + 3] 41 let b4: i64 = buf[offset + 4] 42 let b5: i64 = buf[offset + 5] 43 let b6: i64 = buf[offset + 6] 44 let b7: i64 = buf[offset + 7] 45 return b0 + (b1 << 8) + (b2 << 16) + (b3 << 24) + (b4 << 32) + (b5 << 40) + (b6 << 48) + (b7 << 56) 46} 47 48// Load an image from a raw-binary file at the given path. 49// Returns *Image or 0-pointer on failure. 50func nx_image_load_raw(path: *u8) -> *Image { 51 let len_out: *i64 = (sys_mmap(16)) as *i64 52 let buf: *u8 = sys_read_file(path, len_out) 53 let total_len: i64 = len_out[0] 54 if total_len < 24 { return 0 as *Image } 55 56 let w: i64 = nx_image_load_read_i64_le(buf, 0) 57 let h: i64 = nx_image_load_read_i64_le(buf, 8) 58 let c: i64 = nx_image_load_read_i64_le(buf, 16) 59 if w <= 0 { return 0 as *Image } 60 if h <= 0 { return 0 as *Image } 61 if c <= 0 { return 0 as *Image } 62 let expected_pixels: i64 = w * h * c 63 if total_len < 24 + expected_pixels { return 0 as *Image } 64 65 // Allocate the Image struct, point pixels at buf+24. 66 let raw: *u8 = sys_mmap(NX_IMG_BYTES) 67 let img: *Image = raw as *Image 68 img.width = w 69 img.height = h 70 img.channels = c 71 img.stride = w * c 72 img.pixels = (buf as i64 + 24) as *u8 73 return img 74} 75 76// Pack header + pixel buffer into a single contiguous buffer. Useful 77// for round-trip tests + the inverse "save" path. Caller pre-allocates 78// out_buf of size at least 24 + w*h*c. 79func nx_image_save_raw_pack(img: *Image, out_buf: *u8) -> i64 { 80 let w: i64 = img.width 81 let h: i64 = img.height 82 let c: i64 = img.channels 83 // Write width LE. 84 out_buf[0] = (w >> 0) & 255 85 out_buf[1] = (w >> 8) & 255 86 out_buf[2] = (w >> 16) & 255 87 out_buf[3] = (w >> 24) & 255 88 out_buf[4] = (w >> 32) & 255 89 out_buf[5] = (w >> 40) & 255 90 out_buf[6] = (w >> 48) & 255 91 out_buf[7] = (w >> 56) & 255 92 // Write height LE. 93 out_buf[8] = (h >> 0) & 255 94 out_buf[9] = (h >> 8) & 255 95 out_buf[10] = (h >> 16) & 255 96 out_buf[11] = (h >> 24) & 255 97 out_buf[12] = (h >> 32) & 255 98 out_buf[13] = (h >> 40) & 255 99 out_buf[14] = (h >> 48) & 255 100 out_buf[15] = (h >> 56) & 255 101 // Write channels LE. 102 out_buf[16] = (c >> 0) & 255 103 out_buf[17] = (c >> 8) & 255 104 out_buf[18] = (c >> 16) & 255 105 out_buf[19] = (c >> 24) & 255 106 out_buf[20] = (c >> 32) & 255 107 out_buf[21] = (c >> 40) & 255 108 out_buf[22] = (c >> 48) & 255 109 out_buf[23] = (c >> 56) & 255 110 // Copy pixels. 111 let total: i64 = w * h * c 112 var i: i64 = 0 113 while i < total { 114 out_buf[24 + i] = img.pixels[i] 115 i = i + 1 116 } 117 return 24 + total 118}