Initial commit
This commit is contained in:
commit
049177604f
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
/target
|
1196
Cargo.lock
generated
Normal file
1196
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
10
Cargo.toml
Normal file
10
Cargo.toml
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
[package]
|
||||||
|
name = "yabinary"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
clap = { version = "4.5.9", features = ["derive"] }
|
||||||
|
image = "0.25.2"
|
107
src/main.rs
Normal file
107
src/main.rs
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
use clap::{Parser, ValueEnum};
|
||||||
|
use image::ImageReader;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::{Read, Write};
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
const WHITE: u8 = 0x88;
|
||||||
|
const BLACK: u8 = 0xCC;
|
||||||
|
const SCREEN_WIDTH: usize = 16;
|
||||||
|
|
||||||
|
#[derive(ValueEnum, Clone, Copy)]
|
||||||
|
enum Color {
|
||||||
|
White,
|
||||||
|
Black,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Color {
|
||||||
|
fn as_bytes(&self) -> u8 {
|
||||||
|
match self {
|
||||||
|
Color::White => WHITE,
|
||||||
|
Color::Black => BLACK,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for Color {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
Self::White => f.write_str("white"),
|
||||||
|
Self::Black => f.write_str("black"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Parser)]
|
||||||
|
struct Cli {
|
||||||
|
#[arg(long, requires_all=["header_lines"])]
|
||||||
|
header_from: Option<PathBuf>,
|
||||||
|
|
||||||
|
#[arg(long)]
|
||||||
|
header_lines: Option<usize>,
|
||||||
|
|
||||||
|
image: PathBuf,
|
||||||
|
|
||||||
|
#[arg(long, requires_all=["footer_lines"])]
|
||||||
|
footer_from: Option<PathBuf>,
|
||||||
|
|
||||||
|
#[arg(long)]
|
||||||
|
footer_lines: Option<usize>,
|
||||||
|
|
||||||
|
#[arg(long, default_value_t = Color::White)]
|
||||||
|
background: Color,
|
||||||
|
|
||||||
|
output: PathBuf,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let c = Cli::parse();
|
||||||
|
|
||||||
|
let img = ImageReader::open(c.image)?.decode()?;
|
||||||
|
|
||||||
|
if SCREEN_WIDTH < img.width() as usize {
|
||||||
|
println!(
|
||||||
|
"WARN: {} pixels are ignored",
|
||||||
|
img.width() as usize - SCREEN_WIDTH
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut output = File::create(&c.output)?;
|
||||||
|
|
||||||
|
if let Some(header_path) = c.header_from {
|
||||||
|
let mut buffer = vec![0; c.header_lines.unwrap() * SCREEN_WIDTH];
|
||||||
|
File::open(header_path)?.read_exact(&mut buffer)?;
|
||||||
|
output.write(&buffer)?;
|
||||||
|
};
|
||||||
|
|
||||||
|
for row in img.to_rgba8().rows() {
|
||||||
|
let buffer: Vec<_> = (0..SCREEN_WIDTH)
|
||||||
|
.into_iter()
|
||||||
|
.zip(
|
||||||
|
row.into_iter()
|
||||||
|
.map(|v| {
|
||||||
|
let brightness =
|
||||||
|
(v[0] as f32 / 256.0 + v[1] as f32 / 256.0 + v[2] as f32 / 256.0) / 3.0;
|
||||||
|
|
||||||
|
if brightness > 0.2 {
|
||||||
|
Color::White
|
||||||
|
} else {
|
||||||
|
Color::Black
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.chain(std::iter::repeat(c.background)),
|
||||||
|
)
|
||||||
|
.map(|(_, color)| color.as_bytes())
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
output.write(&buffer)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(footer_path) = c.footer_from {
|
||||||
|
let mut buffer = vec![0; c.footer_lines.unwrap() * SCREEN_WIDTH];
|
||||||
|
File::open(footer_path)?.read_exact(&mut buffer)?;
|
||||||
|
output.write(&buffer)?;
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user