use std::path::Path;
extern crate image;
use image::{GenericImageView, RgbImage, SubImage};
use log::warn;
use crate::error::Error;
pub fn crop_imm_centered<I>(img: &I, width: u32, height: u32) -> SubImage<&I>
where
I: GenericImageView,
{
if width > img.width() || height > img.height() {
warn!("Attempted to crop image to a larger size than the source image");
}
image::imageops::crop_imm(
img,
(img.width() - width) / 2,
(img.height() - height) / 2,
width,
height,
)
}
pub fn read_images_from_dir<P: AsRef<Path>>(tile_dir: P) -> Result<Vec<RgbImage>, Error> {
Ok(tile_dir
.as_ref()
.read_dir()?
.filter_map(|entry| match entry {
Ok(p) => match image::open(p.path()) {
Ok(img) => Some(img.to_rgb8()),
Err(e) => {
warn!("Failed to open image at path {:?}: {:?}", p.path(), e);
None
}
},
Err(e) => {
warn!("Failed to read directory entry: {:?}", e);
None
}
})
.collect::<Vec<_>>())
}
pub fn read_images_from_dir_cropped<P: AsRef<Path>>(
tile_dir: P,
width: u32,
height: u32,
) -> Result<Vec<RgbImage>, Error> {
Ok(read_images_from_dir(tile_dir)?
.iter()
.map(|img| crop_imm_centered(img, width, height).to_image())
.collect::<Vec<_>>())
}
pub fn read_images_from_dir_resized<P: AsRef<Path>>(
tile_dir: P,
width: u32,
height: u32,
filter: image::imageops::FilterType,
) -> Result<Vec<RgbImage>, Error> {
Ok(read_images_from_dir(tile_dir)?
.iter()
.map(|img| image::imageops::resize(img, width, height, filter))
.collect::<Vec<_>>())
}
#[cfg(test)]
mod tests {
use super::*;
use std::path::PathBuf;
fn test_dir() -> PathBuf {
PathBuf::from("tests/data/mosaic")
}
fn test_tile_dir() -> PathBuf {
test_dir().join("tiles/")
}
#[test]
fn test_crop_imm_centered() {
let mut img = image::RgbImage::from_pixel(11, 11, image::Rgb([255, 255, 255]));
img.put_pixel(5, 5, image::Rgb([0, 0, 0]));
let cropped = crop_imm_centered(&img, 5, 5);
assert_eq!(cropped.dimensions(), (5, 5));
assert_eq!(cropped.get_pixel(2, 2), image::Rgb([0, 0, 0]));
let cropped = crop_imm_centered(&img, 1, 1);
assert_eq!(cropped.dimensions(), (1, 1));
assert_eq!(cropped.get_pixel(0, 0), image::Rgb([0, 0, 0]));
}
#[test]
fn test_read_images_from_dir() {
let images = read_images_from_dir(test_tile_dir()).unwrap();
assert_eq!(images.len(), 16);
assert!(images.iter().all(|img| img.dimensions() == (64, 64)));
}
#[test]
fn test_read_images_from_dir_cropped() {
let (width, height) = (32, 32);
let images = read_images_from_dir_cropped(test_tile_dir(), width, height).unwrap();
assert_eq!(images.len(), 16);
assert!(images.iter().all(|img| img.dimensions() == (width, height)));
}
#[test]
fn test_read_images_from_dir_resized() {
let (width, height) = (32, 32);
let images = read_images_from_dir_resized(
test_tile_dir(),
width,
height,
image::imageops::FilterType::Nearest,
)
.unwrap();
assert_eq!(images.len(), 16);
assert!(images.iter().all(|img| img.dimensions() == (width, height)));
}
}