zune_jpeg/upsampler/
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
9pub fn upsample_horizontal(
10    input: &[i16], _ref: &[i16], _in_near: &[i16], _scratch: &mut [i16], output: &mut [i16]
11) {
12    assert_eq!(
13        input.len() * 2,
14        output.len(),
15        "Input length is not half the size of the output length"
16    );
17    assert!(
18        output.len() > 4 && input.len() > 2,
19        "Too Short of a vector, cannot upsample"
20    );
21
22    output[0] = input[0];
23    output[1] = (input[0] * 3 + input[1] + 2) >> 2;
24
25    // This code is written for speed and not readability
26    //
27    // The readable code is
28    //
29    //      for i in 1..input.len() - 1{
30    //         let sample = 3 * input[i] + 2;
31    //         out[i * 2] = (sample + input[i - 1]) >> 2;
32    //         out[i * 2 + 1] = (sample + input[i + 1]) >> 2;
33    //     }
34    //
35    // The output of a pixel is determined by it's surrounding neighbours but we attach more weight to it's nearest
36    // neighbour (input[i]) than to the next nearest neighbour.
37
38    for (output_window, input_window) in output[2..].chunks_exact_mut(2).zip(input.windows(3)) {
39        let sample = 3 * input_window[1] + 2;
40
41        output_window[0] = (sample + input_window[0]) >> 2;
42        output_window[1] = (sample + input_window[2]) >> 2;
43    }
44    // Get lengths
45    let out_len = output.len() - 2;
46    let input_len = input.len() - 2;
47
48    // slice the output vector
49    let f_out = &mut output[out_len..];
50    let i_last = &input[input_len..];
51
52    // write out manually..
53    f_out[0] = (3 * i_last[0] + i_last[1] + 2) >> 2;
54    f_out[1] = i_last[1];
55}
56pub fn upsample_vertical(
57    input: &[i16], in_near: &[i16], in_far: &[i16], _scratch_space: &mut [i16], output: &mut [i16]
58) {
59    assert_eq!(input.len() * 2, output.len());
60    assert_eq!(in_near.len(), input.len());
61    assert_eq!(in_far.len(), input.len());
62
63    let middle = output.len() / 2;
64
65    let (out_top, out_bottom) = output.split_at_mut(middle);
66
67    // for the first row, closest row is in_near
68    for ((near, far), x) in input.iter().zip(in_near.iter()).zip(out_top) {
69        *x = (((3 * near) + 2) + far) >> 2;
70    }
71    // for the second row, the closest row to input is in_far
72    for ((near, far), x) in input.iter().zip(in_far.iter()).zip(out_bottom) {
73        *x = (((3 * near) + 2) + far) >> 2;
74    }
75}
76
77pub fn upsample_hv(
78    input: &[i16], in_near: &[i16], in_far: &[i16], scratch_space: &mut [i16], output: &mut [i16]
79) {
80    assert_eq!(input.len() * 4, output.len());
81
82    let mut t = [0];
83    upsample_vertical(input, in_near, in_far, &mut t, scratch_space);
84    // horizontal upsampling must be done separate for every line
85    // Otherwise it introduces artifacts that may cause the edge colors
86    // to appear on the other line.
87
88    // Since this is called for two scanlines/widths currently
89    // splitting the inputs and outputs into half ensures we only handle
90    // one scanline per iteration
91    let scratch_half = scratch_space.len() / 2;
92
93    let output_half = output.len() / 2;
94
95    upsample_horizontal(
96        &scratch_space[..scratch_half],
97        &[],
98        &[],
99        &mut t,
100        &mut output[..output_half]
101    );
102
103    upsample_horizontal(
104        &scratch_space[scratch_half..],
105        &[],
106        &[],
107        &mut t,
108        &mut output[output_half..]
109    );
110}