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}