pub const R_COEF: i32 = 359;
pub const G_COEF_CB: i32 = 88;
pub const G_COEF_CR: i32 = 183;
pub const B_COEF: i32 = 454;
#[inline]
#[must_use]
#[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
pub fn clamp(v: i32) -> u8 {
crate::pixel_utils::clamp_u8(v)
}
#[inline]
#[must_use]
pub fn yuv_to_bgra(y: u8, cb: u8, cr: u8) -> [u8; 4] {
let y = i32::from(y);
let cb = i32::from(cb) - 128;
let cr = i32::from(cr) - 128;
let r = clamp(y + ((cr * R_COEF) >> 8));
let g = clamp(y - ((cb * G_COEF_CB) >> 8) - ((cr * G_COEF_CR) >> 8));
let b = clamp(y + ((cb * B_COEF) >> 8));
[b, g, r, 255]
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn gray_mid() {
assert_eq!(yuv_to_bgra(128, 128, 128), [128, 128, 128, 255]);
}
#[test]
fn white_full() {
assert_eq!(yuv_to_bgra(255, 128, 128), [255, 255, 255, 255]);
}
#[test]
fn black_full() {
assert_eq!(yuv_to_bgra(0, 128, 128), [0, 0, 0, 255]);
}
#[test]
fn saturated_blue_positive() {
assert_eq!(yuv_to_bgra(128, 255, 128), [255, 85, 128, 255]);
}
#[test]
fn saturated_red_positive() {
assert_eq!(yuv_to_bgra(128, 128, 255), [128, 38, 255, 255]);
}
#[test]
fn clamp_negative_yields_zero() {
let pixel = yuv_to_bgra(0, 0, 0);
assert_eq!(pixel[0], 0, "b channel must clamp to 0"); assert_eq!(pixel[2], 0, "r channel must clamp to 0"); }
#[test]
fn max_chroma_does_not_overflow_green() {
assert_eq!(yuv_to_bgra(255, 255, 255), [255, 122, 255, 255]);
}
#[test]
fn neutral_chroma_various_luma() {
for y in [0u8, 16, 128, 235, 255] {
let pixel = yuv_to_bgra(y, 128, 128);
assert_eq!(pixel, [y, y, y, 255], "neutral chroma must yield gray");
}
}
#[test]
fn clamp_single_values() {
assert_eq!(clamp(-1), 0);
assert_eq!(clamp(0), 0);
assert_eq!(clamp(128), 128);
assert_eq!(clamp(255), 255);
assert_eq!(clamp(256), 255);
assert_eq!(clamp(i32::MIN), 0);
assert_eq!(clamp(i32::MAX), 255);
}
#[test]
fn bgra_output_alpha_is_always_255() {
for y in [0u8, 128, 255] {
for cb in [0u8, 128, 255] {
for cr in [0u8, 128, 255] {
let pixel = yuv_to_bgra(y, cb, cr);
assert_eq!(
pixel[3], 255,
"alpha channel must always be 255 (y={y}, cb={cb}, cr={cr})"
);
}
}
}
}
#[test]
fn broadcast_white() {
assert_eq!(yuv_to_bgra(235, 128, 128), [235, 235, 235, 255]);
}
fn yuv_roundtrip_gray(y: u8) -> bool {
yuv_to_bgra(y, 128, 128)[..3] == [y, y, y]
}
#[test]
fn every_gray_value_roundtrips() {
for y in 0..=255u8 {
assert!(yuv_roundtrip_gray(y), "gray roundtrip failed at y={y}");
}
}
}