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}