use super::types::Subsampling;
use crate::transform::TransformOp;
#[inline]
fn pad(value: usize, alignment: usize) -> usize {
(value + alignment - 1) & !(alignment - 1)
}
pub fn jpeg_buf_size(width: usize, height: usize, subsampling: Subsampling) -> usize {
let mcu_width: usize = subsampling.mcu_width_blocks() * 8;
let mcu_height: usize = subsampling.mcu_height_blocks() * 8;
let chroma_scale_factor: usize = 4 * 64 / (mcu_width * mcu_height);
pad(width, mcu_width) * pad(height, mcu_height) * (2 + chroma_scale_factor) + 2048
}
pub fn yuv_plane_width(component: usize, width: usize, subsampling: Subsampling) -> usize {
let h_factor: usize = subsampling.mcu_width_blocks(); let padded_width: usize = pad(width, h_factor);
if component == 0 {
padded_width
} else {
padded_width * 8 / (h_factor * 8)
}
}
pub fn yuv_plane_height(component: usize, height: usize, subsampling: Subsampling) -> usize {
let v_factor: usize = subsampling.mcu_height_blocks(); let padded_height: usize = pad(height, v_factor);
if component == 0 {
padded_height
} else {
padded_height * 8 / (v_factor * 8)
}
}
pub fn yuv_plane_size(
component: usize,
width: usize,
height: usize,
subsampling: Subsampling,
) -> usize {
let plane_width: usize = yuv_plane_width(component, width, subsampling);
let plane_height: usize = yuv_plane_height(component, height, subsampling);
plane_width * plane_height
}
pub fn yuv_buf_size(width: usize, height: usize, subsampling: Subsampling) -> usize {
let mut total: usize = 0;
for component in 0..3 {
total += yuv_plane_size(component, width, height, subsampling);
}
total
}
pub fn transform_buf_size(
width: usize,
height: usize,
subsampling: Subsampling,
op: TransformOp,
) -> usize {
let swaps_dimensions: bool = matches!(
op,
TransformOp::Transpose | TransformOp::Transverse | TransformOp::Rot90 | TransformOp::Rot270
);
if swaps_dimensions {
jpeg_buf_size(height, width, subsampling)
} else {
jpeg_buf_size(width, height, subsampling)
}
}
pub fn calc_output_dimensions(
width: usize,
height: usize,
scale_num: u32,
scale_denom: u32,
) -> (usize, usize) {
let out_width: usize = (width * scale_num as usize).div_ceil(scale_denom as usize);
let out_height: usize = (height * scale_num as usize).div_ceil(scale_denom as usize);
(out_width, out_height)
}
pub fn calc_jpeg_dimensions(
width: usize,
height: usize,
subsampling: Subsampling,
) -> (usize, usize) {
let mcu_width: usize = subsampling.mcu_width_blocks() * 8;
let mcu_height: usize = subsampling.mcu_height_blocks() * 8;
(pad(width, mcu_width), pad(height, mcu_height))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn pad_rounds_up_to_power_of_two() {
assert_eq!(pad(0, 8), 0);
assert_eq!(pad(1, 8), 8);
assert_eq!(pad(7, 8), 8);
assert_eq!(pad(8, 8), 8);
assert_eq!(pad(9, 8), 16);
assert_eq!(pad(640, 16), 640);
assert_eq!(pad(641, 16), 656);
}
#[test]
fn pad_alignment_one() {
assert_eq!(pad(641, 1), 641);
assert_eq!(pad(0, 1), 0);
}
}