Modular output methods
Using a `std::io::BufWriter` to wrap the output should allow more flexibility.
This commit is contained in:
parent
4d4d246353
commit
b4c7738d69
4 changed files with 56 additions and 58 deletions
|
@ -1,6 +1,6 @@
|
|||
pub mod args {
|
||||
use clap::{Parser, arg, ColorChoice};
|
||||
use super::enums::*;
|
||||
use clap::{arg, ColorChoice, Parser};
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
#[command(author, version, about, long_about = None, color = ColorChoice::Always)]
|
||||
|
@ -29,7 +29,7 @@ pub mod args {
|
|||
|
||||
impl Arguments {
|
||||
pub fn validate(&self) -> Result<(), String> {
|
||||
if self.characters.len() == 0 {
|
||||
if self.characters.is_empty() {
|
||||
return Err("No characters provided".to_string());
|
||||
} else if self.characters.len() == 1 {
|
||||
if self.mode == Mode::NormalAscii {
|
||||
|
@ -53,7 +53,7 @@ pub mod enums {
|
|||
NormalAscii,
|
||||
/// Colored ASCII art, the colors are based on the terminal colors
|
||||
#[clap(alias = "c")]
|
||||
COLORED,
|
||||
Colored,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, ValueEnum, Debug, PartialOrd, Eq, PartialEq)]
|
||||
|
|
|
@ -1,41 +1,50 @@
|
|||
use image::{GenericImageView, DynamicImage};
|
||||
use crate::args::{args::Arguments, enums::Mode};
|
||||
use colored::{ColoredString, Colorize};
|
||||
use crate::args::{
|
||||
args::Arguments,
|
||||
enums::Mode,
|
||||
};
|
||||
use image::{DynamicImage, GenericImageView};
|
||||
|
||||
pub fn generate_ascii(image: DynamicImage, args: &Arguments) -> Vec<ColoredString> {
|
||||
use std::io::{self, BufWriter, Write};
|
||||
|
||||
pub fn generate_ascii<W: Write>(
|
||||
image: DynamicImage,
|
||||
args: &Arguments,
|
||||
mut buffer: BufWriter<W>,
|
||||
) -> io::Result<()> {
|
||||
let characters = args.characters.chars().collect::<Vec<char>>();
|
||||
trace!("Characters: {:?}, length: {}", characters, characters.len());
|
||||
let mut output = Vec::new();
|
||||
let (width, height) = image.dimensions();
|
||||
|
||||
for y in 0..height {
|
||||
for x in 0..width {
|
||||
if y % (args.scale * 2) == 0 && x % args.scale == 0 {
|
||||
output.push(get_character(
|
||||
let element = get_character(
|
||||
image.get_pixel(x, y),
|
||||
&characters, args.mode,
|
||||
&characters,
|
||||
args.mode,
|
||||
&args.background,
|
||||
));
|
||||
);
|
||||
|
||||
buffer.write_all(format!("{element}").as_bytes())?;
|
||||
}
|
||||
}
|
||||
// Add a new line at the end of each row
|
||||
if y % (args.scale * 2) == 0 {
|
||||
output.push("\n".into());
|
||||
buffer.write_all("\n".as_bytes())?;
|
||||
}
|
||||
}
|
||||
|
||||
output
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_character(
|
||||
pixel: image::Rgba<u8>,
|
||||
characters: &Vec<char>, mode: Mode,
|
||||
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];
|
||||
|
||||
|
@ -43,14 +52,11 @@ fn get_character(
|
|||
|
||||
let ch = match mode {
|
||||
Mode::NormalAscii => ColoredString::from(&*ch),
|
||||
Mode::COLORED => {
|
||||
ch.to_string()
|
||||
.truecolor(pixel[0], pixel[1], pixel[2])
|
||||
}
|
||||
Mode::Colored => ch.truecolor(pixel[0], pixel[1], pixel[2]),
|
||||
};
|
||||
|
||||
match background {
|
||||
Some(bg) => ch.on_color(bg.to_string()),
|
||||
None => ch
|
||||
None => ch,
|
||||
}
|
||||
}
|
||||
|
|
42
src/main.rs
42
src/main.rs
|
@ -1,23 +1,22 @@
|
|||
use std::io::Write;
|
||||
use clap::Parser;
|
||||
use image::GenericImageView;
|
||||
|
||||
use std::io::Result;
|
||||
|
||||
extern crate pretty_env_logger;
|
||||
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
|
||||
mod args;
|
||||
mod ascii_processor;
|
||||
mod output;
|
||||
|
||||
use crate::args::{
|
||||
args::Arguments,
|
||||
enums::OutputMethod,
|
||||
};
|
||||
use crate::args::{args::Arguments, enums::OutputMethod};
|
||||
|
||||
use crate::ascii_processor::generate_ascii;
|
||||
|
||||
fn main() {
|
||||
fn main() -> Result<()> {
|
||||
// Initialize the logger
|
||||
pretty_env_logger::init();
|
||||
info!("Successfully initialized logger");
|
||||
|
@ -51,34 +50,7 @@ fn main() {
|
|||
info!("Successfully opened image");
|
||||
trace!("Image dimensions: {:?}", image.dimensions());
|
||||
|
||||
// Process the image
|
||||
let output = generate_ascii(image, &arguments);
|
||||
generate_ascii(image, &arguments, output::prepare_output(&arguments)?)?;
|
||||
info!("Successfully processed image");
|
||||
|
||||
// Output the image
|
||||
info!("Outputting image");
|
||||
match arguments.output_method {
|
||||
OutputMethod::File => {
|
||||
match std::fs::write(
|
||||
arguments.output.clone(),
|
||||
output.iter()
|
||||
.map(|s| format!("{}", s))
|
||||
.collect::<String>(),
|
||||
) {
|
||||
Ok(_) => info!("Successfully outputted image: {}", arguments.output),
|
||||
Err(e) => {
|
||||
error!("Failed to output image: {:?}", e);
|
||||
eprintln!("Failed to output image: {:?}", e);
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
OutputMethod::Stdout => {
|
||||
for char in output {
|
||||
print!("{}", char);
|
||||
std::io::stdout().flush().unwrap();
|
||||
}
|
||||
info!("Successfully outputted image");
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
20
src/output.rs
Normal file
20
src/output.rs
Normal file
|
@ -0,0 +1,20 @@
|
|||
use std::fs::File;
|
||||
use std::io;
|
||||
use std::io::BufWriter;
|
||||
use std::io::Write;
|
||||
|
||||
use super::Arguments;
|
||||
use super::OutputMethod;
|
||||
|
||||
pub fn prepare_output(arguments: &Arguments) -> io::Result<BufWriter<Box<dyn Write>>> {
|
||||
match arguments.output_method {
|
||||
OutputMethod::File => {
|
||||
let output_file = Box::new(File::create(&arguments.output)?);
|
||||
Ok(BufWriter::with_capacity(1024, output_file))
|
||||
}
|
||||
OutputMethod::Stdout => {
|
||||
let output_wrap = Box::new(std::io::stdout().lock());
|
||||
Ok(BufWriter::with_capacity(1024, output_wrap))
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue