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}