use std::path::Path;
use crate::core::{Pix, Pixa, PixelDepth};
use crate::io::{IoError, IoResult};
pub fn partify_files(
dir: impl AsRef<Path>,
substr: Option<&str>,
n_parts: usize,
out_root: &str,
) -> IoResult<Vec<Pixa>> {
if n_parts < 1 {
return Err(IoError::InvalidData("n_parts must be >= 1".into()));
}
let pixa = crate::io::pixa_read_files(dir, substr)?;
partify_pixac(&pixa, n_parts, out_root)
}
pub fn partify_pixac(pixa: &Pixa, n_parts: usize, _out_root: &str) -> IoResult<Vec<Pixa>> {
if n_parts < 1 {
return Err(IoError::InvalidData("n_parts must be >= 1".into()));
}
let n = pixa.len();
if n == 0 {
let mut result = Vec::with_capacity(n_parts);
for _ in 0..n_parts {
result.push(Pixa::new());
}
return Ok(result);
}
let mut parts: Vec<Pixa> = (0..n_parts).map(|_| Pixa::new()).collect();
for i in 0..n {
if let Some(pix) = pixa.get(i) {
let regions = locate_stave_sets(pix);
if regions.is_empty() || regions.len() < n_parts {
let part_idx = i % n_parts;
parts[part_idx].push(pix.clone());
} else {
for (j, region) in regions.iter().enumerate().take(n_parts) {
if let Some(clipped) = clip_to_box(pix, region) {
parts[j].push(clipped);
}
}
}
}
}
Ok(parts)
}
fn locate_stave_sets(pix: &Pix) -> Vec<crate::core::Box> {
if pix.depth() != PixelDepth::Bit1 {
return Vec::new();
}
let reduced = match crate::morph::morph_sequence(pix, "r11") {
Ok(r) => r,
Err(_) => return Vec::new(),
};
let (boxa, _) =
match crate::region::conncomp_pixa(&reduced, crate::region::ConnectivityType::EightWay) {
Ok(r) => r,
Err(_) => return Vec::new(),
};
let filtered = boxa.select_by_area(15000, crate::core::SizeRelation::GreaterThanOrEqual);
let mut boxes: Vec<crate::core::Box> = (0..filtered.len())
.filter_map(|i| filtered.get(i).cloned())
.collect();
boxes.sort_by_key(|b| b.y);
boxes
.into_iter()
.map(|b| crate::core::Box::new(b.x * 4, b.y * 4, b.w * 4, b.h * 4).unwrap_or(b))
.collect()
}
fn clip_to_box(pix: &Pix, boxx: &crate::core::Box) -> Option<Pix> {
let x0 = boxx.x.max(0) as u32;
let y0 = boxx.y.max(0) as u32;
let x1 = ((boxx.x + boxx.w) as u32).min(pix.width());
let y1 = ((boxx.y + boxx.h) as u32).min(pix.height());
if x1 <= x0 || y1 <= y0 {
return None;
}
let w = x1 - x0;
let h = y1 - y0;
let clipped = Pix::new(w, h, pix.depth()).ok()?;
let mut clipped_mut = clipped.try_into_mut().ok()?;
for y in 0..h {
for x in 0..w {
let val = pix.get_pixel(x0 + x, y0 + y).unwrap_or(0);
let _ = clipped_mut.set_pixel(x, y, val);
}
}
Some(clipped_mut.into())
}