use std::{collections::HashMap, fs::create_dir_all, path::Path};
use ab_glyph::{FontRef, PxScale};
use image::{DynamicImage, GenericImageView, ImageBuffer, Luma, Pixel, Rgba};
use imageproc::drawing::draw_text_mut;
use super::font::get_character_dimensions;
pub fn check_and_create_directory(output_directory: Option<&str>) -> Result<(), String> {
if output_directory.is_some() {
let path = Path::new(output_directory.unwrap());
if path.exists() {
if !path.is_dir() {
return Err(format!(
"Path exists but is not a directory: {}",
output_directory.unwrap()
));
}
} else {
let _ = create_dir_all(path);
}
}
return Ok(());
}
pub fn get_character_line_list_based_on_luma(
character_list: Vec<char>,
img: &DynamicImage,
num_cols: u32,
cell_width: u32,
width: u32,
cell_height: u32,
height: u32,
current_row: u32,
) -> Vec<char> {
let index_scale_factor = (character_list.len() - 1) as f32 / 255.0;
let mut character_line_list: Vec<char> = Vec::with_capacity(num_cols as usize);
for i in 0..num_cols {
let pixel = img.get_pixel(
(i * cell_width).min(width),
(current_row * cell_height).min(height),
);
let luma = pixel[0];
let index = (luma as f32 * index_scale_factor).round() as usize;
character_line_list.push(character_list[index]);
}
return character_line_list;
}
pub fn get_character_and_rgba_based_on_rgba(
character_list: Vec<char>,
img: &DynamicImage,
cell_width: u32,
width: u32,
cell_height: u32,
height: u32,
current_row: u32,
current_column: u32,
) -> (char, Rgba<u8>) {
let index_scale_factor = (character_list.len() - 1) as f32 / 255.0;
let pixel_rgba = img
.get_pixel(
(current_column * cell_width).min(width),
(current_row * cell_height).min(height),
)
.to_rgba();
let average_rgb = (pixel_rgba[0] as f32 + pixel_rgba[1] as f32 + pixel_rgba[2] as f32) / 3.0;
let index = (average_rgb * index_scale_factor).round() as usize;
return (character_list[index], pixel_rgba);
}
#[derive(Debug, Clone)]
struct CharacterBrightness {
pub character: char,
pub brightness: f32,
}
pub fn sort_character_brightness(
character_list: Vec<char>,
font_data: &'static [u8],
scale: PxScale,
) -> Vec<char> {
let num_char = character_list.len();
let mut character_brightness_list: Vec<CharacterBrightness> = vec![];
for character in character_list {
let font = FontRef::try_from_slice(font_data).unwrap();
let (width, height) = get_character_dimensions(scale, character, font_data);
let mut img: ImageBuffer<Luma<u8>, Vec<u8>> =
ImageBuffer::from_pixel(width, height, Luma([0]));
draw_text_mut(
&mut img,
Luma([255]),
0,
0,
scale,
&font,
&character.to_string(),
);
let brightness =
(img.pixels().map(|x| x[0] as f32).sum::<f32>()) / (img.pixels().len() as f32);
character_brightness_list.push(CharacterBrightness {
character,
brightness,
});
}
character_brightness_list.sort_by(|a, b| a.brightness.partial_cmp(&b.brightness).unwrap());
let mut character_list_sorted: Vec<char> = vec![];
let increment_step = (character_brightness_list[character_brightness_list.len() - 1]
.brightness
- character_brightness_list[0].brightness)
/ (num_char as f32);
let mut current_value = character_brightness_list[0].brightness;
for item in character_brightness_list.clone() {
if item.brightness >= current_value {
character_list_sorted.push(item.character);
current_value += increment_step;
}
}
if character_list_sorted[character_list_sorted.len() - 1]
!= character_brightness_list[character_brightness_list.len() - 1].character
{
character_list_sorted
.push(character_brightness_list[character_brightness_list.len() - 1].character);
}
return character_list_sorted;
}
pub fn get_img_flatten_rgb_and_color_map(
img_list: &Vec<ImageBuffer<Rgba<u8>, Vec<u8>>>,
) -> (Vec<Vec<u8>>, Vec<u8>) {
let mut flatten_rgb: Vec<Vec<u8>> = Vec::new();
let mut color_map: Vec<u8> = Vec::new();
let mut color_map_hashmap = HashMap::new();
for img in img_list {
let mut flat_rgb_list: Vec<u8> = Vec::new();
for pixel in img.pixels() {
let rgb = [pixel[0], pixel[1], pixel[2]];
if !color_map_hashmap.contains_key(&rgb) && color_map.len() / 3 < 256 {
color_map_hashmap.insert(rgb, color_map.len() / 3);
color_map.extend_from_slice(&rgb);
}
flat_rgb_list.extend_from_slice(&[pixel[0], pixel[1], pixel[2]]);
}
flatten_rgb.push(flat_rgb_list);
}
while color_map.len() / 3 < 256 {
color_map.extend_from_slice(&[0, 0, 0]); }
return (flatten_rgb, color_map);
}
pub fn get_img_flatten_gray_and_color_map(
img_list: &Vec<ImageBuffer<Luma<u8>, Vec<u8>>>,
) -> (Vec<Vec<u8>>, Vec<u8>) {
let mut flatten_gray: Vec<Vec<u8>> = Vec::new();
let mut color_map: Vec<u8> = Vec::new();
for img in img_list {
let mut flat_gray_list: Vec<u8> = Vec::new();
for pixel in img.pixels() {
flat_gray_list.extend_from_slice(&[pixel[0], pixel[0], pixel[0]]);
}
flatten_gray.push(flat_gray_list);
}
for i in 0..=255 {
color_map.extend_from_slice(&[i, i, i]);
}
return (flatten_gray, color_map);
}