implemented braille support, including --threshold flag
This commit is contained in:
parent
3fdaa53d23
commit
2b9817080e
|
|
@ -1,12 +1,13 @@
|
||||||
use std::process::exit;
|
use std::process::exit;
|
||||||
use image::{DynamicImage, GenericImageView, Rgba};
|
use image::{DynamicImage, GenericImageView, imageops, Rgba};
|
||||||
use log::error;
|
use log::error;
|
||||||
use crate::model_rgb_ascii::Ascii;
|
use crate::model_rgb_ascii::Ascii;
|
||||||
|
|
||||||
fn get_color(pixel: (u32, u32, Rgba<u8>)) -> u8 {
|
const BRAILLE_TABLE: [[u8; 2]; 4] = [[1u8, 8u8], [2u8, 16u8], [4u8, 32u8], [64u8, 128u8]];
|
||||||
let vec = pixel.2.0;
|
|
||||||
|
fn get_color(pixel: Rgba<u8>) -> u8 {
|
||||||
//luminosity method of getting lightness
|
//luminosity method of getting lightness
|
||||||
(vec[0] as f32 * 0.3 + vec[1] as f32 * 0.59 + vec[2] as f32 * 0.11) as u8
|
(pixel[0] as f32 * 0.3 + pixel[1] as f32 * 0.59 + pixel[2] as f32 * 0.11) as u8
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_ascii(char_map: String, image: DynamicImage) -> Vec<Vec<Ascii>> {
|
fn to_ascii(char_map: String, image: DynamicImage) -> Vec<Vec<Ascii>> {
|
||||||
|
|
@ -15,8 +16,8 @@ fn to_ascii(char_map: String, image: DynamicImage) -> Vec<Vec<Ascii>> {
|
||||||
let mut out: Vec<Vec<Ascii>> = Vec::new();
|
let mut out: Vec<Vec<Ascii>> = Vec::new();
|
||||||
|
|
||||||
for pixel in image.pixels() {
|
for pixel in image.pixels() {
|
||||||
let ch = char_map.as_bytes()[((get_color(pixel) as f32-1.0)/255f32 * l) as usize];
|
let ch = char_map.as_bytes()[((get_color(pixel.2) as f32-1.0)/255f32 * l) as usize];
|
||||||
//fixme: might break with non-ASCII char_map (ie braille chars, possibly)
|
//fixme: might break with non-ASCII char_map
|
||||||
str.push(Ascii::new(ch, pixel.2[0], pixel.2[1], pixel.2[2]));
|
str.push(Ascii::new(ch, pixel.2[0], pixel.2[1], pixel.2[2]));
|
||||||
|
|
||||||
if pixel.0 == image.width()-1 {
|
if pixel.0 == image.width()-1 {
|
||||||
|
|
@ -35,11 +36,6 @@ pub fn to_complex_ascii(image: DynamicImage) -> Vec<Vec<Ascii>> {
|
||||||
to_ascii(" .'`^\",:;Il!i><~+_-?][}{1)(|\\/tfjrxnuvczXYUJCLQ0OZmwqpdbkhao*#MW&8%B@$".to_owned(), image)
|
to_ascii(" .'`^\",:;Il!i><~+_-?][}{1)(|\\/tfjrxnuvczXYUJCLQ0OZmwqpdbkhao*#MW&8%B@$".to_owned(), image)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_braille_ascii(image: DynamicImage) -> Vec<Vec<Ascii>> {
|
|
||||||
//todo: figure out braille symbols
|
|
||||||
vec![vec![Ascii::new(0, 0, 0, 0)]]
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn to_custom_ascii(char_map: String, image: DynamicImage) -> Vec<Vec<Ascii>> {
|
pub fn to_custom_ascii(char_map: String, image: DynamicImage) -> Vec<Vec<Ascii>> {
|
||||||
if char_map.is_empty() {
|
if char_map.is_empty() {
|
||||||
error!("Custom map can not be empty!");
|
error!("Custom map can not be empty!");
|
||||||
|
|
@ -47,3 +43,35 @@ pub fn to_custom_ascii(char_map: String, image: DynamicImage) -> Vec<Vec<Ascii>>
|
||||||
}
|
}
|
||||||
to_ascii(char_map, image)
|
to_ascii(char_map, image)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn to_braille_ascii(mut image: DynamicImage, threshold: u8) -> Vec<Vec<Ascii>> {
|
||||||
|
let mut str: Vec<Ascii> = Vec::new();
|
||||||
|
let mut out: Vec<Vec<Ascii>> = Vec::new();
|
||||||
|
|
||||||
|
//you know your code is good when you have a quadruple nested for loop
|
||||||
|
for y in (0..image.height()).step_by(4) {
|
||||||
|
for x in (0..image.width()).step_by(2) {
|
||||||
|
let (mut r, mut g, mut b) = (0u16, 0u16, 0u16);
|
||||||
|
let mut braille_value: u32 = 10240;
|
||||||
|
for nx in 0..2 {
|
||||||
|
for ny in 0..4 {
|
||||||
|
let pixel = image.get_pixel(x+nx, y+ny);
|
||||||
|
r = r+pixel[0] as u16;
|
||||||
|
g = g+pixel[1] as u16;
|
||||||
|
b = b+pixel[2] as u16;
|
||||||
|
if get_color(pixel) >= threshold {
|
||||||
|
braille_value += BRAILLE_TABLE[ny as usize][nx as usize] as u32;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
str.push(Ascii { char: char::from_u32(braille_value).unwrap(), rgb: [(r/8) as u8, (g/8) as u8, (b/8) as u8] });
|
||||||
|
}
|
||||||
|
out.push(str);
|
||||||
|
str = Vec::new();
|
||||||
|
}
|
||||||
|
out
|
||||||
|
}
|
||||||
|
pub fn to_box_ascii(image: DynamicImage) -> Vec<Vec<Ascii>> {
|
||||||
|
//todo: this one
|
||||||
|
vec![vec![Ascii::new(0, 0, 0,0 )]]
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,11 @@ pub struct Cli {
|
||||||
/// Takes priority over '--width'
|
/// Takes priority over '--width'
|
||||||
#[arg(short = 'f', long)]
|
#[arg(short = 'f', long)]
|
||||||
pub full: bool,
|
pub full: bool,
|
||||||
|
/// use a custom threshold when converting to braille
|
||||||
|
///
|
||||||
|
/// default is 128
|
||||||
|
#[arg(default_value_t = 128, long)]
|
||||||
|
pub threshold: u8,
|
||||||
/// use a custom character map for output
|
/// use a custom character map for output
|
||||||
///
|
///
|
||||||
/// The character map is interpreted from dark(first character) to light(last character).
|
/// The character map is interpreted from dark(first character) to light(last character).
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use termion::terminal_size;
|
use termion::terminal_size;
|
||||||
use log::{debug, error};
|
use log::{debug, error, trace};
|
||||||
use std::process::exit;
|
use std::process::exit;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use image::DynamicImage;
|
use image::DynamicImage;
|
||||||
|
|
@ -18,7 +18,7 @@ fn get_terminal_size() -> (u32, u32) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resize_image(img: DynamicImage, full: bool, opt_w: Option<u32>) -> DynamicImage {
|
pub fn resize_image(img: DynamicImage, full: bool, braille: bool, opt_w: Option<u32>) -> DynamicImage {
|
||||||
let (mut w, mut h) = (1,1);
|
let (mut w, mut h) = (1,1);
|
||||||
let (max_w, max_h) = get_terminal_size();
|
let (max_w, max_h) = get_terminal_size();
|
||||||
if full {
|
if full {
|
||||||
|
|
@ -36,6 +36,12 @@ pub fn resize_image(img: DynamicImage, full: bool, opt_w: Option<u32>) -> Dynami
|
||||||
h = (img.height() as f32 * w as f32 / img.width() as f32 * 0.5) as u32;
|
h = (img.height() as f32 * w as f32 / img.width() as f32 * 0.5) as u32;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//braille has a 2x4 character map
|
||||||
|
if braille {
|
||||||
|
w *= 2;
|
||||||
|
h *= 4;
|
||||||
|
}
|
||||||
debug!("Resizing image to (w|h): {} | {}", w, h);
|
debug!("Resizing image to (w|h): {} | {}", w, h);
|
||||||
img.resize_exact(w, h, FilterType::CatmullRom)
|
img.resize_exact(w, h, FilterType::CatmullRom)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,12 +28,12 @@ fn main() {
|
||||||
|
|
||||||
//preprocess image
|
//preprocess image
|
||||||
let mut img = open_image(cli.image);
|
let mut img = open_image(cli.image);
|
||||||
img = resize_image(img, cli.full, cli.width);
|
img = resize_image(img, cli.full, cli.braille, cli.width);
|
||||||
|
|
||||||
//converting to ASCII
|
//converting to ASCII
|
||||||
let out: Vec<Vec<Ascii>>;
|
let out: Vec<Vec<Ascii>>;
|
||||||
if cli.braille {
|
if cli.braille {
|
||||||
out = to_braille_ascii(img);
|
out = to_braille_ascii(img, cli.threshold);
|
||||||
} else if cli.complex {
|
} else if cli.complex {
|
||||||
out = to_complex_ascii(img);
|
out = to_complex_ascii(img);
|
||||||
} else if let Some(map) = cli.map {
|
} else if let Some(map) = cli.map {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue