code wiki / (root) / nx_img_bytes_to_rgb.nx

nx_img_bytes_to_rgb.nx source

↩ module page · 226 lines · 9633 B

1// nx_img_bytes_to_rgb.nx -- decode an IN-MEMORY encoded image buffer -> interleaved 8-bit RGB (w*h*3, 2// row-major). THE single decode chokepoint: the bytes-in core shared by nx_img_to_rgb (path variant), 3// the Windows GUI (read_local + this), the reader/tiler, and -- via the nx_image_gray projection -- 4// the whole reverse-image search plane. FORMAT ROSTER (2026-08-05, each gate-proven): JPEG (baseline + 5// progressive + DRI/RST restart markers) · GIF87a/89a (palette colour, de-interlaced, first frame) · 6// WebP VP8L lossless (lossy VP8 refuses -- C3 pending) · BMP (BI_RGB 1/4/8/24/32 + RLE8, both row 7// orders) · TIFF (baseline strips, none+PackBits, gray/RGB/palette, LE+BE) · PNG (all colour types 8// incl palette, sub-byte depths, Adam7 interlace; 16-bit high byte) . TGA (types 1/2/3 + RLE 9/10/11, 9// origin bit honoured) . PCX (8-bit palette, 24-bit planar, 1-bit) . ICO/CUR (largest frame; DIB or 10// PNG body) . PNM P1-P6. Returns the rgb buffer + sets 11// out_wh[0]=w, out_wh[1]=h; returns 0 on failure/unsupported -- NEVER a wrong image. license_tier: ORIGINAL 12import "nx_syscalls.nx" 13import "nx_png_decoder.nx" 14import "nx_jpeg_ascii.nx" 15import "nx_gif_decode.nx" 16import "nx_webp.nx" // webp_decode: VP8L LOSSLESS only (lossy VP8 returns 0) 17import "nx_bmp_decode.nx" // bmp_decode_rgb: BI_RGB 1/4/8/24/32 + RLE8 (2026-08-05) 18import "nx_tiff_decode.nx" // tiff_decode_rgb: baseline strips, none+PackBits (2026-08-05) 19import "nx_tga_decode.nx" // tga_decode_rgb: types 1/2/3 + RLE 9/10/11 (2026-08-05) 20import "nx_pcx_decode.nx" // pcx_decode_rgb: 8-bit palette, 24-bit planar, 1-bit (2026-08-05) 21import "nx_ico_decode.nx" // ico_decode_rgb: largest frame, DIB or PNG body (2026-08-05) 22import "nx_pnm_decode.nx" // pnm_decode_rgb: P1-P6 netpbm (2026-08-05) 23 24// 4-byte tag compare, kept local so the chokepoint does not pull in the 52KB sniffer module. 25func ib_fourcc(b: *u8, off: i64, a: i64, c: i64, d: i64, e: i64) -> i64 { 26 if (b[off] as i64) != a { return 0 } 27 if (b[off+1] as i64) != c { return 0 } 28 if (b[off+2] as i64) != d { return 0 } 29 if (b[off+3] as i64) != e { return 0 } 30 return 1 31} 32 33func nx_img_bytes_to_rgb(raw: *u8, rawlen: i64, out_wh: *i64) -> *u8 { 34 if raw==(0 as *u8) { return 0 as *u8 } 35 // JPEG (magic FF D8 FF) -> sovereign baseline decoder -> packed w*h*3 RGB (YCbCr->RGB inside). 36 if rawlen>=3 { if raw[0]==(255 as u8) { if raw[1]==(216 as u8) { if raw[2]==(255 as u8) { 37 let jr: *i64=sys_mmap(8) as *i64 38 let jw: *i64=sys_mmap(8) as *i64 39 let jh: *i64=sys_mmap(8) as *i64 40 if nx_jpeg_decode_rgb(raw, rawlen, jr, jw, jh)!=0 { return 0 as *u8 } 41 out_wh[0]=jw[0]; out_wh[1]=jh[0] 42 return jr[0] as *u8 43 } } } } 44 // GIF87a/89a (magic "GIF8") -> sovereign LZW decoder, palette COLOR + de-interlaced 45 // (gif_decode_rgb). The old path collapsed to grayscale (R=G=B expand) and left 46 // interlaced rows in pass order -- color and row order both survive now. 47 if rawlen>=6 { if raw[0]==(71 as u8) { if raw[1]==(73 as u8) { if raw[2]==(70 as u8) { if raw[3]==(56 as u8) { 48 let gwh: *i64=sys_mmap(32) as *i64 49 gwh[0]=0 50 gwh[1]=0 51 let grgb: *u8=gif_decode_rgb(raw, rawlen, gwh) 52 if grgb==(0 as *u8) { return 0 as *u8 } 53 if gwh[0]<=0 { return 0 as *u8 } 54 if gwh[1]<=0 { return 0 as *u8 } 55 out_wh[0]=gwh[0]; out_wh[1]=gwh[1] 56 return grgb 57 } } } } } 58 59 // WebP: RIFF....WEBP. webp_decode handles the VP8L LOSSLESS variant and returns ARGB as one i64 60 // per pixel; lossy VP8 returns 0 and we fall through to an honest failure rather than a wrong image. 61 // The decoder and its gates existed all along with no image-path caller -- this is the wiring. 62 var iswebp: i64 = 0 63 if rawlen >= 16 { if ib_fourcc(raw,0,82,73,70,70) == 1 { if ib_fourcc(raw,8,87,69,66,80) == 1 { iswebp = 1 } } } 64 if iswebp == 1 { 65 let wwh: *i64 = sys_mmap(32) as *i64 66 wwh[0]=0 67 wwh[1]=0 68 let argb: *i64 = webp_decode(raw, rawlen, wwh) 69 if argb == (0 as *i64) { return 0 as *u8 } 70 let ww: i64 = wwh[0] 71 let wh2: i64 = wwh[1] 72 if ww <= 0 { return 0 as *u8 } 73 if wh2 <= 0 { return 0 as *u8 } 74 let wrgb: *u8 = sys_mmap(ww*wh2*3+16) 75 var wi: i64 = 0 76 while wi < ww*wh2 { 77 let px: i64 = argb[wi] 78 wrgb[wi*3] = ((px>>16)&255) as u8 79 wrgb[wi*3+1] = ((px>>8)&255) as u8 80 wrgb[wi*3+2] = (px&255) as u8 81 wi = wi + 1 82 } 83 out_wh[0]=ww; out_wh[1]=wh2 84 return wrgb 85 } 86 87 // BMP ('BM'): the 1990s Windows bitmap -- reader added 2026-08-05 (the tree 88 // had only the writer). Refusals inside the decoder return 0 -> honest fail. 89 if rawlen>=54 { if raw[0]==(66 as u8) { if raw[1]==(77 as u8) { 90 let bwh: *i64=sys_mmap(32) as *i64 91 bwh[0]=0 92 bwh[1]=0 93 let brgb: *u8=bmp_decode_rgb(raw, rawlen, bwh) 94 if brgb==(0 as *u8) { return 0 as *u8 } 95 if bwh[0]<=0 { return 0 as *u8 } 96 if bwh[1]<=0 { return 0 as *u8 } 97 out_wh[0]=bwh[0]; out_wh[1]=bwh[1] 98 return brgb 99 } } } 100 // TIFF (II*\0 / MM\0*): baseline reader added 2026-08-05. 101 var istiff: i64 = 0 102 if rawlen>=8 { 103 if raw[0]==(73 as u8) { if raw[1]==(73 as u8) { if raw[2]==(42 as u8) { if raw[3]==(0 as u8) { istiff=1 } } } } 104 if raw[0]==(77 as u8) { if raw[1]==(77 as u8) { if raw[2]==(0 as u8) { if raw[3]==(42 as u8) { istiff=1 } } } } 105 } 106 if istiff==1 { 107 let twh: *i64=sys_mmap(32) as *i64 108 twh[0]=0 109 twh[1]=0 110 let trgb: *u8=tiff_decode_rgb(raw, rawlen, twh) 111 if trgb==(0 as *u8) { return 0 as *u8 } 112 if twh[0]<=0 { return 0 as *u8 } 113 if twh[1]<=0 { return 0 as *u8 } 114 out_wh[0]=twh[0]; out_wh[1]=twh[1] 115 return trgb 116 } 117 // ---- 1990s roster (added 2026-08-05). Each sniff is a MAGIC test, never an 118 // extension test: the chokepoint receives bytes, not filenames. ICO/PNM/PCX 119 // carry distinctive magic; TGA has NONE, so it is deliberately LAST and is 120 // accepted only when its header fields are self-consistent. 121 // ICO/CUR: 00 00 <01|02> 00 <count> 122 if rawlen>=22 { if raw[0]==(0 as u8) { if raw[1]==(0 as u8) { if raw[3]==(0 as u8) { 123 var icok: i64 = 0 124 if raw[2]==(1 as u8) { icok = 1 } 125 if raw[2]==(2 as u8) { icok = 1 } 126 if icok == 1 { 127 let iwh: *i64=sys_mmap(32) as *i64 128 iwh[0]=0 129 iwh[1]=0 130 let irgb: *u8=ico_decode_rgb(raw, rawlen, iwh) 131 if irgb!=(0 as *u8) { if iwh[0]>0 { if iwh[1]>0 { 132 out_wh[0]=iwh[0]; out_wh[1]=iwh[1] 133 return irgb 134 } } } 135 } 136 } } } } 137 // PCX: manufacturer 0x0A, encoding 0x01 at offset 2 138 if rawlen>=129 { if raw[0]==(10 as u8) { if raw[2]==(1 as u8) { 139 let cwh: *i64=sys_mmap(32) as *i64 140 cwh[0]=0 141 cwh[1]=0 142 let crgb: *u8=pcx_decode_rgb(raw, rawlen, cwh) 143 if crgb!=(0 as *u8) { if cwh[0]>0 { if cwh[1]>0 { 144 out_wh[0]=cwh[0]; out_wh[1]=cwh[1] 145 return crgb 146 } } } 147 } } } 148 // PNM: 'P' followed by '1'..'6' 149 if rawlen>=8 { if raw[0]==(80 as u8) { if raw[1]>=(49 as u8) { if raw[1]<=(54 as u8) { 150 let nwh: *i64=sys_mmap(32) as *i64 151 nwh[0]=0 152 nwh[1]=0 153 let nrgb: *u8=pnm_decode_rgb(raw, rawlen, nwh) 154 if nrgb!=(0 as *u8) { if nwh[0]>0 { if nwh[1]>0 { 155 out_wh[0]=nwh[0]; out_wh[1]=nwh[1] 156 return nrgb 157 } } } 158 } } } } 159 // TGA is MAGICLESS -- it must be tried last, and only when the header is 160 // self-consistent (known image type + a colour-map byte that is 0 or 1). 161 if rawlen>=18 { 162 let tt: i64 = (raw[2] as i64) & 255 163 let tc: i64 = (raw[1] as i64) & 255 164 var tok: i64 = 0 165 if tc <= 1 { 166 if tt==1 { tok=1 } 167 if tt==2 { tok=1 } 168 if tt==3 { tok=1 } 169 if tt==9 { tok=1 } 170 if tt==10 { tok=1 } 171 if tt==11 { tok=1 } 172 } 173 if tok == 1 { 174 let twh2: *i64=sys_mmap(32) as *i64 175 twh2[0]=0 176 twh2[1]=0 177 let trgb2: *u8=tga_decode_rgb(raw, rawlen, twh2) 178 if trgb2!=(0 as *u8) { if twh2[0]>0 { if twh2[1]>0 { 179 out_wh[0]=twh2[0]; out_wh[1]=twh2[1] 180 return trgb2 181 } } } 182 } 183 } 184 let res: *NxPngResult=nx_png_decode(raw, rawlen) 185 if res==(0 as *NxPngResult) { return 0 as *u8 } 186 if res.error_code!=0 { return 0 as *u8 } 187 if res.header==(0 as *NxPngHeader) { return 0 as *u8 } 188 let w: i64=res.header.width 189 let h: i64=res.header.height 190 if w<=0 { return 0 as *u8 } 191 if h<=0 { return 0 as *u8 } 192 let ch: i64=res.n_channels 193 let bpp: i64=res.bytes_per_pix 194 var bps: i64=1 195 if ch>0 { bps=bpp/ch } 196 if bps<1 { bps=1 } 197 let px: *u8=res.pixels 198 let rgb: *u8=sys_mmap(w*h*3) 199 var y: i64=0 200 while y<h { 201 var x: i64=0 202 while x<w { 203 let base: i64=(y*w+x)*bpp 204 var r: i64=0 205 var g: i64=0 206 var b: i64=0 207 if ch>=3 { 208 r=px[base] as i64 209 g=px[base+bps] as i64 210 b=px[base+2*bps] as i64 211 } else { 212 r=px[base] as i64 213 g=r 214 b=r 215 } 216 let o: i64=(y*w+x)*3 217 rgb[o]=r as u8 218 rgb[o+1]=g as u8 219 rgb[o+2]=b as u8 220 x=x+1 221 } 222 y=y+1 223 } 224 out_wh[0]=w; out_wh[1]=h 225 return rgb 226}