use oxideav_core::{ColorRange, ColorSignal, PixelFormat};
use crate::image::AvifPixelFormat;
use crate::meta::Colr;
pub fn color_signal_for(colr: Option<&Colr>) -> ColorSignal {
match colr {
Some(Colr::Nclx {
colour_primaries,
transfer_characteristics,
matrix_coefficients,
full_range,
}) => ColorSignal::from_code_points(
clamp_code(*colour_primaries),
clamp_code(*transfer_characteristics),
clamp_code(*matrix_coefficients),
*full_range,
),
Some(Colr::Icc(_)) | Some(Colr::Unknown(_)) | None => miaf_default_signal(),
}
}
pub fn miaf_default_signal() -> ColorSignal {
ColorSignal::from_code_points(1, 13, 6, true)
}
fn clamp_code(v: u16) -> u8 {
u8::try_from(v).unwrap_or(2)
}
pub fn labelled_pixel_format(format: AvifPixelFormat, signal: &ColorSignal) -> PixelFormat {
let identity = signal.matrix.0 == 0;
let full = signal.range == ColorRange::Full;
match format {
AvifPixelFormat::Yuv444P if identity => PixelFormat::Gbrp8,
AvifPixelFormat::Yuva444P if identity => PixelFormat::Gbrap8,
AvifPixelFormat::Yuv444P10Le if identity => PixelFormat::Gbrp10Le,
AvifPixelFormat::Yuva444P10Le if identity => PixelFormat::Gbrap10Le,
AvifPixelFormat::Yuv444P12Le if identity => PixelFormat::Gbrp12Le,
AvifPixelFormat::Yuva444P12Le if identity => PixelFormat::Gbrap12Le,
AvifPixelFormat::Yuv420P if full => PixelFormat::YuvJ420P,
AvifPixelFormat::Yuv422P if full => PixelFormat::YuvJ422P,
AvifPixelFormat::Yuv444P if full => PixelFormat::YuvJ444P,
other => PixelFormat::from(other),
}
}
pub(crate) fn layout_of_record(cfg: &crate::av1_config::Av1CodecConfig) -> Option<AvifPixelFormat> {
AvifPixelFormat::from_layout(
cfg.bit_depth(),
u8::from(cfg.chroma_subsampling_x),
u8::from(cfg.chroma_subsampling_y),
cfg.monochrome,
false,
)
}
#[cfg(test)]
mod tests {
use super::*;
use oxideav_core::{ColorPrimaries, MatrixCoefficients, TransferCharacteristics};
#[test]
fn nclx_code_points_ride_through() {
let s = color_signal_for(Some(&Colr::Nclx {
colour_primaries: 9,
transfer_characteristics: 16,
matrix_coefficients: 9,
full_range: true,
}));
assert_eq!(s.primaries, ColorPrimaries(9));
assert_eq!(s.transfer, TransferCharacteristics(16));
assert_eq!(s.matrix, MatrixCoefficients(9));
assert_eq!(s.range, ColorRange::Full);
let limited = color_signal_for(Some(&Colr::Nclx {
colour_primaries: 1,
transfer_characteristics: 1,
matrix_coefficients: 1,
full_range: false,
}));
assert_eq!(limited, ColorSignal::bt709_limited());
}
#[test]
fn absent_and_icc_take_the_miaf_default() {
let d = miaf_default_signal();
assert_eq!(color_signal_for(None), d);
assert_eq!(color_signal_for(Some(&Colr::Icc(vec![0; 4]))), d);
assert_eq!(color_signal_for(Some(&Colr::Unknown(*b"zzzz"))), d);
assert_eq!(d.range, ColorRange::Full);
assert_eq!(d.matrix, MatrixCoefficients(6));
assert_eq!(d.primaries, ColorPrimaries(1));
assert_eq!(d.transfer, TransferCharacteristics(13));
}
#[test]
fn out_of_table_code_point_is_unspecified() {
let s = color_signal_for(Some(&Colr::Nclx {
colour_primaries: 300,
transfer_characteristics: 13,
matrix_coefficients: 0,
full_range: true,
}));
assert_eq!(s.primaries, ColorPrimaries(2));
assert_eq!(s.matrix, MatrixCoefficients(0));
}
#[test]
fn identity_444_is_planar_rgb_and_full_8bit_is_yuvj() {
let id = ColorSignal::srgb();
assert_eq!(
labelled_pixel_format(AvifPixelFormat::Yuv444P, &id),
PixelFormat::Gbrp8
);
assert_eq!(
labelled_pixel_format(AvifPixelFormat::Yuva444P, &id),
PixelFormat::Gbrap8
);
assert_eq!(
labelled_pixel_format(AvifPixelFormat::Yuv444P10Le, &id),
PixelFormat::Gbrp10Le
);
assert_eq!(
labelled_pixel_format(AvifPixelFormat::Yuva444P12Le, &id),
PixelFormat::Gbrap12Le
);
assert_eq!(
labelled_pixel_format(AvifPixelFormat::Yuv420P, &id),
PixelFormat::YuvJ420P
);
let bt601_full = ColorSignal::from_code_points(1, 13, 6, true);
assert_eq!(
labelled_pixel_format(AvifPixelFormat::Yuv444P, &bt601_full),
PixelFormat::YuvJ444P
);
assert_eq!(
labelled_pixel_format(AvifPixelFormat::Yuv420P10Le, &bt601_full),
PixelFormat::Yuv420P10Le
);
let limited = ColorSignal::bt709_limited();
assert_eq!(
labelled_pixel_format(AvifPixelFormat::Yuv420P, &limited),
PixelFormat::Yuv420P
);
assert_eq!(
labelled_pixel_format(AvifPixelFormat::Gray8, &bt601_full),
PixelFormat::Gray8
);
}
}