code wiki / (root) / nx_ppm.nx

nx_ppm.nx source

↩ module page · 86 lines · 2847 B

1// nx_ppm.nx -- binary PPM (P6) read/write, so organs can ingest and emit REAL 2// image files instead of only synthetic in-memory pixels. The exposure 3// substrate for the MEDIA-STUDIO arc (and reusable by reader/imagegen). 4// 5// P6 = "P6\n<width> <height>\n<maxval>\n<raw RGB bytes>". Comments (#) are not 6// supported (sufficient for files we generate). Pure i64 + syscalls. 7// 8// genealogy_id: netpbm_ppm_p6 (record-hint) 9// lineage_id: ascii_header_parse + raw_rgb_blit 10// license_tier: ORIGINAL 11 12import "syscalls.nx" 13import "nx_image.nx" 14 15func ppm_is_ws(c: i64) -> i64 { 16 if c == 32 { return 1 } 17 if c == 10 { return 1 } 18 if c == 13 { return 1 } 19 if c == 9 { return 1 } 20 return 0 21} 22func ppm_skip_ws(buf: *u8, len: i64, pos: i64) -> i64 { 23 var p: i64 = pos 24 while p < len && ppm_is_ws(buf[p] as i64) == 1 { p = p + 1 } 25 return p 26} 27func ppm_read_int(buf: *u8, len: i64, posptr: *i64) -> i64 { 28 var p: i64 = ppm_skip_ws(buf, len, posptr[0]) 29 var v: i64 = 0 30 while p < len && (buf[p] as i64) >= 48 && (buf[p] as i64) <= 57 { 31 v = v * 10 + ((buf[p] as i64) - 48) 32 p = p + 1 33 } 34 posptr[0] = p 35 return v 36} 37 38// Parse a binary PPM (P6). Returns a fresh RGB *Image, or 0 on bad magic. 39func ppm_parse(buf: *u8, len: i64) -> *Image { 40 if len < 2 { return 0 as *Image } 41 if (buf[0] as i64) != 80 { return 0 as *Image } // 'P' 42 if (buf[1] as i64) != 54 { return 0 as *Image } // '6' 43 let pos: *i64 = sys_mmap(8) as *i64 44 pos[0] = 2 45 let w: i64 = ppm_read_int(buf, len, pos) 46 let h: i64 = ppm_read_int(buf, len, pos) 47 let mx: i64 = ppm_read_int(buf, len, pos) 48 var p: i64 = pos[0] + 1 // single whitespace after maxval, then data 49 if w <= 0 { return 0 as *Image } 50 if h <= 0 { return 0 as *Image } 51 let img: *Image = nx_image_alloc(w, h, 3) 52 let need: i64 = w * h * 3 53 var i: i64 = 0 54 while i < need && (p + i) < len { 55 img.pixels[i] = buf[p + i] 56 i = i + 1 57 } 58 return img 59} 60 61func ppm_wr_int(fd: i64, v: i64) -> i64 { 62 let t: *u8 = sys_mmap(28) 63 var m: i64 = v 64 var k: i64 = 0 65 if m == 0 { t[0] = 48 as u8; k = 1 } 66 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 67 let bb: *u8 = sys_mmap(28) 68 var i: i64 = 0 69 while i < k { bb[i] = t[k - 1 - i]; i = i + 1 } 70 sys_write(fd, bb, k) 71 return 0 72} 73 74// Write an RGB *Image as a binary PPM to `path`. Returns 0 ok / -1 fail. 75func ppm_write(img: *Image, path: *u8) -> i64 { 76 let fd: i64 = sys_openat_wr(path, 420) 77 if fd < 0 { return 0 - 1 } 78 sys_write(fd, "P6\n\x00" as *u8, 3) 79 ppm_wr_int(fd, img.width) 80 sys_write(fd, " \x00" as *u8, 1) 81 ppm_wr_int(fd, img.height) 82 sys_write(fd, "\n255\n\x00" as *u8, 5) 83 sys_write(fd, img.pixels, img.width * img.height * 3) 84 sys_close(fd) 85 return 0 86}