code wiki / (root) / nx_jpeg_ycbcr.nx

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}