code wiki / _hdl_build / nx_jpeg_color_write_gate.nx
nx_jpeg_color_write_gate.nx source
↩ module page · 146 lines · 8439 B
1// nx_jpeg_color_write_gate.nx -- SOVEREIGN gate for the baseline COLOR JFIF writer. Encodes a synthetic RGB
2// image to a real .jpg (/mnt/c/Users/elder/nishi_color_test.jpg), then validates WITHOUT python/3rd-party:
3// T1 SOI+EOI; T2 marker walk -> SOS + SOF0 dims + 3 components; T3 two DQT + DHT present; T4 entropy
4// round-trip (un-stuff, decode the interleaved Y/Cb/Cr MCUs with our own jbe_decode_block, dequant+IDCT,
5// YCbCr->RGB, reconstruct -> faithful); T5 the .jpg compresses below raw RGB; T6 file landed. GREEN iff 6/6.
6// license_tier: ORIGINAL
7import "nx_syscalls.nx"
8import "nx_gate_emit_lib.nx"
9import "nx_h264_bitwriter.nx"
10import "nx_dct8.nx"
11import "nx_quant_table.nx"
12import "nx_zigzag.nx"
13import "nx_jpeg_huff_enc.nx"
14import "nx_jpeg_block_enc.nx"
15import "nx_jpeg_write.nx"
16import "nx_jpeg_color_write.nx"
17
18func g_num(v: i64) -> i64 { let bb: *u8=sys_mmap(28); var m: i64=v; if m<0{m=0-m;sys_write(1,"-" as *u8,1)}; let t: *u8=sys_mmap(28); var k: i64=0; if m==0{t[0]=(48 as u8);k=1}; while m>0{t[k]=((48+(m%10)) as u8);m=m/10;k=k+1}; var i: i64=0; while i<k{bb[i]=t[k-1-i];i=i+1}; sys_write(1,bb,k); return 0 }
19func iabs(v: i64) -> i64 { if v<0 { return 0-v } return v }
20func clamp8(v: i64) -> i64 { if v<0 { return 0 } if v>255 { return 255 } return v }
21func u16b(b: *u8, o: i64) -> i64 { return ((b[o] as i64)<<8) | (b[o+1] as i64) }
22
23func main() -> i64 {
24 g_puts("=== JPEG COLOR WRITE GATE: sovereign baseline YCbCr JFIF -> real .jpg + round-trip ===\n" as *u8)
25 let W: i64=64; let H: i64=64; let npx: i64=W*H
26
27 // synthetic SMOOTH RGB (so lossy JPEG reconstructs faithfully): R ramps x, G ramps y, B diagonal
28 let rgb: *u8=sys_mmap(npx*3 + 16)
29 var y: i64=0
30 while y<H { var x: i64=0; while x<W {
31 let p: i64=(y*W+x)*3
32 rgb[p]=clamp8(x*4) as u8; rgb[p+1]=clamp8(y*4) as u8; rgb[p+2]=clamp8((x+y)*2) as u8
33 x=x+1 } y=y+1 }
34
35 // luma Huffman tables (shared by all components) + generated codes
36 let dcB: *i64=sys_mmap(20*8) as *i64; let dcV: *i64=sys_mmap(20*8) as *i64
37 let acB: *i64=sys_mmap(20*8) as *i64; let acV: *i64=sys_mmap(200*8) as *i64
38 let ndc: i64=jhe_dc_bits(dcB); jhe_dc_val(dcV); let nac: i64=jhe_ac_bits(acB); jhe_ac_val(acV)
39 let dcCO: *i64=sys_mmap(256*8) as *i64; let dcSI: *i64=sys_mmap(256*8) as *i64
40 let acCO: *i64=sys_mmap(256*8) as *i64; let acSI: *i64=sys_mmap(256*8) as *i64
41 jhe_gen(dcB, dcV, ndc, dcCO, dcSI); jhe_gen(acB, acV, nac, acCO, acSI)
42 let qtL: *i64=sys_mmap(64*8) as *i64; nx_qt_luma(qtL, 60)
43 let qtC: *i64=sys_mmap(64*8) as *i64; nx_qt_chroma(qtC, 60)
44 let to_zz: *i64=sys_mmap(64*8) as *i64; let from_zz: *i64=sys_mmap(64*8) as *i64; nx_zigzag_init(to_zz, from_zz)
45 let DM: *i64=sys_mmap(64*8) as *i64; nx_dct8_init(DM)
46 let scratch: *i64=sys_mmap(64*8) as *i64; let ti: *i64=sys_mmap(8*8) as *i64; let to: *i64=sys_mmap(8*8) as *i64
47
48 let out: *u8=sys_mmap(npx*4 + 8192)
49 let jlen: i64=jcw_write_color(out, W, H, rgb, qtL, qtC, dcB, dcV, acB, acV, dcCO, dcSI, acCO, acSI, to_zz, from_zz, DM, scratch, ti, to)
50
51 let fd: i64=sys_openat_wr("/mnt/c/Users/elder/nishi_color_test.jpg" as *u8, 0x1a4)
52 var wrote: i64=0
53 if fd>=0 { wrote=sys_write(fd, out, jlen); sys_close(fd) }
54
55 var t1: i64=0
56 if out[0]==(0xFF as u8) { if out[1]==(0xD8 as u8) { if out[jlen-2]==(0xFF as u8) { if out[jlen-1]==(0xD9 as u8) { t1=1 } } } }
57
58 // marker walk: count DQT, find SOF0 (dims + n_comp), reach SOS
59 var off: i64=2; var scan_start: i64=0; var sofW: i64=0; var sofH: i64=0; var sofNC: i64=0
60 var ndqt: i64=0; var have_dht: i64=0; var walking: i64=1
61 while walking==1 {
62 if off+4 > jlen { walking=0 } else {
63 if out[off]!=(0xFF as u8) { walking=0 } else {
64 let m: i64=out[off+1] as i64
65 if m==0xDA { let len: i64=u16b(out, off+2); scan_start=off+2+len; walking=0 } else {
66 let len: i64=u16b(out, off+2)
67 if m==0xDB { ndqt=ndqt+1 }
68 if m==0xC4 { have_dht=1 }
69 if m==0xC0 { sofH=u16b(out, off+5); sofW=u16b(out, off+7); sofNC=out[off+9] as i64 }
70 off=off+2+len
71 }
72 }
73 }
74 }
75 var t2: i64=0; if scan_start>0 { if sofW==W { if sofH==H { if sofNC==3 { t2=1 } } } }
76 var t3: i64=0; if ndqt==2 { if have_dht==1 { t3=1 } }
77
78 // un-stuff the entropy scan
79 let ebuf: *u8=sys_mmap(npx*4 + 1024)
80 var ip: i64=scan_start; var ep: i64=0; var scanning: i64=1
81 while scanning==1 {
82 if ip>=jlen { scanning=0 } else {
83 let b: i64=out[ip] as i64
84 if b==0xFF { let nb: i64=out[ip+1] as i64; if nb==0x00 { ebuf[ep]=0xFF as u8; ep=ep+1; ip=ip+2 } else { scanning=0 } }
85 else { ebuf[ep]=b as u8; ep=ep+1; ip=ip+1 }
86 }
87 }
88
89 // decode interleaved Y/Cb/Cr MCUs -> planes
90 let yP: *i64=sys_mmap(npx*8) as *i64; let cbP: *i64=sys_mmap(npx*8) as *i64; let crP: *i64=sys_mmap(npx*8) as *i64
91 let pos: *i64=sys_mmap(8) as *i64; pos[0]=0
92 let zz: *i64=sys_mmap(64*8) as *i64; let q: *i64=sys_mmap(64*8) as *i64
93 let co: *i64=sys_mmap(64*8) as *i64; let rsh: *i64=sys_mmap(64*8) as *i64
94 var pdY: i64=0; var pdCb: i64=0; var pdCr: i64=0
95 var by: i64=0
96 while by < H/8 {
97 var bx: i64=0
98 while bx < W/8 {
99 // Y (luma quant)
100 pdY=jbe_decode_block(ebuf, pos, dcCO, dcSI, acCO, acSI, pdY, zz); nx_zigzag_unscan(zz, from_zz, q)
101 var i: i64=0; while i<64 { co[i]=q[i]*qtL[i]; i=i+1 } nx_dct8_inverse_2d(DM, co, rsh, scratch, ti, to)
102 var r: i64=0; while r<8 { var c: i64=0; while c<8 { yP[(by*8+r)*W+(bx*8+c)]=clamp8(rsh[r*8+c]+128); c=c+1 } r=r+1 }
103 // Cb (chroma quant)
104 pdCb=jbe_decode_block(ebuf, pos, dcCO, dcSI, acCO, acSI, pdCb, zz); nx_zigzag_unscan(zz, from_zz, q)
105 i=0; while i<64 { co[i]=q[i]*qtC[i]; i=i+1 } nx_dct8_inverse_2d(DM, co, rsh, scratch, ti, to)
106 r=0; while r<8 { var c2: i64=0; while c2<8 { cbP[(by*8+r)*W+(bx*8+c2)]=clamp8(rsh[r*8+c2]+128); c2=c2+1 } r=r+1 }
107 // Cr (chroma quant)
108 pdCr=jbe_decode_block(ebuf, pos, dcCO, dcSI, acCO, acSI, pdCr, zz); nx_zigzag_unscan(zz, from_zz, q)
109 i=0; while i<64 { co[i]=q[i]*qtC[i]; i=i+1 } nx_dct8_inverse_2d(DM, co, rsh, scratch, ti, to)
110 r=0; while r<8 { var c3: i64=0; while c3<8 { crP[(by*8+r)*W+(bx*8+c3)]=clamp8(rsh[r*8+c3]+128); c3=c3+1 } r=r+1 }
111 bx=bx+1
112 }
113 by=by+1
114 }
115 // YCbCr -> RGB (integer inverse) + compare to source
116 var maxe: i64=0; var sume: i64=0
117 var pp: i64=0
118 while pp<npx {
119 let Y: i64=yP[pp]; let Cb: i64=cbP[pp]-128; let Cr: i64=crP[pp]-128
120 let R: i64=clamp8(Y + ((91881*Cr)>>16))
121 let G: i64=clamp8(Y - ((22554*Cb + 46802*Cr)>>16))
122 let B: i64=clamp8(Y + ((116130*Cb)>>16))
123 let er: i64=iabs(R-(rgb[pp*3] as i64)); let eg: i64=iabs(G-(rgb[pp*3+1] as i64)); let eb: i64=iabs(B-(rgb[pp*3+2] as i64))
124 if er>maxe {maxe=er} if eg>maxe {maxe=eg} if eb>maxe {maxe=eb}
125 sume=sume+er+eg+eb
126 pp=pp+1
127 }
128 let meane: i64=sume/(npx*3)
129 var t4: i64=0; if maxe <= 90 { if meane <= 20 { t4=1 } }
130 var t5: i64=0; if jlen < npx*3 { t5=1 }
131 var t6: i64=0; if wrote==jlen { if jlen>0 { t6=1 } }
132
133 g_puts("-- color .jpg " as *u8); g_num(W); g_puts("x" as *u8); g_num(H); g_puts(": " as *u8); g_num(jlen); g_puts("B vs raw RGB " as *u8); g_num(npx*3)
134 g_puts("B maxErr=" as *u8); g_num(maxe); g_puts(" meanErr=" as *u8); g_num(meane); g_puts(" ndqt=" as *u8); g_num(ndqt); g_puts(" -> /mnt/c/Users/elder/nishi_color_test.jpg\n" as *u8)
135
136 var pass: i64=0; let rows: i64=6
137 pass=pass+g_check(" T1 SOI + EOI framing" as *u8, t1)
138 pass=pass+g_check(" T2 marker walk -> SOS + SOF0 dims + 3 components" as *u8, t2)
139 pass=pass+g_check(" T3 two DQT (luma+chroma) + DHT present" as *u8, t3)
140 pass=pass+g_check(" T4 interleaved YCbCr round-trip faithful" as *u8, t4)
141 pass=pass+g_check(" T5 .jpg compresses below raw RGB" as *u8, t5)
142 pass=pass+g_check(" T6 file written to disk" as *u8, t6)
143 g_puts("----\nJCWRITE rows=" as *u8); g_num(rows); g_puts(" pass=" as *u8); g_num(pass); g_puts("\n" as *u8)
144 if pass==rows { g_puts("JCWRITE GREEN (sovereign color JPEG written + round-trip proven)\n" as *u8); sys_exit(0); return 0 }
145 g_puts("JCWRITE RED\n" as *u8); sys_exit(1); return 1
146}