pub fn scale2x<P>(buf: &[P], width: usize, height: usize) -> (usize, usize, Vec<P>)
where
P: Eq + Clone,
{
let width2 = width * 2;
let height2 = height * 2;
let mut scaled = vec![buf[0].clone(); width2 * height2];
for y in 1..height - 1 {
let y_this = y * width;
let scaled_y = y * 2 * width2;
for x in 1..width - 1 {
let pos = y_this + x;
apply_scale2x_block(
&mut scaled,
scaled_y + x * 2,
width2,
(
&buf[pos],
&buf[pos - width],
&buf[pos - 1],
&buf[pos + width],
&buf[pos + 1],
),
);
}
let y_prev = y_this - width;
let y_next = y_this + width;
let p = &buf[y_this];
apply_scale2x_block(
&mut scaled,
scaled_y,
width2,
(p, &buf[y_prev], p, &buf[y_next], &buf[y_this + 1]),
);
let p = &buf[y_next - 1];
apply_scale2x_block(
&mut scaled,
scaled_y + width2 - 2,
width2,
(
p,
&buf[y_this - 1],
&buf[y_next - 2],
&buf[y_next + width - 1],
p,
),
);
}
for x in 1..width - 1 {
let p = &buf[x];
apply_scale2x_block(
&mut scaled,
x * 2,
width2,
(p, p, &buf[x - 1], &buf[x + width], &buf[x + 1]),
);
let pos = (height - 1) * width + x;
let p = &buf[pos];
let scaled_y_this = ((height - 1) * 2) * width2;
apply_scale2x_block(
&mut scaled,
scaled_y_this + x * 2,
width2,
(p, &buf[pos - width], &buf[pos - 1], p, &buf[pos + 1]),
);
}
let p = &buf[0];
apply_scale2x_block(&mut scaled, 0, width2, (p, p, p, &buf[width], &buf[1]));
let x_right = width - 1;
let p = &buf[x_right];
apply_scale2x_block(
&mut scaled,
width2 - 2,
width2,
(p, p, &buf[x_right - 1], &buf[x_right + width], p),
);
let y_bottom = (height - 1) * width;
let p = &buf[y_bottom];
apply_scale2x_block(
&mut scaled,
(height2 - 2) * width2,
width2,
(p, &buf[y_bottom - width], p, p, &buf[y_bottom + 1]),
);
let y_bottom_right = y_bottom + x_right;
let p = &buf[y_bottom_right];
apply_scale2x_block(
&mut scaled,
(height2 - 2) * width2 + width2 - 2,
width2,
(
p,
&buf[y_bottom_right - width],
&buf[y_bottom_right - 1],
p,
p,
),
);
(width2, height2, scaled)
}
#[inline(always)]
fn apply_scale2x_block<P>(scaled: &mut [P], pos: usize, width: usize, pixels: (&P, &P, &P, &P, &P))
where
P: Eq + Clone,
{
let block_pixels = calculate_scale2x_block(pixels.0, pixels.1, pixels.2, pixels.3, pixels.4);
scaled[pos] = block_pixels.0;
scaled[pos + 1] = block_pixels.1;
scaled[pos + width] = block_pixels.2;
scaled[pos + width + 1] = block_pixels.3;
}
#[inline(always)]
fn calculate_scale2x_block<P>(center: &P, up: &P, left: &P, down: &P, right: &P) -> (P, P, P, P)
where
P: Eq + Clone,
{
(
(if left == up && left != right && up != right {
up
} else {
center
})
.clone(),
(if up == right && up != left && right != right {
right
} else {
center
})
.clone(),
(if right == left && right != right && left != up {
left
} else {
center
})
.clone(),
(if right == down && right != up && right != left {
down
} else {
center
})
.clone(),
)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn scale2x_test() {
let buf = [1, 2, 3, 4];
let (w, h, new) = scale2x(&buf, 2, 2);
assert_eq!(w, 4);
assert_eq!(h, 4);
assert_eq!(new, [1, 1, 2, 2, 1, 1, 2, 2, 3, 3, 4, 4, 3, 3, 4, 4]);
let buf = [1, 2, 3, 4, 5, 6, 7, 8, 9];
let (_, _, new) = scale2x(&buf, 3, 3);
let mut cmp = Vec::<usize>::new();
cmp.extend([1, 1, 2, 2, 3, 3].iter());
cmp.extend([1, 1, 2, 2, 3, 3].iter());
cmp.extend([4, 4, 5, 5, 6, 6].iter());
cmp.extend([4, 4, 5, 5, 6, 6].iter());
cmp.extend([7, 7, 8, 8, 9, 9].iter());
cmp.extend([7, 7, 8, 8, 9, 9].iter());
assert_eq!(new, cmp);
let buf = [1, 2, 3, 4, 5, 6];
let (_, _, new) = scale2x(&buf, 3, 2);
assert_eq!(
new,
[1, 1, 2, 2, 3, 3, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 4, 4, 5, 5, 6, 6]
);
}
}