code wiki / (root) / nx_f32_image_to_bmp.nx

nx_f32_image_to_bmp.nx source

↩ module page · 128 lines · 5311 B

1// nx_f32_image_to_bmp.nx -- sovereign 24-bit BMP writer: f32 CHW RGB [0,1] -> a Windows-viewable .bmp file. 2// 3// The pipeline's missing last mile: every media path (image/video-frame/try-on/decode) ends in an f32 RGB 4// buffer that nothing turned into a viewable file. This writes a standard 24-bit BMP (BM header + BGR, 5// bottom-up, rows padded to 4B). f32->byte is done sovereignly (no f32->int intrinsic exists): clamp[0,1], 6// *255, +0.5, then 128..1 binary decomposition via nx_f32_lt. Gated by re-reading the written file. 7// license_tier: ORIGINAL 8import "nx_syscalls.nx" 9import "nx_le.nx" 10import "nx_f32.nx" 11import "nx_f32_div.nx" 12import "nx_f32_cvt.nx" 13const K_MAGIC_2835: i64 = 2835 14 15// f32 in [0,1] -> byte in [0,255] (clamped, rounded). No f32->int intrinsic; decompose the scaled value. 16func img_f32_to_byte(v: i64) -> i64 { 17 if (v & 0x80000000) != 0 { return 0 } // negative -> 0 18 var x: i64 = nx_f32_add(nx_f32_mul(v, nx_i32_to_f32(255)), 0x3F000000) // v*255 + 0.5 19 var b: i64 = 0 20 var p: i64 = 128 21 while p >= 1 { 22 let pf: i64 = nx_i32_to_f32(p) 23 if nx_f32_lt(x, pf) == 0 { // x >= p 24 x = nx_f32_sub(x, pf) 25 b = b + p 26 } 27 p = p / 2 28 } 29 if b > 255 { b = 255 } 30 return b 31} 32 33// rgb: f32 CHW [3,H,W] in [0,1]. Writes a 24-bit BMP to path. Returns 0 ok. 34func nx_f32_chw_to_bmp(rgb: *i64, H: i64, W: i64, path: *u8) -> i64 { 35 let plane: i64 = H * W 36 let row_bytes: i64 = W * 3 37 let pad: i64 = (4 - (row_bytes - (row_bytes / 4) * 4)) - (((4 - (row_bytes - (row_bytes / 4) * 4)) / 4) * 4) 38 let row_padded: i64 = row_bytes + pad 39 let img_size: i64 = row_padded * H 40 let file_size: i64 = 54 + img_size 41 42 let hdr: *u8 = sys_mmap(54) 43 hdr[0] = 0x42 // 'B' 44 hdr[1] = 0x4D // 'M' 45 nx_le_write_u32(hdr, 2, file_size) 46 nx_le_write_u32(hdr, 6, 0) 47 nx_le_write_u32(hdr, 10, 54) // pixel data offset 48 nx_le_write_u32(hdr, 14, 40) // info header size 49 nx_le_write_u32(hdr, 18, W) 50 nx_le_write_u32(hdr, 22, H) 51 nx_le_write_u16(hdr, 26, 1) // planes 52 nx_le_write_u16(hdr, 28, 24) // bpp 53 nx_le_write_u32(hdr, 30, 0) // compression = BI_RGB 54 nx_le_write_u32(hdr, 34, img_size) 55 nx_le_write_u32(hdr, 38, K_MAGIC_2835) // x pixels/meter (~72dpi) 56 nx_le_write_u32(hdr, 42, K_MAGIC_2835) 57 nx_le_write_u32(hdr, 46, 0) 58 nx_le_write_u32(hdr, 50, 0) 59 60 let body: *u8 = sys_mmap(img_size) 61 var y: i64 = 0 62 while y < H { 63 let src_y: i64 = H - 1 - y // BMP is bottom-up 64 var x: i64 = 0 65 while x < W { 66 let r: i64 = img_f32_to_byte(rgb[0 * plane + src_y * W + x]) 67 let g: i64 = img_f32_to_byte(rgb[1 * plane + src_y * W + x]) 68 let bl: i64 = img_f32_to_byte(rgb[2 * plane + src_y * W + x]) 69 let off: i64 = y * row_padded + x * 3 70 body[off] = bl // BGR order 71 body[off + 1] = g 72 body[off + 2] = r 73 x = x + 1 74 } 75 y = y + 1 76 } 77 78 let fd: i64 = sys_openat_wr(path, 0x1a4) 79 if fd < 0 { return 1 } 80 sys_write(fd, hdr, 54) 81 sys_write(fd, body, img_size) 82 sys_close(fd) 83 return 0 84} 85 86func main() -> i64 { 87 // gate: 2x2 known image -> write -> re-read, verify magic + size + a pixel. 88 let g: *i64 = sys_mmap(3 * 4 * 8) as *i64 89 let one: i64 = nx_i32_to_f32(1) 90 // pixel (0,0) pure red: R=1,G=0,B=0 91 g[0 * 4 + 0] = one; g[1 * 4 + 0] = 0; g[2 * 4 + 0] = 0 92 var i: i64 = 1 93 while i < 4 { g[0 * 4 + i] = 0; g[1 * 4 + i] = 0; g[2 * 4 + i] = 0; i = i + 1 } 94 if nx_f32_chw_to_bmp(g, 2, 2, "/tmp/nx_bmp_gate.bmp" as *u8) != 0 { return 10 } 95 // re-read: file should be 54 + row_padded(8)*2 = 70 bytes; magic 'BM'; bottom row first -> (src_y=1) is black, top row (0,0) red is at the SECOND row in file 96 let rfd: i64 = sys_openat_rd("/tmp/nx_bmp_gate.bmp" as *u8) 97 if rfd < 0 { return 11 } 98 let rb: *u8 = sys_mmap(128) 99 let n: i64 = sys_read(rfd, rb, 128) 100 sys_close(rfd) 101 if n != 70 { return 12 } 102 if rb[0] != 0x42 { return 13 } 103 if rb[1] != 0x4D { return 14 } 104 if nx_le_read_u32(rb, 2) != 70 { return 15 } 105 // top-left red pixel is in the LAST row of pixel data (bottom-up): row1 starts at 54+8=62; B,G,R = 0,0,255 106 if rb[62] != 0 { return 16 } 107 if rb[63] != 0 { return 17 } 108 if rb[64] != 255 { return 18 } 109 110 // deliverable: a real 160x120 gradient image the operator can open 111 let Wd: i64 = 160 112 let Hd: i64 = 120 113 let img: *i64 = sys_mmap(3 * Wd * Hd * 8) as *i64 114 let plane: i64 = Wd * Hd 115 var y: i64 = 0 116 while y < Hd { 117 var x: i64 = 0 118 while x < Wd { 119 img[0 * plane + y * Wd + x] = nx_f32_div(nx_i32_to_f32(x), nx_i32_to_f32(Wd - 1)) // R ramp ->x 120 img[1 * plane + y * Wd + x] = nx_f32_div(nx_i32_to_f32(y), nx_i32_to_f32(Hd - 1)) // G ramp ->y 121 img[2 * plane + y * Wd + x] = nx_f32_div(nx_i32_to_f32(1), nx_i32_to_f32(2)) // B = 0.5 122 x = x + 1 123 } 124 y = y + 1 125 } 126 if nx_f32_chw_to_bmp(img, Hd, Wd, "/mnt/c/Users/elder/nishi_first_image.bmp" as *u8) != 0 { return 20 } 127 return 0 128}