code wiki / (root) / nx_jpeg_ycbcr_test.nx

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}