nx_jpeg_ycbcr.nx source
↩ module page · 79 lines · 2694 B
1// nx_jpeg_ycbcr.nx -- YCbCr -> RGB colour-space conversion for JPEG.
2//
3// Per JFIF v1.02 (ITU-T T.871) the inverse transform is:
4//
5// R = Y + 1.402 * (Cr - 128)
6// G = Y - 0.344136 * (Cb-128) - 0.714136 * (Cr - 128)
7// B = Y + 1.772 * (Cb-128)
8//
9// Where Y, Cb, Cr are post-IDCT 8-bit samples (after level-shift by
10// +128 and clamp to [0..255]).
11//
12// Fixed-point form using 16-bit fractional precision (multiplier 65536):
13//
14// 1.402 -> 91881
15// 0.344136 -> 22554
16// 0.714136 -> 46802
17// 1.772 -> 116130
18//
19// Clamping: output R, G, B to [0..255].
20//
21// nx_safety_envelope:
22// intended_use: "YCbCr-to-RGB conversion for JPEG decode."
23// sil_target: SIL1
24// evidence: [jfif_1_02_canonical_basis,
25// fixed_point_no_floats,
26// clamp_at_boundary]
27// verdict: NOT_YET_EVALUATED
28
29import "nx_syscalls.nx"
30
31func _ycbcr_clamp_u8(v: i64) -> i64 {
32 if v < 0 { return 0 }
33 if v > 255 { return 255 }
34 return v
35}
36
37// Convert one (Y, Cb, Cr) triple to (R, G, B). Inputs are 8-bit
38// unsigned samples after JPEG level-shift (Y=0..255; Cb,Cr=0..255
39// where 128 is neutral).
40//
41// Writes 3 output bytes via *r, *g, *b. Returns 0.
42func nx_jpeg_ycbcr_to_rgb_one(y: i64, cb: i64, cr: i64,
43 r_p: *i64, g_p: *i64, b_p: *i64) -> i64 {
44 let cb_centered: i64 = cb - 128
45 let cr_centered: i64 = cr - 128
46
47 // 1.402 = 91881 / 65536
48 let r_off: i64 = (91881 * cr_centered + 32768) >> 16
49 // 0.344136 = 22554 / 65536
50 // 0.714136 = 46802 / 65536
51 let g_off: i64 = 0 - (((22554 * cb_centered) + (46802 * cr_centered) + 32768) >> 16)
52 // 1.772 = 116130 / 65536
53 let b_off: i64 = (116130 * cb_centered + 32768) >> 16
54
55 r_p[0] = _ycbcr_clamp_u8(y + r_off)
56 g_p[0] = _ycbcr_clamp_u8(y + g_off)
57 b_p[0] = _ycbcr_clamp_u8(y + b_off)
58 return 0
59}
60
61// Bulk variant: convert N (Y, Cb, Cr) samples into N RGB triples.
62// Inputs are 3 separate i64 arrays of length n; output is a packed
63// 3n-byte buffer in R G B R G B ... order (typical framebuffer
64// layout for substrate paint).
65func nx_jpeg_ycbcr_to_rgb_block(y_buf: *i64, cb_buf: *i64, cr_buf: *i64,
66 n: i64, rgb_out: *u8) -> i64 {
67 let rp: *i64 = sys_mmap(8) as *i64
68 let gp: *i64 = sys_mmap(8) as *i64
69 let bp: *i64 = sys_mmap(8) as *i64
70 var i: i64 = 0
71 while i < n {
72 nx_jpeg_ycbcr_to_rgb_one(y_buf[i], cb_buf[i], cr_buf[i], rp, gp, bp)
73 rgb_out[i * 3] = rp[0] as u8
74 rgb_out[i * 3 + 1] = gp[0] as u8
75 rgb_out[i * 3 + 2] = bp[0] as u8
76 i = i + 1
77 }
78 return 0
79}