use crate::bit_writer::BitWriter;
use crate::error::Result;
use super::file_header::BitDepth;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
#[repr(u8)]
pub enum ExtraChannelType {
#[default]
Alpha = 0,
Depth = 1,
SpotColor = 2,
SelectionMask = 3,
Black = 4,
Cfa = 5,
Thermal = 6,
Reserved0 = 7,
Reserved1 = 8,
Reserved2 = 9,
Reserved3 = 10,
Reserved4 = 11,
Reserved5 = 12,
Reserved6 = 13,
Reserved7 = 14,
Optional = 15,
}
#[derive(Debug, Clone)]
pub struct ExtraChannelInfo {
pub ec_type: ExtraChannelType,
pub bit_depth: BitDepth,
pub dim_shift: u32,
pub name: String,
pub alpha_associated: bool,
pub spot_color: [f32; 4],
pub cfa_channel: u32,
}
impl Default for ExtraChannelInfo {
fn default() -> Self {
Self {
ec_type: ExtraChannelType::Alpha,
bit_depth: BitDepth::default(),
dim_shift: 0,
name: String::new(),
alpha_associated: false,
spot_color: [0.0; 4],
cfa_channel: 0,
}
}
}
impl ExtraChannelInfo {
pub fn alpha() -> Self {
Self {
ec_type: ExtraChannelType::Alpha,
..Default::default()
}
}
pub fn depth() -> Self {
Self {
ec_type: ExtraChannelType::Depth,
..Default::default()
}
}
pub fn spot_color(color: [f32; 4]) -> Self {
Self {
ec_type: ExtraChannelType::SpotColor,
spot_color: color,
..Default::default()
}
}
pub fn write(&self, writer: &mut BitWriter) -> Result<()> {
let d_alpha = self.is_default_alpha();
writer.write_bit(d_alpha)?;
if d_alpha {
return Ok(());
}
writer.write_u32_coder(self.ec_type as u32, 0, 1, 2, 3, 4)?;
self.bit_depth.write(writer)?;
writer.write_u32_coder(self.dim_shift, 0, 3, 4, 1, 3)?;
let name_len = self.name.len() as u32;
writer.write_u32_coder(name_len, 0, 0, 0, 0, 10)?;
for byte in self.name.bytes() {
writer.write_u8(byte)?;
}
if self.ec_type == ExtraChannelType::Alpha {
writer.write_bit(self.alpha_associated)?;
}
if self.ec_type == ExtraChannelType::SpotColor {
for &value in &self.spot_color {
writer.write_u32(value.to_bits())?;
}
}
if self.ec_type == ExtraChannelType::Cfa {
writer.write_u32_coder(self.cfa_channel, 1, 0, 2, 3, 4)?;
}
Ok(())
}
fn is_default_alpha(&self) -> bool {
self.ec_type == ExtraChannelType::Alpha
&& self.bit_depth.bits_per_sample == 8
&& !self.bit_depth.float_sample
&& self.dim_shift == 0
&& self.name.is_empty()
&& !self.alpha_associated
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_default_alpha() {
let alpha = ExtraChannelInfo::alpha();
assert!(alpha.is_default_alpha());
}
#[test]
fn test_write_default_alpha() {
let alpha = ExtraChannelInfo::alpha();
let mut writer = BitWriter::new();
alpha.write(&mut writer).unwrap();
writer.zero_pad_to_byte();
assert_eq!(writer.bits_written(), 8); }
#[test]
fn test_non_default_alpha() {
let mut alpha = ExtraChannelInfo::alpha();
alpha.alpha_associated = true; assert!(!alpha.is_default_alpha());
let mut writer = BitWriter::new();
alpha.write(&mut writer).unwrap();
assert!(writer.bits_written() > 1);
}
#[test]
fn test_alpha_with_name() {
let mut alpha = ExtraChannelInfo::alpha();
alpha.name = "MyAlpha".to_string();
assert!(!alpha.is_default_alpha());
let mut writer = BitWriter::new();
alpha.write(&mut writer).unwrap();
assert!(writer.bits_written() > 8);
}
#[test]
fn test_depth_channel() {
let depth = ExtraChannelInfo::depth();
assert_eq!(depth.ec_type, ExtraChannelType::Depth);
let mut writer = BitWriter::new();
depth.write(&mut writer).unwrap();
assert!(writer.bits_written() > 1);
}
#[test]
fn test_spot_color_channel() {
let spot = ExtraChannelInfo::spot_color([1.0, 0.5, 0.25, 1.0]);
assert_eq!(spot.ec_type, ExtraChannelType::SpotColor);
assert_eq!(spot.spot_color, [1.0, 0.5, 0.25, 1.0]);
let mut writer = BitWriter::new();
spot.write(&mut writer).unwrap();
assert!(writer.bits_written() >= 128);
}
#[test]
fn test_cfa_channel() {
let cfa = ExtraChannelInfo {
ec_type: ExtraChannelType::Cfa,
cfa_channel: 2,
..Default::default()
};
let mut writer = BitWriter::new();
cfa.write(&mut writer).unwrap();
assert!(writer.bits_written() > 1);
}
#[test]
fn test_extra_channel_types() {
assert_eq!(ExtraChannelType::Alpha as u8, 0);
assert_eq!(ExtraChannelType::Depth as u8, 1);
assert_eq!(ExtraChannelType::SpotColor as u8, 2);
assert_eq!(ExtraChannelType::SelectionMask as u8, 3);
assert_eq!(ExtraChannelType::Black as u8, 4);
assert_eq!(ExtraChannelType::Cfa as u8, 5);
assert_eq!(ExtraChannelType::Thermal as u8, 6);
assert_eq!(ExtraChannelType::Optional as u8, 15);
}
#[test]
fn test_dim_shift() {
let mut alpha = ExtraChannelInfo::alpha();
alpha.dim_shift = 2; assert!(!alpha.is_default_alpha());
let mut writer = BitWriter::new();
alpha.write(&mut writer).unwrap();
assert!(writer.bits_written() > 1);
}
}