pub const LCD_GAMMA_TABLE: [u8; 32] = [
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 4, 5, 7, 10, 13, 18, 23, 28, 35, 44, 53, 64, 77, 91, 107, 126,
146, 169, 195, 223, 255,
];
#[inline]
pub fn expand5_to_8(c5: u8) -> u8 {
let c5 = c5 & 0x1F;
(c5 << 3) | (c5 >> 2)
}
#[inline]
pub fn bgr555_to_rgb888(bgr555: u16) -> (u8, u8, u8) {
let r5 = (bgr555 & 0x1F) as u8;
let g5 = ((bgr555 >> 5) & 0x1F) as u8;
let b5 = ((bgr555 >> 10) & 0x1F) as u8;
(expand5_to_8(r5), expand5_to_8(g5), expand5_to_8(b5))
}
#[inline]
pub fn write_pixel(buf: &mut [u8], dst: usize, bgr555: u16) {
let (r, g, b) = bgr555_to_rgb888(bgr555);
buf[dst] = r;
buf[dst + 1] = g;
buf[dst + 2] = b;
}
#[inline]
pub fn expand5_to_8_corrected(c5: u8) -> u8 {
LCD_GAMMA_TABLE[(c5 & 0x1F) as usize]
}
#[inline]
pub fn bgr555_to_rgb888_corrected(bgr555: u16) -> (u8, u8, u8) {
let r5 = (bgr555 & 0x1F) as u8;
let g5 = ((bgr555 >> 5) & 0x1F) as u8;
let b5 = ((bgr555 >> 10) & 0x1F) as u8;
(
expand5_to_8_corrected(r5),
expand5_to_8_corrected(g5),
expand5_to_8_corrected(b5),
)
}
#[inline]
pub fn write_pixel_corrected(buf: &mut [u8], dst: usize, bgr555: u16) {
let (r, g, b) = bgr555_to_rgb888_corrected(bgr555);
buf[dst] = r;
buf[dst + 1] = g;
buf[dst + 2] = b;
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn expand5_corrected_endpoints_map_to_endpoints() {
assert_eq!(expand5_to_8_corrected(0x00), 0x00);
assert_eq!(expand5_to_8_corrected(0x1F), 0xFF);
}
#[test]
fn expand5_corrected_ignores_high_bits() {
assert_eq!(expand5_to_8_corrected(0x20), expand5_to_8_corrected(0x00));
assert_eq!(expand5_to_8_corrected(0x3F), expand5_to_8_corrected(0x1F));
}
#[test]
fn expand5_corrected_is_monotonic() {
for c5 in 0u8..0x1F {
assert!(
expand5_to_8_corrected(c5) <= expand5_to_8_corrected(c5 + 1),
"not monotonic at c5={c5}"
);
}
}
#[test]
fn expand5_corrected_dark_range_is_nearly_black() {
for c5 in 0u8..=7 {
assert_eq!(expand5_to_8_corrected(c5), 0, "expected 0 for c5={c5}");
}
assert!(expand5_to_8_corrected(14) <= 10);
}
#[test]
fn expand5_corrected_differs_from_linear_at_midrange() {
let linear = expand5_to_8(16);
let corrected = expand5_to_8_corrected(16);
assert_ne!(
linear, corrected,
"corrected and linear must differ at c5=16"
);
assert!(
corrected < linear,
"corrected ({corrected}) must be darker than linear ({linear}) at c5=16"
);
}
#[test]
fn bgr555_corrected_black_and_white() {
assert_eq!(bgr555_to_rgb888_corrected(0x0000), (0, 0, 0));
assert_eq!(bgr555_to_rgb888_corrected(0x7FFF), (0xFF, 0xFF, 0xFF));
}
#[test]
fn bgr555_corrected_pure_red() {
assert_eq!(bgr555_to_rgb888_corrected(0x001F), (0xFF, 0, 0));
}
#[test]
fn bgr555_corrected_pure_green() {
assert_eq!(bgr555_to_rgb888_corrected(0x03E0), (0, 0xFF, 0));
}
#[test]
fn bgr555_corrected_pure_blue() {
assert_eq!(bgr555_to_rgb888_corrected(0x7C00), (0, 0, 0xFF));
}
#[test]
fn bgr555_corrected_ignores_high_bit() {
assert_eq!(bgr555_to_rgb888_corrected(0x8000), (0, 0, 0));
assert_eq!(bgr555_to_rgb888_corrected(0xFFFF), (0xFF, 0xFF, 0xFF));
}
#[test]
fn write_pixel_corrected_emits_rgb_byte_order() {
let mut buf = [0u8; 6];
write_pixel_corrected(&mut buf, 0, 0x001F); write_pixel_corrected(&mut buf, 3, 0x7C00); assert_eq!(buf, [0xFF, 0, 0, 0, 0, 0xFF]);
}
#[test]
fn expand5_endpoints_map_to_endpoints() {
assert_eq!(expand5_to_8(0x00), 0x00);
assert_eq!(expand5_to_8(0x1F), 0xFF);
}
#[test]
fn expand5_matches_canonical_formula() {
for c5 in 0u8..=0x1F {
let expected = (c5 << 3) | (c5 >> 2);
assert_eq!(expand5_to_8(c5), expected, "c5={c5:#x}");
}
}
#[test]
fn expand5_ignores_high_bits() {
assert_eq!(expand5_to_8(0x20), expand5_to_8(0x00));
assert_eq!(expand5_to_8(0x3F), expand5_to_8(0x1F));
}
#[test]
fn expand5_is_monotonic() {
for c5 in 0u8..0x1F {
assert!(expand5_to_8(c5) <= expand5_to_8(c5 + 1));
}
}
#[test]
fn bgr555_black_and_white() {
assert_eq!(bgr555_to_rgb888(0x0000), (0, 0, 0));
assert_eq!(bgr555_to_rgb888(0x7FFF), (0xFF, 0xFF, 0xFF));
}
#[test]
fn bgr555_pure_red() {
assert_eq!(bgr555_to_rgb888(0x001F), (0xFF, 0, 0));
}
#[test]
fn bgr555_pure_green() {
assert_eq!(bgr555_to_rgb888(0x03E0), (0, 0xFF, 0));
}
#[test]
fn bgr555_pure_blue() {
assert_eq!(bgr555_to_rgb888(0x7C00), (0, 0, 0xFF));
}
#[test]
fn bgr555_ignores_high_bit() {
assert_eq!(bgr555_to_rgb888(0x8000), (0, 0, 0));
assert_eq!(bgr555_to_rgb888(0xFFFF), (0xFF, 0xFF, 0xFF));
}
#[test]
fn bgr555_mid_grey_uses_replication() {
let bgr = 0x10u16 | (0x10u16 << 5) | (0x10u16 << 10);
assert_eq!(bgr555_to_rgb888(bgr), (0x84, 0x84, 0x84));
}
#[test]
fn write_pixel_emits_rgb_byte_order() {
let mut buf = [0u8; 6];
write_pixel(&mut buf, 0, 0x001F); write_pixel(&mut buf, 3, 0x7C00); assert_eq!(buf, [0xFF, 0, 0, 0, 0, 0xFF]);
}
}