jxl_encoder/headers/
extra_channels.rs1use crate::bit_writer::BitWriter;
8use crate::error::Result;
9
10use super::file_header::BitDepth;
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
14#[repr(u8)]
15pub enum ExtraChannelType {
16 #[default]
18 Alpha = 0,
19 Depth = 1,
21 SpotColor = 2,
23 SelectionMask = 3,
25 Black = 4,
27 Cfa = 5,
29 Thermal = 6,
31 Reserved0 = 7,
33 Reserved1 = 8,
34 Reserved2 = 9,
35 Reserved3 = 10,
36 Reserved4 = 11,
37 Reserved5 = 12,
38 Reserved6 = 13,
39 Reserved7 = 14,
40 Optional = 15,
42}
43
44#[derive(Debug, Clone)]
46pub struct ExtraChannelInfo {
47 pub ec_type: ExtraChannelType,
49 pub bit_depth: BitDepth,
51 pub dim_shift: u32,
53 pub name: String,
55 pub alpha_associated: bool,
57 pub spot_color: [f32; 4],
59 pub cfa_channel: u32,
61}
62
63impl Default for ExtraChannelInfo {
64 fn default() -> Self {
65 Self {
66 ec_type: ExtraChannelType::Alpha,
67 bit_depth: BitDepth::default(),
68 dim_shift: 0,
69 name: String::new(),
70 alpha_associated: false,
71 spot_color: [0.0; 4],
72 cfa_channel: 0,
73 }
74 }
75}
76
77impl ExtraChannelInfo {
78 pub fn alpha() -> Self {
80 Self {
81 ec_type: ExtraChannelType::Alpha,
82 ..Default::default()
83 }
84 }
85
86 pub fn depth() -> Self {
88 Self {
89 ec_type: ExtraChannelType::Depth,
90 ..Default::default()
91 }
92 }
93
94 pub fn spot_color(color: [f32; 4]) -> Self {
96 Self {
97 ec_type: ExtraChannelType::SpotColor,
98 spot_color: color,
99 ..Default::default()
100 }
101 }
102
103 pub fn write(&self, writer: &mut BitWriter) -> Result<()> {
105 let d_alpha = self.is_default_alpha();
107 writer.write_bit(d_alpha)?;
108
109 if d_alpha {
110 return Ok(());
111 }
112
113 writer.write_u32_coder(self.ec_type as u32, 0, 1, 2, 3, 4)?;
115
116 self.bit_depth.write(writer)?;
118
119 writer.write_u32_coder(self.dim_shift, 0, 3, 4, 1, 3)?;
121
122 let name_len = self.name.len() as u32;
124 writer.write_u32_coder(name_len, 0, 0, 0, 0, 10)?;
125 for byte in self.name.bytes() {
126 writer.write_u8(byte)?;
127 }
128
129 if self.ec_type == ExtraChannelType::Alpha {
131 writer.write_bit(self.alpha_associated)?;
132 }
133
134 if self.ec_type == ExtraChannelType::SpotColor {
136 for &value in &self.spot_color {
137 writer.write_u32(value.to_bits())?;
138 }
139 }
140
141 if self.ec_type == ExtraChannelType::Cfa {
143 writer.write_u32_coder(self.cfa_channel, 1, 0, 2, 3, 4)?;
144 }
145
146 Ok(())
147 }
148
149 fn is_default_alpha(&self) -> bool {
151 self.ec_type == ExtraChannelType::Alpha
152 && self.bit_depth.bits_per_sample == 8
153 && !self.bit_depth.float_sample
154 && self.dim_shift == 0
155 && self.name.is_empty()
156 && !self.alpha_associated
157 }
158}
159
160#[cfg(test)]
161mod tests {
162 use super::*;
163
164 #[test]
165 fn test_default_alpha() {
166 let alpha = ExtraChannelInfo::alpha();
167 assert!(alpha.is_default_alpha());
168 }
169
170 #[test]
171 fn test_write_default_alpha() {
172 let alpha = ExtraChannelInfo::alpha();
173 let mut writer = BitWriter::new();
174 alpha.write(&mut writer).unwrap();
175 writer.zero_pad_to_byte();
176
177 assert_eq!(writer.bits_written(), 8); }
180
181 #[test]
182 fn test_non_default_alpha() {
183 let mut alpha = ExtraChannelInfo::alpha();
184 alpha.alpha_associated = true; assert!(!alpha.is_default_alpha());
186
187 let mut writer = BitWriter::new();
188 alpha.write(&mut writer).unwrap();
189 assert!(writer.bits_written() > 1);
191 }
192
193 #[test]
194 fn test_alpha_with_name() {
195 let mut alpha = ExtraChannelInfo::alpha();
196 alpha.name = "MyAlpha".to_string();
197 assert!(!alpha.is_default_alpha());
198
199 let mut writer = BitWriter::new();
200 alpha.write(&mut writer).unwrap();
201 assert!(writer.bits_written() > 8);
203 }
204
205 #[test]
206 fn test_depth_channel() {
207 let depth = ExtraChannelInfo::depth();
208 assert_eq!(depth.ec_type, ExtraChannelType::Depth);
209
210 let mut writer = BitWriter::new();
211 depth.write(&mut writer).unwrap();
212 assert!(writer.bits_written() > 1);
214 }
215
216 #[test]
217 fn test_spot_color_channel() {
218 let spot = ExtraChannelInfo::spot_color([1.0, 0.5, 0.25, 1.0]);
219 assert_eq!(spot.ec_type, ExtraChannelType::SpotColor);
220 assert_eq!(spot.spot_color, [1.0, 0.5, 0.25, 1.0]);
221
222 let mut writer = BitWriter::new();
223 spot.write(&mut writer).unwrap();
224 assert!(writer.bits_written() >= 128);
226 }
227
228 #[test]
229 fn test_cfa_channel() {
230 let cfa = ExtraChannelInfo {
231 ec_type: ExtraChannelType::Cfa,
232 cfa_channel: 2,
233 ..Default::default()
234 };
235
236 let mut writer = BitWriter::new();
237 cfa.write(&mut writer).unwrap();
238 assert!(writer.bits_written() > 1);
239 }
240
241 #[test]
242 fn test_extra_channel_types() {
243 assert_eq!(ExtraChannelType::Alpha as u8, 0);
245 assert_eq!(ExtraChannelType::Depth as u8, 1);
246 assert_eq!(ExtraChannelType::SpotColor as u8, 2);
247 assert_eq!(ExtraChannelType::SelectionMask as u8, 3);
248 assert_eq!(ExtraChannelType::Black as u8, 4);
249 assert_eq!(ExtraChannelType::Cfa as u8, 5);
250 assert_eq!(ExtraChannelType::Thermal as u8, 6);
251 assert_eq!(ExtraChannelType::Optional as u8, 15);
252 }
253
254 #[test]
255 fn test_dim_shift() {
256 let mut alpha = ExtraChannelInfo::alpha();
257 alpha.dim_shift = 2; assert!(!alpha.is_default_alpha());
259
260 let mut writer = BitWriter::new();
261 alpha.write(&mut writer).unwrap();
262 assert!(writer.bits_written() > 1);
263 }
264}