code wiki / _hdl_build / nx_png_adam7_gate.nx

nx_png_adam7_gate.nx source

↩ module page · 273 lines · 11337 B

1// nx_png_adam7_gate.nx -- gate for C1 of the codec-chokepoint program (debt 1785903075): PNG Adam7 2// interlace decode, on top of the already-landed palette + sub-byte rungs. Fixtures are hand-built 3// byte-exact PNGs (zlib STORED blocks + real CRC32/adler32): an 8x8 RGB8 image and an 8x8 palette 4// 4-bit image, each written BOTH linear (il=0) and interlaced (il=1, the seven passes laid out by the 5// canonical tables). The interlaced decode must be byte-identical to the linear decode -- with a 6// wire-difference vacuity guard so the tooth cannot pass on two identical files. Inherits 7// nx_gate_verdict. license_tier: ORIGINAL expect_exit: 0 8import "nx_syscalls.nx" 9import "nx_gate_verdict.nx" 10import "nx_crc32.nx" 11import "nx_png_decoder.nx" 12import "nx_img_bytes_to_rgb.nx" 13 14func pa_adler(d: *u8, n: i64) -> i64 { 15 var a: i64=1 16 var b: i64=0 17 var i: i64=0 18 while i<n { a=(a+(d[i] as i64))%65521; b=(b+a)%65521; i=i+1 } 19 return b*65536+a 20} 21 22func pa_be32(out: *u8, o: i64, v: i64) -> i64 { 23 out[o]=((v>>24)&255) as u8; out[o+1]=((v>>16)&255) as u8 24 out[o+2]=((v>>8)&255) as u8; out[o+3]=(v&255) as u8 25 return o+4 26} 27 28// one PNG chunk: len BE + type + data + CRC32(type+data) 29func pa_chunk(out: *u8, o: i64, t0: i64, t1: i64, t2: i64, t3: i64, data: *u8, dlen: i64) -> i64 { 30 var p: i64=pa_be32(out, o, dlen) 31 out[p]=t0 as u8; out[p+1]=t1 as u8; out[p+2]=t2 as u8; out[p+3]=t3 as u8 32 p=p+4 33 var i: i64=0 34 while i<dlen { out[p+i]=data[i]; i=i+1 } 35 p=p+dlen 36 let crc: i64=nx_crc32((out as i64 + o + 4) as *u8, 4+dlen) 37 p=pa_be32(out, p, crc) 38 return p 39} 40 41// zlib wrap with one STORED deflate block (raw < 65536) 42func pa_zlib_store(out: *u8, raw: *u8, rawn: i64) -> i64 { 43 out[0]=0x78 as u8; out[1]=0x01 as u8 44 out[2]=0x01 as u8 45 out[3]=(rawn&255) as u8; out[4]=((rawn>>8)&255) as u8 46 let nl: i64=65535-rawn 47 out[5]=(nl&255) as u8; out[6]=((nl>>8)&255) as u8 48 var i: i64=0 49 while i<rawn { out[7+i]=raw[i]; i=i+1 } 50 let ad: i64=pa_adler(raw, rawn) 51 pa_be32(out, 7+rawn, ad) 52 return 7+rawn+4 53} 54 55// assemble a full PNG: sig + IHDR(w,h,bd,ct,il) + optional PLTE + IDAT(zdata) + IEND 56func pa_png(out: *u8, w: i64, h: i64, bd: i64, ct: i64, il: i64, 57 pal: *u8, paln: i64, zdata: *u8, zlen: i64) -> i64 { 58 out[0]=137 as u8; out[1]=80 as u8; out[2]=78 as u8; out[3]=71 as u8 59 out[4]=13 as u8; out[5]=10 as u8; out[6]=26 as u8; out[7]=10 as u8 60 var o: i64=8 61 let ihdr: *u8=sys_mmap(16) 62 pa_be32(ihdr, 0, w) 63 pa_be32(ihdr, 4, h) 64 ihdr[8]=bd as u8; ihdr[9]=ct as u8; ihdr[10]=0 as u8; ihdr[11]=0 as u8; ihdr[12]=il as u8 65 o=pa_chunk(out, o, 73, 72, 68, 82, ihdr, 13) 66 if paln>0 { o=pa_chunk(out, o, 80, 76, 84, 69, pal, paln*3) } 67 o=pa_chunk(out, o, 73, 68, 65, 84, zdata, zlen) 68 o=pa_chunk(out, o, 73, 69, 78, 68, 0 as *u8, 0) 69 return o 70} 71 72// Adam7 pass tables (must mirror the decoder's canonical tables) 73func pa_row0(p: i64) -> i64 { if p==0 {return 0} if p==1 {return 0} if p==2 {return 4} if p==3 {return 0} if p==4 {return 2} if p==5 {return 0} return 1 } 74func pa_col0(p: i64) -> i64 { if p==0 {return 0} if p==1 {return 4} if p==2 {return 0} if p==3 {return 2} if p==4 {return 0} if p==5 {return 1} return 0 } 75func pa_rowi(p: i64) -> i64 { if p==0 {return 8} if p==1 {return 8} if p==2 {return 8} if p==3 {return 4} if p==4 {return 4} if p==5 {return 2} return 2 } 76func pa_coli(p: i64) -> i64 { if p==0 {return 8} if p==1 {return 8} if p==2 {return 4} if p==3 {return 4} if p==4 {return 2} if p==5 {return 2} return 1 } 77 78// fixture pattern: RGB at (x,y) 79func pa_pr(x: i64, y: i64) -> i64 { return x*30+5 } 80func pa_pg(x: i64, y: i64) -> i64 { return y*30+7 } 81func pa_pb(x: i64, y: i64) -> i64 { return (x+y)*15+3 } 82// palette-index pattern at (x,y), 16 colours 83func pa_pidx(x: i64, y: i64) -> i64 { return (x*3+y*5)%16 } 84 85func main() -> i64 { 86 let ctr: *i64 = gv_ctr() 87 gv_head("nx_png_adam7_gate -- Adam7 interlace: RGB8 + palette-4bit, linear-equivalence + chokepoint" as *u8) 88 let W: i64=8 89 let H: i64=8 90 91 // ---------- fixture A: RGB8 ---------- 92 // linear raw: 8 rows of (filter0 + 24 bytes) 93 let rawA_lin: *u8=sys_mmap(1024) 94 var o1: i64=0 95 var y1: i64=0 96 while y1<H { 97 rawA_lin[o1]=0 as u8; o1=o1+1 98 var x1: i64=0 99 while x1<W { 100 rawA_lin[o1]=pa_pr(x1,y1) as u8; rawA_lin[o1+1]=pa_pg(x1,y1) as u8; rawA_lin[o1+2]=pa_pb(x1,y1) as u8 101 o1=o1+3 102 x1=x1+1 103 } 104 y1=y1+1 105 } 106 // interlaced raw: 7 passes, each row = filter0 + pass samples 107 let rawA_int: *u8=sys_mmap(1024) 108 var o2: i64=0 109 var p2: i64=0 110 while p2<7 { 111 let pw: i64=(W-pa_col0(p2)+pa_coli(p2)-1)/pa_coli(p2) 112 let ph: i64=(H-pa_row0(p2)+pa_rowi(p2)-1)/pa_rowi(p2) 113 if pw>0 { if ph>0 { 114 var sy: i64=0 115 while sy<ph { 116 rawA_int[o2]=0 as u8; o2=o2+1 117 let yy: i64=pa_row0(p2)+sy*pa_rowi(p2) 118 var sx: i64=0 119 while sx<pw { 120 let xx: i64=pa_col0(p2)+sx*pa_coli(p2) 121 rawA_int[o2]=pa_pr(xx,yy) as u8; rawA_int[o2+1]=pa_pg(xx,yy) as u8; rawA_int[o2+2]=pa_pb(xx,yy) as u8 122 o2=o2+3 123 sx=sx+1 124 } 125 sy=sy+1 126 } 127 } } 128 p2=p2+1 129 } 130 let zA_lin: *u8=sys_mmap(2048) 131 let zA_int: *u8=sys_mmap(2048) 132 let zlA: i64=pa_zlib_store(zA_lin, rawA_lin, o1) 133 let ziA: i64=pa_zlib_store(zA_int, rawA_int, o2) 134 let pngA_lin: *u8=sys_mmap(4096) 135 let pngA_int: *u8=sys_mmap(4096) 136 let lenA_lin: i64=pa_png(pngA_lin, W, H, 8, 2, 0, 0 as *u8, 0, zA_lin, zlA) 137 let lenA_int: i64=pa_png(pngA_int, W, H, 8, 2, 1, 0 as *u8, 0, zA_int, ziA) 138 139 // T1 linear RGB8 decodes with the exact pattern (control row) 140 let rA1: *NxPngResult=nx_png_decode(pngA_lin, lenA_lin) 141 var t1: i64=0 142 if rA1.error_code==0 { if rA1.n_channels==3 { 143 var ok1: i64=1 144 var ky: i64=0 145 while ky<H { 146 var kx: i64=0 147 while kx<W { 148 let ko: i64=(ky*W+kx)*3 149 if (rA1.pixels[ko] as i64)!=pa_pr(kx,ky) { ok1=0 } 150 if (rA1.pixels[ko+1] as i64)!=pa_pg(kx,ky) { ok1=0 } 151 if (rA1.pixels[ko+2] as i64)!=pa_pb(kx,ky) { ok1=0 } 152 kx=kx+1 153 } 154 ky=ky+1 155 } 156 t1=ok1 157 } } 158 gv_check("T1 linear RGB8 control decodes exact pattern" as *u8, t1, ctr) 159 160 // T2 interlaced RGB8 decodes BYTE-IDENTICAL to linear (files differ on wire) 161 var wire_differA: i64=0 162 if lenA_lin!=lenA_int { wire_differA=1 } else { 163 var dA: i64=0 164 while dA<lenA_lin { if pngA_lin[dA]!=pngA_int[dA] { wire_differA=1; dA=lenA_lin } else { dA=dA+1 } } 165 } 166 let rA2: *NxPngResult=nx_png_decode(pngA_int, lenA_int) 167 var t2: i64=0 168 if rA2.error_code==0 { if wire_differA==1 { if rA2.pixels_size==rA1.pixels_size { 169 var same2: i64=1 170 var q2: i64=0 171 while q2<rA1.pixels_size { if rA1.pixels[q2]!=rA2.pixels[q2] { same2=0; q2=rA1.pixels_size } else { q2=q2+1 } } 172 t2=same2 173 } } } 174 gv_check("T2 Adam7 RGB8 decode identical to linear (wire differs)" as *u8, t2, ctr) 175 176 // ---------- fixture B: palette 4-bit ---------- 177 let palB: *u8=sys_mmap(64) 178 var pi: i64=0 179 while pi<16 { palB[pi*3]=(pi*16+3) as u8; palB[pi*3+1]=(250-pi*16) as u8; palB[pi*3+2]=(pi*8+1) as u8; pi=pi+1 } 180 // linear raw: rows of filter0 + 4 packed bytes (8 px, 2/byte) 181 let rawB_lin: *u8=sys_mmap(1024) 182 var o3: i64=0 183 var y3: i64=0 184 while y3<H { 185 rawB_lin[o3]=0 as u8; o3=o3+1 186 var x3: i64=0 187 while x3<W { 188 let hi: i64=pa_pidx(x3,y3) 189 let lo: i64=pa_pidx(x3+1,y3) 190 rawB_lin[o3]=((hi<<4)|lo) as u8 191 o3=o3+1 192 x3=x3+2 193 } 194 y3=y3+1 195 } 196 // interlaced raw: per-pass rows, 4-bit packed per pass row (pad last nibble) 197 let rawB_int: *u8=sys_mmap(1024) 198 var o4: i64=0 199 var p4: i64=0 200 while p4<7 { 201 let pw4: i64=(W-pa_col0(p4)+pa_coli(p4)-1)/pa_coli(p4) 202 let ph4: i64=(H-pa_row0(p4)+pa_rowi(p4)-1)/pa_rowi(p4) 203 if pw4>0 { if ph4>0 { 204 var sy4: i64=0 205 while sy4<ph4 { 206 rawB_int[o4]=0 as u8; o4=o4+1 207 let yy4: i64=pa_row0(p4)+sy4*pa_rowi(p4) 208 var acc: i64=0 209 var nacc: i64=0 210 var sx4: i64=0 211 while sx4<pw4 { 212 let xx4: i64=pa_col0(p4)+sx4*pa_coli(p4) 213 acc=(acc<<4)|pa_pidx(xx4,yy4) 214 nacc=nacc+1 215 if nacc==2 { rawB_int[o4]=acc as u8; o4=o4+1; acc=0; nacc=0 } 216 sx4=sx4+1 217 } 218 if nacc==1 { rawB_int[o4]=(acc<<4) as u8; o4=o4+1 } 219 sy4=sy4+1 220 } 221 } } 222 p4=p4+1 223 } 224 let zB_lin: *u8=sys_mmap(2048) 225 let zB_int: *u8=sys_mmap(2048) 226 let zlB: i64=pa_zlib_store(zB_lin, rawB_lin, o3) 227 let ziB: i64=pa_zlib_store(zB_int, rawB_int, o4) 228 let pngB_lin: *u8=sys_mmap(4096) 229 let pngB_int: *u8=sys_mmap(4096) 230 let lenB_lin: i64=pa_png(pngB_lin, W, H, 4, 3, 0, palB, 16, zB_lin, zlB) 231 let lenB_int: i64=pa_png(pngB_int, W, H, 4, 3, 1, palB, 16, zB_int, ziB) 232 233 // T3 palette-4bit: interlaced decode identical to linear + exact PLTE colour KAT 234 let rB1: *NxPngResult=nx_png_decode(pngB_lin, lenB_lin) 235 let rB2: *NxPngResult=nx_png_decode(pngB_int, lenB_int) 236 var t3: i64=0 237 if rB1.error_code==0 { if rB2.error_code==0 { if rB1.n_channels==3 { if rB1.pixels_size==rB2.pixels_size { 238 var same3: i64=1 239 var q3: i64=0 240 while q3<rB1.pixels_size { if rB1.pixels[q3]!=rB2.pixels[q3] { same3=0; q3=rB1.pixels_size } else { q3=q3+1 } } 241 // KAT: (1,0) has idx=(3)%16=3 -> pal[3]=(51,202,25) 242 if (rB1.pixels[3] as i64)!=51 { same3=0 } 243 if (rB1.pixels[4] as i64)!=202 { same3=0 } 244 if (rB1.pixels[5] as i64)!=25 { same3=0 } 245 t3=same3 246 } } } } 247 gv_check("T3 Adam7 palette-4bit decode identical to linear + PLTE KAT" as *u8, t3, ctr) 248 249 // T4 BITE: truncated interlaced IDAT refused; intact file decodes 250 let zBad: *u8=sys_mmap(2048) 251 let zbLen: i64=pa_zlib_store(zBad, rawA_int, o2-4) 252 let pngBad: *u8=sys_mmap(4096) 253 let lenBad: i64=pa_png(pngBad, W, H, 8, 2, 1, 0 as *u8, 0, zBad, zbLen) 254 let rBad: *NxPngResult=nx_png_decode(pngBad, lenBad) 255 var bite_bad: i64=0 256 if rBad.error_code!=0 { bite_bad=1 } 257 var bite_good: i64=0 258 if rA2.error_code!=0 { bite_good=1 } 259 gv_bite("T4 truncated Adam7 stream refusal" as *u8, bite_bad, bite_good, ctr) 260 261 // T5 the CHOKEPOINT decodes an interlaced PNG (browser/reader/search inherit) 262 let wh5: *i64=sys_mmap(32) as *i64 263 let ck5: *u8=nx_img_bytes_to_rgb(pngA_int, lenA_int, wh5) 264 var t5: i64=0 265 if ck5!=(0 as *u8) { if wh5[0]==W { if wh5[1]==H { 266 if (ck5[0] as i64)==pa_pr(0,0) { if (ck5[1] as i64)==pa_pg(0,0) { if (ck5[2] as i64)==pa_pb(0,0) { t5=1 } } } 267 } } } 268 gv_check("T5 chokepoint nx_img_bytes_to_rgb decodes interlaced PNG" as *u8, t5, ctr) 269 270 let rc: i64 = gv_verdict("PNG-ADAM7-GATE" as *u8, ctr, "Adam7 RGB8 + palette-4bit linear-equivalent, chokepoint inherits" as *u8) 271 sys_exit(rc) 272 return rc 273}