1/*
2 * Copyright (c) 2023.
3 *
4 * This software is free software;
5 *
6 * You can redistribute it or modify it under terms of the MIT, Apache License or Zlib license
7 */
8
9use core::convert::TryInto;
10
11/// Limit values to 0 and 255
12#[inline]
13#[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss, dead_code)]
14fn clamp(a: i16) -> u8 {
15 a.clamp(min:0, max:255) as u8
16}
17
18/// YCbCr to RGBA color conversion
19
20/// Convert YCbCr to RGB/BGR
21///
22/// Converts to RGB if const BGRA is false
23///
24/// Converts to BGR if const BGRA is true
25pub fn ycbcr_to_rgba_inner_16_scalar<const BGRA: bool>(
26 y: &[i16; 16], cb: &[i16; 16], cr: &[i16; 16], output: &mut [u8], pos: &mut usize
27) {
28 let (_, output_position) = output.split_at_mut(*pos);
29
30 // Convert into a slice with 64 elements for Rust to see we won't go out of bounds.
31 let opt: &mut [u8; 64] = output_position
32 .get_mut(0..64)
33 .expect("Slice to small cannot write")
34 .try_into()
35 .unwrap();
36 for ((y, (cb, cr)), out) in y
37 .iter()
38 .zip(cb.iter().zip(cr.iter()))
39 .zip(opt.chunks_exact_mut(4))
40 {
41 let cr = cr - 128;
42 let cb = cb - 128;
43
44 let r = y + ((45_i16.wrapping_mul(cr)) >> 5);
45 let g = y - ((11_i16.wrapping_mul(cb) + 23_i16.wrapping_mul(cr)) >> 5);
46 let b = y + ((113_i16.wrapping_mul(cb)) >> 6);
47
48 if BGRA {
49 out[0] = clamp(b);
50 out[1] = clamp(g);
51 out[2] = clamp(r);
52 out[3] = 255;
53 } else {
54 out[0] = clamp(r);
55 out[1] = clamp(g);
56 out[2] = clamp(b);
57 out[3] = 255;
58 }
59 }
60 *pos += 64;
61}
62
63/// Convert YCbCr to RGB/BGR
64///
65/// Converts to RGB if const BGRA is false
66///
67/// Converts to BGR if const BGRA is true
68pub fn ycbcr_to_rgb_inner_16_scalar<const BGRA: bool>(
69 y: &[i16; 16], cb: &[i16; 16], cr: &[i16; 16], output: &mut [u8], pos: &mut usize
70) {
71 let (_, output_position) = output.split_at_mut(*pos);
72
73 // Convert into a slice with 48 elements
74 let opt: &mut [u8; 48] = output_position
75 .get_mut(0..48)
76 .expect("Slice to small cannot write")
77 .try_into()
78 .unwrap();
79
80 for ((y, (cb, cr)), out) in y
81 .iter()
82 .zip(cb.iter().zip(cr.iter()))
83 .zip(opt.chunks_exact_mut(3))
84 {
85 let cr = cr - 128;
86 let cb = cb - 128;
87
88 let r = y + ((45_i16.wrapping_mul(cr)) >> 5);
89 let g = y - ((11_i16.wrapping_mul(cb) + 23_i16.wrapping_mul(cr)) >> 5);
90 let b = y + ((113_i16.wrapping_mul(cb)) >> 6);
91
92 if BGRA {
93 out[0] = clamp(b);
94 out[1] = clamp(g);
95 out[2] = clamp(r);
96 } else {
97 out[0] = clamp(r);
98 out[1] = clamp(g);
99 out[2] = clamp(b);
100 }
101 }
102
103 // Increment pos
104 *pos += 48;
105}
106
107pub fn ycbcr_to_grayscale(y: &[i16], width: usize, padded_width: usize, output: &mut [u8]) {
108 for (y_in: &[i16], out: &mut [u8]) in yChunksExact<'_, i16>
109 .chunks_exact(chunk_size:padded_width)
110 .zip(output.chunks_exact_mut(chunk_size:width))
111 {
112 for (y: &i16, out: &mut u8) in y_in.iter().zip(out.iter_mut()) {
113 *out = *y as u8;
114 }
115 }
116}
117