nx_jpeg_ascii_test.nx source
↩ module page · 135 lines · 4461 B
1// nx_jpeg_ascii_test.nx -- KAT for the JPEG -> luminance ASCII bridge.
2//
3// Builds the same minimal grayscale 8x8 baseline JPEG used by
4// nx_jpeg_decode_test (zero-coefficient block -> every luma sample
5// == 128 after level shift), renders it through nx_jpeg_to_ascii_fb
6// at native 8x8, and verifies:
7// - the bridge returns NX_JPEG_ASCII_OK
8// - the framebuffer is 8x8 grayscale RGBA with every pixel == 128
9// - nx_paint_fb_ascii_dump maps luminance 128 to 'o' (the 128..191
10// bucket) for all 64 content cells, with row newlines.
11//
12// expect_exit: 0
13// license_tier: ORIGINAL
14
15import "nx_syscalls.nx"
16import "nx_paint_solid_rect.nx"
17import "nx_paint_fb_ascii_dump.nx"
18import "nx_jpeg_ascii.nx"
19
20func _fail(n: i64) -> i64 {
21 let b: *u8 = sys_mmap(16)
22 b[0]=0x46; b[1]=0x41; b[2]=0x49; b[3]=0x4C; b[4]=0x3D
23 sys_write(2, b, 5)
24 var x: i64 = n
25 if x < 0 { let m: *u8 = sys_mmap(4); m[0]=0x2D; sys_write(2, m, 1); x = 0 - x }
26 if x == 0 { let z: *u8 = sys_mmap(4); z[0]=0x30; sys_write(2, z, 1) }
27 else {
28 let buf: *u8 = sys_mmap(16)
29 var pos: i64 = 0
30 while x > 0 { buf[pos] = (0x30 + (x % 10)) as u8; x = x / 10; pos = pos + 1 }
31 let out: *u8 = sys_mmap(16)
32 var i: i64 = 0
33 while i < pos { out[i] = buf[pos - 1 - i]; i = i + 1 }
34 sys_write(2, out, pos)
35 }
36 let nl: *u8 = sys_mmap(4); nl[0]=0x0A; sys_write(2, nl, 1)
37 return 0
38}
39
40// Construct the 137-byte all-128 grayscale baseline JPEG. Identical
41// byte layout to nx_jpeg_decode_test.
42func _build_gray_jpeg(jpeg: *u8) -> i64 {
43 var p: i64 = 0
44 // SOI
45 jpeg[p]=0xFF; p=p+1; jpeg[p]=0xD8; p=p+1
46 // DQT (Pq=0 Tq=0, all-ones identity quant)
47 jpeg[p]=0xFF; p=p+1; jpeg[p]=0xDB; p=p+1
48 jpeg[p]=0x00; p=p+1; jpeg[p]=0x43; p=p+1
49 jpeg[p]=0x00; p=p+1
50 var i: i64 = 0
51 while i < 64 { jpeg[p+i] = 1; i = i + 1 }
52 p = p + 64
53 // DHT (DC + AC stacked, 36-byte payload)
54 jpeg[p]=0xFF; p=p+1; jpeg[p]=0xC4; p=p+1
55 jpeg[p]=0x00; p=p+1; jpeg[p]=0x26; p=p+1
56 jpeg[p]=0x00; p=p+1
57 jpeg[p]=0x01; p=p+1
58 i = 0
59 while i < 15 { jpeg[p+i] = 0; i = i + 1 }
60 p = p + 15
61 jpeg[p]=0x00; p=p+1
62 jpeg[p]=0x10; p=p+1
63 jpeg[p]=0x01; p=p+1
64 i = 0
65 while i < 15 { jpeg[p+i] = 0; i = i + 1 }
66 p = p + 15
67 jpeg[p]=0x00; p=p+1
68 // SOF0 (1 comp, 8x8)
69 jpeg[p]=0xFF; p=p+1; jpeg[p]=0xC0; p=p+1
70 jpeg[p]=0x00; p=p+1; jpeg[p]=0x0B; p=p+1
71 jpeg[p]=0x08; p=p+1
72 jpeg[p]=0x00; p=p+1; jpeg[p]=0x08; p=p+1
73 jpeg[p]=0x00; p=p+1; jpeg[p]=0x08; p=p+1
74 jpeg[p]=0x01; p=p+1
75 jpeg[p]=0x01; p=p+1
76 jpeg[p]=0x11; p=p+1
77 jpeg[p]=0x00; p=p+1
78 // SOS (1 comp)
79 jpeg[p]=0xFF; p=p+1; jpeg[p]=0xDA; p=p+1
80 jpeg[p]=0x00; p=p+1; jpeg[p]=0x08; p=p+1
81 jpeg[p]=0x01; p=p+1
82 jpeg[p]=0x01; p=p+1
83 jpeg[p]=0x00; p=p+1
84 jpeg[p]=0x00; p=p+1
85 jpeg[p]=0x3F; p=p+1
86 jpeg[p]=0x00; p=p+1
87 // Entropy: DC cat 0 + AC EOB
88 jpeg[p]=0x00; p=p+1
89 // EOI
90 jpeg[p]=0xFF; p=p+1; jpeg[p]=0xD9; p=p+1
91 return p
92}
93
94func main() -> i64 {
95 let jpeg: *u8 = sys_mmap(256)
96 let jpeg_len: i64 = _build_gray_jpeg(jpeg)
97
98 let fb: *Framebuffer = sys_mmap(NX_FRAMEBUFFER_BYTES) as *Framebuffer
99 let rc: i64 = nx_jpeg_to_ascii_fb(jpeg, jpeg_len, 8, 8, fb)
100 if rc != NX_JPEG_ASCII_OK { _fail(10 + rc); return 10 }
101
102 if fb.width != 8 { _fail(20); return 20 }
103 if fb.height != 8 { _fail(21); return 21 }
104
105 // Every pixel must be grayscale 128, fully opaque.
106 var i: i64 = 0
107 while i < 64 {
108 let o: i64 = i * 4
109 if (fb.pixels[o + 0] as i64 & 255) != 128 { _fail(30 + i); return 30 }
110 if (fb.pixels[o + 3] as i64 & 255) != 255 { _fail(100 + i); return 100 }
111 i = i + 1
112 }
113
114 // ASCII dump: 8 content cells + '\n' per row, 8 rows == 72 bytes.
115 let out: *u8 = sys_mmap(256)
116 let n: i64 = nx_paint_fb_ascii_dump(fb, out, 256)
117 if n != 72 { _fail(200 + n); return 200 }
118
119 // Content cells are 'o' (111); column 8 of each row is '\n' (10).
120 var y: i64 = 0
121 while y < 8 {
122 var x: i64 = 0
123 while x < 8 {
124 if (out[y * 9 + x] as i64 & 255) != 111 { _fail(300 + y * 9 + x); return 300 }
125 x = x + 1
126 }
127 if (out[y * 9 + 8] as i64 & 255) != 10 { _fail(400 + y); return 400 }
128 y = y + 1
129 }
130
131 let pass: *u8 = sys_mmap(16)
132 pass[0]=0x50; pass[1]=0x41; pass[2]=0x53; pass[3]=0x53; pass[4]=0x0A
133 sys_write(1, pass, 5)
134 return 0
135}