nx_jpeg_ycbcr_test.nx source
↩ module page · 116 lines · 4595 B
1// nx_jpeg_ycbcr_test.nx -- KAT for YCbCr -> RGB conversion.
2//
3// Canonical reference points from JFIF v1.02:
4// (Y= 0, Cb=128, Cr=128) -> black (R=0, G=0, B=0)
5// (Y=255, Cb=128, Cr=128) -> white (R=255, G=255, B=255)
6// (Y=128, Cb=128, Cr=128) -> mid grey (R=128, G=128, B=128)
7// (Y= 76, Cb= 85, Cr=255) -> pure red (R=~255, G=~0, B=~0)
8// (Y=150, Cb= 44, Cr= 21) -> pure green (R=~0, G=~255, B=~0)
9// (Y= 29, Cb=255, Cr=107) -> pure blue (R=~0, G=~0, B=~255)
10//
11// JPEG conversion is approximate (Rec 601 coefficients + fixed-point
12// rounding) so we allow +/- 2 ULP tolerance on the pure-colour cases.
13//
14// expect_exit: 0
15// license_tier: ORIGINAL
16
17import "nx_syscalls.nx"
18import "nx_jpeg_ycbcr.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
40func _within(actual: i64, expected: i64, tol: i64) -> i64 {
41 var d: i64 = actual - expected
42 if d < 0 { d = 0 - d }
43 if d <= tol { return 1 }
44 return 0
45}
46
47func main() -> i64 {
48 let r_p: *i64 = sys_mmap(8) as *i64
49 let g_p: *i64 = sys_mmap(8) as *i64
50 let b_p: *i64 = sys_mmap(8) as *i64
51
52 // Test 1: black
53 nx_jpeg_ycbcr_to_rgb_one(0, 128, 128, r_p, g_p, b_p)
54 if r_p[0] != 0 { _fail(1); return 1 }
55 if g_p[0] != 0 { _fail(2); return 2 }
56 if b_p[0] != 0 { _fail(3); return 3 }
57
58 // Test 2: white
59 nx_jpeg_ycbcr_to_rgb_one(255, 128, 128, r_p, g_p, b_p)
60 if r_p[0] != 255 { _fail(4); return 4 }
61 if g_p[0] != 255 { _fail(5); return 5 }
62 if b_p[0] != 255 { _fail(6); return 6 }
63
64 // Test 3: mid grey
65 nx_jpeg_ycbcr_to_rgb_one(128, 128, 128, r_p, g_p, b_p)
66 if r_p[0] != 128 { _fail(7); return 7 }
67 if g_p[0] != 128 { _fail(8); return 8 }
68 if b_p[0] != 128 { _fail(9); return 9 }
69
70 // Test 4: pure red. (Y=76, Cb=85, Cr=255) per JFIF inverse of forward.
71 nx_jpeg_ycbcr_to_rgb_one(76, 85, 255, r_p, g_p, b_p)
72 if _within(r_p[0], 254, 3) != 1 { _fail(10); return 10 } // ~ 255
73 if _within(g_p[0], 0, 3) != 1 { _fail(11); return 11 }
74 if _within(b_p[0], 0, 3) != 1 { _fail(12); return 12 }
75
76 // Test 5: pure green. (Y=150, Cb=44, Cr=21)
77 nx_jpeg_ycbcr_to_rgb_one(150, 44, 21, r_p, g_p, b_p)
78 if _within(r_p[0], 0, 3) != 1 { _fail(13); return 13 }
79 if _within(g_p[0], 254, 3) != 1 { _fail(14); return 14 }
80 if _within(b_p[0], 0, 3) != 1 { _fail(15); return 15 }
81
82 // Test 6: pure blue. (Y=29, Cb=255, Cr=107)
83 nx_jpeg_ycbcr_to_rgb_one(29, 255, 107, r_p, g_p, b_p)
84 if _within(r_p[0], 0, 3) != 1 { _fail(16); return 16 }
85 if _within(g_p[0], 0, 3) != 1 { _fail(17); return 17 }
86 if _within(b_p[0], 254, 3) != 1 { _fail(18); return 18 }
87
88 // Test 7: clamp on overshoot. Y=240, Cb=128, Cr=255 should push R way over 255.
89 // R = 240 + 1.402 * (255 - 128) = 240 + 178 = 418 -> clamped to 255.
90 nx_jpeg_ycbcr_to_rgb_one(240, 128, 255, r_p, g_p, b_p)
91 if r_p[0] != 255 { _fail(20); return 20 }
92
93 // Test 8: clamp on undershoot. Y=10, Cb=128, Cr=0 should push R way negative.
94 nx_jpeg_ycbcr_to_rgb_one(10, 128, 0, r_p, g_p, b_p)
95 if r_p[0] != 0 { _fail(21); return 21 }
96
97 // Test 9: bulk block conversion. 4 samples produce 12 RGB bytes.
98 let yb: *i64 = sys_mmap(32) as *i64
99 let cb: *i64 = sys_mmap(32) as *i64
100 let cr: *i64 = sys_mmap(32) as *i64
101 yb[0]=0; cb[0]=128; cr[0]=128 // black
102 yb[1]=255; cb[1]=128; cr[1]=128 // white
103 yb[2]=128; cb[2]=128; cr[2]=128 // grey
104 yb[3]=76; cb[3]=85; cr[3]=255 // red
105 let rgb: *u8 = sys_mmap(16)
106 nx_jpeg_ycbcr_to_rgb_block(yb, cb, cr, 4, rgb)
107 if rgb[0] != 0 { _fail(30); return 30 }
108 if rgb[3] != 255 { _fail(31); return 31 }
109 if rgb[6] != 128 { _fail(32); return 32 }
110 if _within(rgb[9] as i64, 254, 3) != 1 { _fail(33); return 33 }
111
112 let pass: *u8 = sys_mmap(16)
113 pass[0]=0x50; pass[1]=0x41; pass[2]=0x53; pass[3]=0x53; pass[4]=0x0A
114 sys_write(1, pass, 5)
115 return 0
116}