1use crate::*;
2
3#[derive(Debug, Clone, PartialEq, Eq)]
4#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
5#[non_exhaustive]
6pub enum Colr {
7 Nclx {
8 colour_primaries: u16,
9 transfer_characteristics: u16,
10 matrix_coefficients: u16,
11 full_range_flag: bool,
12 },
13 Nclc {
14 colour_primaries: u16,
15 transfer_characteristics: u16,
16 matrix_coefficients: u16,
17 },
18 Ricc {
19 profile: Vec<u8>,
20 },
21 Prof {
22 profile: Vec<u8>,
23 },
24}
25
26impl Colr {
27 pub fn new(
28 colour_primaries: u16,
29 transfer_characteristics: u16,
30 matrix_coefficients: u16,
31 full_range_flag: bool,
32 ) -> Result<Self> {
33 Ok(Colr::Nclx {
34 colour_primaries,
35 transfer_characteristics,
36 matrix_coefficients,
37 full_range_flag,
38 })
39 }
40}
41
42impl Atom for Colr {
43 const KIND: FourCC = FourCC::new(b"colr");
44
45 fn decode_body<B: Buf>(buf: &mut B) -> Result<Self> {
46 const NCLX: FourCC = FourCC::new(b"nclx");
47 const NCLC: FourCC = FourCC::new(b"nclc");
48 const PROF: FourCC = FourCC::new(b"prof");
49 const RICC: FourCC = FourCC::new(b"rICC");
50
51 let colour_type = FourCC::decode(buf)?;
52 match colour_type {
53 NCLX => {
54 let colour_primaries = u16::decode(buf)?;
55 let transfer_characteristics = u16::decode(buf)?;
56 let matrix_coefficients = u16::decode(buf)?;
57 let full_range_flag = u8::decode(buf)? == 0x80;
58 Ok(Colr::Nclx {
59 colour_primaries,
60 transfer_characteristics,
61 matrix_coefficients,
62 full_range_flag,
63 })
64 }
65 NCLC => {
66 let colour_primaries = u16::decode(buf)?;
67 let transfer_characteristics = u16::decode(buf)?;
68 let matrix_coefficients = u16::decode(buf)?;
69 Ok(Colr::Nclc {
70 colour_primaries,
71 transfer_characteristics,
72 matrix_coefficients,
73 })
74 }
75 PROF => {
76 let profile_len = buf.remaining();
77 let profile = buf.slice(profile_len).to_vec();
78 buf.advance(profile_len);
79 Ok(Colr::Prof { profile })
80 }
81 RICC => {
82 let profile_len = buf.remaining();
83 let profile = buf.slice(profile_len).to_vec();
84 buf.advance(profile_len);
85 Ok(Colr::Ricc { profile })
86 }
87 _ => Err(Error::UnexpectedBox(colour_type)),
88 }
89 }
90
91 fn encode_body<B: BufMut>(&self, buf: &mut B) -> Result<()> {
92 match self {
93 Colr::Nclx {
94 colour_primaries,
95 transfer_characteristics,
96 matrix_coefficients,
97 full_range_flag,
98 } => {
99 b"nclx".encode(buf)?;
100 colour_primaries.encode(buf)?;
101 transfer_characteristics.encode(buf)?;
102 matrix_coefficients.encode(buf)?;
103 if *full_range_flag {
104 0x80u8.encode(buf)?;
105 } else {
106 0x00u8.encode(buf)?;
107 }
108 }
109 Colr::Nclc {
110 colour_primaries,
111 transfer_characteristics,
112 matrix_coefficients,
113 } => {
114 b"nclc".encode(buf)?;
115 colour_primaries.encode(buf)?;
116 transfer_characteristics.encode(buf)?;
117 matrix_coefficients.encode(buf)?;
118 }
119 Colr::Ricc { profile } => {
120 b"rICC".encode(buf)?;
121 profile.encode(buf)?;
122 }
123 Colr::Prof { profile } => {
124 b"prof".encode(buf)?;
125 profile.encode(buf)?;
126 }
127 }
128 Ok(())
129 }
130}
131
132impl Default for Colr {
133 fn default() -> Self {
134 Colr::Nclx {
135 colour_primaries: 1,
137 transfer_characteristics: 13,
138 matrix_coefficients: 5,
139 full_range_flag: true,
140 }
141 }
142}
143
144#[cfg(test)]
145mod tests {
146 use super::*;
147
148 #[test]
149 fn test_nclx_decode() {
150 const ENCODED: &[u8] = &[
151 0x00, 0x00, 0x00, 0x13, 0x63, 0x6f, 0x6c, 0x72, 0x6e, 0x63, 0x6c, 0x78, 0x00, 0x01,
152 0x00, 0x01, 0x00, 0x01, 0x00,
153 ];
154
155 let buf = &mut std::io::Cursor::new(&ENCODED);
156
157 let colr = Colr::decode(buf).expect("failed to decode colr");
158
159 assert_eq!(
160 colr,
161 Colr::Nclx {
162 colour_primaries: 1,
163 transfer_characteristics: 1,
164 matrix_coefficients: 1,
165 full_range_flag: false
166 }
167 );
168 }
169
170 #[test]
171 fn test_prof_decode_roundtrip() {
172 const ENCODED: &[u8] = &[
176 0x00, 0x00, 0x00, 0x13, b'c', b'o', b'l', b'r', b'p', b'r', b'o', b'f', 0x01, 0x02,
177 0x03, 0x04, 0x05, 0x06, 0x07,
178 ];
179 let buf = &mut std::io::Cursor::new(&ENCODED);
180 let colr = Colr::decode(buf).expect("failed to decode prof colr");
181 assert_eq!(
182 colr,
183 Colr::Prof {
184 profile: vec![0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07],
185 }
186 );
187
188 let mut out = Vec::new();
189 colr.encode(&mut out).expect("encode prof colr");
190 assert_eq!(out.as_slice(), ENCODED);
191 }
192
193 #[test]
194 fn test_prof_does_not_leave_remaining_bytes_for_parent() {
195 const ENCODED: &[u8] = &[
200 0x00, 0x00, 0x00, 0x10, b'c', b'o', b'l', b'r', b'p', b'r', b'o', b'f', 0xDE, 0xAD,
201 0xBE, 0xEF,
202 ];
203 let buf = &mut std::io::Cursor::new(&ENCODED);
204 Colr::decode(buf).expect("prof colr must decode without leaving trailing bytes");
205 assert_eq!(
206 Buf::remaining(buf),
207 0,
208 "parent end-check must see an empty body buffer"
209 );
210 }
211
212 #[test]
213 fn test_ricc_decode_roundtrip() {
214 const ENCODED: &[u8] = &[
216 0x00, 0x00, 0x00, 0x13, b'c', b'o', b'l', b'r', b'r', b'I', b'C', b'C', 0xAA, 0xBB,
217 0xCC, 0xDD, 0xEE, 0xFF, 0x00,
218 ];
219 let buf = &mut std::io::Cursor::new(&ENCODED);
220 let colr = Colr::decode(buf).expect("failed to decode rICC colr");
221 assert_eq!(
222 colr,
223 Colr::Ricc {
224 profile: vec![0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x00],
225 }
226 );
227
228 let mut out = Vec::new();
229 colr.encode(&mut out).expect("encode rICC colr");
230 assert_eq!(out.as_slice(), ENCODED);
231 }
232
233 #[test]
234 fn test_nclx_encode() {
235 const ENCODED: &[u8] = &[
236 0x00, 0x00, 0x00, 0x13, 0x63, 0x6f, 0x6c, 0x72, 0x6e, 0x63, 0x6c, 0x78, 0x00, 0x01,
237 0x00, 0x0d, 0x00, 0x06, 0x80,
238 ];
239
240 let colr = Colr::Nclx {
241 colour_primaries: 1,
242 transfer_characteristics: 13,
243 matrix_coefficients: 6,
244 full_range_flag: true,
245 };
246
247 let mut buf = Vec::new();
248 colr.encode(&mut buf).unwrap();
249
250 assert_eq!(buf.as_slice(), ENCODED);
251 }
252
253 #[test]
254 fn test_nclc_decode() {
255 const ENCODED: &[u8] = &[
256 0x00, 0x00, 0x00, 0x12, 0x63, 0x6f, 0x6c, 0x72, 0x6e, 0x63, 0x6c, 0x63, 0x00, 0x01,
257 0x00, 0x0d, 0x00, 0x06,
258 ];
259
260 let buf = &mut std::io::Cursor::new(&ENCODED);
261
262 let colr = Colr::decode(buf).expect("failed to decode colr");
263
264 assert_eq!(
265 colr,
266 Colr::Nclc {
267 colour_primaries: 1,
268 transfer_characteristics: 13,
269 matrix_coefficients: 6,
270 }
271 );
272 }
273
274 #[test]
275 fn test_nclc_encode() {
276 const ENCODED: &[u8] = &[
277 0x00, 0x00, 0x00, 0x12, 0x63, 0x6f, 0x6c, 0x72, 0x6e, 0x63, 0x6c, 0x63, 0x00, 0x01,
278 0x00, 0x0d, 0x00, 0x06,
279 ];
280
281 let colr = Colr::Nclc {
282 colour_primaries: 1,
283 transfer_characteristics: 13,
284 matrix_coefficients: 6,
285 };
286
287 let mut buf = Vec::new();
288 colr.encode(&mut buf).unwrap();
289
290 assert_eq!(buf.as_slice(), ENCODED);
291 }
292}