code wiki / (root) / nx_png_write.nx

nx_png_write.nx source

↩ module page · 108 lines · 4716 B

1// nx_png_write.nx -- sovereign PNG ENCODER so the Nishi ecosystem can output a render that any viewer 2// (and Claude's image reader) can SEE -- closing the "can't inspect our own output" gap. 8-bit RGB, 3// filter 0, zlib stream carrying a REAL DEFLATE payload via nx_deflate_enc. 4// 5// ★2026-07-30 ADOPTION FIX, not a new feature. This writer emitted zlib STORED blocks and its own 6// header called a real DEFLATE pass "a perf rung" -- while `nx_deflate_enc.nx` (LZ77 + fixed Huffman, 7// round-trip verified against nx_deflate's inflate) sat in the SAME DIRECTORY, its header stating it 8// existed to "turn our uncompressed PNGs into real compressed ones so renders ship full-resolution". 9// The encoder was written FOR THIS CALLER and this caller never called it. Same class as the 10// seg-store leak: the capability existed, the leaf never adopted it. 11// Self-contained CRC-32 (IEEE) for chunks + Adler-32 over the RAW (pre-deflate) bytes per RFC 1950. 12// license_tier: ORIGINAL 13import "nx_syscalls.nx" 14import "nx_deflate_enc.nx" 15const K_MAGIC_65521: i64 = 65521 // Adler-32 modulus (RFC 1950), hoisted by the NAS magic campaign 16 17func pw_u32be(fd: i64, v: i64) -> i64 { 18 let b: *u8 = sys_mmap(4) 19 b[0]=((v>>24)&255) as u8; b[1]=((v>>16)&255) as u8; b[2]=((v>>8)&255) as u8; b[3]=(v&255) as u8 20 sys_write(fd, b, 4); return 0 21} 22// CRC-32 (IEEE) over buf[off..off+len), continuing from `crc` (NOT finalized). 23func pw_crc_block(crc: i64, buf: *u8, off: i64, len: i64) -> i64 { 24 var c: i64 = crc 25 var i: i64 = 0 26 while i < len { 27 c = c ^ (buf[off+i] & 0xff) 28 var k: i64 = 0 29 while k < 8 { 30 let m: i64 = c & 1 31 c = c >> 1 32 if m == 1 { c = c ^ 0xEDB88320 } 33 k = k + 1 34 } 35 i = i + 1 36 } 37 return c 38} 39func pw_adler32(buf: *u8, off: i64, len: i64) -> i64 { 40 var a: i64 = 1 41 var b: i64 = 0 42 var i: i64 = 0 43 while i < len { 44 a = (a + (buf[off+i] & 0xff)) % K_MAGIC_65521 45 b = (b + a) % K_MAGIC_65521 46 i = i + 1 47 } 48 return (b << 16) | a 49} 50// write a chunk (type 4 bytes + data) with length + CRC. 51func pw_chunk(fd: i64, typ: *u8, data: *u8, dlen: i64) -> i64 { 52 pw_u32be(fd, dlen) 53 sys_write(fd, typ, 4) 54 if dlen > 0 { sys_write(fd, data, dlen) } 55 var crc: i64 = pw_crc_block(0xFFFFFFFF, typ, 0, 4) 56 if dlen > 0 { crc = pw_crc_block(crc, data, 0, dlen) } 57 pw_u32be(fd, crc ^ 0xFFFFFFFF) 58 return 0 59} 60 61// Write an 8-bit RGB image (rgb = w*h*3 bytes, row-major top-down) as a PNG file. Returns 0 ok. 62func nx_png_write_rgb(path: *u8, rgb: *u8, w: i64, h: i64) -> i64 { 63 let fd: i64 = sys_openat_wr(path, 420) 64 if fd < 0 { return 0 - 1 } 65 // signature 66 let sig: *u8 = sys_mmap(8) 67 sig[0]=137 as u8; sig[1]=80 as u8; sig[2]=78 as u8; sig[3]=71 as u8; sig[4]=13 as u8; sig[5]=10 as u8; sig[6]=26 as u8; sig[7]=10 as u8 68 sys_write(fd, sig, 8) 69 // IHDR 70 let ihdr: *u8 = sys_mmap(13) 71 ihdr[0]=((w>>24)&255) as u8; ihdr[1]=((w>>16)&255) as u8; ihdr[2]=((w>>8)&255) as u8; ihdr[3]=(w&255) as u8 72 ihdr[4]=((h>>24)&255) as u8; ihdr[5]=((h>>16)&255) as u8; ihdr[6]=((h>>8)&255) as u8; ihdr[7]=(h&255) as u8 73 ihdr[8]=8 as u8 // bit depth 74 ihdr[9]=2 as u8 // color type 2 = truecolor RGB 75 ihdr[10]=0 as u8 // compression 76 ihdr[11]=0 as u8 // filter 77 ihdr[12]=0 as u8 // interlace 78 pw_chunk(fd, "IHDR\x00" as *u8, ihdr, 13) 79 // filtered scanlines: each row = filter(0) + w*3 RGB 80 let rowbytes: i64 = w * 3 81 let raw_len: i64 = h * (1 + rowbytes) 82 let raw: *u8 = sys_mmap(raw_len + 16) 83 var y: i64 = 0 84 var rp: i64 = 0 85 while y < h { 86 raw[rp] = 0 as u8; rp = rp + 1 87 var x: i64 = 0 88 let srow: i64 = y * rowbytes 89 while x < rowbytes { raw[rp] = rgb[srow + x]; rp = rp + 1; x = x + 1 } 90 y = y + 1 91 } 92 // zlib stream: 0x78 0x01 + REAL deflate payload + adler32(raw). 93 // Output bound is the encoder's documented contract -- fixed-Huffman EXPANDS high-entropy input 94 // (~1.30x worst case), so sizing this at raw_len+64 would overflow on noisy images. 95 let zcap: i64 = 2 + raw_len + (raw_len >> 1) + 64 + 4 96 let z: *u8 = sys_mmap(zcap + 16) 97 z[0]=0x78 as u8; z[1]=0x01 as u8 98 let dz: *u8 = (z as i64 + 2) as *u8 99 let zn: i64 = dfe_compress(raw, raw_len, dz) 100 if zn <= 0 { sys_close(fd); return 0 - 2 } 101 var zp: i64 = 2 + zn 102 let ad: i64 = pw_adler32(raw, 0, raw_len) 103 z[zp]=((ad>>24)&255) as u8; z[zp+1]=((ad>>16)&255) as u8; z[zp+2]=((ad>>8)&255) as u8; z[zp+3]=(ad&255) as u8; zp = zp + 4 104 pw_chunk(fd, "IDAT\x00" as *u8, z, zp) 105 pw_chunk(fd, "IEND\x00" as *u8, sig, 0) 106 sys_close(fd) 107 return 0 108}