fixed resizing image
This commit is contained in:
parent
5a1eda07da
commit
b00ef93c1c
|
|
@ -1,4 +1,6 @@
|
||||||
|
use std::process::exit;
|
||||||
use image::{DynamicImage, GenericImageView, Rgba};
|
use image::{DynamicImage, GenericImageView, Rgba};
|
||||||
|
use log::error;
|
||||||
|
|
||||||
//todo: consider how to take care of the a channel => do we want to render that as background?
|
//todo: consider how to take care of the a channel => do we want to render that as background?
|
||||||
fn get_color(pixel: (u32, u32, Rgba<u8>)) -> u8 {
|
fn get_color(pixel: (u32, u32, Rgba<u8>)) -> u8 {
|
||||||
|
|
@ -8,7 +10,6 @@ fn get_color(pixel: (u32, u32, Rgba<u8>)) -> u8 {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_ascii(char_map: String, image: DynamicImage) -> Vec<String> {
|
fn to_ascii(char_map: String, image: DynamicImage) -> Vec<String> {
|
||||||
//todo: add color support
|
|
||||||
let l = char_map.len() as f32;
|
let l = char_map.len() as f32;
|
||||||
let mut str = String::new();
|
let mut str = String::new();
|
||||||
let mut out: Vec<String> = Vec::new();
|
let mut out: Vec<String> = Vec::new();
|
||||||
|
|
@ -39,6 +40,11 @@ pub fn to_braille_ascii(image: DynamicImage) -> Vec<String> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_custom_ascii(char_map: String, image: DynamicImage) -> Vec<String> {
|
pub fn to_custom_ascii(char_map: String, image: DynamicImage) -> Vec<String> {
|
||||||
//todo: this
|
if char_map.is_empty() {
|
||||||
vec!["not implemented".to_owned()]
|
error!("Custom map can not be empty!");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
to_ascii(char_map, image)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//todo: replace Vec<String> with a custom struct containing rgb information as well as character (for coloured output)
|
||||||
30
src/cli.rs
30
src/cli.rs
|
|
@ -3,7 +3,6 @@ use std::path::PathBuf;
|
||||||
use std::process::exit;
|
use std::process::exit;
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use log::{debug, error};
|
use log::{debug, error};
|
||||||
use image;
|
|
||||||
|
|
||||||
/// Convert an image to ASCII art and print it to the terminal.
|
/// Convert an image to ASCII art and print it to the terminal.
|
||||||
///
|
///
|
||||||
|
|
@ -11,23 +10,40 @@ use image;
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
pub struct Cli {
|
pub struct Cli {
|
||||||
/// Use a larger range of characters
|
/// Use a larger range of characters
|
||||||
|
///
|
||||||
|
/// Takes priority over '--map'
|
||||||
#[arg(short = 'c', long)]
|
#[arg(short = 'c', long)]
|
||||||
pub complex: bool,
|
pub complex: bool,
|
||||||
/// Display ASCII art in full colour
|
/// Display ASCII art in full colour
|
||||||
#[arg(short = 'C', long)]
|
#[arg(short = 'C', long)]
|
||||||
pub colour: bool,
|
pub colour: bool,
|
||||||
/// Use braille characters instead of ASCII
|
/// Use braille characters instead of ASCII
|
||||||
|
///
|
||||||
|
/// Takes priority over '--complex' and '--map'
|
||||||
#[arg(short = 'b', long)]
|
#[arg(short = 'b', long)]
|
||||||
pub braille: bool,
|
pub braille: bool,
|
||||||
/// Print debugging information
|
/// Print debugging information
|
||||||
#[arg(short = 'd', long)]
|
#[arg(short = 'd', long)]
|
||||||
pub debug: bool,
|
pub debug: bool,
|
||||||
|
/// use the full width of the terminal
|
||||||
|
///
|
||||||
|
/// Takes priority over '--width'
|
||||||
|
#[arg(short = 'f', long)]
|
||||||
|
pub full: bool,
|
||||||
|
/// use a custom character map for output
|
||||||
|
///
|
||||||
|
/// The character map is interpreted from dark(first character) to light(last character).
|
||||||
|
/// The map can be any size, but at least 2 characters is recommended.
|
||||||
|
#[arg(short = 'M', long)]
|
||||||
|
pub map: Option<String>,
|
||||||
/// Image path
|
/// Image path
|
||||||
pub image: PathBuf,
|
pub image: PathBuf,
|
||||||
#[arg(short = 'w', long)]
|
|
||||||
/// Set the width of the output, instead of using terminal width
|
/// Set the width of the output, instead of using terminal width
|
||||||
pub width: Option<u16>,
|
#[arg(short = 'w', long)]
|
||||||
|
pub width: Option<u32>,
|
||||||
/// Save the output to a file, instead of printing to terminal
|
/// Save the output to a file, instead of printing to terminal
|
||||||
|
///
|
||||||
|
/// Incompatible with '--colour' and '--braille'
|
||||||
#[arg(short = 'o', long = "output")]
|
#[arg(short = 'o', long = "output")]
|
||||||
pub output: Option<PathBuf>,
|
pub output: Option<PathBuf>,
|
||||||
}
|
}
|
||||||
|
|
@ -39,7 +55,13 @@ impl Cli {
|
||||||
debug!("colour: {}", self.colour);
|
debug!("colour: {}", self.colour);
|
||||||
debug!("braille: {}", self.braille);
|
debug!("braille: {}", self.braille);
|
||||||
debug!("debug: {}", self.debug);
|
debug!("debug: {}", self.debug);
|
||||||
debug!("width: {}", self.width.unwrap_or(u16::MAX));
|
debug!("full: {}", self.full);
|
||||||
|
if let Some(map) = self.map.clone() {
|
||||||
|
debug!("map: \"{}\"", map);
|
||||||
|
} else {
|
||||||
|
debug!("map: None");
|
||||||
|
}
|
||||||
|
debug!("width: {}", self.width.unwrap_or(u32::MAX));
|
||||||
debug!("image: {}", self.image.display());
|
debug!("image: {}", self.image.display());
|
||||||
if let Some(output) = self.output.clone() {
|
if let Some(output) = self.output.clone() {
|
||||||
debug!("output: {}", output.display());
|
debug!("output: {}", output.display());
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,15 @@
|
||||||
use std::cmp::min;
|
|
||||||
use termion::terminal_size;
|
use termion::terminal_size;
|
||||||
use log::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;
|
||||||
|
use image::imageops::FilterType;
|
||||||
|
|
||||||
fn get_terminal_size() -> u32 {
|
fn get_terminal_size() -> (u32, u32) {
|
||||||
let size = terminal_size();
|
let size = terminal_size();
|
||||||
match size {
|
match size {
|
||||||
Ok(size) => {
|
Ok(size) => {
|
||||||
size.0 as u32
|
(size.0 as u32, size.1 as u32)
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error!("Failed to get terminal size: {}", e.to_string());
|
error!("Failed to get terminal size: {}", e.to_string());
|
||||||
|
|
@ -18,12 +18,26 @@ fn get_terminal_size() -> u32 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_size(w: Option<u16>, img_w: u32) -> u16 {
|
pub fn resize_image(img: DynamicImage, full: bool, opt_w: Option<u32>) -> DynamicImage {
|
||||||
if None == w {
|
let (mut w, mut h) = (1,1);
|
||||||
min(get_terminal_size(), img_w) as u16
|
if full {
|
||||||
|
w = get_terminal_size().0;
|
||||||
|
h = (img.height() as f32 * w as f32 / img.width() as f32 * 0.5) as u32;
|
||||||
|
} else if let Some(act_w) = opt_w {
|
||||||
|
w = act_w;
|
||||||
|
h = (img.height() as f32 * w as f32 / img.width() as f32 * 0.5) as u32;
|
||||||
} else {
|
} else {
|
||||||
w.unwrap()
|
let (max_w, max_h) = get_terminal_size();
|
||||||
|
if max_h*max_w/2 > img.height()*img.width() {
|
||||||
|
h = max_h;
|
||||||
|
w = (img.width() as f32 * h as f32 / img.height() as f32 * 2.0) as u32;
|
||||||
|
} else {
|
||||||
|
w = max_w;
|
||||||
|
h = (img.height() as f32 * w as f32 / img.height() as f32 * 0.5) as u32;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
debug!("Resizing image to (w|h): {} | {}", w, h);
|
||||||
|
img.resize_exact(w, h, FilterType::CatmullRom)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn open_image(path: PathBuf) -> DynamicImage {
|
pub fn open_image(path: PathBuf) -> DynamicImage {
|
||||||
|
|
|
||||||
40
src/main.rs
40
src/main.rs
|
|
@ -1,8 +1,8 @@
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use image::imageops::FilterType;
|
use crate::ascii_manipulation::*;
|
||||||
use crate::ascii_manipulation::to_simple_ascii;
|
|
||||||
use crate::cli::Cli;
|
use crate::cli::Cli;
|
||||||
use crate::output::print_terminal;
|
use crate::output::*;
|
||||||
|
use crate::image_manipulation::*;
|
||||||
|
|
||||||
mod cli;
|
mod cli;
|
||||||
mod image_manipulation;
|
mod image_manipulation;
|
||||||
|
|
@ -10,7 +10,9 @@ mod ascii_manipulation;
|
||||||
mod output;
|
mod output;
|
||||||
|
|
||||||
//todo: general
|
//todo: general
|
||||||
/* https://stackoverflow.com/questions/69981449/how-do-i-print-colored-text-to-the-terminal-in-rust
|
/* Documentation
|
||||||
|
* Readme
|
||||||
|
* https://stackoverflow.com/questions/69981449/how-do-i-print-colored-text-to-the-terminal-in-rust
|
||||||
*/
|
*/
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
@ -21,21 +23,33 @@ fn main() {
|
||||||
cli.init();
|
cli.init();
|
||||||
cli.validate();
|
cli.validate();
|
||||||
|
|
||||||
let mut img = image_manipulation::open_image(cli.image);
|
//preprocess image
|
||||||
let w = image_manipulation::get_size(cli.width, img.width());
|
let mut img = open_image(cli.image);
|
||||||
|
img = resize_image(img, cli.full, cli.width);
|
||||||
|
|
||||||
//todo: change logic to include -full flag for max width, otherwise use max height?
|
//converting to ASCII
|
||||||
let h: u32 = (img.height() as f32 * w as f32 / img.width() as f32 * 0.5) as u32;
|
let out: Vec<String>;
|
||||||
img = img.resize_exact(w as u32, h, FilterType::CatmullRom);
|
if cli.braille {
|
||||||
|
out = to_braille_ascii(img);
|
||||||
|
} else if cli.complex {
|
||||||
|
out = to_complex_ascii(img);
|
||||||
|
} else if let Some(map) = cli.map {
|
||||||
|
out = to_custom_ascii(map, img);
|
||||||
|
} else {
|
||||||
|
out = to_simple_ascii(img);
|
||||||
|
}
|
||||||
|
|
||||||
let out = to_simple_ascii(img);
|
//output
|
||||||
|
if let Some(output) = cli.output {
|
||||||
print_terminal(out);
|
print_file(out, output);
|
||||||
|
} else {
|
||||||
|
print_terminal(out, cli.colour);
|
||||||
|
}
|
||||||
|
|
||||||
//todo:
|
//todo:
|
||||||
/* function that converts image to braille (if -b)
|
/* function that converts image to braille (if -b)
|
||||||
* something about printing in colour
|
* something about printing in colour
|
||||||
* a function to let the user define a custom map
|
* output to file
|
||||||
*/
|
*/
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
pub fn print_terminal(ascii: Vec<String>) {
|
pub fn print_terminal(ascii: Vec<String>, in_colour: bool) {
|
||||||
for line in ascii {
|
for line in ascii {
|
||||||
println!("{}", line);
|
println!("{}", line);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn print_file(ascii: Vec<String>, out: PathBuf) {
|
pub fn print_file(ascii: Vec<String>, out: PathBuf) {
|
||||||
//todo: output
|
//todo: this
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue