use crate::format::PixelFormat;
pub fn resize(
src: &[u8],
src_width: usize,
src_height: usize,
dst_width: usize,
dst_height: usize,
format: PixelFormat,
) -> Vec<u8> {
let bpp = format.bpp();
let mut dst = vec![0u8; dst_width * dst_height * bpp];
let x_ratio = if dst_width > 1 {
(src_width - 1) as f64 / (dst_width - 1) as f64
} else {
0.0
};
let y_ratio = if dst_height > 1 {
(src_height - 1) as f64 / (dst_height - 1) as f64
} else {
0.0
};
for dy in 0..dst_height {
let sy = y_ratio * dy as f64;
let y0 = sy.floor() as usize;
let y1 = (y0 + 1).min(src_height - 1);
let y_frac = (sy - y0 as f64) as f32;
for dx in 0..dst_width {
let sx = x_ratio * dx as f64;
let x0 = sx.floor() as usize;
let x1 = (x0 + 1).min(src_width - 1);
let x_frac = (sx - x0 as f64) as f32;
let dst_offset = (dy * dst_width + dx) * bpp;
for c in 0..bpp {
let tl = src[(y0 * src_width + x0) * bpp + c] as f32;
let tr = src[(y0 * src_width + x1) * bpp + c] as f32;
let bl = src[(y1 * src_width + x0) * bpp + c] as f32;
let br = src[(y1 * src_width + x1) * bpp + c] as f32;
let top = tl + (tr - tl) * x_frac;
let bot = bl + (br - bl) * x_frac;
let val = top + (bot - top) * y_frac;
dst[dst_offset + c] = val.round().clamp(0.0, 255.0) as u8;
}
}
}
dst
}
pub fn interpolate_row(
row_top: &[u8],
row_bot: &[u8],
y_frac: f32,
src_width: usize,
dst_width: usize,
bpp: usize,
output: &mut [u8],
) {
debug_assert_eq!(row_top.len(), src_width * bpp);
debug_assert_eq!(row_bot.len(), src_width * bpp);
debug_assert_eq!(output.len(), dst_width * bpp);
let x_ratio = if dst_width > 1 {
(src_width - 1) as f64 / (dst_width - 1) as f64
} else {
0.0
};
for dx in 0..dst_width {
let sx = x_ratio * dx as f64;
let x0 = sx.floor() as usize;
let x1 = (x0 + 1).min(src_width - 1);
let x_frac = (sx - x0 as f64) as f32;
let dst_offset = dx * bpp;
for c in 0..bpp {
let tl = row_top[x0 * bpp + c] as f32;
let tr = row_top[x1 * bpp + c] as f32;
let bl = row_bot[x0 * bpp + c] as f32;
let br = row_bot[x1 * bpp + c] as f32;
let top = tl + (tr - tl) * x_frac;
let bot = bl + (br - bl) * x_frac;
let val = top + (bot - top) * y_frac;
output[dst_offset + c] = val.round().clamp(0.0, 255.0) as u8;
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_resize_identity() {
let src = vec![10, 20, 30, 40, 50, 60, 70, 80]; let dst = resize(&src, 2, 2, 2, 2, PixelFormat::GrayAlpha8);
assert_eq!(src, dst);
}
#[test]
fn test_resize_upscale_gray() {
let src = vec![0u8, 255];
let dst = resize(&src, 2, 1, 3, 1, PixelFormat::Gray8);
assert_eq!(dst.len(), 3);
assert_eq!(dst[0], 0);
assert!((dst[1] as i32 - 128).abs() <= 1);
assert_eq!(dst[2], 255);
}
#[test]
fn test_resize_downscale() {
let src = vec![0, 85, 170, 255];
let dst = resize(&src, 4, 1, 2, 1, PixelFormat::Gray8);
assert_eq!(dst[0], 0);
assert_eq!(dst[1], 255);
}
#[test]
fn test_interpolate_row_no_vertical() {
let top = vec![0u8, 255]; let bot = vec![128, 128];
let mut out = vec![0u8; 3];
interpolate_row(&top, &bot, 0.0, 2, 3, 1, &mut out);
assert_eq!(out[0], 0);
assert!((out[1] as i32 - 128).abs() <= 1);
assert_eq!(out[2], 255);
}
#[test]
fn test_interpolate_row_pure_vertical() {
let top = vec![0u8; 4]; let bot = vec![200, 200, 200, 255]; let mut out = vec![0u8; 4];
interpolate_row(&top, &bot, 0.5, 1, 1, 4, &mut out);
assert_eq!(out[0], 100);
assert_eq!(out[1], 100);
assert_eq!(out[2], 100);
assert!((out[3] as i32 - 128).abs() <= 1);
}
}