code wiki / (root) / nx_img_dims.nx

nx_img_dims.nx source

↩ module page · 85 lines · 5268 B

1// nx_img_dims.nx -- read an image's pixel WIDTH/HEIGHT straight from its header bytes (no decode). Powers the 2// media importer's junk filter: reject nav icons / spacer gifs / 1x1 tracking pixels by their REAL dimensions 3// (URL heuristics lie; header bytes don't). Handles PNG (IHDR), GIF (screen descriptor), JPEG (SOF marker walk), 4// and WEBP (VP8X extended / VP8 lossy / VP8L lossless). Unknown/short -> returns 0 (caller decides: we KEEP on 5// unknown so a novel format is never silently dropped). Integer-only, deterministic. license_tier: INDEPENDENT_REDERIVE 6import "nx_syscalls.nx" 7 8func _be16(b: *u8, o: i64) -> i64 { return ((b[o] as i64 & 0xff) << 8) | (b[o+1] as i64 & 0xff) } 9func _be32(b: *u8, o: i64) -> i64 { return ((b[o] as i64 & 0xff) << 24) | ((b[o+1] as i64 & 0xff) << 16) | ((b[o+2] as i64 & 0xff) << 8) | (b[o+3] as i64 & 0xff) } 10func _le16(b: *u8, o: i64) -> i64 { return (b[o] as i64 & 0xff) | ((b[o+1] as i64 & 0xff) << 8) } 11func _le24(b: *u8, o: i64) -> i64 { return (b[o] as i64 & 0xff) | ((b[o+1] as i64 & 0xff) << 8) | ((b[o+2] as i64 & 0xff) << 16) } 12 13// width into wh[0], height into wh[1]. returns 1 if parsed, 0 if unknown. 14func nx_img_dims(buf: *u8, n: i64, wh: *i64) -> i64 { 15 wh[0] = 0; wh[1] = 0 16 if n < 16 { return 0 } 17 let b0: i64 = buf[0] as i64 & 0xff 18 // ---- PNG: 89 50 4E 47 0D 0A 1A 0A, then len(4) "IHDR"(4) W(4) H(4) => W@16 H@20 ---- 19 if b0 == 0x89 { if (buf[1] as i64 & 0xff)==0x50 { if (buf[2] as i64 & 0xff)==0x4e { if (buf[3] as i64 & 0xff)==0x47 { 20 wh[0] = _be32(buf, 16); wh[1] = _be32(buf, 20); return 1 } } } } 21 // ---- GIF: "GIF8" then W(2 LE)@6 H(2 LE)@8 ---- 22 if b0 == 0x47 { if (buf[1] as i64 & 0xff)==0x49 { if (buf[2] as i64 & 0xff)==0x46 { if (buf[3] as i64 & 0xff)==0x38 { 23 wh[0] = _le16(buf, 6); wh[1] = _le16(buf, 8); return 1 } } } } 24 // ---- WEBP: "RIFF"....."WEBP" then a format chunk ---- 25 if b0 == 0x52 { if (buf[1] as i64 & 0xff)==0x49 { if (buf[2] as i64 & 0xff)==0x46 { if (buf[3] as i64 & 0xff)==0x46 { 26 if n >= 30 { if (buf[8] as i64 & 0xff)==0x57 { if (buf[9] as i64 & 0xff)==0x45 { // "WE" 27 let f3: i64 = buf[15] as i64 & 0xff // 4th char of the fourcc at 12..16 28 // VP8X (extended): "VP8X" -> canvas W-1 @24 (24 LE), H-1 @27 (24 LE) 29 if f3 == 0x58 { wh[0] = _le24(buf, 24) + 1; wh[1] = _le24(buf, 27) + 1; return 1 } 30 // VP8 (lossy) : "VP8 " -> after RIFF(4)+size(4)+WEBP(4)+VP8 (4)+chunksz(4)+frametag(3)+startcode(3) => W@26 H@28 (14 bits) 31 if f3 == 0x20 { wh[0] = _le16(buf, 26) & 0x3fff; wh[1] = _le16(buf, 28) & 0x3fff; return 1 } 32 // VP8L (lossless): "VP8L" -> sig 0x2f @20, then 14b W-1 then 14b H-1 33 if f3 == 0x4c { if (buf[20] as i64 & 0xff)==0x2f { 34 let bits0: i64 = _le32b(buf, 21) 35 wh[0] = (bits0 & 0x3fff) + 1 36 wh[1] = ((bits0 >> 14) & 0x3fff) + 1 37 return 1 } } 38 } } } 39 } } } } 40 // ---- JPEG: FF D8, walk markers to a SOF ---- 41 if b0 == 0xff { if (buf[1] as i64 & 0xff)==0xd8 { 42 var p: i64 = 2 43 while p + 9 < n { 44 if (buf[p] as i64 & 0xff) != 0xff { p = p + 1 } else { 45 let m: i64 = buf[p+1] as i64 & 0xff 46 if m == 0xd8 { p = p + 2 } else { 47 if m == 0xd9 { return 0 } 48 if m == 0x01 { p = p + 2 } else { 49 if m >= 0xd0 { if m <= 0xd7 { p = p + 2 } else { 50 // a segment with a length 51 var is_sof: i64 = 0 52 if m >= 0xc0 { if m <= 0xcf { if m != 0xc4 { if m != 0xc8 { if m != 0xcc { is_sof = 1 } } } } } 53 if is_sof == 1 { wh[1] = _be16(buf, p+5); wh[0] = _be16(buf, p+7); return 1 } 54 let seglen: i64 = _be16(buf, p+2) 55 if seglen < 2 { return 0 } 56 p = p + 2 + seglen 57 } } else { 58 var is_sof2: i64 = 0 59 if m >= 0xc0 { if m <= 0xcf { if m != 0xc4 { if m != 0xc8 { if m != 0xcc { is_sof2 = 1 } } } } } 60 if is_sof2 == 1 { wh[1] = _be16(buf, p+5); wh[0] = _be16(buf, p+7); return 1 } 61 let seglen2: i64 = _be16(buf, p+2) 62 if seglen2 < 2 { return 0 } 63 p = p + 2 + seglen2 64 } 65 } 66 } 67 } 68 } 69 return 0 70 } } 71 return 0 72} 73 74// little helper: 32-bit LE read (for VP8L bit unpack) 75func _le32b(b: *u8, o: i64) -> i64 { return (b[o] as i64 & 0xff) | ((b[o+1] as i64 & 0xff) << 8) | ((b[o+2] as i64 & 0xff) << 16) | ((b[o+3] as i64 & 0xff) << 24) } 76 77// convenience: the LONGER edge in pixels, or 0x7fffffff if unknown (so an unknown format is KEPT, not dropped). 78func nx_img_long_edge(buf: *u8, n: i64) -> i64 { 79 let wh: *i64 = sys_mmap(16) as *i64 80 if nx_img_dims(buf, n, wh) == 0 { return 0x7fffffff } 81 var mx: i64 = wh[0] 82 if wh[1] > mx { mx = wh[1] } 83 if mx <= 0 { return 0x7fffffff } // parsed as 0 (corrupt) -> don't use dims to drop 84 return mx 85}