Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Style options #9

Merged
merged 1 commit into from
Dec 1, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
55 changes: 53 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion asciic/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
clap = "3.2.22"
clap = { version = "3.2.22", features = ["derive"] }
ctrlc = { version = "3.2.3", features = ["termination"] }
image = "0.24.4"
rayon = "1.5.3"
Expand Down
79 changes: 79 additions & 0 deletions asciic/src/cli.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
use std::path::PathBuf;

use clap::{value_parser, Arg, Command};

use crate::primitives::{OutputSize, PaintStyle};

#[inline]
pub fn cli() -> Command<'static> {
Command::new("asciic")
.version("0.3.0")
.about("An asciinema compiler")
.author("by S0ra")
.args(args())
}

#[inline]
fn args() -> [Arg<'static>; 10] {
[
Arg::new("video")
.required_unless_present("image")
.conflicts_with("image")
.index(1)
.help("Input video to transform in asciinema")
.takes_value(true),
Arg::new("output")
.value_parser(value_parser!(PathBuf))
.default_value("output")
.conflicts_with("image")
.help("Output file name")
.index(2),
Arg::new("frame-size")
.short('s')
.default_value("216x56")
.long("size")
.takes_value(true)
.required(false)
.help("The ratio that each frame should be resized")
.value_parser(value_parser!(OutputSize)),
Arg::new("image")
.short('i')
.long("image")
.takes_value(true)
.help("Compiles a single image"),
Arg::new("colorize").short('c').help("Colorize output"),
Arg::new("no-compression")
.short('n')
.long("skip-compression")
.help("Disables compression on colored outputs")
.requires("colorize"),
Arg::new("compression-threshold")
.short('t')
.long("threshold")
.default_value("10")
.requires("colorize")
.takes_value(true)
.value_parser(value_parser!(u8))
.help("Manually sets the compression threshold"),
Arg::new("ffmpeg-flags")
.index(3)
.multiple_occurrences(true)
.allow_hyphen_values(true)
.takes_value(true)
.conflicts_with("image")
.multiple_values(true)
.value_parser(value_parser!(String))
.help("Pass extra flags to ffmpeg")
.last(true),
Arg::new("no-audio")
.long("no-audio")
.help("Skips audio generation")
.conflicts_with("image"),
Arg::new("style")
.takes_value(true)
.long("style")
.help("Sets a style to follow when generating frames")
.default_value("bg-only")
.value_parser(value_parser!(PaintStyle)),
]
}
28 changes: 21 additions & 7 deletions asciic/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#![warn(clippy::pedantic)]
#![allow(clippy::struct_excessive_bools)] // Allowing since struct Options is not a state machine.

use std::{
error::Error,
Expand All @@ -17,11 +16,17 @@ use image::{imageops::FilterType, io::Reader, GenericImageView, ImageError};
use rayon::iter::{IntoParallelIterator, ParallelIterator};
use tar::Builder;
use tempfile::TempDir;
use util::{add_file, cli, ffmpeg, max_sub, Options, OutputSize};
use zstd::encode_all;

use crate::util::{clean, clean_abort, pause};
use cli::cli;
use primitives::{
Options, OutputSize,
PaintStyle::{self, BgOnly, BgPaint, FgPaint},
};
use util::{add_file, clean, clean_abort, ffmpeg, max_sub, pause};

mod cli;
mod primitives;
mod util;

fn main() -> Result<(), Box<dyn Error>> {
Expand All @@ -31,7 +36,7 @@ fn main() -> Result<(), Box<dyn Error>> {
redimension: *matches.get_one::<OutputSize>("frame-size").unwrap(),
colorize: matches.contains_id("colorize"),
skip_compression: matches.contains_id("no-compression"),
paint_fg: matches.contains_id("paint-fg"),
style: *matches.get_one::<PaintStyle>("style").unwrap(),
compression_threshold: *matches.get_one::<u8>("compression-threshold").unwrap(),
skip_audio: matches.contains_id("no-audio"),
};
Expand Down Expand Up @@ -222,11 +227,20 @@ fn process_image(image: &PathBuf, options: Options) -> Result<String, ImageError
{
res.push_str(&format!(
"\x1b[{}8;2;{r};{g};{b}m{}",
if options.paint_fg { 3 } else { 4 },
$input
match options.style {
BgPaint | BgOnly => 4,
FgPaint => 3,
},
match options.style {
BgPaint | FgPaint => $input,
BgOnly => ' ',
}
));
} else {
res.push($input);
res.push(match options.style {
BgPaint | FgPaint => $input,
BgOnly => ' ',
});
}
};
}
Expand Down
75 changes: 75 additions & 0 deletions asciic/src/primitives.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
use clap::{
builder::{TypedValueParser, ValueParserFactory},
ErrorKind, ValueEnum,
};

#[derive(Clone, Copy)]
pub struct Options {
pub compression_threshold: u8,
pub redimension: OutputSize,
pub skip_compression: bool,
pub style: PaintStyle,
pub colorize: bool,
pub skip_audio: bool,
}

#[derive(Clone, Copy, Debug, ValueEnum)]
pub enum PaintStyle {
FgPaint,
BgPaint,
BgOnly,
}

#[derive(Debug, Clone, Copy)]
pub struct OutputSize(pub u32, pub u32);
impl ValueParserFactory for OutputSize {
type Parser = OutputSizeParser;

fn value_parser() -> Self::Parser {
OutputSizeParser
}
}

#[derive(Debug, Clone, Copy)]
pub struct OutputSizeParser;
impl TypedValueParser for OutputSizeParser {
type Value = OutputSize;

fn parse_ref(
&self,
cmd: &clap::Command,
_: Option<&clap::Arg>,
value: &std::ffi::OsStr,
) -> Result<Self::Value, clap::Error> {
let value = value
.to_str()
.ok_or_else(|| {
cmd.clone()
.error(ErrorKind::InvalidUtf8, "Not UTF8, try 216x56.")
})?
.to_ascii_lowercase();

let vals = value.split('x').collect::<Vec<_>>();
if vals.len() != 2 {
return Err(cmd
.clone()
.error(ErrorKind::InvalidValue, "Wrong pattern, try 216x56."));
}
let output_size = OutputSize(
vals.first()
.unwrap()
.parse::<u32>()
.map_err(|e| cmd.clone().error(ErrorKind::InvalidValue, e.to_string()))?,
vals.last()
.unwrap()
.parse::<u32>()
.map_err(|e| cmd.clone().error(ErrorKind::InvalidValue, e.to_string()))?,
);

if output_size.0 > 400 || output_size.1 > 200 {
println!("WARN: Usually going too high on frame size makes stuff a bit wonky.");
}

Ok(output_size)
}
}