use image::{Luma, Pixel as _, Rgb};
use nom::{
bytes::complete::{tag, take_while_m_n},
combinator::map_res,
multi::separated_list0,
IResult, Parser as _,
};
use super::VobSubError;
pub const DEFAULT_PALETTE: Palette = [
Rgb([0x00, 0x00, 0x00]),
Rgb([0xf0, 0xf0, 0xf0]),
Rgb([0xcc, 0xcc, 0xcc]),
Rgb([0x99, 0x99, 0x99]),
Rgb([0x33, 0x33, 0xfa]),
Rgb([0x11, 0x11, 0xbb]),
Rgb([0xfa, 0x33, 0x33]),
Rgb([0xbb, 0x11, 0x11]),
Rgb([0x33, 0xfa, 0x33]),
Rgb([0x11, 0xbb, 0x11]),
Rgb([0xfa, 0xfa, 0x33]),
Rgb([0xbb, 0xbb, 0x11]),
Rgb([0xfa, 0x33, 0xfa]),
Rgb([0xbb, 0x11, 0xbb]),
Rgb([0x33, 0xfa, 0xfa]),
Rgb([0x11, 0xbb, 0xbb]),
];
fn from_hex(input: &[u8]) -> std::result::Result<u8, std::num::ParseIntError> {
let input = std::str::from_utf8(input).unwrap();
u8::from_str_radix(input, 16)
}
fn hex_primary(input: &[u8]) -> IResult<&[u8], u8> {
map_res(
take_while_m_n(2, 2, |c: u8| c.is_ascii_hexdigit()),
from_hex,
)
.parse(input)
}
fn hex_rgb(input: &[u8]) -> IResult<&[u8], Rgb<u8>> {
let (input, color) = (hex_primary, hex_primary, hex_primary).parse(input)?;
Ok((input, Rgb(color.into())))
}
pub type Palette = [Rgb<u8>; 16];
pub fn palette(input: &[u8]) -> IResult<&[u8], Palette> {
const SEPARATOR_TAG: &[u8] = b", ";
let res = map_res(
separated_list0(tag(SEPARATOR_TAG), hex_rgb),
|vec: Vec<Rgb<u8>>| {
if vec.len() != 16 {
return Err(VobSubError::PaletteInvalidEntriesNumbers(vec.len()));
}
let mut result = [Rgb([0, 0, 0]); 16];
<[Rgb<u8>; 16] as AsMut<_>>::as_mut(&mut result).clone_from_slice(&vec[0..16]);
Ok(result)
},
)
.parse(input);
res
}
pub type PaletteLuma = [Luma<u8>; 16];
#[must_use]
pub fn palette_rgb_to_luminance(palette: &Palette) -> PaletteLuma {
palette.map(|rgb| rgb.to_luma())
}
#[cfg(test)]
mod tests {
use super::*;
use image::Rgb;
#[test]
fn parse_rgb() {
use nom::IResult;
assert_eq!(
hex_rgb(&b"1234ab"[..]),
IResult::Ok((&b""[..], Rgb::<u8>([0x12, 0x34, 0xab])))
);
}
#[test]
fn parse_palette() {
use nom::IResult;
let input = b"\
000000, f0f0f0, cccccc, 999999, 3333fa, 1111bb, fa3333, bb1111, \
33fa33, 11bb11, fafa33, bbbb11, fa33fa, bb11bb, 33fafa, 11bbbb";
assert_eq!(palette(input), {
let palette = [
Rgb([0x00, 0x00, 0x00]),
Rgb([0xf0, 0xf0, 0xf0]),
Rgb([0xcc, 0xcc, 0xcc]),
Rgb([0x99, 0x99, 0x99]),
Rgb([0x33, 0x33, 0xfa]),
Rgb([0x11, 0x11, 0xbb]),
Rgb([0xfa, 0x33, 0x33]),
Rgb([0xbb, 0x11, 0x11]),
Rgb([0x33, 0xfa, 0x33]),
Rgb([0x11, 0xbb, 0x11]),
Rgb([0xfa, 0xfa, 0x33]),
Rgb([0xbb, 0xbb, 0x11]),
Rgb([0xfa, 0x33, 0xfa]),
Rgb([0xbb, 0x11, 0xbb]),
Rgb([0x33, 0xfa, 0xfa]),
Rgb([0x11, 0xbb, 0xbb]),
];
IResult::Ok((&[][..], palette))
});
}
}