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 | |
9 | use 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)] |
14 | fn 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 |
25 | pub 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 |
68 | pub 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 | |
107 | pub 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 | |