1use std::{cmp, io, u8};
2
3use num_traits::cast::NumCast;
4
5use crate::bits::{BitsIOReader, BitsIOWriter, BitsReader, BitsWriter};
6use crate::encode::{signed_code, signed_decode};
7use crate::errors::DecompressError;
8use crate::header;
9
10#[cfg(test)]
11mod test;
12
13#[derive(Clone, Debug, PartialEq)]
14pub struct ChannelTransformFactor {
15 pub src_channel: usize,
16 pub factor: isize,
17}
18
19#[derive(Clone, Debug, PartialEq)]
20pub struct ChannelTransform {
21 pub dest_channel: usize,
22 pub channel_factors: Vec<ChannelTransformFactor>,
23 pub denominator: isize,
24 pub is_chroma: bool,
25}
26
27pub struct ChannelTransformBuilder {
28 dest_channel: usize,
29 channel_factors: Vec<ChannelTransformFactor>,
30 denominator: isize,
31 is_chroma: bool,
32}
33
34impl ChannelTransformBuilder {
35 pub fn with_dest_channel(dest_channel: usize) -> ChannelTransformBuilder {
36 ChannelTransformBuilder {
37 dest_channel,
38 channel_factors: vec![],
39 denominator: 1,
40 is_chroma: false,
41 }
42 }
43
44 pub fn set_chroma(&mut self) -> &mut Self {
45 self.is_chroma = true;
46 self
47 }
48
49 pub fn add_channel_factor(&mut self, src_channel: usize, factor: isize) -> &mut Self {
50 self.channel_factors.push(ChannelTransformFactor {
51 src_channel,
52 factor,
53 });
54 self
55 }
56
57 pub fn set_denominator(&mut self, denominator: isize) -> &mut Self {
58 assert!(
59 self.denominator > 0,
60 "Denominator should be positive integer"
61 );
62 self.denominator = denominator;
63 self
64 }
65
66 pub fn build(&self) -> ChannelTransform {
67 ChannelTransform {
68 dest_channel: self.dest_channel,
69 channel_factors: self.channel_factors.clone(),
70 denominator: self.denominator,
71 is_chroma: self.is_chroma,
72 }
73 }
74}
75
76#[derive(Clone, Debug, Default, PartialEq)]
77pub struct ColorTransformProgram {
78 channel_transforms: Vec<ChannelTransform>,
79}
80
81impl ColorTransformProgram {
82 pub fn new() -> Self {
83 ColorTransformProgram {
84 channel_transforms: vec![],
85 }
86 }
87
88 pub fn yuv444_to_yuv444() -> Self {
91 let mut program = Self::new();
92
93 program
94 .add_channel_transform(
95 ChannelTransformBuilder::with_dest_channel(1)
96 .set_chroma()
97 .build(),
98 )
99 .add_channel_transform(
100 ChannelTransformBuilder::with_dest_channel(2)
101 .set_chroma()
102 .build(),
103 );
104 program
105 }
106
107 pub fn rgb_to_yuv() -> Self {
110 let mut program = Self::new();
111
112 program
113 .add_channel_transform(
114 ChannelTransformBuilder::with_dest_channel(0)
115 .add_channel_factor(1, -1)
116 .set_chroma()
117 .build(),
118 )
119 .add_channel_transform(
120 ChannelTransformBuilder::with_dest_channel(2)
121 .add_channel_factor(1, -1)
122 .set_chroma()
123 .build(),
124 )
125 .add_channel_transform(
126 ChannelTransformBuilder::with_dest_channel(1)
127 .add_channel_factor(0, 1)
128 .add_channel_factor(2, 1)
129 .set_denominator(4)
130 .build(),
131 );
132 program
133 }
134
135 pub fn bgr_to_a710() -> Self {
139 let mut program = Self::new();
140
141 program
142 .add_channel_transform(
143 ChannelTransformBuilder::with_dest_channel(2)
144 .add_channel_factor(1, -1)
145 .set_chroma()
146 .build(),
147 )
148 .add_channel_transform(
149 ChannelTransformBuilder::with_dest_channel(0)
150 .add_channel_factor(1, -2)
151 .add_channel_factor(2, -1)
152 .set_denominator(2)
153 .set_chroma()
154 .build(),
155 )
156 .add_channel_transform(
157 ChannelTransformBuilder::with_dest_channel(1)
158 .add_channel_factor(0, 2)
159 .add_channel_factor(2, 3)
160 .set_denominator(8)
161 .build(),
162 );
163 program
164 }
165
166 pub fn rgb_to_a710() -> Self {
170 let mut program = Self::new();
171
172 program
173 .add_channel_transform(
174 ChannelTransformBuilder::with_dest_channel(0)
175 .add_channel_factor(1, -1)
176 .set_chroma()
177 .build(),
178 )
179 .add_channel_transform(
180 ChannelTransformBuilder::with_dest_channel(2)
181 .add_channel_factor(1, -2)
182 .add_channel_factor(0, -1)
183 .set_denominator(2)
184 .set_chroma()
185 .build(),
186 )
187 .add_channel_transform(
188 ChannelTransformBuilder::with_dest_channel(1)
189 .add_channel_factor(2, 2)
190 .add_channel_factor(0, 3)
191 .set_denominator(8)
192 .build(),
193 );
194 program
195 }
196
197 pub fn decode(
198 mut buffer: &mut impl io::Read,
199 is_chroma: &mut [bool],
200 ) -> Result<Self, DecompressError> {
201 let mut stream = BitsIOReader::new(&mut buffer);
202 let mut color_transform_program = ColorTransformProgram::new();
203 loop {
204 let dest_channel = signed_decode(&mut stream, 2)?;
205
206 if dest_channel < 0 {
207 break;
208 }
209 let dest_channel = dest_channel as usize;
210
211 if dest_channel >= is_chroma.len() {
212 return Err(DecompressError::Malformed);
213 }
214
215 let mut channel_transform_builder =
216 ChannelTransformBuilder::with_dest_channel(dest_channel);
217 loop {
218 let src_channel = signed_decode(&mut stream, 2)?;
219
220 if src_channel < 0 {
221 break;
222 }
223 if src_channel as usize >= is_chroma.len() {
224 return Err(DecompressError::Malformed);
225 }
226
227 let factor = signed_decode(&mut stream, 2)?;
228 channel_transform_builder.add_channel_factor(src_channel as usize, factor as isize);
229 }
230 let denominator = signed_decode(&mut stream, 2)?;
231 if denominator == 0 {
232 return Err(DecompressError::Malformed);
233 }
234 channel_transform_builder.set_denominator(denominator as isize);
235
236 let channel_is_chroma = signed_decode(&mut stream, 2)?;
237
238 if channel_is_chroma != 0 {
239 channel_transform_builder.set_chroma();
240 is_chroma[dest_channel] = true;
241 }
242
243 color_transform_program.add_channel_transform(channel_transform_builder.build());
244 }
245 stream.flush_read_word();
246 Ok(color_transform_program)
247 }
248
249 pub fn add_channel_transform(&mut self, channel_transform: ChannelTransform) -> &mut Self {
250 self.channel_transforms.push(channel_transform);
251 self
252 }
253
254 pub fn is_channel_has_transform(&self, channel: usize) -> bool {
255 self.channel_transforms
256 .iter()
257 .filter(|t| t.dest_channel == channel)
258 .any(|c| c.denominator > 1 || !c.channel_factors.is_empty())
259 }
260
261 pub fn iter(&self) -> impl DoubleEndedIterator<Item = &ChannelTransform> {
262 self.channel_transforms.iter()
263 }
264
265 pub fn encode(
266 &self,
267 channels: usize,
268 mut buffer: &mut impl io::Write,
269 ) -> io::Result<Vec<bool>> {
270 let mut stream = BitsIOWriter::new(&mut buffer);
271 let mut is_chroma = vec![false; channels];
272
273 for channel_transform in &self.channel_transforms {
274 signed_code(channel_transform.dest_channel as i32, &mut stream, 2)?;
275
276 for channel_factor in &channel_transform.channel_factors {
277 signed_code(channel_factor.src_channel as i32, &mut stream, 2)?;
278 signed_code(channel_factor.factor as i32, &mut stream, 2)?;
279 }
280 signed_code(-1, &mut stream, 2)?;
281
282 signed_code(channel_transform.denominator as i32, &mut stream, 2)?;
283 signed_code(channel_transform.is_chroma as i32, &mut stream, 2)?;
284
285 is_chroma[channel_transform.dest_channel] = channel_transform.is_chroma;
286 }
287
288 signed_code(-1, &mut stream, 2)?;
290 stream.flush_write_word()?;
291
292 Ok(is_chroma)
293 }
294
295 fn transform_base<T, F>(
296 &self,
297 image: &[T],
298 header: &header::Header,
299 aux: &mut [i16],
300 channels_in_index: usize,
301 channel_layer: F,
302 ) where
303 T: Into<i16> + Copy,
304 F: Fn(usize, usize, usize) -> usize,
305 {
306 assert!(aux.len() >= image.len());
307
308 let boost = header.get_boost() as i16;
309 let channels = header.channels as usize;
310 let channel_size = header.get_channel_size();
311 let mut is_channel_transformed = vec![false; channels * header.layers as usize];
312
313 for channel_transform in &self.channel_transforms {
314 let dest_base = channel_transform.dest_channel * channel_size;
315
316 for channel_factor in &channel_transform.channel_factors {
317 if is_channel_transformed[channel_factor.src_channel] {
318 for i in 0..channel_size {
319 aux[dest_base + i] += aux[channel_factor.src_channel * channel_size + i]
320 * channel_factor.factor as i16;
321 }
322 } else {
323 let boosted_factor = channel_factor.factor as i16 * boost;
324 let layer = channel_layer(channel_factor.src_channel, channels, channel_size);
325 for i in 0..channel_size {
326 aux[dest_base + i] +=
327 image[layer + i * channels_in_index].into() * boosted_factor;
328 }
329 }
330 }
331
332 let layer = channel_layer(channel_transform.dest_channel, channels, channel_size);
333 for i in 0..channel_size {
334 aux[dest_base + i] /= channel_transform.denominator as i16;
335 aux[dest_base + i] += image[layer + i * channels_in_index].into() * boost;
336 }
337
338 is_channel_transformed[channel_transform.dest_channel] = true;
339 }
340
341 for (channel, is_transformed) in is_channel_transformed.iter().enumerate() {
342 if !is_transformed {
343 let dest_base = channel * channel_size;
344 let layer = channel_layer(channel, channels, channel_size);
345 for i in 0..channel_size {
346 aux[dest_base + i] = image[layer + i * channels_in_index].into() * boost;
347 }
348 }
349 }
350 }
351
352 pub fn transform_and_to_planar<T>(
353 &self,
354 image: &[T],
355 header: &header::Header,
356 mut aux: &mut [i16],
357 ) where
358 T: Into<i16> + Copy,
359 {
360 ColorTransformProgram::transform_base(
361 &self,
362 &image,
363 &header,
364 &mut aux,
365 header.channels as usize,
366 get_layer,
367 );
368 }
369
370 pub fn transform<T>(&self, image: &[T], header: &header::Header, mut aux: &mut [i16])
371 where
372 T: Into<i16> + Copy,
373 {
374 ColorTransformProgram::transform_base(
375 &self,
376 &image,
377 &header,
378 &mut aux,
379 1,
380 |channel, _, channel_size| channel * channel_size,
381 );
382 }
383
384 fn detransform_base<'a, T>(
385 &self,
386 aux: &mut [i16],
387 header: &header::Header,
388 channel_size: usize,
389 image: &'a mut [T],
390 ) -> (&'a mut [T], i16)
391 where
392 T: NumCast,
393 {
394 assert!(image.len() >= aux.len());
395
396 for channel_transform in self.channel_transforms.iter().rev() {
397 let mut transform_temp = vec![0_i16; channel_size];
398 let dest_base = channel_transform.dest_channel * channel_size;
399
400 for channel_factor in &channel_transform.channel_factors {
401 for i in 0..channel_size {
402 transform_temp[i] += aux[channel_factor.src_channel * channel_size + i]
403 * channel_factor.factor as i16;
404 }
405 }
406
407 for i in 0..channel_size {
408 transform_temp[i] /= channel_transform.denominator as i16;
409 aux[dest_base + i] -= transform_temp[i];
410 }
411 }
412
413 let (image, _) = image.split_at_mut(aux.len());
415
416 let boost = header.get_boost();
417
418 (image, boost)
419 }
420
421 pub fn detransform_and_to_interleaved<T>(
422 &self,
423 mut aux: &mut [i16],
424 header: &header::Header,
425 channel_size: usize,
426 mut image: &mut [T],
427 ) where
428 T: NumCast,
429 {
430 let (image, boost) = ColorTransformProgram::detransform_base(
431 &self,
432 &mut aux,
433 &header,
434 channel_size,
435 &mut image,
436 );
437
438 let channels = header.channels as usize;
439 for c in 0..channels * header.layers as usize {
440 let layer = get_layer(c, channels, channel_size);
441 for i in 0..channel_size {
442 image[layer + i * channels] =
443 T::from(cut_with_u8(aux[c * channel_size + i] / boost)).unwrap();
444 }
445 }
446 }
447
448 pub fn detransform<T>(
449 &self,
450 mut aux: &mut [i16],
451 header: &header::Header,
452 channel_size: usize,
453 mut image: &mut [T],
454 ) where
455 T: NumCast,
456 {
457 let (image, boost) = ColorTransformProgram::detransform_base(
458 &self,
459 &mut aux,
460 &header,
461 channel_size,
462 &mut image,
463 );
464
465 for (dest, src) in image.iter_mut().zip(aux.iter()) {
466 *dest = T::from(cut_with_u8(*src / boost)).unwrap();
467 }
468 }
469}
470
471fn convert_between_interleaved_and_planar<F, T>(
472 len: usize,
473 channels: usize,
474 skip_channels: &[usize],
475 mut output: &mut [T],
476 func: F,
477) where
478 F: Fn(&mut [T], usize, usize, usize),
479{
480 let channel_size = len / channels;
481
482 let mut skipped = 0;
483 for c in 0..channels {
484 if skip_channels.contains(&c) {
485 skipped += 1;
486 continue;
487 }
488 let dest_base = (c - skipped) * channel_size;
489 let layer = get_layer(c, channels, channel_size);
490 for i in 0..channel_size {
491 func(&mut output, layer, dest_base, i);
492 }
493 }
494}
495
496pub fn interleaved_to_planar<T>(
497 input: &[T],
498 channels: usize,
499 boost: i16,
500 mut output: &mut [i16],
501 skip_channels: &[usize],
502) where
503 T: Into<i16> + Copy,
504{
505 convert_between_interleaved_and_planar(
506 input.len(),
507 channels,
508 &skip_channels,
509 &mut output,
510 |output, layer, dest_base, i| {
511 output[dest_base + i] = input[layer + i * channels].into() * boost;
512 },
513 );
514}
515
516pub fn planar_to_interleaved<T>(
517 input: &[i16],
518 channels: usize,
519 boost: i16,
520 mut output: &mut [T],
521 skip_channels: &[usize],
522) where
523 T: NumCast,
524{
525 convert_between_interleaved_and_planar(
526 output.len(),
527 channels,
528 &skip_channels,
529 &mut output,
530 |output, layer, dest_base, i| {
531 output[layer + i * channels] =
532 T::from(cut_with_u8(input[dest_base + i] / boost)).unwrap();
533 },
534 );
535}
536
537fn get_layer(channel: usize, channels: usize, channel_size: usize) -> usize {
538 (channel / channels) * channel_size * channels + channel % channels
539}
540
541fn cut_with_u8<T>(value: T) -> T
542where
543 T: cmp::Ord + From<u8>,
544{
545 value.min(u8::MAX.into()).max(u8::MIN.into())
546}