image_splitting/
lib.rs

1//! Image Splitting Library
2//! 
3//! This library provides functionality to split images into smaller sub-images.
4//! It supports both equal division (3x3 grid) and custom-sized sub-images.
5
6use image::{GenericImageView, ImageBuffer, Rgba};
7use std::path::Path;
8
9/// Splits an image into 9 equal parts (3x3 grid).
10/// 
11/// # Arguments
12/// 
13/// * `image_path` - Path to the input image file
14/// 
15/// # Returns
16/// 
17/// * `Result<Vec<ImageBuffer<Rgba<u8>, Vec<u8>>>, image::ImageError>` - A vector of 9 sub-images or an error if the operation fails
18/// 
19/// # Example
20/// 
21/// ```
22/// use image_splitting::split_image;
23/// 
24/// let sub_images = split_image("path/to/image.png")?;
25/// assert_eq!(sub_images.len(), 9);
26/// ```
27pub fn split_image<P: AsRef<Path>>(image_path: P) -> Result<Vec<ImageBuffer<Rgba<u8>, Vec<u8>>>, image::ImageError> {
28    // Load the image
29    let img = image::open(image_path)?;
30    
31    // Get image dimensions
32    let (width, height) = img.dimensions();
33    
34    // Calculate dimensions for each sub-image
35    let sub_width = width / 3;
36    let sub_height = height / 3;
37    
38    let mut sub_images = Vec::new();
39    
40    // Split the image into 9 parts
41    for y in 0..3 {
42        for x in 0..3 {
43            let sub_img = img.crop_imm(
44                x * sub_width,
45                y * sub_height,
46                sub_width,
47                sub_height
48            );
49            
50            sub_images.push(sub_img.to_rgba8());
51        }
52    }
53    
54    Ok(sub_images)
55}
56
57/// Splits an image into sub-images of specified dimensions.
58/// 
59/// This function allows splitting an image into sub-images of any size. The last row and column
60/// may be smaller if the image dimensions aren't perfectly divisible by the specified sub-image size.
61/// 
62/// # Arguments
63/// 
64/// * `image_path` - Path to the input image file
65/// * `sub_width` - Desired width of each sub-image
66/// * `sub_height` - Desired height of each sub-image
67/// 
68/// # Returns
69/// 
70/// * `Result<Vec<ImageBuffer<Rgba<u8>, Vec<u8>>>, image::ImageError>` - A vector of sub-images or an error if the operation fails
71/// 
72/// # Example
73/// 
74/// ```
75/// use image_splitting::split_image_with_size;
76/// 
77/// let sub_images = split_image_with_size("path/to/image.png", 100, 100)?;
78/// ```
79pub fn split_image_with_size<P: AsRef<Path>>(
80    image_path: P,
81    sub_width: u32,
82    sub_height: u32,
83) -> Result<Vec<ImageBuffer<Rgba<u8>, Vec<u8>>>, image::ImageError> {
84    // Load the image
85    let img = image::open(image_path)?;
86    
87    // Get image dimensions
88    let (width, height) = img.dimensions();
89    
90    // Calculate number of sub-images in each dimension using ceiling division
91    let num_cols = (width + sub_width - 1) / sub_width;
92    let num_rows = (height + sub_height - 1) / sub_height;
93    
94    let mut sub_images = Vec::new();
95    
96    // Split the image into parts
97    for y in 0..num_rows {
98        for x in 0..num_cols {
99            let x_pos = x * sub_width;
100            let y_pos = y * sub_height;
101            
102            // Calculate actual dimensions for the last row/column
103            let actual_width = (width - x_pos).min(sub_width);
104            let actual_height = (height - y_pos).min(sub_height);
105            
106            let sub_img = img.crop_imm(
107                x_pos,
108                y_pos,
109                actual_width,
110                actual_height
111            );
112            
113            sub_images.push(sub_img.to_rgba8());
114        }
115    }
116    
117    Ok(sub_images)
118}
119
120#[cfg(test)]
121mod tests {
122    use super::*;
123
124    #[test]
125    fn test_split_image() {
126        // This test assumes there's a test image in the tests directory
127        let result = split_image("tests/test_image.png");
128        assert!(result.is_ok());
129        let sub_images = result.unwrap();
130        assert_eq!(sub_images.len(), 9);
131    }
132
133    #[test]
134    fn test_split_image_with_size() {
135        let result = split_image_with_size("tests/test_image.png", 100, 100);
136        assert!(result.is_ok());
137        let sub_images = result.unwrap();
138        assert!(sub_images.len() > 0);
139    }
140}