zune_jpeg/color_convert/
scalar.rs

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(0, 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, out) in y
109        .chunks_exact(padded_width)
110        .zip(output.chunks_exact_mut(width))
111    {
112        for (y, out) in y_in.iter().zip(out.iter_mut()) {
113            *out = *y as u8;
114        }
115    }
116}