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