code wiki / (root) / nx_webp_decode.nx

nx_webp_decode.nx source

↩ module page · 101 lines · 5303 B

1// nx_webp_decode.nx -- SOVEREIGN WebP decoder, built from the first byte up (operator 2026-07-29: 2// "build all the missing codecs... anything WebKit does and beyond"). 3// WHY IT MATTERS: Wikimedia CONTENT-NEGOTIATES and serves WebP under .png URLs, so with PNG/JPEG/GIF/ 4// BMP only, EVERY image on a wikipedia article decoded to nothing (measured: nsrc=11 spawn=6 dec=0). 5// WebP is not optional in 2026 — it is the default web image format. 6// 7// LAYER 1 (this file, LANDED): RIFF/WEBP container + VP8L header + chunk routing. Exposes exact 8// dimensions and the bitstream span, so the pipeline can size boxes and the KAT can prove the parse. 9// LAYER 2 (next): VP8L LOSSLESS pixel decode -- LSB-first bit reader, canonical prefix (Huffman) 10// code build, meta-prefix groups, colour cache, and the 4 transforms (predictor / colour / 11// subtract-green / colour-indexing). That is what these thumbnails use. 12// LAYER 3: VP8 LOSSY (boolean/arith decoder, DCT, prediction, loop filter) then VP8X/ALPH + animation. 13// ★NOTHING HERE FABRICATES PIXELS: until layer 2 lands, decode_rgb reports NOT-YET (0), never a 14// plausible-looking buffer -- a codec that guesses is worse than one that declines. 15import "nx_syscalls.nx" 16import "nx_webp_vp8l.nx" 17 18const NX_WEBP_OK: i64 = 0 19const NX_WEBP_NOT_WEBP: i64 = 1 20const NX_WEBP_TRUNCATED: i64 = 2 21const NX_WEBP_UNSUP: i64 = 3 // a WebP variant whose PIXEL decode is not built yet 22 23// out[0]=width out[1]=height out[2]=chunk-kind (0=VP8L lossless,1=VP8 lossy,2=VP8X extended) 24// out[3]=bitstream byte offset out[4]=bitstream length out[5]=alpha flag (VP8L) 25func nx_webp_parse(buf: *u8, len: i64, out: *i64) -> i64 { 26 var k: i64 = 0 27 while k < 8 { out[k] = 0; k = k + 1 } 28 if len < 20 { return NX_WEBP_TRUNCATED } 29 if (buf[0]&0xff) != 82 { return NX_WEBP_NOT_WEBP } // R 30 if (buf[1]&0xff) != 73 { return NX_WEBP_NOT_WEBP } // I 31 if (buf[2]&0xff) != 70 { return NX_WEBP_NOT_WEBP } // F 32 if (buf[3]&0xff) != 70 { return NX_WEBP_NOT_WEBP } // F 33 if (buf[8]&0xff) != 87 { return NX_WEBP_NOT_WEBP } // W 34 if (buf[9]&0xff) != 69 { return NX_WEBP_NOT_WEBP } // E 35 if (buf[10]&0xff) != 66 { return NX_WEBP_NOT_WEBP } // B 36 if (buf[11]&0xff) != 80 { return NX_WEBP_NOT_WEBP } // P 37 // fourth FourCC = the chunk: "VP8L" (lossless) / "VP8 " (lossy) / "VP8X" (extended) 38 let c0: i64 = buf[12]&0xff 39 let c1: i64 = buf[13]&0xff 40 let c2: i64 = buf[14]&0xff 41 let c3: i64 = buf[15]&0xff 42 let csz: i64 = (buf[16]&0xff) + ((buf[17]&0xff)*256) + ((buf[18]&0xff)*65536) + ((buf[19]&0xff)*16777216) 43 if c0 != 86 { return NX_WEBP_NOT_WEBP } // V 44 if c1 != 80 { return NX_WEBP_NOT_WEBP } // P 45 if c2 != 56 { return NX_WEBP_NOT_WEBP } // 8 46 if c3 == 76 { // 'L' -- VP8L LOSSLESS 47 if len < 26 { return NX_WEBP_TRUNCATED } 48 if (buf[20]&0xff) != 47 { return NX_WEBP_NOT_WEBP } // VP8L signature 0x2F 49 // header is LSB-first bit-packed: 14 bits (w-1), 14 bits (h-1), 1 bit alpha, 3 bits version 50 let b1: i64 = buf[21]&0xff 51 let b2: i64 = buf[22]&0xff 52 let b3: i64 = buf[23]&0xff 53 let b4: i64 = buf[24]&0xff 54 let bits: i64 = b1 + b2*256 + b3*65536 + b4*16777216 55 let w: i64 = (bits & 16383) + 1 56 let h: i64 = ((bits / 16384) & 16383) + 1 57 let alpha: i64 = (bits / 268435456) & 1 58 out[0] = w 59 out[1] = h 60 out[2] = 0 61 out[3] = 21 62 out[4] = csz - 1 63 out[5] = alpha 64 return NX_WEBP_OK 65 } 66 if c3 == 32 { // ' ' -- VP8 LOSSY 67 if len < 30 { return NX_WEBP_TRUNCATED } 68 // keyframe header: 3-byte frame tag, then start code 9D 01 2A, then 14-bit w / 14-bit h 69 if (buf[23]&0xff) != 157 { return NX_WEBP_UNSUP } 70 if (buf[24]&0xff) != 1 { return NX_WEBP_UNSUP } 71 if (buf[25]&0xff) != 42 { return NX_WEBP_UNSUP } 72 out[0] = ((buf[26]&0xff) + ((buf[27]&0xff)*256)) & 16383 73 out[1] = ((buf[28]&0xff) + ((buf[29]&0xff)*256)) & 16383 74 out[2] = 1 75 out[3] = 20 76 out[4] = csz 77 return NX_WEBP_OK 78 } 79 if c3 == 88 { // 'X' -- VP8X extended (canvas size only) 80 if len < 30 { return NX_WEBP_TRUNCATED } 81 out[0] = (buf[24]&0xff) + ((buf[25]&0xff)*256) + ((buf[26]&0xff)*65536) + 1 82 out[1] = (buf[27]&0xff) + ((buf[28]&0xff)*256) + ((buf[29]&0xff)*65536) + 1 83 out[2] = 2 84 out[3] = 20 85 out[4] = csz 86 return NX_WEBP_OK 87 } 88 return NX_WEBP_NOT_WEBP 89} 90 91// Pixel decode. Layer 2 lands VP8L here. Returns 0 (and sets no pixels) until then -- DECLINING is 92// correct; fabricating is not. The consumer already treats 0 as "no image" safely. 93func nx_webp_decode_rgb(buf: *u8, len: i64, wh: *i64) -> *u8 { 94 let info: *i64 = sys_mmap(64) as *i64 95 if nx_webp_parse(buf, len, info) != NX_WEBP_OK { return 0 as *u8 } 96 wh[0] = info[0] 97 wh[1] = info[1] 98 // VP8L LOSSLESS -> real pixels (layer 2). Other variants still DECLINE rather than fabricate. 99 if info[2] == 0 { return nx_vp8l_decode(buf, len, 20, info[0], info[1], wh) } 100 return 0 as *u8 101}