use clap::ValueEnum;
#[derive(Copy, Clone, Debug, ValueEnum)]
pub enum LayoutType {
#[value(name = "two-up")]
TwoUp,
#[value(name = "four-up")]
FourUp,
}
pub fn generate_booklet_imposition(n: u32, layout: LayoutType) -> Vec<u32> {
if n == 0 {
return Vec::new();
}
let pages_per_physical_sheet: u32 = match layout {
LayoutType::TwoUp => 4,
LayoutType::FourUp => 8,
};
let total_pages = n.div_ceil(pages_per_physical_sheet) * pages_per_physical_sheet;
let mut imposition_list: Vec<u32> = Vec::new();
let num_physical_sheets = total_pages / pages_per_physical_sheet;
for k in 0..num_physical_sheets {
match layout {
LayoutType::FourUp => {
let side_a_pages = [
total_pages - (4 * k), 1 + (4 * k), total_pages - (4 * k + 2), 3 + (4 * k), ];
imposition_list.extend_from_slice(&side_a_pages);
let side_b_pages = [
2 + (4 * k), total_pages - (4 * k + 1), 4 + (4 * k), total_pages - (4 * k + 3), ];
imposition_list.extend_from_slice(&side_b_pages);
}
LayoutType::TwoUp => {
let side_a_pages = [
total_pages - (2 * k), 1 + (2 * k), ];
imposition_list.extend_from_slice(&side_a_pages);
let side_b_pages = [
2 + (2 * k), total_pages - (2 * k + 1), ];
imposition_list.extend_from_slice(&side_b_pages);
}
}
}
let final_imposition_list: Vec<u32> = imposition_list
.into_iter()
.map(|p| if p > n { 0 } else { p })
.collect();
final_imposition_list
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_eight_up_n_0_pages() {
assert_eq!(generate_booklet_imposition(0, LayoutType::FourUp), vec![]);
}
#[test]
fn test_eight_up_n_16_pages() {
let expected = vec![
16, 1, 14, 3, 2, 15, 4, 13, 12, 5, 10, 7, 6, 11, 8, 9, ];
assert_eq!(
generate_booklet_imposition(16, LayoutType::FourUp),
expected
);
}
#[test]
fn test_eight_up_n_1_page() {
let expected = vec![0, 1, 0, 0, 0, 0, 0, 0];
assert_eq!(generate_booklet_imposition(1, LayoutType::FourUp), expected);
}
#[test]
fn test_eight_up_n_8_pages() {
let expected = vec![8, 1, 6, 3, 2, 7, 4, 5];
assert_eq!(generate_booklet_imposition(8, LayoutType::FourUp), expected);
}
#[test]
fn test_eight_up_n_5_pages() {
let expected = vec![0, 1, 0, 3, 2, 0, 4, 5];
assert_eq!(generate_booklet_imposition(5, LayoutType::FourUp), expected);
}
#[test]
fn test_four_up_n_0_pages() {
assert_eq!(generate_booklet_imposition(0, LayoutType::TwoUp), vec![]);
}
#[test]
fn test_four_up_n_4_pages() {
let expected = vec![4, 1, 2, 3];
assert_eq!(generate_booklet_imposition(4, LayoutType::TwoUp), expected);
}
#[test]
fn test_four_up_n_8_pages() {
let expected = vec![8, 1, 2, 7, 6, 3, 4, 5];
assert_eq!(generate_booklet_imposition(8, LayoutType::TwoUp), expected);
}
#[test]
fn test_four_up_n_1_page() {
let expected = vec![0, 1, 0, 0];
assert_eq!(generate_booklet_imposition(1, LayoutType::TwoUp), expected);
}
#[test]
fn test_four_up_n_6_pages() {
let expected = vec![
0, 1, 2, 0, 6, 3, 4, 5,
];
assert_eq!(generate_booklet_imposition(6, LayoutType::TwoUp), expected);
}
}