Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 520d8ddd00 | |||
| bb92920e65 | |||
| f4d7e60a07 | |||
| c138c047ed | |||
| 8de99aefac |
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "img2ascii"
|
name = "img2ascii"
|
||||||
version = "1.0.0"
|
version = "1.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|||||||
13
README.md
13
README.md
@@ -6,6 +6,8 @@ It can be configured using flags on the command line, a few options of which are
|
|||||||
* Complex ASCII (using the map ``` .'`^",:;Il!i><~+_-?][}{1)(|\/tfjrxnuvczXYUJCLQ0OZmwqpdbkhao*#MW&8%B@$```)
|
* Complex ASCII (using the map ``` .'`^",:;Il!i><~+_-?][}{1)(|\/tfjrxnuvczXYUJCLQ0OZmwqpdbkhao*#MW&8%B@$```)
|
||||||
* [Braille symbols](https://en.wikipedia.org/wiki/Braille_Patterns)
|
* [Braille symbols](https://en.wikipedia.org/wiki/Braille_Patterns)
|
||||||
* Custom character maps (through the `--map` flag)
|
* Custom character maps (through the `--map` flag)
|
||||||
|
* Output in full colour
|
||||||
|
* Output in grayscale
|
||||||
|
|
||||||
# Prerequisites
|
# Prerequisites
|
||||||
* [Rust](https://www.rust-lang.org/) (building from source only)
|
* [Rust](https://www.rust-lang.org/) (building from source only)
|
||||||
@@ -32,6 +34,8 @@ Of course the output can be customized, by using one (or more) flags.
|
|||||||
## options
|
## options
|
||||||
* -c, --complex: uses the extended character map
|
* -c, --complex: uses the extended character map
|
||||||
* -C, --colour: Display ASCII art in full 24-bit colour
|
* -C, --colour: Display ASCII art in full 24-bit colour
|
||||||
|
* --background: Colour the background instead of the foreground
|
||||||
|
* -g, --grayscale: Display ASCII art in grayscale
|
||||||
* -b, --braille: Use braille characters instead of a character map
|
* -b, --braille: Use braille characters instead of a character map
|
||||||
* -d, --debug: Print debugging information
|
* -d, --debug: Print debugging information
|
||||||
* -f, --full: use the full width of the terminal, instead of fitting the image to the terminal dimensions
|
* -f, --full: use the full width of the terminal, instead of fitting the image to the terminal dimensions
|
||||||
@@ -47,14 +51,19 @@ When two or more of these are entered in the same command,
|
|||||||
the program uses the one with the highest precedence, in the order
|
the program uses the one with the highest precedence, in the order
|
||||||
`braille > complex > map`.
|
`braille > complex > map`.
|
||||||
|
|
||||||
The flags `--output` and `--colour` also conflict.
|
The flags `--output`, `--colour` and `--grayscale` also conflict.
|
||||||
When both are entered, the flag `--output` takes precedence
|
When both are entered, the flag `--output` takes precedence
|
||||||
(leading to a simple txt file).
|
(leading to a simple txt file).
|
||||||
|
|
||||||
Lastly, the flags `--full` and `--width` are mutually exclusive.
|
The flags `--full` and `--width` are mutually exclusive.
|
||||||
When both are entered, the flag `-full` will be applied
|
When both are entered, the flag `-full` will be applied
|
||||||
(`full > width`).
|
(`full > width`).
|
||||||
|
|
||||||
|
Lastly, the flags `--colour` and `--grayscale` are not mutually applicable.
|
||||||
|
When both are entered, the flag `--colour` will be applied.
|
||||||
|
|
||||||
|
Note also that the `--background` flag requires either `--colour` or `--grayscale` to do anything.
|
||||||
|
|
||||||
# Documentation
|
# Documentation
|
||||||
The program has been documented with RustDoc,
|
The program has been documented with RustDoc,
|
||||||
which can be compiled and viewed with
|
which can be compiled and viewed with
|
||||||
|
|||||||
@@ -36,8 +36,10 @@ 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.2) as f32-1.0)/255f32 * l) as usize];
|
let mut ascii = Ascii::new(0, pixel.2[0], pixel.2[1], pixel.2[2]);
|
||||||
str.push(Ascii::new(ch, pixel.2[0], pixel.2[1], pixel.2[2]));
|
let ch = char_map.as_bytes()[((ascii.col_depth as f32-1.0)/255f32 * l) as usize];
|
||||||
|
ascii.char = char::from(ch);
|
||||||
|
str.push(ascii);
|
||||||
|
|
||||||
if pixel.0 == image.width()-1 {
|
if pixel.0 == image.width()-1 {
|
||||||
out.push(str);
|
out.push(str);
|
||||||
@@ -116,7 +118,7 @@ pub fn to_braille_ascii(image: DynamicImage, threshold: u8) -> Vec<Vec<Ascii>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
str.push(Ascii { char: char::from_u32(braille_value).unwrap(), rgb: [(r/8) as u8, (g/8) as u8, (b/8) as u8] });
|
str.push(Ascii::new_with_char(char::from_u32(braille_value).unwrap(), (r/8) as u8, (g/8) as u8, (b/8) as u8));
|
||||||
}
|
}
|
||||||
out.push(str);
|
out.push(str);
|
||||||
str = Vec::new();
|
str = Vec::new();
|
||||||
|
|||||||
16
src/cli.rs
16
src/cli.rs
@@ -18,8 +18,20 @@ pub struct Cli {
|
|||||||
#[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
|
||||||
|
///
|
||||||
|
/// Takes priority over '--grayscale'
|
||||||
#[arg(short = 'C', long)]
|
#[arg(short = 'C', long)]
|
||||||
pub colour: bool,
|
pub colour: bool,
|
||||||
|
/// Colour the background instead of the foreground
|
||||||
|
///
|
||||||
|
/// Requires '--colour' or '--grayscale' to be passed
|
||||||
|
#[arg(long)]
|
||||||
|
pub background: bool,
|
||||||
|
/// Display ASCII art in grayscale
|
||||||
|
///
|
||||||
|
/// incompatible with '--color'
|
||||||
|
#[arg(short= 'g', long)]
|
||||||
|
pub grayscale: bool,
|
||||||
/// Use braille characters instead of ASCII
|
/// Use braille characters instead of ASCII
|
||||||
///
|
///
|
||||||
/// Takes priority over '--complex' and '--map'
|
/// Takes priority over '--complex' and '--map'
|
||||||
@@ -49,7 +61,7 @@ pub struct Cli {
|
|||||||
pub width: Option<u32>,
|
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'
|
/// Incompatible with '--colour' and '--grayscale'
|
||||||
#[arg(short = 'o', long = "output")]
|
#[arg(short = 'o', long = "output")]
|
||||||
pub output: Option<PathBuf>,
|
pub output: Option<PathBuf>,
|
||||||
}
|
}
|
||||||
@@ -62,6 +74,8 @@ impl Cli {
|
|||||||
pub fn debug_print(&self) {
|
pub fn debug_print(&self) {
|
||||||
debug!("complex: {}", self.complex);
|
debug!("complex: {}", self.complex);
|
||||||
debug!("colour: {}", self.colour);
|
debug!("colour: {}", self.colour);
|
||||||
|
debug!("background: {}", self.background);
|
||||||
|
debug!("grayscale: {}", self.grayscale);
|
||||||
debug!("braille: {}", self.braille);
|
debug!("braille: {}", self.braille);
|
||||||
debug!("debug: {}", self.debug);
|
debug!("debug: {}", self.debug);
|
||||||
debug!("full: {}", self.full);
|
debug!("full: {}", self.full);
|
||||||
|
|||||||
@@ -45,6 +45,10 @@ fn main() {
|
|||||||
if let Some(output) = cli.output {
|
if let Some(output) = cli.output {
|
||||||
print_file(out, output);
|
print_file(out, output);
|
||||||
} else {
|
} else {
|
||||||
print_terminal(out, cli.colour);
|
if cli.background && (cli.colour || cli.grayscale) {
|
||||||
|
print_terminal_background(out, cli.colour, cli.grayscale);
|
||||||
|
} else {
|
||||||
|
print_terminal(out, cli.colour, cli.grayscale);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,15 @@
|
|||||||
//! This module contains the Ascii struct.
|
//! This module contains the Ascii struct.
|
||||||
|
|
||||||
/// This struct represents one character + rgb colour.
|
/// This struct represents one character + rgb colour.
|
||||||
|
///
|
||||||
|
/// attributes:
|
||||||
|
/// char: char - the character associated with this ASCII value
|
||||||
|
/// rgb: [u8; 3] - vec of 3 u8 values representing red, green, and blue respectively
|
||||||
|
/// col_depthL u8 - the depth of the rgb values, calculated through the luminosity method
|
||||||
pub struct Ascii {
|
pub struct Ascii {
|
||||||
pub char: char,
|
pub char: char,
|
||||||
pub rgb: [u8; 3],
|
pub rgb: [u8; 3],
|
||||||
|
pub col_depth: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Ascii {
|
impl Ascii {
|
||||||
@@ -21,6 +27,25 @@ impl Ascii {
|
|||||||
Ascii {
|
Ascii {
|
||||||
char: char::from(ch),
|
char: char::from(ch),
|
||||||
rgb: [r, g, b],
|
rgb: [r, g, b],
|
||||||
|
col_depth: (r as f32 * 0.3 + g as f32 * 0.59 + b as f32 * 0.11) as u8,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This function creates a new Ascii instance.
|
||||||
|
///
|
||||||
|
/// Arguments:
|
||||||
|
/// ch: char - the character
|
||||||
|
/// r: u8 - Red colour value
|
||||||
|
/// g: u8 - Green colour value
|
||||||
|
/// b: u8 - Blue colour value
|
||||||
|
///
|
||||||
|
/// returns:
|
||||||
|
/// self
|
||||||
|
pub fn new_with_char(ch: char, r: u8, g: u8, b: u8) -> Self {
|
||||||
|
Ascii {
|
||||||
|
char: ch,
|
||||||
|
rgb: [r, g, b],
|
||||||
|
col_depth: (r as f32 * 0.3 + g as f32 * 0.59 + b as f32 * 0.11) as u8,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4,7 +4,7 @@ use std::io::{stdout, Write};
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::process::exit;
|
use std::process::exit;
|
||||||
use crossterm::execute;
|
use crossterm::execute;
|
||||||
use crossterm::style::{Color, SetForegroundColor, Print, ResetColor};
|
use crossterm::style::{Color, SetForegroundColor, SetBackgroundColor, Print, ResetColor};
|
||||||
use log::error;
|
use log::error;
|
||||||
use crate::model_rgb_ascii::Ascii;
|
use crate::model_rgb_ascii::Ascii;
|
||||||
|
|
||||||
@@ -13,7 +13,8 @@ use crate::model_rgb_ascii::Ascii;
|
|||||||
/// arguments:
|
/// arguments:
|
||||||
/// art: Vec<Vec<Ascii>> - vector of vectors representing the art
|
/// art: Vec<Vec<Ascii>> - vector of vectors representing the art
|
||||||
/// in_colour: bool - whether to print in colour or as hard white
|
/// in_colour: bool - whether to print in colour or as hard white
|
||||||
pub fn print_terminal(art: Vec<Vec<Ascii>>, in_colour: bool) {
|
/// grayscale: bool - whether to print grayscale
|
||||||
|
pub fn print_terminal(art: Vec<Vec<Ascii>>, in_colour: bool, grayscale: bool) {
|
||||||
for line in art {
|
for line in art {
|
||||||
for ascii in line {
|
for ascii in line {
|
||||||
if in_colour {
|
if in_colour {
|
||||||
@@ -21,6 +22,11 @@ pub fn print_terminal(art: Vec<Vec<Ascii>>, in_colour: bool) {
|
|||||||
SetForegroundColor(Color::Rgb {r: ascii.rgb[0], g: ascii.rgb[1], b: ascii.rgb[2]}),
|
SetForegroundColor(Color::Rgb {r: ascii.rgb[0], g: ascii.rgb[1], b: ascii.rgb[2]}),
|
||||||
Print(ascii.char),
|
Print(ascii.char),
|
||||||
ResetColor);
|
ResetColor);
|
||||||
|
} else if grayscale {
|
||||||
|
let _ = execute!(stdout(),
|
||||||
|
SetForegroundColor(Color::Rgb {r: ascii.col_depth, g: ascii.col_depth, b: ascii.col_depth}),
|
||||||
|
Print(ascii.char),
|
||||||
|
ResetColor);
|
||||||
} else {
|
} else {
|
||||||
print!("{}", ascii.char);
|
print!("{}", ascii.char);
|
||||||
}
|
}
|
||||||
@@ -29,6 +35,36 @@ pub fn print_terminal(art: Vec<Vec<Ascii>>, in_colour: bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This function prints ASCII art to the background of stdout.
|
||||||
|
///
|
||||||
|
/// arguments:
|
||||||
|
/// art: Vec<Vec<Ascii>> - vector of vectors representing the art
|
||||||
|
/// in_colour: bool - whether to print in colour
|
||||||
|
/// grayscale: bool - whether to print grayscale
|
||||||
|
pub fn print_terminal_background(art: Vec<Vec<Ascii>>, in_colour: bool, grayscale: bool) {
|
||||||
|
for line in art {
|
||||||
|
for ascii in line {
|
||||||
|
if in_colour {
|
||||||
|
let _ = execute!(stdout(),
|
||||||
|
SetBackgroundColor(Color::Rgb {r: ascii.rgb[0], g: ascii.rgb[1], b: ascii.rgb[2]}),
|
||||||
|
SetForegroundColor(Color::Rgb {r: 255-ascii.rgb[0], g: 255-ascii.rgb[1], b: 255-ascii.rgb[2]}),
|
||||||
|
Print(ascii.char),
|
||||||
|
ResetColor);
|
||||||
|
} else if grayscale {
|
||||||
|
let _ = execute!(stdout(),
|
||||||
|
SetBackgroundColor(Color::Rgb {r: ascii.col_depth, g: ascii.col_depth, b: ascii.col_depth}),
|
||||||
|
SetForegroundColor(Color::Rgb {r: 255-ascii.col_depth, g: 255-ascii.col_depth, b: 255-ascii.col_depth}),
|
||||||
|
Print(ascii.char),
|
||||||
|
ResetColor);
|
||||||
|
} else {
|
||||||
|
error!("This should be unreachable!");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// This function prints ASCII art to a file.
|
/// This function prints ASCII art to a file.
|
||||||
///
|
///
|
||||||
/// arguments:
|
/// arguments:
|
||||||
|
|||||||
Reference in New Issue
Block a user