code wiki / (root) / nx_bmp_decode.nx

nx_bmp_decode.nx source

↩ module page · 138 lines · 5528 B

1// nx_bmp_decode.nx -- sovereign BMP READER (the 1990s Windows workhorse; the tree had only the 2// writer nx_bmp.nx). bmp_decode_rgb(raw,n,out_wh) -> w*h*3 packed RGB, TOP-DOWN row order. 3// Covers: BITMAPINFOHEADER (biSize>=40), bit depths 1/4/8 (palette), 24 (BGR), 32 (BGRX); 4// BI_RGB (0) for all depths + BI_RLE8 (1) for 8-bit (runs, absolute mode, EOL/EOD/delta escapes); 5// positive height = bottom-up (flipped here), negative = top-down. REFUSED (0 return, never a 6// wrong image): BITMAPCOREHEADER, BI_RLE4, BI_BITFIELDS, 16-bit. license_tier: ORIGINAL 7import "nx_syscalls.nx" 8const K_MAGIC_2147483648: i64 = 2147483648 9const K_MAGIC_4294967296: i64 = 4294967296 10const K_MAGIC_32767: i64 = 32767 11 12func bd_u16(b: *u8, o: i64) -> i64 { return (b[o] as i64) | ((b[o+1] as i64)<<8) } 13func bd_u32(b: *u8, o: i64) -> i64 { return (b[o] as i64) | ((b[o+1] as i64)<<8) | ((b[o+2] as i64)<<16) | ((b[o+3] as i64)<<24) } 14func bd_s32(b: *u8, o: i64) -> i64 { var v: i64=bd_u32(b,o); if v>=K_MAGIC_2147483648 { v=v-K_MAGIC_4294967296 } return v } 15 16func bmp_decode_rgb(raw: *u8, n: i64, out_wh: *i64) -> *u8 { 17 if n<54 { return 0 as *u8 } 18 if (raw[0] as i64)!=0x42 { return 0 as *u8 } 19 if (raw[1] as i64)!=0x4D { return 0 as *u8 } 20 let data_off: i64 = bd_u32(raw, 10) 21 let hsz: i64 = bd_u32(raw, 14) 22 if hsz<40 { return 0 as *u8 } 23 let w: i64 = bd_s32(raw, 18) 24 var h: i64 = bd_s32(raw, 22) 25 let bits: i64 = bd_u16(raw, 28) 26 let comp: i64 = bd_u32(raw, 30) 27 var clr_used: i64 = bd_u32(raw, 46) 28 if w<=0 { return 0 as *u8 } 29 var topdown: i64 = 0 30 if h<0 { topdown=1; h=0-h } 31 if h<=0 { return 0 as *u8 } 32 if w>K_MAGIC_32767 { return 0 as *u8 } 33 if h>K_MAGIC_32767 { return 0 as *u8 } 34 var depth_ok: i64 = 0 35 if bits==1 { depth_ok=1 } 36 if bits==4 { depth_ok=1 } 37 if bits==8 { depth_ok=1 } 38 if bits==24 { depth_ok=1 } 39 if bits==32 { depth_ok=1 } 40 if depth_ok==0 { return 0 as *u8 } 41 if comp!=0 { if comp!=1 { return 0 as *u8 } } 42 if comp==1 { if bits!=8 { return 0 as *u8 } } 43 // palette (BGRA quads) sits after the info header 44 let pal_off: i64 = 14 + hsz 45 var pal_n: i64 = 0 46 if bits<=8 { 47 pal_n = clr_used 48 if pal_n==0 { pal_n = 1<<bits } 49 if pal_off + pal_n*4 > n { return 0 as *u8 } 50 } 51 let npix: i64 = w*h 52 let rgb: *u8 = sys_mmap(npix*3+16) 53 if comp==1 { 54 // BI_RLE8: decode into an index plane in BOTTOM-UP coordinate space, 55 // then emit top-down through the palette. 56 let idxp: *u8 = sys_mmap(npix+16) 57 var x: i64=0 58 var y: i64=0 59 var p: i64=data_off 60 var run: i64=1 61 while run==1 { 62 if p+1>=n { run=0 } else { 63 let c0: i64 = raw[p] as i64 64 let c1: i64 = raw[p+1] as i64 65 p=p+2 66 if c0>0 { 67 var k: i64=0 68 while k<c0 { if x<w { if y<h { idxp[y*w+x]=c1 as u8 } } x=x+1; k=k+1 } 69 } else { 70 if c1==0 { x=0; y=y+1 } else { 71 if c1==1 { run=0 } else { 72 if c1==2 { if p+1<n { x=x+(raw[p] as i64); y=y+(raw[p+1] as i64); p=p+2 } else { run=0 } } else { 73 var k2: i64=0 74 while k2<c1 { if p<n { if x<w { if y<h { idxp[y*w+x]=raw[p] } } x=x+1; p=p+1 } k2=k2+1 } 75 if (c1%2)==1 { p=p+1 } 76 } } } 77 } 78 if y>h { run=0 } 79 } 80 } 81 var oy: i64=0 82 while oy<h { 83 var sy: i64=h-1-oy 84 if topdown==1 { sy=oy } 85 var ox: i64=0 86 while ox<w { 87 var ci: i64=idxp[sy*w+ox] as i64 88 if ci>=pal_n { ci=pal_n-1 } 89 let po: i64=pal_off+ci*4 90 rgb[(oy*w+ox)*3] =raw[po+2] 91 rgb[(oy*w+ox)*3+1]=raw[po+1] 92 rgb[(oy*w+ox)*3+2]=raw[po] 93 ox=ox+1 94 } 95 oy=oy+1 96 } 97 out_wh[0]=w; out_wh[1]=h 98 return rgb 99 } 100 // uncompressed paths: row stride padded to 4 bytes 101 let rowbits: i64 = w*bits 102 let stride: i64 = ((rowbits+31)/32)*4 103 if data_off + stride*h > n { return 0 as *u8 } 104 var oy2: i64=0 105 while oy2<h { 106 var sy2: i64=h-1-oy2 107 if topdown==1 { sy2=oy2 } 108 let ro: i64=data_off+sy2*stride 109 var ox2: i64=0 110 while ox2<w { 111 var rv: i64=0 112 var gv: i64=0 113 var bv: i64=0 114 if bits==24 { 115 let po2: i64=ro+ox2*3 116 bv=raw[po2] as i64; gv=raw[po2+1] as i64; rv=raw[po2+2] as i64 117 } else { if bits==32 { 118 let po3: i64=ro+ox2*4 119 bv=raw[po3] as i64; gv=raw[po3+1] as i64; rv=raw[po3+2] as i64 120 } else { 121 var ci2: i64=0 122 if bits==8 { ci2=raw[ro+ox2] as i64 } 123 if bits==4 { let bb4: i64=raw[ro+ox2/2] as i64; if (ox2%2)==0 { ci2=(bb4>>4)&15 } else { ci2=bb4&15 } } 124 if bits==1 { let bb1: i64=raw[ro+ox2/8] as i64; ci2=(bb1>>(7-(ox2%8)))&1 } 125 if ci2>=pal_n { ci2=pal_n-1 } 126 let po4: i64=pal_off+ci2*4 127 bv=raw[po4] as i64; gv=raw[po4+1] as i64; rv=raw[po4+2] as i64 128 } } 129 rgb[(oy2*w+ox2)*3] =rv as u8 130 rgb[(oy2*w+ox2)*3+1]=gv as u8 131 rgb[(oy2*w+ox2)*3+2]=bv as u8 132 ox2=ox2+1 133 } 134 oy2=oy2+1 135 } 136 out_wh[0]=w; out_wh[1]=h 137 return rgb 138}