Add the background option 🥰

This commit is contained in:
Anas Elgarhy 2022-10-03 20:50:48 +02:00
parent b885cc3fb7
commit b180ca5f56
3 changed files with 26 additions and 48 deletions

View file

@ -19,6 +19,9 @@ pub mod args {
/// The output scale (1 is the original size) /// The output scale (1 is the original size)
#[arg(short, long, default_value="4")] #[arg(short, long, default_value="4")]
pub scale: u32, pub scale: u32,
/// The background color to use
#[arg(short, long, default_value=None)]
pub background: Option<String>,
/// The output file to write to (if output_method is file) /// The output file to write to (if output_method is file)
#[arg(short, long, default_value="ascii_image.txt")] #[arg(short, long, default_value="ascii_image.txt")]
pub output: String, pub output: String,

View file

@ -1,4 +1,5 @@
use clap::arg; use clap::arg;
use clap::builder::Str;
use image::{GenericImageView, DynamicImage}; use image::{GenericImageView, DynamicImage};
use colored::{ColoredString, Colorize}; use colored::{ColoredString, Colorize};
use crate::args::{ use crate::args::{
@ -6,7 +7,7 @@ use crate::args::{
enums::Mode enums::Mode
}; };
pub fn generate_ascii(image: DynamicImage, args: &Arguments) -> Result<Vec<ColoredString>, error::ASCIIProcessingError> { pub fn generate_ascii(image: DynamicImage, args: &Arguments) -> Vec<ColoredString> {
let characters = args.characters.chars().collect::<Vec<char>>(); let characters = args.characters.chars().collect::<Vec<char>>();
trace!("Characters: {:?}, length: {}", characters, characters.len()); trace!("Characters: {:?}, length: {}", characters, characters.len());
let mut output = Vec::new(); let mut output = Vec::new();
@ -15,7 +16,11 @@ pub fn generate_ascii(image: DynamicImage, args: &Arguments) -> Result<Vec<Color
for y in 0..height { for y in 0..height {
for x in 0..width { for x in 0..width {
if y % (args.scale * 2) == 0 && x % args.scale == 0 { if y % (args.scale * 2) == 0 && x % args.scale == 0 {
output.push(get_character(image.get_pixel(x, y), &characters, args.mode)); output.push(get_character(
image.get_pixel(x, y),
&characters, args.mode,
&args.background
));
} }
} }
// Add a new line at the end of each row // Add a new line at the end of each row
@ -24,51 +29,30 @@ pub fn generate_ascii(image: DynamicImage, args: &Arguments) -> Result<Vec<Color
} }
} }
Ok(output) output
} }
fn get_character(pixel: image::Rgba<u8>, characters: &Vec<char>, mode: Mode) -> ColoredString { fn get_character(
pixel: image::Rgba<u8>,
characters: &Vec<char>, mode: Mode,
background: &Option<String>
) -> ColoredString {
let intent = if pixel[3] == 0 { 0 } else { pixel[0] / 3 + pixel[1] / 3 + pixel[2] / 3 }; let intent = if pixel[3] == 0 { 0 } else { pixel[0] / 3 + pixel[1] / 3 + pixel[2] / 3 };
let ch = characters[(intent / (32 + 7 - (7 + (characters.len() - 7)) as u8)) as usize]; let ch = characters[(intent / (32 + 7 - (7 + (characters.len() - 7)) as u8)) as usize];
let ch = String::from(ch); let ch = String::from(ch);
match mode { let ch = match mode {
Mode::NormalAscii => ColoredString::from(&*ch), Mode::NormalAscii => ColoredString::from(&*ch),
Mode::COLORED => { Mode::COLORED => {
ch.to_string() ch.to_string()
.truecolor(pixel[0], pixel[1], pixel[2]) .truecolor(pixel[0], pixel[1], pixel[2])
} }
} };
}
mod error { match background {
use std::error::Error; Some(bg) => ch.on_color(bg.to_string()),
use std::fmt::{Debug, Display, Formatter}; None => ch
#[derive(Debug)]
pub struct ASCIIProcessingError {
message: String,
}
impl ASCIIProcessingError {
pub fn new(message: String) -> Self {
ASCIIProcessingError {
message
}
}
}
impl Display for ASCIIProcessingError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.message)
}
}
impl Error for ASCIIProcessingError {
fn description(&self) -> &str {
&self.message
}
} }
} }

View file

@ -1,7 +1,7 @@
use std::io::Write; use std::io::Write;
use clap::Parser; use clap::Parser;
use image::GenericImageView; use image::GenericImageView;
use colored::Colorize;
extern crate pretty_env_logger; extern crate pretty_env_logger;
#[macro_use] #[macro_use]
@ -12,7 +12,7 @@ mod ascii_processor;
use crate::args::{ use crate::args::{
args::Arguments, args::Arguments,
enums::{Mode, OutputMethod}, enums::OutputMethod,
}; };
use crate::ascii_processor::generate_ascii; use crate::ascii_processor::generate_ascii;
@ -52,17 +52,8 @@ fn main() {
trace!("Image dimensions: {:?}", image.dimensions()); trace!("Image dimensions: {:?}", image.dimensions());
// Process the image // Process the image
let output = match generate_ascii(image, &arguments) { let output = generate_ascii(image, &arguments);
Ok(out) => {
info!("Successfully processed image"); info!("Successfully processed image");
out
}
Err(e) => {
error!("Failed to process image: {:?}", e);
eprintln!("Failed to process image: {:?}", e);
std::process::exit(1);
}
};
// Output the image // Output the image
info!("Outputting image"); info!("Outputting image");