extern crate image;
use image::{imageops::FilterType, GenericImageView};
use std::{ffi::OsStr, path::Path};
#[cfg(feature = "fetch")]
use reqwest::IntoUrl;
#[cfg(feature = "fetch")]
use std::{fs::File, io::Write};
#[cfg(feature = "fetch")]
use tempfile::tempfile;
const CHARACTER_SET: [&str; 11] = [" ", "'", ",", ".", ":", ";", "/", "O", "0", "#", "@"];
pub struct Dimension {
width: u32,
height: u32,
}
impl Dimension {
pub fn new(width: u32, height: u32) -> Self {
Dimension { width, height }
}
pub fn width(&self) -> u32 {
self.width
}
pub fn height(&self) -> u32 {
self.height
}
}
pub fn convert_to_ascii<S: AsRef<OsStr> + ?Sized>(
path: &S,
dimensions: Option<Dimension>,
) -> String {
let path = Path::new(path);
let mut art = String::new();
if let Ok(mut image) = image::open(&path) {
let mut last_y = 0;
let dimensions = dimensions.unwrap_or(Dimension {
width: 250,
height: 250,
});
if image.width() > dimensions.width() || image.height() > dimensions.height() {
image = image.resize(dimensions.width(), dimensions.height(), FilterType::Nearest);
}
for pixel in image.pixels() {
if last_y != pixel.1 {
art.push_str("\n");
last_y = pixel.1;
}
let rgba = pixel.2;
let brightness: f64 = ((0.2126 * rgba[0] as f64)
+ (0.7152 * rgba[1] as f64)
+ (0.0722 * rgba[2] as f64)) as f64;
let position =
((brightness / 255.0) * (CHARACTER_SET.len() - 1) as f64).round() as usize;
art.push_str(CHARACTER_SET[position])
}
}
art
}
#[cfg(feature = "fetch")]
pub async fn fetch_remote_image<T: IntoUrl>(url: T) -> Result<File, Box<dyn std::error::Error>> {
let bytes = reqwest::get(url).await?.bytes().await?;
let mut out_file = tempfile()?;
out_file.write_all(&bytes)?;
Ok(out_file)
}